Compare commits

..

78 Commits

Author SHA1 Message Date
ccab2c7648 Initial work on background task. 2018-11-01 21:51:31 +01:00
880dd1db5c New Crowdin translations (#231)
* New translations strings.xml (Catalan)

* New translations strings.xml (Japanese)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Turkish)

* New translations strings.xml (Swedish)

* New translations strings.xml (Spanish)

* New translations strings.xml (Serbian (Cyrillic))

* New translations strings.xml (Russian)

* New translations strings.xml (Romanian)

* New translations strings.xml (Portuguese, Brazilian)

* New translations strings.xml (Portuguese)

* New translations strings.xml (Polish)

* New translations strings.xml (Norwegian)

* New translations strings.xml (Korean)

* New translations strings.xml (Italian)

* New translations strings.xml (Afrikaans)

* New translations strings.xml (Indonesian)

* New translations strings.xml (Hungarian)

* New translations strings.xml (Hebrew)

* New translations strings.xml (Greek)

* New translations strings.xml (German)

* New translations strings.xml (French)

* New translations strings.xml (Finnish)

* New translations strings.xml (Dutch)

* New translations strings.xml (Danish)

* New translations strings.xml (Czech)

* New translations strings.xml (Chinese Traditional)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Arabic)

* New translations strings.xml (Galician)
2018-11-01 21:27:59 +01:00
ed18fea356 Closes #38. 2018-11-01 21:11:54 +01:00
9816b20bf6 Only do api calls on network available. 2018-11-01 21:10:00 +01:00
0bb2195bff Network status on articles loading. 2018-11-01 20:42:49 +01:00
ab2d0c4036 Closes #230. 2018-10-31 20:14:20 +01:00
99fc417109 Fixed #230. 2018-10-29 19:53:41 +01:00
dc304ef8c1 Updated gradle. 2018-10-20 09:29:09 +02:00
c5511880bc Just trying to fix fragment issues. 2018-10-19 05:27:16 +02:00
5fe76d735e Remiving items from the cache on swipe. 2018-10-17 20:19:35 +02:00
3064b3b835 Closes #228 by removing the list action bar. Action buttons are exclusively on the card view from now on. 2018-10-17 19:46:30 +02:00
70dc8af3ce New Crowdin translations (#227)
* New translations strings.xml (Spanish)

* New translations strings.xml (Galician)
2018-10-16 08:33:34 +02:00
53c8c241da Order By id desc for items. 2018-10-14 18:56:07 +02:00
bdc4f5680b Merge branch 'crowdin_translation' 2018-10-14 16:58:15 +02:00
ed290573b2 Merge branch 'master' into crowdin_translation 2018-10-14 16:57:45 +02:00
1616a97a8a New translations strings.xml (French) 2018-10-14 16:32:43 +02:00
d090183007 New translations strings.xml (French) 2018-10-14 16:31:09 +02:00
de337fd260 Moving to version 1.7 with caching. 2018-10-14 15:59:02 +02:00
12dc206323 Build with optional publish. 2018-10-14 15:57:22 +02:00
d47c508dee New translations strings.xml (Galician) 2018-10-14 15:42:10 +02:00
ed75f55437 New translations strings.xml (Arabic) 2018-10-14 15:42:09 +02:00
5ad3ad4a57 New translations strings.xml (Chinese Simplified) 2018-10-14 15:42:07 +02:00
aeac1bd1d4 New translations strings.xml (Chinese Traditional) 2018-10-14 15:42:06 +02:00
4d18085072 New translations strings.xml (Czech) 2018-10-14 15:42:04 +02:00
0c9f8214ca New translations strings.xml (Danish) 2018-10-14 15:42:03 +02:00
a7ce7ce02e New translations strings.xml (Dutch) 2018-10-14 15:42:01 +02:00
820986c7f0 New translations strings.xml (Finnish) 2018-10-14 15:42:00 +02:00
8079cae745 New translations strings.xml (French) 2018-10-14 15:41:59 +02:00
6f067bd258 New translations strings.xml (German) 2018-10-14 15:41:58 +02:00
b6ade0f212 New translations strings.xml (Greek) 2018-10-14 15:41:56 +02:00
27dadc1be3 New translations strings.xml (Hebrew) 2018-10-14 15:41:55 +02:00
95e4162b4c New translations strings.xml (Hungarian) 2018-10-14 15:41:54 +02:00
f75557585e New translations strings.xml (Indonesian) 2018-10-14 15:41:52 +02:00
1b4c26919b New translations strings.xml (Afrikaans) 2018-10-14 15:41:51 +02:00
ad085bf129 New translations strings.xml (Italian) 2018-10-14 15:41:50 +02:00
8fcd551105 New translations strings.xml (Korean) 2018-10-14 15:41:48 +02:00
a0954700e2 New translations strings.xml (Norwegian) 2018-10-14 15:41:47 +02:00
9705560442 New translations strings.xml (Polish) 2018-10-14 15:41:45 +02:00
1f47a13ce5 New translations strings.xml (Portuguese) 2018-10-14 15:41:44 +02:00
6f0ff2c975 New translations strings.xml (Portuguese, Brazilian) 2018-10-14 15:41:43 +02:00
76e5477986 New translations strings.xml (Romanian) 2018-10-14 15:41:41 +02:00
7f308d5be3 New translations strings.xml (Russian) 2018-10-14 15:41:40 +02:00
54a43c83e8 New translations strings.xml (Serbian (Cyrillic)) 2018-10-14 15:41:38 +02:00
8fe7266c84 New translations strings.xml (Spanish) 2018-10-14 15:41:37 +02:00
d7a46b27b7 New translations strings.xml (Swedish) 2018-10-14 15:41:36 +02:00
2257d09fdd New translations strings.xml (Turkish) 2018-10-14 15:41:34 +02:00
047c5481c4 New translations strings.xml (Ukrainian) 2018-10-14 15:41:33 +02:00
8a6719f934 New translations strings.xml (Vietnamese) 2018-10-14 15:41:32 +02:00
51a692f3be New translations strings.xml (Japanese) 2018-10-14 15:41:30 +02:00
b333f93171 New translations strings.xml (Catalan) 2018-10-14 15:41:29 +02:00
50bcf18096 New translations strings.xml (Galician) 2018-10-13 22:11:24 +02:00
a089ced03f New translations strings.xml (Arabic) 2018-10-13 22:11:23 +02:00
1f18dddf8b New translations strings.xml (Chinese Simplified) 2018-10-13 22:11:21 +02:00
f5934e240e New translations strings.xml (Chinese Traditional) 2018-10-13 22:11:20 +02:00
6b8da2eacf New translations strings.xml (Czech) 2018-10-13 22:11:19 +02:00
f4757a67b7 New translations strings.xml (Danish) 2018-10-13 22:11:17 +02:00
6edeb9d840 New translations strings.xml (Dutch) 2018-10-13 22:11:16 +02:00
43ce0fd7bc New translations strings.xml (Finnish) 2018-10-13 22:11:15 +02:00
5599f5a8fc New translations strings.xml (French) 2018-10-13 22:11:13 +02:00
6fd45ceb4f New translations strings.xml (German) 2018-10-13 22:11:12 +02:00
05ad8aac29 New translations strings.xml (Greek) 2018-10-13 22:11:11 +02:00
fa4f2476b7 New translations strings.xml (Hebrew) 2018-10-13 22:11:10 +02:00
00818a94e9 New translations strings.xml (Hungarian) 2018-10-13 22:11:08 +02:00
5d5250e44a New translations strings.xml (Indonesian) 2018-10-13 22:11:07 +02:00
3052b33132 New translations strings.xml (Afrikaans) 2018-10-13 22:11:06 +02:00
50de6f8b5b New translations strings.xml (Italian) 2018-10-13 22:11:04 +02:00
f88a2f415f New translations strings.xml (Norwegian) 2018-10-13 22:11:02 +02:00
96f9813e01 New translations strings.xml (Polish) 2018-10-13 22:11:01 +02:00
fee739cb17 New translations strings.xml (Portuguese) 2018-10-13 22:11:00 +02:00
b1814c63b9 New translations strings.xml (Portuguese, Brazilian) 2018-10-13 22:10:59 +02:00
c1d45678f8 New translations strings.xml (Romanian) 2018-10-13 22:10:58 +02:00
3d34e59a94 New translations strings.xml (Russian) 2018-10-13 22:10:56 +02:00
f1133bea8b New translations strings.xml (Spanish) 2018-10-13 22:10:54 +02:00
ec64c88ff1 New translations strings.xml (Swedish) 2018-10-13 22:10:53 +02:00
be66dbba6c New translations strings.xml (Turkish) 2018-10-13 22:10:52 +02:00
8926cdbbf5 New translations strings.xml (Vietnamese) 2018-10-13 22:10:50 +02:00
a956870dec New translations strings.xml (Japanese) 2018-10-13 22:10:49 +02:00
8ed7951c9b New translations strings.xml (Catalan) 2018-10-13 22:10:48 +02:00
55 changed files with 5299 additions and 4958 deletions

View File

@ -1,3 +1,11 @@
**1.7.x**
- Closing #1. Initial article caching.
- Closing #228 by removing the list action bar. Action buttons are exclusively on the card view from now on.
- Closing #38. Only doing api calls on network available.
**1.6.x** **1.6.x**
- Handling hidden tags. - Handling hidden tags.

View File

@ -160,6 +160,8 @@ dependencies {
implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version" kapt "androidx.room:room-compiler:$room_version"
implementation "android.arch.work:work-runtime-ktx:$work_version"
} }

View File

@ -30,22 +30,6 @@
<fields>; <fields>;
} }
##Retrofit
#-keep class com.google.gson.** { *; }
#-keep class com.google.inject.** { *; }
#-keep class org.apache.http.** { *; }
#-keep class org.apache.james.mime4j.** { *; }
#-keep class javax.inject.** { *; }
#-keep class retrofit.** { *; }
#-keepclassmembernames interface * {
# @retrofit.http.* <methods>;
#}
#-keep class retrofit.** { *; }
#-keep class apps.amine.bou.readerforselfoss.api.selfoss.model.** { *; }
#-keepclassmembernames interface * {
# @retrofit.http.* <methods>;
#}
-dontwarn okio.** -dontwarn okio.**
-dontwarn retrofit2.Platform$Java8 -dontwarn retrofit2.Platform$Java8
-keep class retrofit.** { *; } -keep class retrofit.** { *; }
@ -76,3 +60,6 @@
-dontwarn javax.annotation.** -dontwarn javax.annotation.**
-keep class android.support.v7.widget.SearchView { *; } -keep class android.support.v7.widget.SearchView { *; }
# maybe remove later ?
-keep class * extends androidx.fragment.app.Fragment

View File

@ -3,6 +3,7 @@
package="apps.amine.bou.readerforselfoss" package="apps.amine.bou.readerforselfoss"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<application <application

View File

@ -25,6 +25,10 @@ import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.room.Room import androidx.room.Room
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.work.Constraints
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter
import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter import apps.amine.bou.readerforselfoss.adapters.ItemListAdapter
import apps.amine.bou.readerforselfoss.adapters.ItemsAdapter import apps.amine.bou.readerforselfoss.adapters.ItemsAdapter
@ -34,6 +38,7 @@ import apps.amine.bou.readerforselfoss.api.selfoss.Source
import apps.amine.bou.readerforselfoss.api.selfoss.Stats import apps.amine.bou.readerforselfoss.api.selfoss.Stats
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.api.selfoss.Tag import apps.amine.bou.readerforselfoss.api.selfoss.Tag
import apps.amine.bou.readerforselfoss.background.LoadingWorker
import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase
import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_1_2 import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_1_2
import apps.amine.bou.readerforselfoss.settings.SettingsActivity import apps.amine.bou.readerforselfoss.settings.SettingsActivity
@ -47,6 +52,7 @@ import apps.amine.bou.readerforselfoss.utils.drawer.CustomUrlPrimaryDrawerItem
import apps.amine.bou.readerforselfoss.utils.flattenTags import apps.amine.bou.readerforselfoss.utils.flattenTags
import apps.amine.bou.readerforselfoss.utils.longHash import apps.amine.bou.readerforselfoss.utils.longHash
import apps.amine.bou.readerforselfoss.utils.maybeHandleSilentException import apps.amine.bou.readerforselfoss.utils.maybeHandleSilentException
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
import apps.amine.bou.readerforselfoss.utils.persistence.toView import apps.amine.bou.readerforselfoss.utils.persistence.toView
import co.zsmb.materialdrawerkt.builders.accountHeader import co.zsmb.materialdrawerkt.builders.accountHeader
@ -74,6 +80,7 @@ import org.acra.ACRA
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread import kotlin.concurrent.thread
class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
@ -179,6 +186,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
handleDrawer() handleDrawer()
handleSwipeRefreshLayout() handleSwipeRefreshLayout()
handleRecurringTask()
} }
private fun handleSwipeRefreshLayout() { private fun handleSwipeRefreshLayout() {
@ -203,7 +212,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
recyclerView: RecyclerView, recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder viewHolder: RecyclerView.ViewHolder
): Int = ): Int =
if (elementsShown != UNREAD_SHOWN) { if (elementsShown != UNREAD_SHOWN || !this@HomeActivity.isNetworkAccessible(null)) {
0 0
} else { } else {
super.getSwipeDirs( super.getSwipeDirs(
@ -333,7 +342,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
getElementsAccordingToTab() getElementsAccordingToTab()
handleGDPRDialog(sharedPref.getBoolean("GDPR_shown", false)) handleGDPRDialog(sharedPref.getBoolean("GDPR_shown", false))
} }
@ -696,6 +704,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
var sources: List<Source>? var sources: List<Source>?
fun sourcesApiCall() { fun sourcesApiCall() {
if (this@HomeActivity.isNetworkAccessible(null)) {
api.sources.enqueue(object : Callback<List<Source>> { api.sources.enqueue(object : Callback<List<Source>> {
override fun onResponse( override fun onResponse(
call: Call<List<Source>>?, call: Call<List<Source>>?,
@ -712,7 +721,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
} }
}) })
} }
}
if (this@HomeActivity.isNetworkAccessible(null)) {
api.tags.enqueue(object : Callback<List<Tag>> { api.tags.enqueue(object : Callback<List<Tag>> {
override fun onResponse( override fun onResponse(
call: Call<List<Tag>>, call: Call<List<Tag>>,
@ -727,6 +738,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
} }
}) })
} }
}
drawer.addItem( drawer.addItem(
PrimaryDrawerItem().withName(getString(R.string.drawer_loading)).withSelectable( PrimaryDrawerItem().withName(getString(R.string.drawer_loading)).withSelectable(
@ -817,12 +829,52 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
override fun onTabSelected(position: Int) { override fun onTabSelected(position: Int) {
offset = 0 offset = 0
lastFetchDone = false lastFetchDone = false
if (itemsCaching) {
if (!swipeRefreshLayout.isRefreshing) {
swipeRefreshLayout.post { swipeRefreshLayout.isRefreshing = true }
}
thread {
val dbItems = db.itemsDao().items().map { it.toView() }
runOnUiThread {
if (dbItems.isNotEmpty()) {
items = when (position) {
0 -> ArrayList(dbItems.filter { it.unread })
1 -> ArrayList(dbItems.filter { !it.unread })
2 -> ArrayList(dbItems.filter { it.starred })
else -> ArrayList(dbItems.filter { it.unread })
}
handleListResult()
when (position) { when (position) {
0 -> getUnRead() 0 -> getUnRead()
1 -> getRead() 1 -> getRead()
2 -> getStarred() 2 -> getStarred()
else -> Unit else -> Unit
} }
} else {
if (this@HomeActivity.isNetworkAccessible(this@HomeActivity.findViewById(R.id.coordLayout))) {
when (position) {
0 -> getUnRead()
1 -> getRead()
2 -> getStarred()
else -> Unit
}
getAndStoreAllItems()
}
}
}
}
} else {
when (position) {
0 -> getUnRead()
1 -> getRead()
2 -> getStarred()
else -> Unit
}
}
} }
}) })
} }
@ -899,11 +951,13 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
handleListResult() handleListResult()
doGetAccordingToTab() doGetAccordingToTab()
} else { } else {
if (this@HomeActivity.isNetworkAccessible(this@HomeActivity.findViewById(R.id.coordLayout))) {
doGetAccordingToTab() doGetAccordingToTab()
getAndStoreAllItems() getAndStoreAllItems()
} }
} }
} }
}
} else { } else {
doGetAccordingToTab() doGetAccordingToTab()
@ -956,6 +1010,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
swipeRefreshLayout.post { swipeRefreshLayout.isRefreshing = true } swipeRefreshLayout.post { swipeRefreshLayout.isRefreshing = true }
} }
if (this@HomeActivity.isNetworkAccessible(this@HomeActivity.findViewById(R.id.coordLayout))) {
call(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter) call(maybeTagFilter?.tag, maybeSourceFilter?.id?.toLong(), maybeSearchFilter)
.enqueue(object : Callback<List<Item>> { .enqueue(object : Callback<List<Item>> {
override fun onResponse( override fun onResponse(
@ -974,6 +1029,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
).show() ).show()
} }
}) })
} else {
swipeRefreshLayout.post { swipeRefreshLayout.isRefreshing = false }
}
} }
private fun getUnRead(appendResults: Boolean = false) { private fun getUnRead(appendResults: Boolean = false) {
@ -1034,6 +1092,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
this, this,
items, items,
api, api,
db,
customTabActivityHelper, customTabActivityHelper,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
@ -1050,6 +1109,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
this, this,
items, items,
api, api,
db,
customTabActivityHelper, customTabActivityHelper,
internalBrowser, internalBrowser,
articleViewer, articleViewer,
@ -1080,7 +1140,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
} }
private fun reloadBadges() { private fun reloadBadges() {
if (displayUnreadCount || displayAllCount) { if (this@HomeActivity.isNetworkAccessible(null) && (displayUnreadCount || displayAllCount)) {
api.stats.enqueue(object : Callback<Stats> { api.stats.enqueue(object : Callback<Stats> {
override fun onResponse(call: Call<Stats>, response: Response<Stats>) { override fun onResponse(call: Call<Stats>, response: Response<Stats>) {
if (response.body() != null) { if (response.body() != null) {
@ -1186,6 +1246,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.refresh -> { R.id.refresh -> {
if (this@HomeActivity.isNetworkAccessible(null)) {
needsConfirmation(R.string.menu_home_refresh, R.string.refresh_dialog_message) { needsConfirmation(R.string.menu_home_refresh, R.string.refresh_dialog_message) {
api.update().enqueue(object : Callback<String> { api.update().enqueue(object : Callback<String> {
override fun onResponse( override fun onResponse(
@ -1210,9 +1271,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show()
} }
return true return true
} else {
return false
}
} }
R.id.readAll -> { R.id.readAll -> {
if (elementsShown == UNREAD_SHOWN) { if (elementsShown == UNREAD_SHOWN && this@HomeActivity.isNetworkAccessible(null)) {
needsConfirmation(R.string.readAll, R.string.markall_dialog_message) { needsConfirmation(R.string.readAll, R.string.markall_dialog_message) {
swipeRefreshLayout.isRefreshing = false swipeRefreshLayout.isRefreshing = false
val ids = allItems.map { it.id } val ids = allItems.map { it.id }
@ -1332,5 +1396,24 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
alertDialog.show() alertDialog.show()
} }
} }
private fun handleRecurringTask() {
// TODO: add network type
val myConstraints = Constraints.Builder()
.setRequiresBatteryNotLow(true)
.setRequiresStorageNotLow(true)
.build()
// TODO: make the time variable from the settings.
val backgroundWork =
PeriodicWorkRequestBuilder<LoadingWorker>(4, TimeUnit.HOURS)
.setConstraints(myConstraints)
.addTag("selfoss-loading")
.build()
WorkManager.getInstance().enqueue(backgroundWork)
}
} }

View File

@ -21,6 +21,7 @@ import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.utils.Config import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid
import apps.amine.bou.readerforselfoss.utils.maybeHandleSilentException import apps.amine.bou.readerforselfoss.utils.maybeHandleSilentException
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.LibsBuilder import com.mikepenz.aboutlibraries.LibsBuilder
import kotlinx.android.synthetic.main.activity_login.* import kotlinx.android.synthetic.main.activity_login.*
@ -196,6 +197,8 @@ class LoginActivity : AppCompatActivity() {
isWithSelfSignedCert, isWithSelfSignedCert,
isWithSelfSignedCert isWithSelfSignedCert
) )
if (this@LoginActivity.isNetworkAccessible(this@LoginActivity.findViewById(R.id.loginForm))) {
api.login().enqueue(object : Callback<SuccessResponse> { api.login().enqueue(object : Callback<SuccessResponse> {
private fun preferenceError(t: Throwable) { private fun preferenceError(t: Throwable) {
editor.remove("url") editor.remove("url")
@ -235,6 +238,9 @@ class LoginActivity : AppCompatActivity() {
preferenceError(t) preferenceError(t)
} }
}) })
} else {
showProgress(false)
}
} }
} }

View File

@ -13,14 +13,19 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.room.Room
import apps.amine.bou.readerforselfoss.api.selfoss.Item import apps.amine.bou.readerforselfoss.api.selfoss.Item
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.fragments.ArticleFragment import apps.amine.bou.readerforselfoss.fragments.ArticleFragment
import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase
import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_1_2
import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.themes.Toppings import apps.amine.bou.readerforselfoss.themes.Toppings
import apps.amine.bou.readerforselfoss.transformers.DepthPageTransformer import apps.amine.bou.readerforselfoss.transformers.DepthPageTransformer
import apps.amine.bou.readerforselfoss.utils.maybeHandleSilentException import apps.amine.bou.readerforselfoss.utils.maybeHandleSilentException
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
import apps.amine.bou.readerforselfoss.utils.succeeded import apps.amine.bou.readerforselfoss.utils.succeeded
import apps.amine.bou.readerforselfoss.utils.toggleStar import apps.amine.bou.readerforselfoss.utils.toggleStar
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
@ -30,6 +35,7 @@ import org.acra.ACRA
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import kotlin.concurrent.thread
class ReaderActivity : AppCompatActivity() { class ReaderActivity : AppCompatActivity() {
@ -42,6 +48,8 @@ class ReaderActivity : AppCompatActivity() {
private lateinit var toolbarMenu: Menu private lateinit var toolbarMenu: Menu
private lateinit var db: AppDatabase
private fun showMenuItem(willAddToFavorite: Boolean) { private fun showMenuItem(willAddToFavorite: Boolean) {
toolbarMenu.findItem(R.id.save).isVisible = willAddToFavorite toolbarMenu.findItem(R.id.save).isVisible = willAddToFavorite
toolbarMenu.findItem(R.id.unsave).isVisible = !willAddToFavorite toolbarMenu.findItem(R.id.unsave).isVisible = !willAddToFavorite
@ -60,6 +68,11 @@ class ReaderActivity : AppCompatActivity() {
setContentView(R.layout.activity_reader) setContentView(R.layout.activity_reader)
db = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java, "selfoss-database"
).addMigrations(MIGRATION_1_2).build()
val scoop = Scoop.getInstance() val scoop = Scoop.getInstance()
scoop.bind(this, Toppings.PRIMARY.value, toolBar) scoop.bind(this, Toppings.PRIMARY.value, toolBar)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@ -89,9 +102,10 @@ class ReaderActivity : AppCompatActivity() {
currentItem = intent.getIntExtra("currentItem", 0) currentItem = intent.getIntExtra("currentItem", 0)
readItem(allItems[currentItem].id) readItem(allItems[currentItem])
pager.adapter = ScreenSlidePagerAdapter(supportFragmentManager, AppColors(this@ReaderActivity)) pager.adapter =
ScreenSlidePagerAdapter(supportFragmentManager, AppColors(this@ReaderActivity))
pager.currentItem = currentItem pager.currentItem = currentItem
} }
@ -113,15 +127,18 @@ class ReaderActivity : AppCompatActivity() {
} else { } else {
canFavorite() canFavorite()
} }
readItem(allItems[pager.currentItem].id) readItem(allItems[pager.currentItem])
} }
} }
) )
} }
fun readItem(id: String) { fun readItem(item: Item) {
if (markOnScroll) { if (this@ReaderActivity.isNetworkAccessible(this@ReaderActivity.findViewById(R.id.reader_activity_view)) && markOnScroll) {
api.markItem(id).enqueue( thread {
db.itemsDao().delete(item.toEntity())
}
api.markItem(item.id).enqueue(
object : Callback<SuccessResponse> { object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
@ -145,8 +162,12 @@ class ReaderActivity : AppCompatActivity() {
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
t: Throwable t: Throwable
) { ) {
thread {
db.itemsDao().insertAllItems(item.toEntity())
}
if (debugReadingItems) { if (debugReadingItems) {
ACRA.getErrorReporter().maybeHandleSilentException(t, this@ReaderActivity) ACRA.getErrorReporter()
.maybeHandleSilentException(t, this@ReaderActivity)
} }
} }
} }
@ -173,7 +194,6 @@ class ReaderActivity : AppCompatActivity() {
private inner class ScreenSlidePagerAdapter(fm: FragmentManager, val appColors: AppColors) : private inner class ScreenSlidePagerAdapter(fm: FragmentManager, val appColors: AppColors) :
FragmentStatePagerAdapter(fm) { FragmentStatePagerAdapter(fm) {
override fun getCount(): Int { override fun getCount(): Int {
return allItems.size return allItems.size
} }
@ -185,7 +205,12 @@ class ReaderActivity : AppCompatActivity() {
override fun startUpdate(container: ViewGroup) { override fun startUpdate(container: ViewGroup) {
super.startUpdate(container) super.startUpdate(container)
container.background = ColorDrawable(ContextCompat.getColor(this@ReaderActivity, appColors.colorBackground)) container.background = ColorDrawable(
ContextCompat.getColor(
this@ReaderActivity,
appColors.colorBackground
)
)
} }
} }
@ -210,6 +235,7 @@ class ReaderActivity : AppCompatActivity() {
return true return true
} }
R.id.save -> { R.id.save -> {
if (this@ReaderActivity.isNetworkAccessible(null)) {
api.starrItem(allItems[pager.currentItem].id) api.starrItem(allItems[pager.currentItem].id)
.enqueue(object : Callback<SuccessResponse> { .enqueue(object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
@ -233,7 +259,9 @@ class ReaderActivity : AppCompatActivity() {
} }
}) })
} }
}
R.id.unsave -> { R.id.unsave -> {
if (this@ReaderActivity.isNetworkAccessible(null)) {
api.unstarrItem(allItems[pager.currentItem].id) api.unstarrItem(allItems[pager.currentItem].id)
.enqueue(object : Callback<SuccessResponse> { .enqueue(object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
@ -258,6 +286,7 @@ class ReaderActivity : AppCompatActivity() {
}) })
} }
} }
}
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }

View File

@ -13,6 +13,7 @@ import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.Source import apps.amine.bou.readerforselfoss.api.selfoss.Source
import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.themes.Toppings import apps.amine.bou.readerforselfoss.themes.Toppings
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import com.ftinc.scoop.Scoop import com.ftinc.scoop.Scoop
import kotlinx.android.synthetic.main.activity_sources.* import kotlinx.android.synthetic.main.activity_sources.*
import retrofit2.Call import retrofit2.Call
@ -66,6 +67,7 @@ class SourcesActivity : AppCompatActivity() {
recyclerView.setHasFixedSize(true) recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = mLayoutManager recyclerView.layoutManager = mLayoutManager
if (this@SourcesActivity.isNetworkAccessible(this@SourcesActivity.findViewById(R.id.recyclerView))) {
api.sources.enqueue(object : Callback<List<Source>> { api.sources.enqueue(object : Callback<List<Source>> {
override fun onResponse( override fun onResponse(
call: Call<List<Source>>, call: Call<List<Source>>,
@ -94,6 +96,7 @@ class SourcesActivity : AppCompatActivity() {
).show() ).show()
} }
}) })
}
fab.setOnClickListener { fab.setOnClickListener {
startActivity(Intent(this@SourcesActivity, AddSourceActivity::class.java)) startActivity(Intent(this@SourcesActivity, AddSourceActivity::class.java))

View File

@ -14,11 +14,14 @@ import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item import apps.amine.bou.readerforselfoss.api.selfoss.Item
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.persistence.database.AppDatabase
import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.utils.LinkOnTouchListener
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.glide.bitmapCenterCrop import apps.amine.bou.readerforselfoss.utils.glide.bitmapCenterCrop
import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import apps.amine.bou.readerforselfoss.utils.openInBrowserAsNewTask import apps.amine.bou.readerforselfoss.utils.openInBrowserAsNewTask
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
@ -38,6 +41,7 @@ class ItemCardAdapter(
override val app: Activity, override val app: Activity,
override var items: ArrayList<Item>, override var items: ArrayList<Item>,
override val api: SelfossApi, override val api: SelfossApi,
override val db: AppDatabase,
private val helper: CustomTabActivityHelper, private val helper: CustomTabActivityHelper,
private val internalBrowser: Boolean, private val internalBrowser: Boolean,
private val articleViewer: Boolean, private val articleViewer: Boolean,
@ -63,6 +67,7 @@ class ItemCardAdapter(
holder.mView.favButton.isLiked = itm.starred holder.mView.favButton.isLiked = itm.starred
holder.mView.title.text = Html.fromHtml(itm.title) holder.mView.title.text = Html.fromHtml(itm.title)
holder.mView.title.setOnTouchListener(LinkOnTouchListener())
holder.mView.title.setLinkTextColor(appColors.colorAccent) holder.mView.title.setLinkTextColor(appColors.colorAccent)
@ -113,6 +118,7 @@ class ItemCardAdapter(
mView.favButton.setOnLikeListener(object : OnLikeListener { mView.favButton.setOnLikeListener(object : OnLikeListener {
override fun liked(likeButton: LikeButton) { override fun liked(likeButton: LikeButton) {
if (c.isNetworkAccessible(null)) {
val (id) = items[adapterPosition] val (id) = items[adapterPosition]
api.starrItem(id).enqueue(object : Callback<SuccessResponse> { api.starrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
@ -134,8 +140,10 @@ class ItemCardAdapter(
} }
}) })
} }
}
override fun unLiked(likeButton: LikeButton) { override fun unLiked(likeButton: LikeButton) {
if (c.isNetworkAccessible(null)) {
val (id) = items[adapterPosition] val (id) = items[adapterPosition]
api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> { api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
@ -157,6 +165,7 @@ class ItemCardAdapter(
} }
}) })
} }
}
}) })
mView.shareBtn.setOnClickListener { mView.shareBtn.setOnClickListener {

View File

@ -5,16 +5,22 @@ import android.content.Context
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.text.Html import android.text.Html
import android.text.Spannable
import android.text.style.ClickableSpan
import android.util.TypedValue import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item import apps.amine.bou.readerforselfoss.api.selfoss.Item
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.persistence.database.AppDatabase
import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.utils.LinkOnTouchListener
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.glide.bitmapCenterCrop import apps.amine.bou.readerforselfoss.utils.glide.bitmapCenterCrop
@ -39,6 +45,7 @@ class ItemListAdapter(
override val app: Activity, override val app: Activity,
override var items: ArrayList<Item>, override var items: ArrayList<Item>,
override val api: SelfossApi, override val api: SelfossApi,
override val db: AppDatabase,
private val helper: CustomTabActivityHelper, private val helper: CustomTabActivityHelper,
private val internalBrowser: Boolean, private val internalBrowser: Boolean,
private val articleViewer: Boolean, private val articleViewer: Boolean,
@ -49,7 +56,6 @@ class ItemListAdapter(
) : ItemsAdapter<ItemListAdapter.ViewHolder>() { ) : ItemsAdapter<ItemListAdapter.ViewHolder>() {
private val generator: ColorGenerator = ColorGenerator.MATERIAL private val generator: ColorGenerator = ColorGenerator.MATERIAL
private val c: Context = app.baseContext private val c: Context = app.baseContext
private val bars: ArrayList<Boolean> = ArrayList(Collections.nCopies(items.size + 1, false))
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(c).inflate( val v = LayoutInflater.from(c).inflate(
@ -66,6 +72,8 @@ class ItemListAdapter(
holder.mView.title.text = Html.fromHtml(itm.title) holder.mView.title.text = Html.fromHtml(itm.title)
holder.mView.title.setOnTouchListener(LinkOnTouchListener())
holder.mView.title.setLinkTextColor(appColors.colorAccent) holder.mView.title.setLinkTextColor(appColors.colorAccent)
holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText() holder.mView.sourceTitleAndDate.text = itm.sourceAndDateText()
@ -105,19 +113,6 @@ class ItemListAdapter(
} else { } else {
c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage) c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage)
} }
// TODO: maybe handle this differently. It crashes when changing tab
try {
if (bars[position]) {
holder.mView.actionBar.visibility = View.VISIBLE
} else {
holder.mView.actionBar.visibility = View.GONE
}
} catch (e: IndexOutOfBoundsException) {
holder.mView.actionBar.visibility = View.GONE
}
holder.mView.favButton.isLiked = itm.starred
} }
override fun getItemCount(): Int = items.size override fun getItemCount(): Int = items.size
@ -125,76 +120,14 @@ class ItemListAdapter(
inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) { inner class ViewHolder(val mView: ConstraintLayout) : RecyclerView.ViewHolder(mView) {
init { init {
handleClickListeners()
handleCustomTabActions() handleCustomTabActions()
} }
private fun handleClickListeners() {
mView.favButton.setOnLikeListener(object : OnLikeListener {
override fun liked(likeButton: LikeButton) {
val (id) = items[adapterPosition]
api.starrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(
call: Call<SuccessResponse>,
t: Throwable
) {
mView.favButton.isLiked = false
Toast.makeText(
c,
R.string.cant_mark_favortie,
Toast.LENGTH_SHORT
).show()
}
})
}
override fun unLiked(likeButton: LikeButton) {
val (id) = items[adapterPosition]
api.unstarrItem(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse(
call: Call<SuccessResponse>,
response: Response<SuccessResponse>
) {
}
override fun onFailure(
call: Call<SuccessResponse>,
t: Throwable
) {
mView.favButton.isLiked = true
Toast.makeText(
c,
R.string.cant_unmark_favortie,
Toast.LENGTH_SHORT
).show()
}
})
}
})
mView.shareBtn.setOnClickListener {
c.shareLink(items[adapterPosition].getLinkDecoded())
}
mView.browserBtn.setOnClickListener {
c.openInBrowserAsNewTask(items[adapterPosition])
}
}
private fun handleCustomTabActions() { private fun handleCustomTabActions() {
val customTabsIntent = c.buildCustomTabsIntent() val customTabsIntent = c.buildCustomTabsIntent()
helper.bindCustomTabsService(app) helper.bindCustomTabsService(app)
mView.setOnClickListener { actionBarShowHide() } mView.setOnClickListener {
mView.setOnLongClickListener {
c.openItemUrl( c.openItemUrl(
items, items,
adapterPosition, adapterPosition,
@ -204,16 +137,6 @@ class ItemListAdapter(
articleViewer, articleViewer,
app app
) )
true
}
}
private fun actionBarShowHide() {
bars[adapterPosition] = true
if (mView.actionBar.visibility == View.GONE) {
mView.actionBar.visibility = View.VISIBLE
} else {
mView.actionBar.visibility = View.GONE
} }
} }
} }

View File

@ -10,17 +10,22 @@ import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.api.selfoss.Item import apps.amine.bou.readerforselfoss.api.selfoss.Item
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.persistence.database.AppDatabase
import apps.amine.bou.readerforselfoss.themes.AppColors import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.utils.maybeHandleSilentException import apps.amine.bou.readerforselfoss.utils.maybeHandleSilentException
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
import apps.amine.bou.readerforselfoss.utils.succeeded import apps.amine.bou.readerforselfoss.utils.succeeded
import org.acra.ACRA import org.acra.ACRA
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import kotlin.concurrent.thread
abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapter<VH>() { abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapter<VH>() {
abstract var items: ArrayList<Item> abstract var items: ArrayList<Item>
abstract val api: SelfossApi abstract val api: SelfossApi
abstract val db: AppDatabase
abstract val debugReadingItems: Boolean abstract val debugReadingItems: Boolean
abstract val userIdentifier: String abstract val userIdentifier: String
abstract val app: Activity abstract val app: Activity
@ -41,7 +46,11 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
Snackbar.LENGTH_LONG Snackbar.LENGTH_LONG
) )
.setAction(R.string.undo_string) { .setAction(R.string.undo_string) {
if (app.isNetworkAccessible(null)) {
items.add(position, i) items.add(position, i)
thread {
db.itemsDao().insertAllItems(i.toEntity())
}
notifyItemInserted(position) notifyItemInserted(position)
updateItems(items) updateItems(items)
@ -54,12 +63,16 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) { override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
items.remove(i) items.remove(i)
thread {
db.itemsDao().delete(i.toEntity())
}
notifyItemRemoved(position) notifyItemRemoved(position)
updateItems(items) updateItems(items)
doUnmark(i, position) doUnmark(i, position)
} }
}) })
} }
}
val view = s.view val view = s.view
val tv: TextView = view.findViewById(com.google.android.material.R.id.snackbar_text) val tv: TextView = view.findViewById(com.google.android.material.R.id.snackbar_text)
@ -68,13 +81,19 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
} }
fun removeItemAtIndex(position: Int) { fun removeItemAtIndex(position: Int) {
if (app.isNetworkAccessible(null)) {
val i = items[position] val i = items[position]
items.remove(i) items.remove(i)
notifyItemRemoved(position) notifyItemRemoved(position)
updateItems(items) updateItems(items)
// TODO: Handle network status.
// IF offline, delete from cached articles, and add to some table that will replay the calls on network activation.
thread {
db.itemsDao().delete(i.toEntity())
}
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> { api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
@ -93,6 +112,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
ACRA.getErrorReporter().maybeHandleSilentException(Exception(message), app) ACRA.getErrorReporter().maybeHandleSilentException(Exception(message), app)
Toast.makeText(app.baseContext, message, Toast.LENGTH_LONG).show() Toast.makeText(app.baseContext, message, Toast.LENGTH_LONG).show()
} }
doUnmark(i, position) doUnmark(i, position)
} }
@ -110,9 +130,13 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
notifyItemInserted(position) notifyItemInserted(position)
updateItems(items) updateItems(items)
thread {
db.itemsDao().insertAllItems(i.toEntity())
}
} }
}) })
} }
}
fun addItemAtIndex(item: Item, position: Int) { fun addItemAtIndex(item: Item, position: Int) {
items.add(position, item) items.add(position, item)

View File

@ -13,6 +13,7 @@ import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.Source import apps.amine.bou.readerforselfoss.api.selfoss.Source
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable import apps.amine.bou.readerforselfoss.utils.glide.circularBitmapDrawable
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import apps.amine.bou.readerforselfoss.utils.toTextDrawableString import apps.amine.bou.readerforselfoss.utils.toTextDrawableString
import com.amulyakhare.textdrawable.TextDrawable import com.amulyakhare.textdrawable.TextDrawable
import com.amulyakhare.textdrawable.util.ColorGenerator import com.amulyakhare.textdrawable.util.ColorGenerator
@ -70,6 +71,7 @@ class SourcesListAdapter(
val deleteBtn: Button = mView.findViewById(R.id.deleteBtn) val deleteBtn: Button = mView.findViewById(R.id.deleteBtn)
deleteBtn.setOnClickListener { deleteBtn.setOnClickListener {
if (c.isNetworkAccessible(null)) {
val (id) = items[adapterPosition] val (id) = items[adapterPosition]
api.deleteSource(id).enqueue(object : Callback<SuccessResponse> { api.deleteSource(id).enqueue(object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
@ -101,3 +103,4 @@ class SourcesListAdapter(
} }
} }
} }
}

View File

@ -21,7 +21,7 @@ import java.util.concurrent.ConcurrentHashMap
class SelfossApi( class SelfossApi(
c: Context, c: Context,
callingActivity: Activity, callingActivity: Activity?,
isWithSelfSignedCert: Boolean, isWithSelfSignedCert: Boolean,
shouldLog: Boolean shouldLog: Boolean
) { ) {
@ -91,9 +91,11 @@ class SelfossApi(
.build() .build()
service = retrofit.create(SelfossService::class.java) service = retrofit.create(SelfossService::class.java)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
if (callingActivity != null) {
Config.logoutAndRedirect(c, callingActivity, config.settings.edit(), baseUrlFail = true) Config.logoutAndRedirect(c, callingActivity, config.settings.edit(), baseUrlFail = true)
} }
} }
}
fun login(): Call<SuccessResponse> = fun login(): Call<SuccessResponse> =
service.loginToSelfoss(config.userLogin, config.userPassword) service.loginToSelfoss(config.userLogin, config.userPassword)

View File

@ -0,0 +1,57 @@
package apps.amine.bou.readerforselfoss.background
import android.content.Context
import android.preference.PreferenceManager
import androidx.room.Room
import androidx.work.Worker
import androidx.work.WorkerParameters
import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase
import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_1_2
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import kotlin.concurrent.thread
class LoadingWorker(val context: Context, params: WorkerParameters) : Worker(context, params) {
override fun doWork(): Result {
val settings = this.context.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
val sharedPref = PreferenceManager.getDefaultSharedPreferences(this.context)
val shouldLogEverything = sharedPref.getBoolean("should_log_everything", false)
val db = Room.databaseBuilder(
applicationContext,
AppDatabase::class.java, "selfoss-database"
).addMigrations(MIGRATION_1_2).build()
val api = SelfossApi(
this.context,
null,
settings.getBoolean("isSelfSignedCert", false),
shouldLogEverything
)
api.allItems().enqueue(object : Callback<List<Item>> {
override fun onFailure(call: Call<List<Item>>, t: Throwable) {
}
override fun onResponse(
call: Call<List<Item>>,
response: Response<List<Item>>
) {
thread {
if (response.body() != null) {
val apiItems = (response.body() as ArrayList<Item>)
db.itemsDao().deleteAllItems()
db.itemsDao()
.insertAllItems(*(apiItems.map { it.toEntity() }).toTypedArray())
}
}
}
})
return Result.SUCCESS
}
}

View File

@ -29,6 +29,7 @@ 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.isEmptyOrNullOrNullString import apps.amine.bou.readerforselfoss.utils.isEmptyOrNullOrNullString
import apps.amine.bou.readerforselfoss.utils.maybeHandleSilentException import apps.amine.bou.readerforselfoss.utils.maybeHandleSilentException
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
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 apps.amine.bou.readerforselfoss.utils.sourceAndDateText import apps.amine.bou.readerforselfoss.utils.sourceAndDateText
@ -135,7 +136,8 @@ class ArticleFragment : Fragment() {
false, false,
activity!! activity!!
) )
R.id.unread_action -> api.unmarkItem(allItems[pageNumber.toInt()].id).enqueue( R.id.unread_action -> if ((context != null && context!!.isNetworkAccessible(null)) || context == null) {
api.unmarkItem(allItems[pageNumber.toInt()].id).enqueue(
object : Callback<SuccessResponse> { object : Callback<SuccessResponse> {
override fun onResponse( override fun onResponse(
call: Call<SuccessResponse>, call: Call<SuccessResponse>,
@ -164,6 +166,7 @@ class ArticleFragment : Fragment() {
} }
} }
) )
}
else -> Unit else -> Unit
} }
} }
@ -212,6 +215,7 @@ class ArticleFragment : Fragment() {
customTabsIntent: CustomTabsIntent, customTabsIntent: CustomTabsIntent,
prefs: SharedPreferences prefs: SharedPreferences
) { ) {
if ((context != null && context!!.isNetworkAccessible(null)) || context == null) {
rootView.progressBar.visibility = View.VISIBLE rootView.progressBar.visibility = View.VISIBLE
val parser = MercuryApi( val parser = MercuryApi(
prefs.getBoolean("should_log_everything", false) prefs.getBoolean("should_log_everything", false)
@ -303,6 +307,7 @@ class ArticleFragment : Fragment() {
} }
) )
} }
}
private fun htmlToWebview(c: String, prefs: SharedPreferences) { private fun htmlToWebview(c: String, prefs: SharedPreferences) {
val stringColor = String.format("#%06X", 0xFFFFFF and appColors.colorAccent) val stringColor = String.format("#%06X", 0xFFFFFF and appColors.colorAccent)

View File

@ -1,6 +1,7 @@
package apps.amine.bou.readerforselfoss.persistence.dao package apps.amine.bou.readerforselfoss.persistence.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
@ -11,15 +12,18 @@ import androidx.room.Update
@Dao @Dao
interface ItemsDao { interface ItemsDao {
@Query("SELECT * FROM items") @Query("SELECT * FROM items order by id desc")
fun items(): List<ItemEntity> fun items(): List<ItemEntity>
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAllItems(vararg tags: ItemEntity) fun insertAllItems(vararg items: ItemEntity)
@Query("DELETE FROM items") @Query("DELETE FROM items")
fun deleteAllItems() fun deleteAllItems()
@Delete
fun delete(item: ItemEntity)
@Update @Update
fun updateItem(item: ItemEntity) fun updateItem(item: ItemEntity)
} }

View File

@ -6,8 +6,13 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.text.Spannable
import android.text.style.ClickableSpan
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import android.util.Patterns import android.util.Patterns
import android.view.MotionEvent
import android.view.View
import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import apps.amine.bou.readerforselfoss.R import apps.amine.bou.readerforselfoss.R
import apps.amine.bou.readerforselfoss.ReaderActivity import apps.amine.bou.readerforselfoss.ReaderActivity
@ -146,3 +151,40 @@ fun Context.openInBrowserAsNewTask(i: Item) {
intent.data = Uri.parse(i.getLinkDecoded().toStringUriWithHttp()) intent.data = Uri.parse(i.getLinkDecoded().toStringUriWithHttp())
startActivity(intent) startActivity(intent)
} }
class LinkOnTouchListener: View.OnTouchListener {
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
var ret = false
val widget: TextView = v as TextView
val text: CharSequence = widget.text
val stext = Spannable.Factory.getInstance().newSpannable(text)
val action = event!!.action
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
var x: Float = event.x
var y: Float = event.y
x -= widget.totalPaddingLeft
y -= widget.totalPaddingTop
x += widget.scrollX
y += widget.scrollY
val layout = widget.layout
val line = layout.getLineForVertical(y.toInt())
val off = layout.getOffsetForHorizontal(line, x)
val link = stext.getSpans(off, off, ClickableSpan::class.java)
if (link.isNotEmpty()) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget)
}
ret = true
}
}
return ret
}
}

View File

@ -0,0 +1,41 @@
package apps.amine.bou.readerforselfoss.utils.network
import android.content.Context
import android.graphics.Color
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.view.View
import android.widget.TextView
import apps.amine.bou.readerforselfoss.R
import com.google.android.material.snackbar.Snackbar
var snackBarShown = false
var view: View? = null
fun Context.isNetworkAccessible(v: View?): Boolean {
val cm = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val activeNetwork: NetworkInfo? = cm.activeNetworkInfo
val networkIsAccessible = activeNetwork != null && activeNetwork.isConnectedOrConnecting
if (v != null && !networkIsAccessible && (!snackBarShown || v != view)) {
view = v
val s = Snackbar
.make(
v,
R.string.no_network_connectivity,
Snackbar.LENGTH_INDEFINITE
)
s.setAction(android.R.string.ok) {
snackBarShown = false
s.dismiss()
}
val view = s.view
val tv: TextView = view.findViewById(com.google.android.material.R.id.snackbar_text)
tv.setTextColor(Color.WHITE)
s.show()
snackBarShown = true
}
return networkIsAccessible
}

View File

@ -2,6 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:id="@+id/reader_activity_view"
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout

View File

@ -11,7 +11,6 @@
android:id="@+id/itemImage" android:id="@+id/itemImage"
android:layout_width="88dp" android:layout_width="88dp"
android:layout_height="88dp" android:layout_height="88dp"
app:layout_constraintBottom_toBottomOf="@+id/actionBar"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
@ -40,79 +39,16 @@
android:id="@+id/sourceTitleAndDate" android:id="@+id/sourceTitleAndDate"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:gravity="start" android:gravity="start"
android:textAlignment="viewStart" android:textAlignment="viewStart"
android:textSize="14sp" android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@+id/actionBar"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/itemImage" app:layout_constraintStart_toEndOf="@+id/itemImage"
app:layout_constraintTop_toBottomOf="@+id/title" app:layout_constraintTop_toBottomOf="@+id/title"
tools:text="Google Actualité Il y a 5h" /> tools:text="Google Actualité Il y a 5h" />
<RelativeLayout
android:id="@+id/actionBar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="#BBBBBB"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible">
<com.like.LikeButton
android:id="@+id/favButton"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:elevation="5dp"
android:padding="4dp"
app:icon_size="22dp"
app:icon_type="heart" />
<ImageButton
android:id="@+id/shareBtn"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_centerVertical="true"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_toLeftOf="@+id/favButton"
android:layout_toStartOf="@+id/favButton"
android:adjustViewBounds="true"
android:background="@android:color/transparent"
android:backgroundTint="?android:attr/textColorPrimary"
android:elevation="5dp"
android:padding="4dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_share_black_24dp" />
<ImageButton
android:id="@+id/browserBtn"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_centerVertical="true"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_toLeftOf="@+id/shareBtn"
android:layout_toStartOf="@+id/shareBtn"
android:adjustViewBounds="true"
android:background="@android:color/transparent"
android:backgroundTint="?android:attr/textColorPrimary"
android:elevation="5dp"
android:padding="4dp"
android:scaleType="centerCrop"
android:src="@drawable/ic_open_in_browser_black_24dp" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Habilita el registre</string> <string name="acra_login">Habilita el registre</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Habilitar el registro</string> <string name="acra_login">Habilitar el registro</string>
<string name="drawer_item_hidden_tags">Etiquetas ocultas</string> <string name="drawer_item_hidden_tags">Etiquetas ocultas</string>
<string name="unmark">Marcar artículo como no leído</string> <string name="unmark">Marcar artículo como no leído</string>
<string name="pref_header_offline">Sin conexión y caché</string>
<string name="pref_switch_items_caching_off">Los artículos no se guardarán en la memoria del dispositivo y la aplicación no se podrá utilizar sin conexión.</string>
<string name="pref_switch_items_caching_on">Los artículos se guardarán en la memoria del dispositivo y se utilizarán para el uso sin conexión.</string>
<string name="pref_switch_items_caching">Guardar elementos para uso sin conexión</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Activer les logs</string> <string name="acra_login">Activer les logs</string>
<string name="drawer_item_hidden_tags">Tags Cachés</string> <string name="drawer_item_hidden_tags">Tags Cachés</string>
<string name="unmark">Marquer l\'article comme non lu</string> <string name="unmark">Marquer l\'article comme non lu</string>
<string name="pref_header_offline">Hors ligne et cache</string>
<string name="pref_switch_items_caching_off">Les articles ne seront pas enregistrés et l\'application ne sera pas utilisable hors ligne.</string>
<string name="pref_switch_items_caching_on">Les articles seront enregistrés et l\'application sera utilisable hors ligne.</string>
<string name="pref_switch_items_caching">Sauvegarder les articles pour une utilisation hors ligne</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Habilitar o rexistro</string> <string name="acra_login">Habilitar o rexistro</string>
<string name="drawer_item_hidden_tags">Etiquetas ocultas</string> <string name="drawer_item_hidden_tags">Etiquetas ocultas</string>
<string name="unmark">Marcar artículo como non lido</string> <string name="unmark">Marcar artículo como non lido</string>
<string name="pref_header_offline">Sen conexión e caché</string>
<string name="pref_switch_items_caching_off">Os artigos non se gardaran na memoria do dispositivo e non se poderá utilizar a aplicación sen conexión.</string>
<string name="pref_switch_items_caching_on">Os artigos gardaranse na memoria do dispositivo e estarán dispoñibles sen conexión.</string>
<string name="pref_switch_items_caching">Gardar elementos para uso sen conexión</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Segna come non letto</string> <string name="unmark">Segna come non letto</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Ativar registro de erros</string> <string name="acra_login">Ativar registro de erros</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -148,4 +148,9 @@
<string name="acra_login">Enable logging</string> <string name="acra_login">Enable logging</string>
<string name="drawer_item_hidden_tags">Hidden Tags</string> <string name="drawer_item_hidden_tags">Hidden Tags</string>
<string name="unmark">Mark item as unread</string> <string name="unmark">Mark item as unread</string>
<string name="pref_header_offline">Offline and cache</string>
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -152,4 +152,5 @@
<string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string> <string name="pref_switch_items_caching_off">Articles won\'t be saved to the device memory, and the app won\'t be usable offline.</string>
<string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string> <string name="pref_switch_items_caching_on">Articles will be saved to the device memory and will be used for offline use.</string>
<string name="pref_switch_items_caching">Save items for offline use</string> <string name="pref_switch_items_caching">Save items for offline use</string>
<string name="no_network_connectivity">Not connected !</string>
</resources> </resources>

View File

@ -6,6 +6,7 @@ buildscript {
android_version = '1.0.0' android_version = '1.0.0'
lifecycle_version = '2.0.0' lifecycle_version = '2.0.0'
room_version = '2.1.0-alpha01' room_version = '2.1.0-alpha01'
work_version = "1.0.0-alpha10"
} }
repositories { repositories {
google() google()
@ -15,7 +16,7 @@ buildscript {
} }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.0' classpath 'com.android.tools.build:gradle:3.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }

View File

@ -1,10 +1,15 @@
#!/bin/bash #!/bin/bash
BASE_VERSION="1.6" BASE_VERSION="1.7"
TODAYS_VERSION="1" TODAYS_VERSION="1"
VERSION="${BASE_VERSION//./}$(date '+%y%m%j')$TODAYS_VERSION" VERSION="${BASE_VERSION//./}$(date '+%y%m%j')$TODAYS_VERSION"
./version.sh ${VERSION} $@ ./version.sh ${VERSION} $1
if [[ "$@" == *'--publish'* ]]
then
./publish-version.sh ${VERSION} ./publish-version.sh ${VERSION}
else
echo "Did not publish. If you wanted to do so, call the script with \"--publish\"."
fi

View File

@ -1 +1,14 @@
include ':app' include ':app'
ext.isCiServer = !!System.getProperty("CI")
buildCache {
local {
enabled = !isCiServer
}
remote(HttpBuildCache) {
// DO NOT COMMIT !!!!!
url = 'http://amine-bou.fr:8885/cache/'
push = isCiServer
}
}