Fixes #67. May need fine tuning.

This commit is contained in:
Amine 2017-09-10 19:22:07 +02:00
parent 54b2ac7f24
commit 04feb66b07
18 changed files with 127 additions and 67 deletions

View File

@ -1,6 +1,11 @@
**1.5.3.00**
- (BETA) Added pull from bottom to load more pages of results. May be buggy.
**1.5.2.18/19** **1.5.2.18/19**
- APK minification finally working. That means less space taken ! - APK minification finally working. That means less space taken !
- Added an option to log every API call.
**1.5.2.17** **1.5.2.17**

View File

@ -131,7 +131,7 @@ dependencies {
// Retrofit + http logging + okhttp // Retrofit + http logging + okhttp
compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.8.0' compile 'com.squareup.okhttp3:logging-interceptor:3.9.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.burgstaller:okhttp-digest:1.12' compile 'com.burgstaller:okhttp-digest:1.12'
@ -143,10 +143,8 @@ dependencies {
compile 'org.sufficientlysecure:html-textview:3.3' compile 'org.sufficientlysecure:html-textview:3.3'
// glide // glide
compile('com.github.bumptech.glide:glide:4.1.0@aar') { compile 'com.github.bumptech.glide:glide:4.1.1'
transitive = true; compile 'com.github.bumptech.glide:okhttp3-integration:4.1.1'
}
compile('com.github.bumptech.glide:okhttp3-integration:4.1.0@aar')
// Asking politely users to rate the app // Asking politely users to rate the app
compile 'com.github.stkent:amplify:2.1.0' compile 'com.github.stkent:amplify:2.1.0'

View File

@ -61,6 +61,11 @@
# self signed glidemodule # self signed glidemodule
-keep public class * implements com.bumptech.glide.module.GlideModule -keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-dontwarn com.anupcowkur.reservoir.** -dontwarn com.anupcowkur.reservoir.**

View File

@ -97,6 +97,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private var maybeSearchFilter: String? = null private var maybeSearchFilter: String? = null
private var userIdentifier: String = "" private var userIdentifier: String = ""
private var displayAccountHeader: Boolean = false private var displayAccountHeader: Boolean = false
private var infiniteScroll: Boolean = false
private lateinit var emptyText: TextView private lateinit var emptyText: TextView
private lateinit var recyclerView: RecyclerView private lateinit var recyclerView: RecyclerView
@ -114,6 +115,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private lateinit var sharedPref: SharedPreferences private lateinit var sharedPref: SharedPreferences
private lateinit var firebaseRemoteConfig: FirebaseRemoteConfig private lateinit var firebaseRemoteConfig: FirebaseRemoteConfig
private lateinit var appColors: AppColors private lateinit var appColors: AppColors
private var offset: Int = 0
private var firstVisible: Int = 0
private var recyclerViewScrollListener: RecyclerView.OnScrollListener? = null
@ -294,6 +299,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
itemsNumber = sharedPref.getString("prefer_api_items_number", "200").toInt() itemsNumber = sharedPref.getString("prefer_api_items_number", "200").toInt()
userIdentifier = sharedPref.getString("unique_id", "") userIdentifier = sharedPref.getString("unique_id", "")
displayAccountHeader = sharedPref.getBoolean("account_header_displaying", false) displayAccountHeader = sharedPref.getBoolean("account_header_displaying", false)
infiniteScroll = sharedPref.getBoolean("infinite_loading", false)
} }
private fun handleDrawer(dirtyPref: SharedPreferences) { private fun handleDrawer(dirtyPref: SharedPreferences) {
@ -374,7 +380,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
} }
else { else {
for (tag in maybeTags) { for (tag in maybeTags) {
val gd: GradientDrawable = GradientDrawable() val gd = GradientDrawable()
gd.setColor(Color.parseColor(tag.color)) gd.setColor(Color.parseColor(tag.color))
gd.shape = GradientDrawable.RECTANGLE gd.shape = GradientDrawable.RECTANGLE
gd.setSize(30, 30) gd.setSize(30, 30)
@ -567,6 +573,30 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
recyclerView.layoutManager = mLayoutManager recyclerView.layoutManager = mLayoutManager
recyclerView.setHasFixedSize(true) recyclerView.setHasFixedSize(true)
if (infiniteScroll) {
if (recyclerViewScrollListener == null)
recyclerViewScrollListener = object: RecyclerView.OnScrollListener() {
override fun onScrolled(localRecycler: RecyclerView?, dx: Int, dy: Int) {
if (dy > 0) {
if (localRecycler != null) {
val lastVisibleItem: Int = when (mLayoutManager) {
is StaggeredGridLayoutManager -> mLayoutManager.findLastCompletelyVisibleItemPositions(null).last()
is GridLayoutManager -> mLayoutManager.findLastCompletelyVisibleItemPosition()
else -> 0
}
if (lastVisibleItem == (items.size - 1)) {
getElementsAccordingToTab(appendResults = true)
}
}
}
}
}
recyclerView.clearOnScrollListeners()
recyclerView.addOnScrollListener(recyclerViewScrollListener)
}
bottomBar.setTabSelectedListener(object: BottomNavigationBar.OnTabSelectedListener { bottomBar.setTabSelectedListener(object: BottomNavigationBar.OnTabSelectedListener {
override fun onTabUnselected(position: Int) = Unit override fun onTabUnselected(position: Int) = Unit
@ -605,26 +635,31 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
recyclerView.visibility = View.VISIBLE recyclerView.visibility = View.VISIBLE
} }
private fun getElementsAccordingToTab() = private fun getElementsAccordingToTab(appendResults: Boolean = false) =
when (elementsShown) { when (elementsShown) {
UNREAD_SHOWN -> getUnRead() UNREAD_SHOWN -> getUnRead(appendResults)
READ_SHOWN -> getRead() READ_SHOWN -> getRead(appendResults)
FAV_SHOWN -> getStarred() FAV_SHOWN -> getStarred(appendResults)
else -> getUnRead() else -> getUnRead(appendResults)
} }
private fun doCallTo(toastMessage: Int, call: (String?, Long?, String?) -> Call<List<Item>>) { private fun doCallTo(appendResults: Boolean, toastMessage: Int, call: (String?, Long?, String?) -> Call<List<Item>>) {
fun handleItemsResponse(response: Response<List<Item>>) { fun handleItemsResponse(response: Response<List<Item>>) {
val didUpdate = (response.body() != items) val didUpdate = (response.body() != items)
if (response.body() != null) { if (response.body() != null) {
if (response.body() != items) { if (response.body() != items) {
items = response.body() as ArrayList<Item> if (appendResults)
items.addAll(response.body() as ArrayList<Item>)
else
items = response.body() as ArrayList<Item>
} }
} else { } else {
items = ArrayList() if (!appendResults)
items = ArrayList()
} }
if (didUpdate) if (didUpdate)
handleListResult() handleListResult(appendResults)
mayBeEmpty() mayBeEmpty()
swipeRefreshLayout.isRefreshing = false swipeRefreshLayout.isRefreshing = false
} }
@ -645,22 +680,40 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
}) })
} }
private fun getUnRead() { private fun getUnRead(appendResults: Boolean = false) {
offset = if (appendResults) (offset + itemsNumber)
else 0
firstVisible = if (appendResults) firstVisible else 0
elementsShown = UNREAD_SHOWN elementsShown = UNREAD_SHOWN
doCallTo(R.string.cant_get_new_elements){t, id, f -> api.newItems(t, id, f, itemsNumber)} doCallTo(appendResults, R.string.cant_get_new_elements){t, id, f -> api.newItems(t, id, f, itemsNumber, offset)}
} }
private fun getRead() { private fun getRead(appendResults: Boolean = false) {
offset = if (appendResults) (offset + itemsNumber)
else 0
firstVisible = if (appendResults) firstVisible else 0
elementsShown = READ_SHOWN elementsShown = READ_SHOWN
doCallTo(R.string.cant_get_read){t, id, f -> api.readItems(t, id, f)} doCallTo(appendResults, R.string.cant_get_read){t, id, f -> api.readItems(t, id, f, itemsNumber, offset)}
} }
private fun getStarred() { private fun getStarred(appendResults: Boolean = false) {
offset = if (appendResults) (offset + itemsNumber)
else 0
firstVisible = if (appendResults) firstVisible else 0
elementsShown = FAV_SHOWN elementsShown = FAV_SHOWN
doCallTo(R.string.cant_get_favs){t, id, f -> api.starredItems(t, id, f)} doCallTo(appendResults, R.string.cant_get_favs){t, id, f -> api.starredItems(t, id, f, itemsNumber, offset)}
} }
private fun handleListResult() { private fun handleListResult(appendResults: Boolean = false) {
if (appendResults) {
val oldManager = recyclerView.layoutManager
firstVisible = if ((oldManager is StaggeredGridLayoutManager)) {
oldManager.findFirstCompletelyVisibleItemPositions(null).last()
}
else
(oldManager as GridLayoutManager)?.findFirstCompletelyVisibleItemPosition()
}
reloadLayoutManager() reloadLayoutManager()
val mAdapter: RecyclerView.Adapter<*> val mAdapter: RecyclerView.Adapter<*>
@ -693,6 +746,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
recyclerView.adapter = mAdapter recyclerView.adapter = mAdapter
mAdapter.notifyDataSetChanged() mAdapter.notifyDataSetChanged()
if (appendResults) {
recyclerView.scrollToPosition(firstVisible!!)
}
reloadBadges() reloadBadges()
} }

View File

@ -17,7 +17,7 @@ class IntroActivity : MaterialIntroActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)
addSlide(SlideFragmentBuilder() addSlide(SlideFragmentBuilder()
.backgroundColor(R.color.colorPrimary) .backgroundColor(R.color.colorPrimary)

View File

@ -16,14 +16,6 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.* import android.widget.*
import com.google.firebase.analytics.FirebaseAnalytics
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.LibsBuilder
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.Config
@ -31,7 +23,12 @@ import apps.amine.bou.readerforselfoss.utils.checkAndDisplayStoreApk
import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import io.fabric.sdk.android.Fabric import com.google.firebase.analytics.FirebaseAnalytics
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.LibsBuilder
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class LoginActivity : AppCompatActivity() { class LoginActivity : AppCompatActivity() {

View File

@ -1,7 +1,5 @@
package apps.amine.bou.readerforselfoss package apps.amine.bou.readerforselfoss
import android.content.Intent
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -9,23 +7,21 @@ import android.view.ViewGroup
import android.widget.ImageButton import android.widget.ImageButton
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import com.bumptech.glide.Glide
import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter
import org.sufficientlysecure.htmltextview.HtmlTextView
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import xyz.klinker.android.drag_dismiss.activity.DragDismissActivity
import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi
import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent import apps.amine.bou.readerforselfoss.api.mercury.ParsedContent
import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent import apps.amine.bou.readerforselfoss.utils.buildCustomTabsIntent
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import apps.amine.bou.readerforselfoss.utils.openItemUrl import apps.amine.bou.readerforselfoss.utils.openItemUrl
import apps.amine.bou.readerforselfoss.utils.shareLink import apps.amine.bou.readerforselfoss.utils.shareLink
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import org.sufficientlysecure.htmltextview.HtmlHttpImageGetter
import org.sufficientlysecure.htmltextview.HtmlTextView
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import xyz.klinker.android.drag_dismiss.activity.DragDismissActivity
class ReaderActivity : DragDismissActivity() { class ReaderActivity : DragDismissActivity() {

View File

@ -99,17 +99,17 @@ class SelfossApi(c: Context, callingActivity: Activity, isWithSelfSignedCert: Bo
fun login(): Call<SuccessResponse> = fun login(): Call<SuccessResponse> =
service.loginToSelfoss(config.userLogin, config.userPassword) service.loginToSelfoss(config.userLogin, config.userPassword)
fun readItems(tag: String?, sourceId: Long?, search: String?): Call<List<Item>> = fun readItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> =
getItems("read", tag, sourceId, search, 200) getItems("read", tag, sourceId, search, itemsNumber, offset)
fun newItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int): Call<List<Item>> = fun newItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> =
getItems("unread", tag, sourceId, search, itemsNumber) getItems("unread", tag, sourceId, search, itemsNumber, offset)
fun starredItems(tag: String?, sourceId: Long?, search: String?): Call<List<Item>> = fun starredItems(tag: String?, sourceId: Long?, search: String?, itemsNumber: Int, offset: Int): Call<List<Item>> =
getItems("starred", tag, sourceId, search, 200) getItems("starred", tag, sourceId, search, itemsNumber, offset)
private fun getItems(type: String, tag: String?, sourceId: Long?, search: String?, items: Int): Call<List<Item>> = private fun getItems(type: String, tag: String?, sourceId: Long?, search: String?, items: Int, offset: Int): Call<List<Item>> =
service.getItems(type, tag, sourceId, search, userName, password, items) service.getItems(type, tag, sourceId, search, userName, password, items, offset)
fun markItem(itemId: String): Call<SuccessResponse> = fun markItem(itemId: String): Call<SuccessResponse> =
service.markAsRead(itemId, userName, password) service.markAsRead(itemId, userName, password)

View File

@ -114,14 +114,14 @@ data class Item(@SerializedName("id") val id: String,
// TODO: maybe find a better way to handle these kind of urls // TODO: maybe find a better way to handle these kind of urls
fun getLinkDecoded(): String { fun getLinkDecoded(): String {
var stringUrl: String var stringUrl: String
if (link.startsWith("http://news.google.com/news/") || link.startsWith("https://news.google.com/news/")) { stringUrl = if (link.startsWith("http://news.google.com/news/") || link.startsWith("https://news.google.com/news/")) {
if (link.contains("&amp;url=")) { if (link.contains("&amp;url=")) {
stringUrl = link.substringAfter("&amp;url=") link.substringAfter("&amp;url=")
} else { } else {
stringUrl = this.link.replace("&amp;", "&") this.link.replace("&amp;", "&")
} }
} else { } else {
stringUrl = this.link.replace("&amp;", "&") this.link.replace("&amp;", "&")
} }
// handle :443 => https // handle :443 => https

View File

@ -23,7 +23,8 @@ internal interface SelfossService {
@Query("search") search: String?, @Query("search") search: String?,
@Query("username") username: String, @Query("username") username: String,
@Query("password") password: String, @Query("password") password: String,
@Query("items") items: Int): Call<List<Item>> @Query("items") items: Int,
@Query("offset") offset: Int): Call<List<Item>>
@POST("mark/{id}") @POST("mark/{id}")
fun markAsRead(@Path("id") id: String, fun markAsRead(@Path("id") id: String,

View File

@ -5,8 +5,6 @@ import android.content.Context
import android.support.annotation.ColorInt import android.support.annotation.ColorInt
import android.util.TypedValue import android.util.TypedValue
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
import java.lang.reflect.AccessibleObject.setAccessible
class AppColors(a: Activity) { class AppColors(a: Activity) {

View File

@ -97,7 +97,7 @@ fun String.longHash(): Long {
val l = this.length val l = this.length
val chars = this.toCharArray() val chars = this.toCharArray()
for (i in 0..l - 1) { for (i in 0 until l) {
h = 31 * h + chars[i].toLong() h = 31 * h + chars[i].toLong()
} }
return h return h

View File

@ -16,7 +16,7 @@ fun String.toTextDrawableString(): String {
} }
fun Item.sourceAndDateText(): String { fun Item.sourceAndDateText(): String {
var formattedDate: String = try { val formattedDate: String = try {
" " + DateUtils.getRelativeTimeSpanString( " " + DateUtils.getRelativeTimeSpanString(
SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(this.datetime).time, SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(this.datetime).time,
Date().time, Date().time,

View File

@ -7,14 +7,10 @@ import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.support.customtabs.CustomTabsIntent import android.support.customtabs.CustomTabsIntent
import xyz.klinker.android.drag_dismiss.DragDismissIntentBuilder
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.ReaderActivity import apps.amine.bou.readerforselfoss.ReaderActivity
import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper import apps.amine.bou.readerforselfoss.utils.customtabs.CustomTabActivityHelper
import xyz.klinker.android.drag_dismiss.DragDismissIntentBuilder
fun Context.buildCustomTabsIntent(): CustomTabsIntent { fun Context.buildCustomTabsIntent(): CustomTabsIntent {

View File

@ -150,4 +150,5 @@
<string name="login_everything_title">Log de tous les appels à l\'API</string> <string name="login_everything_title">Log de tous les appels à l\'API</string>
<string name="login_everything_off">Aucun appel à l\'API ne sera logué</string> <string name="login_everything_off">Aucun appel à l\'API ne sera logué</string>
<string name="login_everything_on">Tous les appels à l\'API vont êtres logués</string> <string name="login_everything_on">Tous les appels à l\'API vont êtres logués</string>
<string name="pref_general_infinite_loading_title">(BETA) Charger plus d\'articles au scroll</string>
</resources> </resources>

View File

@ -151,4 +151,5 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string>
</resources> </resources>

View File

@ -153,4 +153,5 @@
<string name="login_everything_title">Logging every api calls</string> <string name="login_everything_title">Logging every api calls</string>
<string name="login_everything_on">This will log every api call for debug purpose.</string> <string name="login_everything_on">This will log every api call for debug purpose.</string>
<string name="login_everything_off">No api call will be logged</string> <string name="login_everything_off">No api call will be logged</string>
<string name="pref_general_infinite_loading_title">(BETA) Load more articles on scroll</string>
</resources> </resources>

View File

@ -1,5 +1,4 @@
<PreferenceScreen xmlns:tools="http://schemas.android.com/tools" <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
xmlns:android="http://schemas.android.com/apk/res/android">
<!--<SwitchPreference <!--<SwitchPreference
android:defaultValue="false" android:defaultValue="false"
@ -18,6 +17,11 @@
android:selectAllOnFocus="true" android:selectAllOnFocus="true"
android:singleLine="true" android:singleLine="true"
android:title="@string/pref_api_items_number_title" /> android:title="@string/pref_api_items_number_title" />
<SwitchPreference
android:defaultValue="false"
android:key="infinite_loading"
android:title="@string/pref_general_infinite_loading_title" />
<PreferenceCategory <PreferenceCategory
android:title="@string/pref_general_category_links"> android:title="@string/pref_general_category_links">