Compare commits
7 Commits
16b10dc1b7
...
v122113101
Author | SHA1 | Date | |
---|---|---|---|
|
e36189e2e7 | ||
|
d6bdf510a4 | ||
|
a464e93370 | ||
4b63afe62a | |||
ac4c4b9441 | |||
02d734eee8 | |||
c5cdfc0d53 |
@@ -6,6 +6,7 @@ plugins {
|
|||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
kotlin("android")
|
kotlin("android")
|
||||||
kotlin("kapt")
|
kotlin("kapt")
|
||||||
|
id("com.mikepenz.aboutlibraries.plugin")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Project.execWithOutput(cmd: String, ignore: Boolean = false): String {
|
fun Project.execWithOutput(cmd: String, ignore: Boolean = false): String {
|
||||||
@@ -62,7 +63,7 @@ android {
|
|||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "11"
|
jvmTarget = "11"
|
||||||
}
|
}
|
||||||
compileSdk = 32
|
compileSdk = 33
|
||||||
buildToolsVersion = "31.0.0"
|
buildToolsVersion = "31.0.0"
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
@@ -70,7 +71,7 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "bou.amine.apps.readerforselfossv2.android"
|
applicationId = "bou.amine.apps.readerforselfossv2.android"
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 32
|
targetSdk = 33
|
||||||
versionCode = versionCodeFromGit()
|
versionCode = versionCodeFromGit()
|
||||||
versionName = versionNameFromGit()
|
versionName = versionNameFromGit()
|
||||||
|
|
||||||
@@ -138,9 +139,8 @@ dependencies {
|
|||||||
implementation("androidx.multidex:multidex:2.0.1")
|
implementation("androidx.multidex:multidex:2.0.1")
|
||||||
|
|
||||||
// About
|
// About
|
||||||
implementation("com.mikepenz:aboutlibraries-core:8.9.4")
|
implementation("com.mikepenz:aboutlibraries-core:10.5.1")
|
||||||
implementation("com.mikepenz:aboutlibraries:8.9.4")
|
implementation("com.mikepenz:aboutlibraries:10.5.1")
|
||||||
implementation("com.mikepenz:aboutlibraries-definitions:8.9.4")
|
|
||||||
|
|
||||||
// Retrofit + http logging + okhttp
|
// Retrofit + http logging + okhttp
|
||||||
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||||
@@ -209,4 +209,14 @@ tasks.withType<Test> {
|
|||||||
)
|
)
|
||||||
showStandardStreams = true
|
showStandardStreams = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aboutLibraries {
|
||||||
|
offlineMode = true
|
||||||
|
fetchRemoteLicense = false
|
||||||
|
fetchRemoteFunding = false
|
||||||
|
includePlatform = false
|
||||||
|
strictMode = com.mikepenz.aboutlibraries.plugin.StrictMode.FAIL
|
||||||
|
duplicationMode = com.mikepenz.aboutlibraries.plugin.DuplicateMode.MERGE
|
||||||
|
duplicationRule = com.mikepenz.aboutlibraries.plugin.DuplicateRule.GROUP
|
||||||
}
|
}
|
@@ -18,6 +18,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.core.view.doOnNextLayout
|
import androidx.core.view.doOnNextLayout
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.*
|
import androidx.recyclerview.widget.*
|
||||||
import androidx.work.Constraints
|
import androidx.work.Constraints
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy
|
import androidx.work.ExistingPeriodicWorkPolicy
|
||||||
@@ -178,8 +179,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
adapter.handleItemAtIndex(position)
|
adapter.handleItemAtIndex(position)
|
||||||
|
|
||||||
reloadBadgeContent()
|
|
||||||
|
|
||||||
val tagHashes = i.tags.map { it.longHash() }
|
val tagHashes = i.tags.map { it.longHash() }
|
||||||
tagsBadge = tagsBadge.map {
|
tagsBadge = tagsBadge.map {
|
||||||
if (tagHashes.contains(it.key)) {
|
if (tagHashes.contains(it.key)) {
|
||||||
@@ -207,6 +206,16 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(binding.recyclerView)
|
ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(binding.recyclerView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateBottomBarBadgeCount(badge: TextBadgeItem, count: Int) {
|
||||||
|
if (count > 0) {
|
||||||
|
badge
|
||||||
|
.setText(count.toString())
|
||||||
|
.maybeShow()
|
||||||
|
} else {
|
||||||
|
badge.removeBadge()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleBottomBar() {
|
private fun handleBottomBar() {
|
||||||
|
|
||||||
tabNewBadge = TextBadgeItem()
|
tabNewBadge = TextBadgeItem()
|
||||||
@@ -219,6 +228,28 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
.setText("")
|
.setText("")
|
||||||
.setHideOnSelect(false).hide(false)
|
.setHideOnSelect(false).hide(false)
|
||||||
|
|
||||||
|
if (appSettingsService.isDisplayUnreadCountEnabled()) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
repository.badgeUnread.collect {
|
||||||
|
updateBottomBarBadgeCount(tabNewBadge, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (appSettingsService.isDisplayAllCountEnabled()) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
repository.badgeAll.collect {
|
||||||
|
updateBottomBarBadgeCount(tabArchiveBadge, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
repository.badgeStarred.collect {
|
||||||
|
updateBottomBarBadgeCount(tabStarredBadge, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val tabNew =
|
val tabNew =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
R.drawable.ic_tab_fiber_new_black_24dp,
|
R.drawable.ic_tab_fiber_new_black_24dp,
|
||||||
@@ -714,29 +745,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private fun reloadBadges() {
|
private fun reloadBadges() {
|
||||||
if (appSettingsService.isDisplayUnreadCountEnabled() || appSettingsService.isDisplayAllCountEnabled()) {
|
if (appSettingsService.isDisplayUnreadCountEnabled() || appSettingsService.isDisplayAllCountEnabled()) {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.reloadBadges()
|
repository.reloadBadges()
|
||||||
reloadBadgeContent()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reloadBadgeContent() {
|
|
||||||
if (appSettingsService.isDisplayUnreadCountEnabled()) {
|
|
||||||
tabNewBadge
|
|
||||||
.setText(repository.badgeUnread.toString())
|
|
||||||
.maybeShow()
|
|
||||||
}
|
|
||||||
if (appSettingsService.isDisplayAllCountEnabled()) {
|
|
||||||
tabArchiveBadge
|
|
||||||
.setText(repository.badgeAll.toString())
|
|
||||||
.maybeShow()
|
|
||||||
tabStarredBadge
|
|
||||||
.setText(repository.badgeStarred.toString())
|
|
||||||
.maybeShow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun reloadTagsBadges() {
|
private fun reloadTagsBadges() {
|
||||||
tagsBadge.forEach {
|
tagsBadge.forEach {
|
||||||
binding.mainDrawer.updateBadge(it.key, StringHolder(it.value.toString()))
|
binding.mainDrawer.updateBadge(it.key, StringHolder(it.value.toString()))
|
||||||
@@ -858,10 +872,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private fun maxItemNumber(): Int =
|
private fun maxItemNumber(): Int =
|
||||||
when (elementsShown) {
|
when (elementsShown) {
|
||||||
ItemType.UNREAD -> repository.badgeUnread
|
ItemType.UNREAD -> repository.badgeUnread.value
|
||||||
ItemType.ALL -> repository.badgeAll
|
ItemType.ALL -> repository.badgeAll.value
|
||||||
ItemType.STARRED -> repository.badgeStarred
|
ItemType.STARRED -> repository.badgeStarred.value
|
||||||
else -> repository.badgeUnread // if !elementsShown then unread are fetched.
|
else -> repository.badgeUnread.value // if !elementsShown then unread are fetched.
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateItems(adapterItems: ArrayList<SelfossModel.Item>) {
|
private fun updateItems(adapterItems: ArrayList<SelfossModel.Item>) {
|
||||||
|
@@ -36,9 +36,9 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
|
|
||||||
private fun showMenuItem(willAddToFavorite: Boolean) {
|
private fun showMenuItem(willAddToFavorite: Boolean) {
|
||||||
if (willAddToFavorite) {
|
if (willAddToFavorite) {
|
||||||
toolbarMenu.findItem(R.id.star).icon.setTint(Color.WHITE)
|
toolbarMenu.findItem(R.id.star).icon?.setTint(Color.WHITE)
|
||||||
} else {
|
} else {
|
||||||
toolbarMenu.findItem(R.id.star).icon.setTint(Color.RED)
|
toolbarMenu.findItem(R.id.star).icon?.setTint(Color.RED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -111,13 +111,11 @@ class ItemCardAdapter(
|
|||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.unstarr(item)
|
repository.unstarr(item)
|
||||||
}
|
}
|
||||||
item.starred = false
|
|
||||||
binding.favButton.isSelected = false
|
binding.favButton.isSelected = false
|
||||||
} else {
|
} else {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.starr(item)
|
repository.starr(item)
|
||||||
}
|
}
|
||||||
item.starred = true
|
|
||||||
binding.favButton.isSelected = true
|
binding.favButton.isSelected = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -389,7 +389,7 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val gestureDetector = GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() {
|
val gestureDetector = GestureDetector(activity, object : GestureDetector.SimpleOnGestureListener() {
|
||||||
override fun onSingleTapUp(e: MotionEvent?): Boolean {
|
override fun onSingleTapUp(e: MotionEvent): Boolean {
|
||||||
return performClick()
|
return performClick()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@@ -299,9 +299,9 @@ class RepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertSame(true, success)
|
assertSame(true, success)
|
||||||
assertSame(NUMBER_ARTICLES, repository.badgeAll)
|
assertEquals(NUMBER_ARTICLES, repository.badgeAll.value)
|
||||||
assertSame(NUMBER_UNREAD, repository.badgeUnread)
|
assertEquals(NUMBER_UNREAD, repository.badgeUnread.value)
|
||||||
assertSame(NUMBER_STARRED, repository.badgeStarred)
|
assertEquals(NUMBER_STARRED, repository.badgeStarred.value)
|
||||||
coVerify(atLeast = 1) { api.stats() }
|
coVerify(atLeast = 1) { api.stats() }
|
||||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
||||||
}
|
}
|
||||||
@@ -318,9 +318,9 @@ class RepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertSame(false, success)
|
assertSame(false, success)
|
||||||
assertSame(0, repository.badgeAll)
|
assertSame(0, repository.badgeAll.value)
|
||||||
assertSame(0, repository.badgeUnread)
|
assertSame(0, repository.badgeUnread.value)
|
||||||
assertSame(0, repository.badgeStarred)
|
assertSame(0, repository.badgeStarred.value)
|
||||||
coVerify(atLeast = 1) { api.stats() }
|
coVerify(atLeast = 1) { api.stats() }
|
||||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
||||||
}
|
}
|
||||||
@@ -338,9 +338,9 @@ class RepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(success)
|
assertTrue(success)
|
||||||
assertSame(1, repository.badgeAll)
|
assertEquals(1, repository.badgeAll.value)
|
||||||
assertSame(1, repository.badgeUnread)
|
assertEquals(1, repository.badgeUnread.value)
|
||||||
assertSame(1, repository.badgeStarred)
|
assertEquals(1, repository.badgeStarred.value)
|
||||||
coVerify(exactly = 0) { api.stats() }
|
coVerify(exactly = 0) { api.stats() }
|
||||||
verify(atLeast = 1) { db.itemsQueries.items().executeAsList() }
|
verify(atLeast = 1) { db.itemsQueries.items().executeAsList() }
|
||||||
}
|
}
|
||||||
@@ -358,9 +358,9 @@ class RepositoryTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertFalse(success)
|
assertFalse(success)
|
||||||
assertSame(0, repository.badgeAll)
|
assertSame(0, repository.badgeAll.value)
|
||||||
assertSame(0, repository.badgeUnread)
|
assertSame(0, repository.badgeUnread.value)
|
||||||
assertSame(0, repository.badgeStarred)
|
assertSame(0, repository.badgeStarred.value)
|
||||||
coVerify(exactly = 0) { api.stats() }
|
coVerify(exactly = 0) { api.stats() }
|
||||||
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
verify(exactly = 0) { db.itemsQueries.items().executeAsList() }
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,7 @@ plugins {
|
|||||||
kotlin("android").version("1.7.20").apply(false)
|
kotlin("android").version("1.7.20").apply(false)
|
||||||
kotlin("multiplatform").version("1.7.20").apply(false)
|
kotlin("multiplatform").version("1.7.20").apply(false)
|
||||||
id("org.sonarqube").version("3.4.0.2513").apply(false)
|
id("org.sonarqube").version("3.4.0.2513").apply(false)
|
||||||
|
id("com.mikepenz.aboutlibraries.plugin").version("10.5.1").apply(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(plugin = "org.sonarqube")
|
apply(plugin = "org.sonarqube")
|
||||||
|
@@ -10,6 +10,7 @@ import io.github.aakira.napier.Napier
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class Repository(private val api: SelfossApi, private val appSettingsService: AppSettingsService, val isConnectionAvailable: MutableStateFlow<Boolean>, private val db: ReaderForSelfossDB) {
|
class Repository(private val api: SelfossApi, private val appSettingsService: AppSettingsService, val isConnectionAvailable: MutableStateFlow<Boolean>, private val db: ReaderForSelfossDB) {
|
||||||
@@ -27,12 +28,12 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
|
|
||||||
var offlineOverride = false
|
var offlineOverride = false
|
||||||
|
|
||||||
var badgeUnread = 0
|
private val _badgeUnread = MutableStateFlow(0)
|
||||||
set(value) {field = if (value < 0) { 0 } else { value } }
|
val badgeUnread = _badgeUnread.asStateFlow()
|
||||||
var badgeAll = 0
|
private val _badgeAll = MutableStateFlow(0)
|
||||||
set(value) {field = if (value < 0) { 0 } else { value } }
|
val badgeAll = _badgeAll.asStateFlow()
|
||||||
var badgeStarred = 0
|
private val _badgeStarred = MutableStateFlow(0)
|
||||||
set(value) {field = if (value < 0) { 0 } else { value } }
|
val badgeStarred = _badgeStarred.asStateFlow()
|
||||||
|
|
||||||
private var fetchedSources = false
|
private var fetchedSources = false
|
||||||
private var fetchedTags = false
|
private var fetchedTags = false
|
||||||
@@ -125,17 +126,17 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
if (isNetworkAvailable()) {
|
if (isNetworkAvailable()) {
|
||||||
val response = api.stats()
|
val response = api.stats()
|
||||||
if (response.success && response.data != null) {
|
if (response.success && response.data != null) {
|
||||||
badgeUnread = response.data.unread
|
_badgeUnread.value = response.data.unread
|
||||||
badgeAll = response.data.total
|
_badgeAll.value = response.data.total
|
||||||
badgeStarred = response.data.starred
|
_badgeStarred.value = response.data.starred
|
||||||
success = true
|
success = true
|
||||||
}
|
}
|
||||||
} else if (appSettingsService.isItemCachingEnabled()) {
|
} else if (appSettingsService.isItemCachingEnabled()) {
|
||||||
// TODO: do this differently, because it's not efficient
|
// TODO: do this differently, because it's not efficient
|
||||||
val dbItems = getDBItems()
|
val dbItems = getDBItems()
|
||||||
badgeUnread = dbItems.filter { item -> item.unread }.size
|
_badgeUnread.value = dbItems.filter { item -> item.unread }.size
|
||||||
badgeStarred = dbItems.filter { item -> item.starred }.size
|
_badgeStarred.value = dbItems.filter { item -> item.starred }.size
|
||||||
badgeAll = dbItems.size
|
_badgeAll.value = dbItems.size
|
||||||
success = true
|
success = true
|
||||||
}
|
}
|
||||||
return success
|
return success
|
||||||
@@ -283,7 +284,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
private fun markAsReadLocally(item: SelfossModel.Item) {
|
private fun markAsReadLocally(item: SelfossModel.Item) {
|
||||||
if (item.unread) {
|
if (item.unread) {
|
||||||
item.unread = false
|
item.unread = false
|
||||||
badgeUnread -= 1
|
_badgeUnread.value -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@@ -294,7 +295,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
private fun unmarkAsReadLocally(item: SelfossModel.Item) {
|
private fun unmarkAsReadLocally(item: SelfossModel.Item) {
|
||||||
if (!item.unread) {
|
if (!item.unread) {
|
||||||
item.unread = true
|
item.unread = true
|
||||||
badgeUnread += 1
|
_badgeUnread.value += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@@ -305,7 +306,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
private fun starrLocally(item: SelfossModel.Item) {
|
private fun starrLocally(item: SelfossModel.Item) {
|
||||||
if (!item.starred) {
|
if (!item.starred) {
|
||||||
item.starred = true
|
item.starred = true
|
||||||
badgeStarred += 1
|
_badgeStarred.value += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
@@ -316,7 +317,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
private fun unstarrLocally(item: SelfossModel.Item) {
|
private fun unstarrLocally(item: SelfossModel.Item) {
|
||||||
if (item.starred) {
|
if (item.starred) {
|
||||||
item.starred = false
|
item.starred = false
|
||||||
badgeStarred -= 1
|
_badgeStarred.value -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
Reference in New Issue
Block a user