diff --git a/app/build.gradle b/app/build.gradle index e1f496c..7c830e9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,6 +24,8 @@ def versionNameFromGit() { return gitVersion() } +apply plugin: 'kotlin-kapt' + apply plugin: 'com.android.application' apply plugin: 'kotlin-android' @@ -134,7 +136,6 @@ dependencies { // Drawer implementation 'co.zsmb:materialdrawer-kt:2.0.1' - implementation 'com.anupcowkur:reservoir:3.1.0' // Themes implementation 'com.52inc:scoops:1.0.0' @@ -149,6 +150,12 @@ dependencies { // Crash implementation 'ch.acra:acra-http:5.1.3' implementation 'ch.acra:acra-dialog:5.1.3' + + implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version" + implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" + + implementation "androidx.room:room-runtime:$room_version" + kapt "androidx.room:room-compiler:$room_version" } diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/HomeActivity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/HomeActivity.kt index d05afe8..e40d68f 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/HomeActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/HomeActivity.kt @@ -23,15 +23,18 @@ import android.view.Menu import android.view.MenuItem import android.view.View import android.widget.Toast +import androidx.room.Room +import androidx.room.RoomDatabase import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter import apps.amine.bou.readerforselfoss.adapters.ItemsAdapter import apps.amine.bou.readerforselfoss.api.selfoss.Item import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi -import apps.amine.bou.readerforselfoss.api.selfoss.Sources +import apps.amine.bou.readerforselfoss.api.selfoss.Source import apps.amine.bou.readerforselfoss.api.selfoss.Stats import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.api.selfoss.Tag +import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase import apps.amine.bou.readerforselfoss.settings.SettingsActivity import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.themes.Toppings @@ -42,14 +45,13 @@ import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper import apps.amine.bou.readerforselfoss.utils.drawer.CustomUrlPrimaryDrawerItem import apps.amine.bou.readerforselfoss.utils.flattenTags import apps.amine.bou.readerforselfoss.utils.longHash +import apps.amine.bou.readerforselfoss.utils.persistence.toEntity +import apps.amine.bou.readerforselfoss.utils.persistence.toView import co.zsmb.materialdrawerkt.builders.accountHeader import co.zsmb.materialdrawerkt.builders.drawer import co.zsmb.materialdrawerkt.builders.footer import co.zsmb.materialdrawerkt.draweritems.badgeable.primaryItem import co.zsmb.materialdrawerkt.draweritems.profile.profile -import com.anupcowkur.reservoir.Reservoir -import com.anupcowkur.reservoir.ReservoirGetCallback -import com.anupcowkur.reservoir.ReservoirPutCallback import com.ashokvarma.bottomnavigation.BottomNavigationBar import com.ashokvarma.bottomnavigation.BottomNavigationItem import com.ashokvarma.bottomnavigation.TextBadgeItem @@ -65,9 +67,12 @@ import com.mikepenz.materialdrawer.model.DividerDrawerItem import com.mikepenz.materialdrawer.model.PrimaryDrawerItem import com.mikepenz.materialdrawer.model.SecondaryDrawerItem import kotlinx.android.synthetic.main.activity_home.* +import kotlinx.android.synthetic.main.fragment_article.* import retrofit2.Call import retrofit2.Callback import retrofit2.Response +import kotlin.concurrent.thread + class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { private val MENU_PREFERENCES = 12302 @@ -94,7 +99,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { private var itemsNumber: Int = 200 private var elementsShown: Int = 0 private var maybeTagFilter: Tag? = null - private var maybeSourceFilter: Sources? = null + private var maybeSourceFilter: Source? = null private var maybeSearchFilter: String? = null private var userIdentifier: String = "" private var displayAccountHeader: Boolean = false @@ -126,7 +131,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { private lateinit var tagsBadge: Map - data class DrawerData(val tags: List?, val sources: List?) + private lateinit var db: AppDatabase + + data class DrawerData(val tags: List?, val sources: List?) override fun onStart() { super.onStart() @@ -147,6 +154,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { Amplify.getSharedInstance().promptIfReady(promptView) } + db = Room.databaseBuilder( + applicationContext, + AppDatabase::class.java!!, "selfoss-database" + ).build() + + customTabActivityHelper = CustomTabActivityHelper() sharedPref = PreferenceManager.getDefaultSharedPreferences(this) @@ -544,7 +557,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } } - fun handleSources(maybeSources: List?) { + fun handleSources(maybeSources: List?) { if (maybeSources == null) { if (loadedFromCache) { drawer.addItem( @@ -643,14 +656,18 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { if (!loadedFromCache) { - Reservoir.putAsync( - "drawerData", maybeDrawerData, object : ReservoirPutCallback { - override fun onSuccess() { - } - - override fun onFailure(p0: Exception?) { - } - }) + if (maybeDrawerData.tags != null) { + thread { + val tagEntities = maybeDrawerData.tags.map { it.toEntity() } + db.drawerDataDao().insertAllTags(*tagEntities.toTypedArray()) + } + } + if (maybeDrawerData.sources != null) { + thread { + val sourceEntities = maybeDrawerData.sources.map { it.toEntity(this@HomeActivity) } + db.drawerDataDao().insertAllSources(*sourceEntities.toTypedArray()) + } + } } } else { if (!loadedFromCache) { @@ -672,13 +689,13 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { fun drawerApiCalls(maybeDrawerData: DrawerData?) { var tags: List? = null - var sources: List? + var sources: List? fun sourcesApiCall() { - api.sources.enqueue(object : Callback> { + api.sources.enqueue(object : Callback> { override fun onResponse( - call: Call>?, - response: Response> + call: Call>?, + response: Response> ) { sources = response.body() val apiDrawerData = DrawerData(tags, sources) @@ -687,7 +704,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { } } - override fun onFailure(call: Call>?, t: Throwable?) { + override fun onFailure(call: Call>?, t: Throwable?) { } }) } @@ -713,18 +730,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { ) ) - val resultType = object : TypeToken() {}.type - Reservoir.getAsync( - "drawerData", resultType, object : ReservoirGetCallback { - override fun onSuccess(maybeDrawerData: DrawerData?) { - handleDrawerData(maybeDrawerData, loadedFromCache = true) - drawerApiCalls(maybeDrawerData) + db.drawerDataDao().tags().observeForever { tags -> + db.drawerDataDao().sources().observeForever { sources -> + var drawerData = DrawerData(null, null) + if (tags != null) { + drawerData = drawerData.copy(tags = tags.map { it.toView() }) } - - override fun onFailure(p0: Exception?) { - drawerApiCalls(null) + if (sources != null) { + drawerData = drawerData.copy(sources = sources.map { it.toView() }) } - }) + handleDrawerData(drawerData, loadedFromCache = true) + drawerApiCalls(drawerData) + } + } } private fun reloadLayoutManager() { diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/MyApp.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/MyApp.kt index c567395..c9aecc9 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/MyApp.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/MyApp.kt @@ -1,14 +1,12 @@ package apps.amine.bou.readerforselfoss import android.content.Context -import android.content.SharedPreferences import android.graphics.drawable.Drawable import android.net.Uri import android.preference.PreferenceManager import androidx.multidex.MultiDexApplication import android.widget.ImageView import apps.amine.bou.readerforselfoss.utils.Config -import com.anupcowkur.reservoir.Reservoir import com.bumptech.glide.Glide import com.bumptech.glide.request.RequestOptions import com.ftinc.scoop.Scoop @@ -49,8 +47,6 @@ class MyApp : MultiDexApplication() { initAmplify() - initCache() - val prefs = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE) if (prefs.getString("unique_id", "").isEmpty()) { val editor = prefs.edit() @@ -80,14 +76,6 @@ class MyApp : MultiDexApplication() { .applyAllDefaultRules() } - private fun initCache() { - try { - Reservoir.init(this, 8192) //in bytes - } catch (e: IOException) { - //failure - } - } - private fun initDrawerImageLoader() { DrawerImageLoader.init(object : AbstractDrawerImageLoader() { override fun set( diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/SourcesActivity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/SourcesActivity.kt index b454155..3321e0b 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/SourcesActivity.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/SourcesActivity.kt @@ -10,7 +10,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import android.widget.Toast import apps.amine.bou.readerforselfoss.adapters.SourcesListAdapter import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi -import apps.amine.bou.readerforselfoss.api.selfoss.Sources +import apps.amine.bou.readerforselfoss.api.selfoss.Source import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.themes.Toppings import com.ftinc.scoop.Scoop @@ -61,18 +61,18 @@ class SourcesActivity : AppCompatActivity() { prefs.getBoolean("isSelfSignedCert", false), prefs.getBoolean("should_log_everything", false) ) - var items: ArrayList = ArrayList() + var items: ArrayList = ArrayList() recyclerView.setHasFixedSize(true) recyclerView.layoutManager = mLayoutManager - api.sources.enqueue(object : Callback> { + api.sources.enqueue(object : Callback> { override fun onResponse( - call: Call>, - response: Response> + call: Call>, + response: Response> ) { if (response.body() != null && response.body()!!.isNotEmpty()) { - items = response.body() as ArrayList + items = response.body() as ArrayList } val mAdapter = SourcesListAdapter(this@SourcesActivity, items, api) recyclerView.adapter = mAdapter @@ -86,7 +86,7 @@ class SourcesActivity : AppCompatActivity() { } } - override fun onFailure(call: Call>, t: Throwable) { + override fun onFailure(call: Call>, t: Throwable) { Toast.makeText( this@SourcesActivity, R.string.cant_get_sources, diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/SourcesListAdapter.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/SourcesListAdapter.kt index 13d14ed..02810e3 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/SourcesListAdapter.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/adapters/SourcesListAdapter.kt @@ -10,7 +10,7 @@ import android.widget.Button import android.widget.Toast import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi -import apps.amine.bou.readerforselfoss.api.selfoss.Sources +import apps.amine.bou.readerforselfoss.api.selfoss.Source import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable import apps.amine.bou.readerforselfoss.utils.toTextDrawableString @@ -23,7 +23,7 @@ import retrofit2.Response class SourcesListAdapter( private val app: Activity, - private val items: ArrayList, + private val items: ArrayList, private val api: SelfossApi ) : RecyclerView.Adapter() { private val c: Context = app.baseContext diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossApi.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossApi.kt index 22750b5..4e2e855 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossApi.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossApi.kt @@ -159,7 +159,7 @@ class SelfossApi( fun update(): Call = service.update(userName, password) - val sources: Call> + val sources: Call> get() = service.sources(userName, password) fun deleteSource(id: String): Call = diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt index d6405e9..1b69670 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossModels.kt @@ -42,7 +42,7 @@ data class Spout( @SerializedName("description") val description: String ) -data class Sources( +data class Source( @SerializedName("id") val id: String, @SerializedName("title") val title: String, @SerializedName("tags") val tags: String, diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossService.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossService.kt index 10fc80c..c57d880 100644 --- a/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossService.kt +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/api/selfoss/SelfossService.kt @@ -95,7 +95,7 @@ internal interface SelfossService { fun sources( @Query("username") username: String, @Query("password") password: String - ): Call> + ): Call> @DELETE("source/{id}") fun deleteSource( diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/persistence/dao/DrawerDataDao.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/persistence/dao/DrawerDataDao.kt new file mode 100644 index 0000000..70f7182 --- /dev/null +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/persistence/dao/DrawerDataDao.kt @@ -0,0 +1,37 @@ +package apps.amine.bou.readerforselfoss.persistence.dao + +import androidx.lifecycle.LiveData +import androidx.room.Delete +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import apps.amine.bou.readerforselfoss.persistence.entities.SourceEntity +import apps.amine.bou.readerforselfoss.persistence.entities.TagEntity + +@Dao +interface DrawerDataDao { + @Query("SELECT * FROM tags") + fun tags(): LiveData> + + @Query("SELECT * FROM sources") + fun sources(): LiveData> + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertAllTags(vararg tags: TagEntity) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertAllSources(vararg sources: SourceEntity) + + @Query("DELETE FROM tags") + fun deleteAllTags() + + @Query("DELETE FROM sources") + fun deleteAllSources() + + @Delete + fun deleteTag(tag: TagEntity) + + @Delete + fun deleteSource(source: SourceEntity) +} \ No newline at end of file diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/persistence/database/AppDatabase.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/persistence/database/AppDatabase.kt new file mode 100644 index 0000000..eccf36d --- /dev/null +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/persistence/database/AppDatabase.kt @@ -0,0 +1,12 @@ +package apps.amine.bou.readerforselfoss.persistence.database + +import androidx.room.RoomDatabase +import androidx.room.Database +import apps.amine.bou.readerforselfoss.persistence.dao.DrawerDataDao +import apps.amine.bou.readerforselfoss.persistence.entities.SourceEntity +import apps.amine.bou.readerforselfoss.persistence.entities.TagEntity + +@Database(entities = [TagEntity::class, SourceEntity::class], version = 1) +abstract class AppDatabase : RoomDatabase() { + abstract fun drawerDataDao(): DrawerDataDao +} \ No newline at end of file diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/persistence/entities/DrawerDataEntity.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/persistence/entities/DrawerDataEntity.kt new file mode 100644 index 0000000..4676548 --- /dev/null +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/persistence/entities/DrawerDataEntity.kt @@ -0,0 +1,33 @@ +package apps.amine.bou.readerforselfoss.persistence.entities + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "tags") +data class TagEntity( + @PrimaryKey + @ColumnInfo(name = "tag") + val tag: String, + @ColumnInfo(name = "color") + val color: String, + @ColumnInfo(name = "unread") + val unread: Int +) + +@Entity(tableName = "sources") +data class SourceEntity( + @PrimaryKey + @ColumnInfo(name = "id") + val id: String, + @ColumnInfo(name = "title") + val title: String, + @ColumnInfo(name = "tags") + val tags: String, + @ColumnInfo(name = "spout") + val spout: String, + @ColumnInfo(name = "error") + val error: String, + @ColumnInfo(name = "icon") + val icon: String +) \ No newline at end of file diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/persistence/EntitiesUtils.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/persistence/EntitiesUtils.kt new file mode 100644 index 0000000..d2f1416 --- /dev/null +++ b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/persistence/EntitiesUtils.kt @@ -0,0 +1,41 @@ +package apps.amine.bou.readerforselfoss.utils.persistence + +import android.content.Context +import apps.amine.bou.readerforselfoss.api.selfoss.Source +import apps.amine.bou.readerforselfoss.api.selfoss.Tag +import apps.amine.bou.readerforselfoss.persistence.entities.SourceEntity +import apps.amine.bou.readerforselfoss.persistence.entities.TagEntity + +fun TagEntity.toView(): Tag = + Tag( + this.tag, + this.color, + this.unread + ) + +fun SourceEntity.toView(): Source = + Source( + this.id, + this.title, + this.tags, + this.spout, + this.error, + this.icon + ) + +fun Source.toEntity(context: Context): SourceEntity = + SourceEntity( + this.id, + this.title, + this.tags, + this.spout, + this.error, + this.getIcon(context) + ) + +fun Tag.toEntity(): TagEntity = + TagEntity( + this.tag, + this.color, + this.unread + ) \ No newline at end of file diff --git a/build.gradle b/build.gradle index eabae3a..8fe06fa 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,8 @@ buildscript { ext { kotlin_version = '1.2.51' android_version = '1.0.0' + lifecycle_version = '2.0.0' + room_version = '2.1.0-alpha01' } repositories { jcenter()