diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6db0d1..6cbcfac 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+**1.5.0.3**
+
+- Added a drawer for filtering sources and tags.
+
**1.5.0.2**
- If the content in the article viewer is empty, the article will open in a custom tab.
diff --git a/app/build.gradle b/app/build.gradle
index e824ecd..ff6975c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -113,6 +113,12 @@ dependencies {
// For the article reader
compile 'com.klinkerapps:drag-dismiss-activity:1.4.0'
+ // Drawer
+ compile('com.mikepenz:materialdrawer:5.9.2@aar') {
+ transitive = true
+ }
+ compile 'com.anupcowkur:reservoir:3.1.0'
+
}
apply plugin: 'com.google.gms.google-services'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 15c5231..e779c4c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -31,7 +31,8 @@
-
+
= ArrayList()
@@ -77,6 +92,10 @@ class HomeActivity : AppCompatActivity() {
private var tabStarred: BottomBarTab? = null
private var mFirebaseRemoteConfig: FirebaseRemoteConfig? = null
private var fullHeightCards: Boolean = false
+ private var toolbar: Toolbar? = null
+ private var drawer: Drawer? = null
+
+ data class DrawerData(val tags: List?, val sources: List?)
private fun handleSharedPrefs() {
clickBehavior = this.sharedPref!!.getBoolean("tab_on_tap", false)
@@ -91,6 +110,8 @@ class HomeActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
+ handleDrawerItems()
+
sharedPref = PreferenceManager.getDefaultSharedPreferences(this)
val settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
@@ -110,13 +131,150 @@ class HomeActivity : AppCompatActivity() {
getElementsAccordingToTab()
}
+ fun handleDrawer() {
+
+ drawer = DrawerBuilder()
+ .withActivity(this)
+ .withRootView(R.id.drawer_layout)
+ .withToolbar(toolbar!!)
+ .withActionBarDrawerToggle(true)
+ .withActionBarDrawerToggleAnimated(true)
+ .withShowDrawerOnFirstLaunch(true)
+ .build()
+
+ }
+
+ fun handleDrawerItems() {
+ fun handleDrawerData(maybeDrawerData: DrawerData?, loadedFromCache: Boolean = false) {
+ fun handleTags(maybeTags: List?) {
+ if (maybeTags == null) {
+ if (loadedFromCache)
+ drawer!!.addItem(PrimaryDrawerItem().withName("Error loading tags..."))
+ }
+ else {
+ for (tag in maybeTags) {
+ val gd: GradientDrawable = GradientDrawable()
+ gd.setColor(Color.parseColor(tag.color))
+ gd.shape = GradientDrawable.RECTANGLE
+ gd.setSize(30, 30)
+ gd.cornerRadius = 30F
+ drawer!!.addItem(
+ PrimaryDrawerItem()
+ .withName(tag.tag)
+ .withIdentifier(longHash(tag.tag))
+ .withIcon(gd)
+ .withOnDrawerItemClickListener { _, _, _ ->
+ getElementsAccordingToTab(maybeTagFilter = tag)
+ true
+ }
+ )
+ }
+ }
+
+ }
+
+ fun handleSources(maybeSources: List?) {
+ if (maybeSources == null) {
+ if (loadedFromCache)
+ drawer!!.addItem(PrimaryDrawerItem().withName("Error loading sources..."))
+ }
+ else
+ for (tag in maybeSources)
+ drawer!!.addItem(
+ PrimaryDrawerItem()
+ .withName(tag.title)
+ .withIdentifier(tag.id.toLong())
+ .withOnDrawerItemClickListener { _, _, _ ->
+ getElementsAccordingToTab(maybeSourceFilter = tag)
+ true
+ }
+ )
+
+ }
+
+ drawer!!.removeAllItems()
+ if (maybeDrawerData != null) {
+ drawer!!.addItem(SecondaryDrawerItem().withName("Tags").withIdentifier(DRAWER_ID_TAGS).withSelectable(false))
+ handleTags(maybeDrawerData.tags)
+ drawer!!.addItem(DividerDrawerItem())
+ drawer!!.addItem(SecondaryDrawerItem().withName("Sources").withIdentifier(DRAWER_ID_TAGS).withSelectable(false))
+ handleSources(maybeDrawerData.sources)
+ if (!loadedFromCache)
+ Reservoir.putAsync("drawerData", maybeDrawerData, object : ReservoirPutCallback {
+ override fun onSuccess() {}
+
+ override fun onFailure(p0: Exception?) {
+ Toast.makeText(this@HomeActivity, "Couldn't cache your drawer data", Toast.LENGTH_SHORT).show()
+ }
+
+ })
+ } else {
+ if (!loadedFromCache) {
+ drawer!!.addItem(SecondaryDrawerItem().withName("No tags loaded").withIdentifier(DRAWER_ID_TAGS).withSelectable(false))
+ drawer!!.addItem(SecondaryDrawerItem().withName("No sources loaded").withIdentifier(DRAWER_ID_SOURCES).withSelectable(false))
+ }
+ }
+
+ }
+
+ fun drawerApiCalls(maybeDrawerData: DrawerData?) {
+ var tags: List? = null
+ var sources: List? = null
+
+ fun sourcesApiCall() {
+ api!!.sources.enqueue(object: Callback> {
+ override fun onResponse(call: Call>?, response: Response>) {
+ sources = response.body()
+ val apiDrawerData = DrawerData(tags, sources)
+ if (maybeDrawerData == null || (maybeDrawerData != null && maybeDrawerData != apiDrawerData))
+ handleDrawerData(apiDrawerData)
+ }
+
+ override fun onFailure(call: Call>?, t: Throwable?) {
+
+ }
+
+ })
+ }
+
+ api!!.tags.enqueue(object: Callback> {
+ override fun onResponse(call: Call>, response: Response>) {
+ tags = response.body()
+ sourcesApiCall()
+ }
+
+ override fun onFailure(call: Call>?, t: Throwable?) {
+ sourcesApiCall()
+ }
+
+ })
+ }
+
+ drawer!!.addItem(SecondaryDrawerItem().withName("Loading ...").withSelectable(false))
+
+ val resultType = object : TypeToken() {}.type
+ Reservoir.getAsync("drawerData", resultType, object: ReservoirGetCallback {
+ override fun onSuccess(maybeDrawerData: DrawerData?) {
+ handleDrawerData(maybeDrawerData, loadedFromCache = true)
+ drawerApiCalls(maybeDrawerData)
+ }
+
+ override fun onFailure(p0: Exception?) {
+ drawerApiCalls(null)
+ }
+
+ })
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
+ toolbar = findViewById(R.id.toolbar) as Toolbar?
+ setSupportActionBar(toolbar)
+
if (savedInstanceState == null) {
val promptView = findViewById(R.id.prompt_view) as DefaultLayoutPromptView
-
Amplify.getSharedInstance().promptIfReady(promptView)
}
@@ -130,6 +288,8 @@ class HomeActivity : AppCompatActivity() {
mBottomBar = findViewById(R.id.bottomBar) as BottomBar
+ handleDrawer()
+
// TODO: clean this hack
val listenerAlreadySet = booleanArrayOf(false)
mBottomBar!!.setOnTabSelectListener { tabId ->
@@ -228,20 +388,20 @@ class HomeActivity : AppCompatActivity() {
}
}
- private fun getElementsAccordingToTab() {
+ private fun getElementsAccordingToTab(maybeTagFilter: Tag? = null, maybeSourceFilter: Sources? = null) {
items = ArrayList()
when (elementsShown) {
- UNREAD_SHOWN -> getUnRead()
- READ_SHOWN -> getRead()
- FAV_SHOWN -> getStarred()
- else -> getUnRead()
+ UNREAD_SHOWN -> getUnRead(maybeTagFilter, maybeSourceFilter)
+ READ_SHOWN -> getRead(maybeTagFilter, maybeSourceFilter)
+ FAV_SHOWN -> getStarred(maybeTagFilter, maybeSourceFilter)
+ else -> getUnRead(maybeTagFilter, maybeSourceFilter)
}
}
- private fun getUnRead() {
+ private fun getUnRead(maybeTagFilter: Tag? = null, maybeSourceFilter: Sources? = null) {
elementsShown = UNREAD_SHOWN
- api!!.unreadItems.enqueue(object : Callback> {
+ api!!.unreadItems(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong()).enqueue(object : Callback> {
override fun onResponse(call: Call>, response: Response>) {
if (response.body() != null && response.body()!!.isNotEmpty()) {
items = response.body() as ArrayList-
@@ -259,9 +419,9 @@ class HomeActivity : AppCompatActivity() {
})
}
- private fun getRead() {
+ private fun getRead(maybeTagFilter: Tag? = null, maybeSourceFilter: Sources? = null) {
elementsShown = READ_SHOWN
- api!!.readItems.enqueue(object : Callback
> {
+ api!!.readItems(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong()).enqueue(object : Callback> {
override fun onResponse(call: Call>, response: Response>) {
if (response.body() != null && response.body()!!.isNotEmpty()) {
items = response.body() as ArrayList-
@@ -279,9 +439,9 @@ class HomeActivity : AppCompatActivity() {
})
}
- private fun getStarred() {
+ private fun getStarred(maybeTagFilter: Tag? = null, maybeSourceFilter: Sources? = null) {
elementsShown = FAV_SHOWN
- api!!.starredItems.enqueue(object : Callback
> {
+ api!!.starredItems(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong()).enqueue(object : Callback> {
override fun onResponse(call: Call>, response: Response>) {
if (response.body() != null && response.body()!!.isNotEmpty()) {
items = response.body() as ArrayList-
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 9e2f304..62a8e6e 100644
--- a/app/src/main/java/apps/amine/bou/readerforselfoss/MyApp.kt
+++ b/app/src/main/java/apps/amine/bou/readerforselfoss/MyApp.kt
@@ -4,6 +4,8 @@ import android.support.multidex.MultiDexApplication
import com.crashlytics.android.Crashlytics
import com.github.stkent.amplify.tracking.Amplify
import io.fabric.sdk.android.Fabric
+import com.anupcowkur.reservoir.Reservoir
+import java.io.IOException
class MyApp : MultiDexApplication() {
@@ -16,5 +18,11 @@ class MyApp : MultiDexApplication() {
.setFeedbackEmailAddress(getString(R.string.feedback_email))
.setAlwaysShow(BuildConfig.DEBUG)
.applyAllDefaultRules()
+
+ try {
+ Reservoir.init(this, 4096) //in bytes
+ } catch (e: IOException) {
+ //failure
+ }
}
}
\ No newline at end of file
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 eec5a62..baced67 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
@@ -72,17 +72,17 @@ class SelfossApi(c: Context) {
return service.loginToSelfoss(config.userLogin, config.userPassword)
}
- val readItems: Call
>
- get() = getItems("read")
+ fun readItems(tag: String?, sourceId: Long?): Call> =
+ getItems("read", tag, sourceId)
- val unreadItems: Call>
- get() = getItems("unread")
+ fun unreadItems(tag: String?, sourceId: Long?): Call> =
+ getItems("unread", tag, sourceId)
- val starredItems: Call>
- get() = getItems("starred")
+ fun starredItems(tag: String?, sourceId: Long?): Call> =
+ getItems("starred", tag, sourceId)
- private fun getItems(type: String): Call> {
- return service.getItems(type, userName, password)
+ private fun getItems(type: String, tag: String?, sourceId: Long?): Call> {
+ return service.getItems(type, tag, sourceId, userName, password)
}
fun markItem(itemId: 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 a67510f..0038934 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
@@ -17,7 +17,7 @@ private fun constructUrl(config: Config?, path: String, file: String): String {
}
-data class Tag(val tag: String, val color: String, val unread: Int)
+data class Tag(val tag: String, val color: String)
class SuccessResponse(val success: Boolean) {
val isSuccess: Boolean
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 b281007..3b48401 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
@@ -16,7 +16,11 @@ internal interface SelfossService {
fun loginToSelfoss(@Query("username") username: String, @Query("password") password: String): Call
@GET("items")
- fun getItems(@Query("type") type: String, @Query("username") username: String, @Query("password") password: String): Call>
+ fun getItems(@Query("type") type: String,
+ @Query("tag") tag: String?,
+ @Query("source") source: Long?,
+ @Query("username") username: String,
+ @Query("password") password: String): Call>
@POST("mark/{id}")
fun markAsRead(@Path("id") id: String, @Query("username") username: String, @Query("password") password: String): Call
diff --git a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/AppUtils.kt b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/AppUtils.kt
index 0706115..3381bcd 100644
--- a/app/src/main/java/apps/amine/bou/readerforselfoss/utils/AppUtils.kt
+++ b/app/src/main/java/apps/amine/bou/readerforselfoss/utils/AppUtils.kt
@@ -85,4 +85,15 @@ private fun isThereAnUpdate(settings: SharedPreferences, editor: SharedPreferenc
alertDialog.show()
}
+}
+
+fun longHash(string: String): Long {
+ var h = 98764321261L
+ val l = string.length
+ val chars = string.toCharArray()
+
+ for (i in 0..l - 1) {
+ h = 31 * h + chars[i].toLong()
+ }
+ return h
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml
index 78dd711..89677b4 100644
--- a/app/src/main/res/layout/activity_home.xml
+++ b/app/src/main/res/layout/activity_home.xml
@@ -5,6 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="apps.amine.bou.readerforselfoss.HomeActivity"
+ android:fitsSystemWindows="true"
xmlns:app="http://schemas.android.com/apk/res-auto">
-
-
-
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index e06c743..0f1e291 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -13,4 +13,20 @@
- @drawable/background_splash
+
+
+
+
+