Compare commits

..

67 Commits

Author SHA1 Message Date
Amine Louveau
e32699c93f Merge pull request 'ios/init' (#85) from ios/init into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/85
2022-10-24 18:18:16 +00:00
aminecmi
059a237b99 Commenting tests for now.
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-10-23 20:39:09 +02:00
aminecmi
d2bdbae6c8 Launching ios APP. 2022-10-23 20:38:43 +02:00
Amine Louveau
510fcbe47e Merge pull request 'Prevent crash when logging in' (#81) from davidoskky/ReaderForSelfoss-multiplatform:login_crash into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/81
2022-10-22 19:53:59 +00:00
667e9c1a5d Adjust tests to changes in the repository
All checks were successful
continuous-integration/drone/pr Build is passing
2022-10-21 22:56:35 +02:00
53b1d1f8b2 Rework repository initialization 2022-10-21 22:42:32 +02:00
c25e8889a4 Prevent crash when logging in
Some checks reported errors
continuous-integration/drone/pr Build was killed
2022-10-17 19:35:52 +02:00
Amine Louveau
8b0bbe71c9 Merge pull request 'Allow offline filtering' (#75) from davidoskky/ReaderForSelfoss-multiplatform:offline_filters into master
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing
Reviewed-on: https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/75
2022-10-14 07:18:42 +00:00
8bfe14c019 Actually filter database items
All checks were successful
continuous-integration/drone/pr Build is passing
2022-10-14 00:10:35 +02:00
208babbce3 Correct tests 2022-10-14 00:03:20 +02:00
02098a7aa9 Rearrange filtering steps
All checks were successful
continuous-integration/drone/pr Build is passing
2022-10-11 00:52:12 +02:00
d0a982f385 Add tests for offline filtering
All checks were successful
continuous-integration/drone/pr Build is passing
2022-10-08 17:15:41 +02:00
1d1c121aab Filter items from database according to tag and source 2022-10-08 17:15:22 +02:00
fe12819163 Correct database source title 2022-10-08 17:14:12 +02:00
Amine Louveau
023a30c008 Merge pull request 'Simplify sources and tags handling' (#70) from davidoskky/ReaderForSelfoss-multiplatform:drawer_data into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/70
2022-10-04 18:52:39 +00:00
Amine Louveau
a2862a2587 Merge pull request 'Correct mechanism of mark and unmark snackbars' (#74) from davidoskky/ReaderForSelfoss-multiplatform:snackbar-mark into master
Some checks are pending
continuous-integration/drone/push Build is running
Reviewed-on: https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/74
2022-10-04 18:43:44 +00:00
Amine Louveau
054e936657 Merge pull request 'Correct boolean serialization' (#73) from davidoskky/ReaderForSelfoss-multiplatform:swiping into master
Some checks are pending
continuous-integration/drone/push Build is running
Reviewed-on: https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/73
2022-10-04 18:40:14 +00:00
1d2e5069b8 Avoid double snackbar generation
All checks were successful
continuous-integration/drone/pr Build is passing
2022-10-04 16:47:13 +02:00
a147646743 Correct mechanism of mark and unmark snackbars
Some checks are pending
continuous-integration/drone/pr Build is running
2022-10-04 16:43:21 +02:00
32e7fc0038 Correct boolean serialization
All checks were successful
continuous-integration/drone/pr Build is passing
2022-10-04 15:01:22 +02:00
c15bf44032 Adjust repository tests
All checks were successful
continuous-integration/drone/pr Build is passing
2022-10-02 01:01:39 +02:00
0bcd55bd4e Add translated strings
Some checks failed
continuous-integration/drone/pr Build is failing
2022-10-01 22:51:09 +02:00
ebef0b3511 Start monitoring connectivity status when the repository is initiated.
Some checks are pending
continuous-integration/drone/pr Build is running
2022-10-01 22:43:48 +02:00
713ceb05bf Remove unnecessary data class
Some checks failed
continuous-integration/drone/pr Build is failing
2022-09-30 15:07:17 +02:00
dc8381b661 Add missing string 2022-09-30 15:00:25 +02:00
b5b820c64b Remove database access from the Home 2022-09-30 15:00:01 +02:00
f7055626d9 Start monitoring the connectivity before loading the Repository 2022-09-30 14:56:10 +02:00
Amine Louveau
6ec3e96909 Merge pull request 'Repository Unit Tests' (#50) from davidoskky/ReaderForSelfoss-multiplatform:repository_tests into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: https://gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform/pulls/50
2022-09-30 11:31:55 +00:00
22da30eaa8 Remove unnecessary call to api
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-30 13:17:40 +02:00
79fd115f5e Only return new cached items 2022-09-30 13:16:42 +02:00
8dc3d319cd Cleanup
Some checks failed
continuous-integration/drone/pr Build is failing
2022-09-30 11:59:08 +02:00
27bb056397 Cleanup
Some checks are pending
continuous-integration/drone/pr Build is running
2022-09-30 11:49:31 +02:00
f9ba13dc32 Always cache images in background
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-30 11:23:43 +02:00
6f60ef4346 Remove unnecessary return value
Some checks failed
continuous-integration/drone/pr Build is failing
2022-09-30 09:11:55 +02:00
28b950f467 Merge branch 'master' into repository_tests
Some checks are pending
continuous-integration/drone/pr Build is running
2022-09-30 07:04:09 +00:00
a9c7ec3dc1 Cache items in background without filtering
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-30 01:19:28 +02:00
920d4ac1ef Correctly implement disabling sources update 2022-09-29 19:37:33 +02:00
0e96d313ec Add tags parameters explicitly 2022-09-29 19:09:09 +02:00
7211fdb1a3 Fix update remote tests 2022-09-29 18:58:00 +02:00
aminecmi
381d6acc82 Analyzing should be with the rest.
All checks were successful
continuous-integration/drone/push Build is passing
2022-09-29 15:34:12 +02:00
d311c2cdeb Fix sources tests 2022-09-28 18:45:21 +02:00
219cae5d74 Fix tags tests 2022-09-28 18:22:06 +02:00
2968aee309 Fix badges tests 2022-09-28 09:43:28 +02:00
6cb4b35c93 Introduce useful assertions in repository instantiation tests 2022-09-28 09:14:47 +02:00
15ec0f2d26 Merge branch 'master' into repository_tests
Some checks failed
continuous-integration/drone/pr Build is failing
2022-09-28 06:57:02 +00:00
4781e30da2 Remove unnecessary safe calls
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-27 23:44:42 +02:00
c8759cc035 Fix tags tests
Some checks are pending
continuous-integration/drone/pr Build is running
2022-09-27 23:37:30 +02:00
cb4f2f02ef Fix repository.tags() returning null 2022-09-27 23:26:44 +02:00
7517626ab7 Include database return definition within test function 2022-09-27 23:25:47 +02:00
41c951b659 Add test cases for repository instantiation cases
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-27 23:16:30 +02:00
e2afff0b8e Add comment
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-26 23:19:31 +02:00
a382fc89ea Test item caching
Some checks are pending
continuous-integration/drone/pr Build is running
2022-09-26 23:11:26 +02:00
3f0a3903ae Test refresh login information
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-26 22:50:55 +02:00
f46f98cef0 Test login
Some checks are pending
continuous-integration/drone/pr Build is running
2022-09-26 22:46:37 +02:00
bf6f1a917e Test update remote
Some checks are pending
continuous-integration/drone/pr Build is running
2022-09-26 22:42:24 +02:00
71c0a4d340 Test delete source
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-26 22:26:01 +02:00
63c550ead3 Test create source
Some checks are pending
continuous-integration/drone/pr Build is running
2022-09-26 22:21:48 +02:00
366b2e10f1 Adjust tests to changes in the data models
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-25 22:02:25 +02:00
d2436bb976 Merge branch 'master' into repository_tests
# Conflicts:
#	.drone.yml
2022-09-25 20:24:46 +02:00
ef994460c1 get sources tests
Some checks failed
continuous-integration/drone/pr Build is failing
2022-09-18 18:14:14 +02:00
758708e18d Tags tests
Some checks failed
continuous-integration/drone/pr Build is failing
2022-09-17 22:04:24 +02:00
c0381144d1 Add CI test step
Some checks failed
continuous-integration/drone/pr Build is failing
2022-09-17 21:29:37 +02:00
cda3ba6cb4 Test badge fetching
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-16 12:04:05 +02:00
a4636cc0c8 Add item fetching tests
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-15 14:07:50 +02:00
60c24fc75a Check that the api is being used rather than the db
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-10 09:37:14 +02:00
5853a19937 Normal items fetch test
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-10 09:08:26 +02:00
99f2c04bf6 Initial testing setup
All checks were successful
continuous-integration/drone/pr Build is passing
2022-09-09 13:43:53 +02:00
35 changed files with 1612 additions and 524 deletions

View File

@@ -3,28 +3,19 @@ type: docker
name: test
steps:
- name: Anylyse
- name: AnylyseBuildTest
image: mingc/android-build-box:latest
failure: ignore
detach: true
commands:
- echo "---------------------------------------------------------"
- echo "Analysing..."
- ./gradlew sonarqube -Dsonar.projectKey=RFS2 -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\""
- echo "---------------------------------------------------------"
environment:
SONAR_HOST_URL:
from_secret: sonarScannerHostUrl
SONAR_LOGIN:
from_secret: sonarScannerLogin
- name: BuildAndTest
image: mingc/android-build-box:latest
commands:
- echo "Building..."
- ./gradlew :androidApp:build -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
- echo "---------------------------------------------------------"
- echo "Testing..."
- echo "---------------------------------------------------------"
- ./gradlew test -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
environment:
SONAR_HOST_URL:
from_secret: sonarScannerHostUrl

View File

@@ -58,7 +58,7 @@ android {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
compileSdk = 31
compileSdk = 32
buildToolsVersion = "31.0.0"
buildFeatures {
viewBinding = true
@@ -66,7 +66,7 @@ android {
defaultConfig {
applicationId = "bou.amine.apps.readerforselfossv2.android"
minSdk = 21
targetSdk = 31
targetSdk = 32
versionCode = versionCodeFromGit()
versionName = versionNameFromGit()
@@ -79,6 +79,11 @@ android {
// tests
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
packagingOptions {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
buildTypes {
getByName("release") {
isMinifyEnabled = true
@@ -98,9 +103,6 @@ android {
dimension = "build"
}
}
kotlinOptions {
jvmTarget = "1.8"
}
namespace = "bou.amine.apps.readerforselfossv2.android"
}

View File

@@ -15,9 +15,6 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
import androidx.appcompat.widget.SearchView
import androidx.core.view.doOnNextLayout
import androidx.drawerlayout.widget.DrawerLayout
@@ -98,8 +95,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
private val repository : Repository by instance()
private val appSettingsService : AppSettingsService by instance()
data class DrawerData(val tags: List<SelfossModel.Tag>?, val sources: List<SelfossModel.Source>?)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHomeBinding.inflate(layoutInflater)
@@ -352,27 +347,15 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
)
CoroutineScope(Dispatchers.IO).launch {
val drawerData = DrawerData(repository.getDBTags().map { it.toView() },
repository.getDBSources().map { it.toView() })
val tags = repository.getTags()
val sources = repository.getSources()
runOnUiThread {
// Only refresh if there is no data in the DB, or if the `UpdateSources` setting is enabled
if (drawerData.sources?.isEmpty() == true || appSettingsService.isUpdateSourcesEnabled()) {
drawerApiCalls(drawerData)
} else {
handleDrawerData(drawerData, loadedFromCache = true)
}
handleDrawerData(tags, sources)
}
}
}
private fun drawerApiCalls(drawerData: DrawerData) {
CoroutineScope(Dispatchers.Main).launch {
val apiDrawerData = DrawerData(repository.getTags(), repository.getSources())
handleDrawerData(if (drawerData != apiDrawerData) apiDrawerData else drawerData)
}
}
private fun handleDrawerData(drawerData: DrawerData, loadedFromCache: Boolean = false) {
private fun handleDrawerData(tags: List<SelfossModel.Tag>, sources: List<SelfossModel.Source>) {
binding.mainDrawer.itemAdapter.clear()
// Filters title with clear action
@@ -386,24 +369,24 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
}
// Hidden tags
if (drawerData.tags != null && drawerData.tags.isNotEmpty() && appSettingsService.getHiddenTags().isNotEmpty()) {
if (tags.isNotEmpty() && appSettingsService.getHiddenTags().isNotEmpty()) {
secondaryItem(
withDivider = true,
R.string.drawer_item_hidden_tags,
DRAWER_ID_HIDDEN_TAGS
)
handleHiddenTags(drawerData.tags)
handleHiddenTags(tags)
}
// Tags
secondaryItem(withDivider = true, R.string.drawer_item_tags, DRAWER_ID_TAGS)
if (drawerData.tags == null && !loadedFromCache) {
if (tags.isEmpty()) {
binding.mainDrawer.itemAdapter.add(
SecondaryDrawerItem()
.apply { nameRes = R.string.drawer_error_loading_tags; isSelectable = false }
)
} else {
handleTags(drawerData.tags!!)
handleTags(tags)
}
// Sources
@@ -411,15 +394,15 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
startActivity(Intent(v!!.context, SourcesActivity::class.java))
false
}
if (drawerData.sources == null && !loadedFromCache) {
if (sources.isEmpty()) {
binding.mainDrawer.itemAdapter.add(
SecondaryDrawerItem().apply {
nameRes = R.string.drawer_error_loading_tags
nameRes = R.string.drawer_error_loading_sources
isSelectable = false
}
)
} else {
handleSources(drawerData.sources!!)
handleSources(sources)
}
// About action

View File

@@ -93,6 +93,9 @@ class LoginActivity : AppCompatActivity(), DIAware {
}
private fun goToMain() {
CoroutineScope(Dispatchers.Main).launch {
repository.updateApiVersion()
}
val intent = Intent(this, HomeActivity::class.java)
startActivity(intent)
finish()
@@ -163,7 +166,6 @@ class LoginActivity : AppCompatActivity(), DIAware {
CoroutineScope(Dispatchers.IO).launch {
val result = repository.login()
if (result) {
repository.updateApiVersion()
goToMain()
} else {
CoroutineScope(Dispatchers.Main).launch {

View File

@@ -14,6 +14,7 @@ import androidx.lifecycle.ProcessLifecycleOwner
import androidx.multidex.MultiDexApplication
import androidx.preference.PreferenceManager
import bou.amine.apps.readerforselfossv2.DI.networkModule
import bou.amine.apps.readerforselfossv2.android.utils.network.isNetworkAccessible
import bou.amine.apps.readerforselfossv2.android.viewmodel.AppViewModel
import bou.amine.apps.readerforselfossv2.dao.DriverFactory
import bou.amine.apps.readerforselfossv2.dao.ReaderForSelfossDB
@@ -28,6 +29,7 @@ import io.github.aakira.napier.DebugAntilog
import io.github.aakira.napier.Napier
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import org.kodein.di.*
@@ -37,7 +39,7 @@ class MyApp : MultiDexApplication(), DIAware {
import(networkModule)
bind<DriverFactory>() with singleton { DriverFactory(applicationContext) }
bind<ReaderForSelfossDB>() with singleton { ReaderForSelfossDB(driverFactory.createDriver()) }
bind<Repository>() with singleton { Repository(instance(), instance(), connectivityStatus, instance()) }
bind<Repository>() with singleton { Repository(instance(), instance(), isConnectionAvailable, instance()) }
bind<ConnectivityStatus>() with singleton { ConnectivityStatus(applicationContext) }
bind<AppViewModel>() with singleton { AppViewModel(repository = instance()) }
}
@@ -47,6 +49,9 @@ class MyApp : MultiDexApplication(), DIAware {
private val connectivityStatus: ConnectivityStatus by instance()
private val driverFactory: DriverFactory by instance()
// TODO: handle with the "previous" way
private val isConnectionAvailable: MutableStateFlow<Boolean> = MutableStateFlow(true)
override fun onCreate() {
super.onCreate()
Napier.base(DebugAntilog())
@@ -75,7 +80,6 @@ class MyApp : MultiDexApplication(), DIAware {
).show()
}
}
}
private fun handleNotificationChannels() {

View File

@@ -28,7 +28,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
updateItems(this.items)
}
private fun unmarkSnackbar(position: Int) {
private fun unmarkSnackbar(item: SelfossModel.Item, position: Int) {
val s = Snackbar
.make(
app.findViewById(R.id.coordLayout),
@@ -37,7 +37,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
)
.setAction(R.string.undo_string) {
CoroutineScope(Dispatchers.IO).launch {
unreadItemAtIndex(position, false)
unreadItemAtIndex(item, position, false)
}
}
@@ -47,7 +47,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
s.show()
}
private fun markSnackbar(position: Int) {
private fun markSnackbar(item: SelfossModel.Item, position: Int) {
val s = Snackbar
.make(
app.findViewById(R.id.coordLayout),
@@ -55,7 +55,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
Snackbar.LENGTH_LONG
)
.setAction(R.string.undo_string) {
readItemAtIndex(position)
readItemAtIndex(item, position, false)
}
val view = s.view
@@ -66,37 +66,36 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
fun handleItemAtIndex(position: Int) {
if (items[position].unread) {
readItemAtIndex(position)
readItemAtIndex(items[position], position)
} else {
unreadItemAtIndex(position)
unreadItemAtIndex(items[position], position)
}
}
private fun readItemAtIndex(position: Int, showSnackbar: Boolean = true) {
val i = items[position]
private fun readItemAtIndex(item: SelfossModel.Item, position: Int, showSnackbar: Boolean = true) {
CoroutineScope(Dispatchers.IO).launch {
repository.markAsRead(i)
repository.markAsRead(item)
}
if (repository.displayedItems == ItemType.UNREAD) {
items.remove(i)
items.remove(item)
notifyItemRemoved(position)
updateItems(items)
} else {
notifyItemChanged(position)
}
if (showSnackbar) {
unmarkSnackbar(position)
unmarkSnackbar(item, position)
}
}
private fun unreadItemAtIndex(position: Int, showSnackbar: Boolean = true) {
private fun unreadItemAtIndex(item: SelfossModel.Item, position: Int, showSnackbar: Boolean = true) {
CoroutineScope(Dispatchers.IO).launch {
repository.unmarkAsRead(items[position])
repository.unmarkAsRead(item)
}
notifyItemChanged(position)
if (showSnackbar) {
markSnackbar(position)
markSnackbar(item, position)
}
}

View File

@@ -52,11 +52,13 @@ override fun doWork(): Result {
repository.handleDBActions()
val apiItems = repository.tryToCacheItemsAndGetNewOnes()
if (appSettingsService.isNotifyNewItemsEnabled()) {
launch {
handleNewItemsNotification(repository.tryToCacheItemsAndGetNewOnes(), notificationManager)
handleNewItemsNotification(apiItems, notificationManager)
}
}
apiItems.map { it.preloadImages(context) }
}
}
return Result.success()
@@ -66,6 +68,7 @@ override fun doWork(): Result {
newItems: List<SelfossModel.Item>?,
notificationManager: NotificationManager
) {
// TODO: Check if this coroutine is actually required
CoroutineScope(Dispatchers.IO).launch {
val apiItems = newItems.orEmpty()
@@ -102,7 +105,6 @@ override fun doWork(): Result {
notificationManager.notify(2, newItemsNotification.build())
}
}
apiItems.map { it.preloadImages(context) }
Timer("", false).schedule(4000) {
notificationManager.cancel(1)
}

View File

@@ -354,6 +354,7 @@ class ArticleFragment : Fragment(), DIAware {
binding.webcontent.settings.javaScriptEnabled = false
binding.webcontent.webViewClient = object : WebViewClient() {
@Deprecated("Deprecated in Java")
override fun shouldOverrideUrlLoading(view: WebView?, url : String): Boolean {
if (binding.webcontent.hitTestResult.type != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
requireContext().startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
@@ -361,6 +362,7 @@ class ArticleFragment : Fragment(), DIAware {
return true
}
@Deprecated("Deprecated in Java")
override fun shouldInterceptRequest(view: WebView?, url: String): WebResourceResponse? {
val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL)
if (url.lowercase(Locale.US).contains(".jpg") || url.lowercase(Locale.US).contains(".jpeg")) {

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Thème sombre</string>
<string name="mode_system">Utiliser les paramètres système</string>
<string name="mode_light">Thème clair</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">深色模式</string>
<string name="mode_system">遵循系统设置</string>
<string name="mode_light">浅色模式</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -132,4 +132,5 @@
<string name="mode_dark">Dark mode</string>
<string name="mode_system">Follow the system setting</string>
<string name="mode_light">Light mode</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
</resources>

View File

@@ -63,6 +63,7 @@
<string name="card_height_off">Card height will be fixed</string>
<string name="source_code">Source code</string>
<string name="drawer_error_loading_tags">Error loading tags…</string>
<string name="drawer_error_loading_sources">Error loading sources…</string>
<string name="drawer_item_filters">Filters</string>
<string name="drawer_action_clear">clear</string>
<string name="drawer_item_tags">Tags</string>
@@ -109,7 +110,7 @@
<string name="pref_switch_periodic_refresh_on">Articles will periodically be synced</string>
<string name="pref_periodic_refresh_minutes_title"><![CDATA[Sync interval ( >= 15 minutes)]]></string>
<string name="pref_switch_refresh_when_charging">Only refresh when phone is charging</string>
<string name="loading_notification_title">Loading ...</string>
<string name="loading_notification_title">Loading </string>
<string name="loading_notification_text">Selfoss is syncing your articles</string>
<string name="notification_channel_sync">Sync notification</string>
<string name="new_items_channel_sync">New items notification</string>

View File

@@ -1,21 +1,19 @@
buildscript {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
classpath("com.android.tools.build:gradle:7.3.0")
// sonarquve
classpath("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513")
// SqlDelight
classpath("com.squareup.sqldelight:gradle-plugin:1.5.3")
}
}
plugins {
//trick: for the same plugin versions in all sub-modules
id("com.android.application").version("7.3.1").apply(false)
id("com.android.library").version("7.3.1").apply(false)
kotlin("android").version("1.7.10").apply(false)
kotlin("multiplatform").version("1.7.10").apply(false)
id("org.sonarqube").version("3.4.0.2513").apply(false)
}
apply(plugin = "org.sonarqube")
allprojects {
@@ -27,6 +25,7 @@ allprojects {
}
}
tasks.register("clean", Delete::class) {
delete(rootProject.buildDir)
}
}

View File

@@ -11,14 +11,27 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#Tue Mar 22 16:50:00 CET 2022
#Gradle
org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
#Kotlin
kotlin.code.style=official
kotlin.mpp.enableCInteropCommonization=true
org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"
kotlin.native.enableDependencyPropagation=false
#Android
android.useAndroidX=true
kotlin.native.enableDependencyPropagation=false
#android.nonTransitiveRClass=true
android.enableJetifier=true
#MPP
kotlin.mpp.enableCInteropCommonization=true
kotlin.mpp.enableGranularSourceSetsMetadata=true
org.gradle.parallel=true
org.gradle.caching=true
ignoreGitVersion=false
kotlin.native.cacheKind.iosX64=none
pushCache=true

View File

@@ -1,383 +1,383 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; };
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; };
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; };
7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXBuildFile section */
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; };
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; };
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; };
7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
7555FFB4242A642300829871 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXCopyFilesBuildPhase section */
7555FFB4242A642300829871 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; };
7555FF7B242A565900829871 /* iosApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iosApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFileReference section */
058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = "<group>"; };
7555FF7B242A565900829871 /* iosApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iosApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
7555FF78242A565900829871 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXFrameworksBuildPhase section */
7555FF78242A565900829871 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
058557D7273AAEEB004C7B11 /* Preview Content */ = {
isa = PBXGroup;
children = (
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "<group>";
};
7555FF72242A565900829871 = {
isa = PBXGroup;
children = (
7555FF7D242A565900829871 /* iosApp */,
7555FF7C242A565900829871 /* Products */,
7555FFB0242A642200829871 /* Frameworks */,
);
sourceTree = "<group>";
};
7555FF7C242A565900829871 /* Products */ = {
isa = PBXGroup;
children = (
7555FF7B242A565900829871 /* iosApp.app */,
);
name = Products;
sourceTree = "<group>";
};
7555FF7D242A565900829871 /* iosApp */ = {
isa = PBXGroup;
children = (
058557BA273AAA24004C7B11 /* Assets.xcassets */,
7555FF82242A565900829871 /* ContentView.swift */,
7555FF8C242A565B00829871 /* Info.plist */,
2152FB032600AC8F00CF470E /* iOSApp.swift */,
058557D7273AAEEB004C7B11 /* Preview Content */,
);
path = iosApp;
sourceTree = "<group>";
};
7555FFB0242A642200829871 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXGroup section */
058557D7273AAEEB004C7B11 /* Preview Content */ = {
isa = PBXGroup;
children = (
058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "<group>";
};
7555FF72242A565900829871 = {
isa = PBXGroup;
children = (
7555FF7D242A565900829871 /* iosApp */,
7555FF7C242A565900829871 /* Products */,
7555FFB0242A642200829871 /* Frameworks */,
);
sourceTree = "<group>";
};
7555FF7C242A565900829871 /* Products */ = {
isa = PBXGroup;
children = (
7555FF7B242A565900829871 /* iosApp.app */,
);
name = Products;
sourceTree = "<group>";
};
7555FF7D242A565900829871 /* iosApp */ = {
isa = PBXGroup;
children = (
058557BA273AAA24004C7B11 /* Assets.xcassets */,
7555FF82242A565900829871 /* ContentView.swift */,
7555FF8C242A565B00829871 /* Info.plist */,
2152FB032600AC8F00CF470E /* iOSApp.swift */,
058557D7273AAEEB004C7B11 /* Preview Content */,
);
path = iosApp;
sourceTree = "<group>";
};
7555FFB0242A642200829871 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
7555FF7A242A565900829871 /* iosApp */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */;
buildPhases = (
7555FFB5242A651A00829871 /* ShellScript */,
7555FF77242A565900829871 /* Sources */,
7555FF78242A565900829871 /* Frameworks */,
7555FF79242A565900829871 /* Resources */,
7555FFB4242A642300829871 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = iosApp;
productName = iosApp;
productReference = 7555FF7B242A565900829871 /* iosApp.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXNativeTarget section */
7555FF7A242A565900829871 /* iosApp */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */;
buildPhases = (
7555FFB5242A651A00829871 /* ShellScript */,
7555FF77242A565900829871 /* Sources */,
7555FF78242A565900829871 /* Frameworks */,
7555FF79242A565900829871 /* Resources */,
7555FFB4242A642300829871 /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = iosApp;
productName = iosApp;
productReference = 7555FF7B242A565900829871 /* iosApp.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
7555FF73242A565900829871 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1130;
LastUpgradeCheck = 1130;
ORGANIZATIONNAME = orgName;
TargetAttributes = {
7555FF7A242A565900829871 = {
CreatedOnToolsVersion = 11.3.1;
};
};
};
buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 7555FF72242A565900829871;
productRefGroup = 7555FF7C242A565900829871 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
7555FF7A242A565900829871 /* iosApp */,
);
};
/* End PBXProject section */
/* Begin PBXProject section */
7555FF73242A565900829871 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1130;
LastUpgradeCheck = 1130;
ORGANIZATIONNAME = orgName;
TargetAttributes = {
7555FF7A242A565900829871 = {
CreatedOnToolsVersion = 11.3.1;
};
};
};
buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 7555FF72242A565900829871;
productRefGroup = 7555FF7C242A565900829871 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
7555FF7A242A565900829871 /* iosApp */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
7555FF79242A565900829871 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */,
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXResourcesBuildPhase section */
7555FF79242A565900829871 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */,
058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
7555FFB5242A651A00829871 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "cd \"$SRCROOT/..\"\n./gradlew :shared:embedAndSignAppleFrameworkForXcode\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
7555FFB5242A651A00829871 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "cd \"$SRCROOT/..\"\n./gradlew :shared:embedAndSignAppleFrameworkForXcode\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
7555FF77242A565900829871 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */,
7555FF83242A565900829871 /* ContentView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
7555FF77242A565900829871 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */,
7555FF83242A565900829871 /* ContentView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
7555FFA3242A565B00829871 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
7555FFA4242A565B00829871 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
7555FFA6242A565B00829871 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)";
INFOPLIST_FILE = iosApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
shared,
);
PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
7555FFA7242A565B00829871 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)";
INFOPLIST_FILE = iosApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
shared,
);
PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCBuildConfiguration section */
7555FFA3242A565B00829871 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
7555FFA4242A565B00829871 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.1;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
7555FFA6242A565B00829871 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)";
INFOPLIST_FILE = iosApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
shared,
);
PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
7555FFA7242A565B00829871 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)";
INFOPLIST_FILE = iosApp/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
shared,
);
PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7555FFA3242A565B00829871 /* Debug */,
7555FFA4242A565B00829871 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7555FFA6242A565B00829871 /* Debug */,
7555FFA7242A565B00829871 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 7555FF73242A565900829871 /* Project object */;
}
/* Begin XCConfigurationList section */
7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7555FFA3242A565B00829871 /* Debug */,
7555FFA4242A565B00829871 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7555FFA6242A565B00829871 /* Debug */,
7555FFA7242A565B00829871 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 7555FF73242A565900829871 /* Project object */;
}

View File

@@ -2,12 +2,9 @@ import SwiftUI
import shared
struct ContentView: View {
let greet = Greeting().greeting()
let toto = SelfossApi().getItems()
var body: some View {
Text(greet)
Text("ototot")
}
}

View File

@@ -8,6 +8,14 @@ pluginManagement {
}
}
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
buildCache {
remote<HttpBuildCache> {
url = uri("http://18.0.0.7:3071/cache/")

View File

@@ -18,7 +18,7 @@ kotlin {
listOf(
iosX64(),
iosArm64(),
//iosSimulatorArm64() sure all ios dependencies support this target
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "shared"
@@ -45,9 +45,6 @@ kotlin {
//Logging
implementation("io.github.aakira:napier:2.6.1")
// Network information
implementation("com.github.ln-12:multiplatform-connectivity-status:1.3.0")
// Sql
implementation(SqlDelight.runtime)
}
@@ -56,6 +53,9 @@ kotlin {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
// implementation("io.mockk:mockk:1.12.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
}
}
val androidMain by getting {
@@ -74,39 +74,36 @@ kotlin {
}
val iosX64Main by getting
val iosArm64Main by getting
//val iosSimulatorArm64Main by getting
val iosSimulatorArm64Main by getting
val iosMain by creating {
dependsOn(commonMain)
iosX64Main.dependsOn(this)
iosArm64Main.dependsOn(this)
//iosSimulatorArm64Main.dependsOn(this)
iosSimulatorArm64Main.dependsOn(this)
// Sql
dependencies {
implementation(SqlDelight.native)
implementation("io.ktor:ktor-client-ios:2.1.1")
}
}
val iosX64Test by getting
val iosArm64Test by getting
//val iosSimulatorArm64Test by getting
val iosSimulatorArm64Test by getting
val iosTest by creating {
dependsOn(commonTest)
iosX64Test.dependsOn(this)
iosArm64Test.dependsOn(this)
dependencies {
implementation("io.ktor:ktor-client-ios:2.1.1")
}
//iosSimulatorArm64Test.dependsOn(this)
iosSimulatorArm64Test.dependsOn(this)
}
}
}
android {
compileSdk = 31
compileSdk = 32
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdk = 21
targetSdk = 31
targetSdk = 32
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -115,10 +112,11 @@ android {
namespace = "bou.amine.apps.readerforselfossv2"
}
sqldelight {
database("ReaderForSelfossDB") {
packageName = "bou.amine.apps.readerforselfossv2.dao"
sourceFolders = listOf("sqldelight")
}
}
}

View File

@@ -138,7 +138,11 @@ class SelfossModel {
object BooleanSerializer : KSerializer<Boolean> {
override fun deserialize(decoder: Decoder): Boolean {
val json = ((decoder as JsonDecoder).decodeJsonElement()).jsonPrimitive
return json.booleanOrNull ?: json.int == 1
return if (json.booleanOrNull != null) {
json.boolean
} else {
json.int == 1
}
}
override val descriptor: SerialDescriptor

View File

@@ -6,16 +6,16 @@ import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.rest.SelfossApi
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
import bou.amine.apps.readerforselfossv2.utils.*
import com.github.ln_12.library.ConnectivityStatus
import io.github.aakira.napier.Napier
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
class Repository(private val api: SelfossApi, private val appSettingsService: AppSettingsService, connectivityStatus: ConnectivityStatus, private val db: ReaderForSelfossDB) {
class Repository(private val api: SelfossApi, private val appSettingsService: AppSettingsService, val isConnectionAvailable: MutableStateFlow<Boolean>, private val db: ReaderForSelfossDB) {
var items = ArrayList<SelfossModel.Item>()
val isConnectionAvailable = connectivityStatus.isNetworkConnected
var connectionMonitored = false
var baseUrl = appSettingsService.getBaseUrl()
@@ -36,14 +36,8 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
var badgeStarred = 0
set(value) {field = if (value < 0) { 0 } else { value } }
init {
// TODO: Dispatchers.IO not available in KMM, an alternative solution should be found
CoroutineScope(Dispatchers.Main).launch {
updateApiVersion()
dateUtils = DateUtils(appSettingsService)
reloadBadges()
}
}
private var fetchedSources = false
private var fetchedTags = false
suspend fun getNewerItems(): ArrayList<SelfossModel.Item> {
// TODO: Use the updatedSince parameter
@@ -61,12 +55,19 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
} else {
if (appSettingsService.isItemCachingEnabled()) {
fromDB = true
var dbItems = getDBItems().filter {
displayedItems == ItemType.ALL ||
(it.unread && displayedItems == ItemType.UNREAD) ||
(it.starred && displayedItems == ItemType.STARRED)
}
if (tagFilter != null) {
dbItems = dbItems.filter { it.tags.split(',').contains(tagFilter!!.tag) }
}
if (sourceFilter != null) {
dbItems = dbItems.filter { it.sourcetitle == sourceFilter!!.title }
}
fetchedItems = SelfossModel.StatusAndData.succes(
getDBItems().filter {
displayedItems == ItemType.ALL ||
(it.unread && displayedItems == ItemType.UNREAD) ||
(it.starred && displayedItems == ItemType.STARRED)
}.map { it.toView() }
dbItems.map { it.toView() }
)
}
}
@@ -105,9 +106,9 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
val items = api.getItems(
itemType.type,
0,
tagFilter?.tag,
sourceFilter?.id?.toLong(),
searchFilter,
null,
null,
null,
null,
200
)
@@ -131,32 +132,40 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
badgeStarred = response.data.starred
success = true
}
} else {
} else if (appSettingsService.isItemCachingEnabled()) {
// TODO: do this differently, because it's not efficient
val dbItems = getDBItems()
badgeUnread = dbItems.filter { item -> item.unread }.size
badgeStarred = dbItems.filter { item -> item.starred }.size
badgeAll = items.size
badgeAll = dbItems.size
success = true
}
return success
}
suspend fun getTags(): List<SelfossModel.Tag>? {
return if (isNetworkAvailable()) {
suspend fun getTags(): List<SelfossModel.Tag> {
val isDatabaseEnabled = appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled()
return if (isNetworkAvailable() && !fetchedTags) {
val apiTags = api.tags()
if (apiTags.success && apiTags.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
if (apiTags.success && apiTags.data != null && isDatabaseEnabled) {
resetDBTagsWithData(apiTags.data)
if (!appSettingsService.isUpdateSourcesEnabled()) {
fetchedTags = true
}
}
apiTags.data
} else {
apiTags.data ?: emptyList()
} else if (isDatabaseEnabled) {
getDBTags().map { it.toView() }
} else {
emptyList()
}
}
suspend fun getSpouts(): Map<String, SelfossModel.Spout>? {
// TODO: Add tests
suspend fun getSpouts(): Map<String, SelfossModel.Spout> {
return if (isNetworkAvailable()) {
val spouts = api.spouts()
return if (spouts.success && spouts.data != null) {
if (spouts.success && spouts.data != null) {
spouts.data
} else {
emptyMap() // TODO: do something here
@@ -166,18 +175,25 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
}
}
suspend fun getSources(): ArrayList<SelfossModel.Source>? {
return if (isNetworkAvailable()) {
suspend fun getSources(): ArrayList<SelfossModel.Source> {
val isDatabaseEnabled = appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled()
return if (isNetworkAvailable() && !fetchedSources) {
val apiSources = api.sources()
if (apiSources.success && apiSources.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
if (apiSources.success && apiSources.data != null && isDatabaseEnabled) {
resetDBSourcesWithData(apiSources.data)
if (!appSettingsService.isUpdateSourcesEnabled()) {
fetchedSources = true
}
}
apiSources.data
} else {
apiSources.data ?: ArrayList()
} else if (isDatabaseEnabled) {
ArrayList(getDBSources().map { it.toView() })
} else {
ArrayList()
}
}
// TODO: Add tests
suspend fun markAsRead(item: SelfossModel.Item): Boolean {
val success = markAsReadById(item.id)
@@ -189,14 +205,14 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
private suspend fun markAsReadById(id: Int): Boolean {
return if (isNetworkAvailable()) {
api.markAsRead(id.toString())?.isSuccess
api.markAsRead(id.toString()).isSuccess
} else {
insertDBAction(id.toString(), read = true)
true
}
}
// TODO: Add tests
suspend fun unmarkAsRead(item: SelfossModel.Item): Boolean {
val success = unmarkAsReadById(item.id)
@@ -208,13 +224,14 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
private suspend fun unmarkAsReadById(id: Int): Boolean {
return if (isNetworkAvailable()) {
api.unmarkAsRead(id.toString())?.isSuccess
api.unmarkAsRead(id.toString()).isSuccess
} else {
insertDBAction(id.toString(), unread = true)
true
}
}
// TODO: Add tests
suspend fun starr(item: SelfossModel.Item): Boolean {
val success = starrById(item.id)
@@ -226,13 +243,14 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
private suspend fun starrById(id: Int): Boolean {
return if (isNetworkAvailable()) {
api.starr(id.toString())?.isSuccess
api.starr(id.toString()).isSuccess
} else {
insertDBAction(id.toString(), starred = true)
true
}
}
// TODO: Add tests
suspend fun unstarr(item: SelfossModel.Item): Boolean {
val success = unstarrById(item.id)
@@ -244,17 +262,18 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
private suspend fun unstarrById(id: Int): Boolean {
return if (isNetworkAvailable()) {
api.unstarr(id.toString())?.isSuccess
api.unstarr(id.toString()).isSuccess
} else {
insertDBAction(id.toString(), starred = true)
true
}
}
// TODO: Add tests
suspend fun markAllAsRead(items: ArrayList<SelfossModel.Item>): Boolean {
var success = false
if (isNetworkAvailable() && api.markAllAsRead(items.map { it.id.toString() })?.isSuccess) {
if (isNetworkAvailable() && api.markAllAsRead(items.map { it.id.toString() }).isSuccess) {
success = true
for (item in items) {
markAsReadLocally(item)
@@ -323,7 +342,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
tags,
filter,
appSettingsService.getApiVersion()
)?.isSuccess == true
).isSuccess == true
}
return response
@@ -333,9 +352,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
var success = false
if (isNetworkAvailable()) {
val response = api.deleteSource(id)
if (response != null) {
success = response.isSuccess
}
success = response.isSuccess
}
return success
@@ -343,7 +360,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
suspend fun updateRemote(): Boolean {
return if (isNetworkAvailable()) {
api.update()?.equals("finished")
api.update().data.equals("finished")
} else {
false
}
@@ -354,10 +371,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
if (isNetworkAvailable()) {
try {
val response = api.login()
result = response?.isSuccess == true
if (result) {
updateApiVersion()
}
result = response.isSuccess == true
} catch (cause: Throwable) {
Napier.e(cause.stackTraceToString(), tag = "RepositoryImpl.updateRemote")
}
@@ -380,6 +394,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
appSettingsService.updateApiVersion(fetchedVersion.data.getApiMajorVersion())
}
}
dateUtils = DateUtils(appSettingsService)
}
fun isNetworkAvailable() = isConnectionAvailable.value && !offlineOverride
@@ -390,9 +405,9 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
private fun deleteDBAction(action: ACTION) =
db.actionsQueries.deleteAction(action.id)
fun getDBTags(): List<TAG> = db.tagsQueries.tags().executeAsList()
private fun getDBTags(): List<TAG> = db.tagsQueries.tags().executeAsList()
fun getDBSources(): List<SOURCE> = db.sourcesQueries.sources().executeAsList()
private fun getDBSources(): List<SOURCE> = db.sourcesQueries.sources().executeAsList()
private fun resetDBTagsWithData(tagEntities: List<SelfossModel.Tag>) {
db.tagsQueries.deleteAllTags()
@@ -430,8 +445,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
private fun updateDBItem(item: SelfossModel.Item) =
db.itemsQueries.updateItem(item.datetime, item.title.getHtmlDecoded(), item.content, item.unread, item.starred, item.thumbnail, item.icon, item.link, item.sourcetitle, item.tags.joinToString(","), item.id.toString())
suspend fun tryToCacheItemsAndGetNewOnes(): List<SelfossModel.Item>? {
suspend fun tryToCacheItemsAndGetNewOnes(): List<SelfossModel.Item> {
try {
val newItems = getMaxItemsForBackground(ItemType.UNREAD)
val allItems = getMaxItemsForBackground(ItemType.ALL)
@@ -444,6 +458,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
return emptyList()
}
// TODO: Add tests
suspend fun handleDBActions() {
val actions: List<ACTION> = getDBActions()

View File

@@ -65,6 +65,6 @@ fun SelfossModel.Item.toEntity(): ITEM =
this.thumbnail,
this.icon,
this.link,
this.title.getHtmlDecoded(),
this.sourcetitle.getHtmlDecoded(),
this.tags.joinToString(",")
)