Compare commits
19 Commits
v171901005
...
v171901015
Author | SHA1 | Date | |
---|---|---|---|
ddc754ec25 | |||
134a0766d6 | |||
69da932ab5 | |||
592fb6328a | |||
a0aead6491 | |||
722b6cc06d | |||
6d7c4b40f6 | |||
f538ed39fc | |||
65821492ad | |||
6ede718a9f | |||
f1757937a4 | |||
2bd2e0a953 | |||
b5aef28af0 | |||
45747a1506 | |||
c6e2e08bcb | |||
25bf18661e | |||
6b088dcd24 | |||
d2b18e1880 | |||
eec7c94e98 |
@ -67,7 +67,7 @@ android {
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
shrinkResources false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
||||
'proguard-rules.pro'
|
||||
}
|
||||
@ -112,7 +112,7 @@ dependencies {
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
|
||||
|
||||
//multidex
|
||||
implementation 'androidx.multidex:multidex:2.0.0'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
|
||||
// About
|
||||
implementation('com.mikepenz:aboutlibraries:6.2.0@aar') {
|
||||
|
@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="apps.amine.bou.readerforselfoss"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
package="apps.amine.bou.readerforselfoss">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
@ -19,11 +18,11 @@
|
||||
android:theme="@style/SplashTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data android:name="android.app.shortcuts"
|
||||
<meta-data
|
||||
android:name="android.app.shortcuts"
|
||||
android:resource="@xml/shortcuts" />
|
||||
</activity>
|
||||
<activity
|
||||
@ -38,7 +37,7 @@
|
||||
android:parentActivityName=".HomeActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="apps.amine.bou.readerforselfoss.HomeActivity" />
|
||||
android:value=".HomeActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".SourcesActivity"
|
||||
@ -56,9 +55,7 @@
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEND" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
@ -77,6 +74,9 @@
|
||||
android:value="true" />
|
||||
|
||||
<meta-data android:name="android.max_aspect" android:value="2.1" />
|
||||
<meta-data
|
||||
android:name="preloaded_fonts"
|
||||
android:resource="@array/preloaded_fonts" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
@ -1,5 +1,6 @@
|
||||
package apps.amine.bou.readerforselfoss
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@ -85,10 +86,12 @@ class AddSourceActivity : AppCompatActivity() {
|
||||
|
||||
try {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
val settings =
|
||||
getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||
api = SelfossApi(
|
||||
this,
|
||||
this@AddSourceActivity,
|
||||
prefs.getBoolean("isSelfSignedCert", false),
|
||||
settings.getBoolean("isSelfSignedCert", false),
|
||||
prefs.getString("api_timeout", "-1").toLong(),
|
||||
prefs.getBoolean("should_log_everything", false)
|
||||
)
|
||||
|
@ -18,17 +18,13 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter
|
||||
@ -69,7 +65,6 @@ import com.ashokvarma.bottomnavigation.BottomNavigationItem
|
||||
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
||||
import com.ftinc.scoop.Scoop
|
||||
import com.github.stkent.amplify.tracking.Amplify
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.mikepenz.aboutlibraries.Libs
|
||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||
import com.mikepenz.materialdrawer.Drawer
|
||||
@ -79,7 +74,6 @@ import com.mikepenz.materialdrawer.model.DividerDrawerItem
|
||||
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
|
||||
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
|
||||
import kotlinx.android.synthetic.main.activity_home.*
|
||||
import kotlinx.android.synthetic.main.fragment_article.*
|
||||
import org.acra.ACRA
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
@ -233,7 +227,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
recyclerView: RecyclerView,
|
||||
viewHolder: RecyclerView.ViewHolder
|
||||
): Int =
|
||||
if (elementsShown != UNREAD_SHOWN) {
|
||||
if (elementsShown != UNREAD_SHOWN && elementsShown != READ_SHOWN) {
|
||||
0
|
||||
} else {
|
||||
super.getSwipeDirs(
|
||||
@ -253,14 +247,18 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
val i = items.elementAtOrNull(position)
|
||||
|
||||
if (i != null) {
|
||||
val adapter = recyclerView.adapter
|
||||
val adapter = recyclerView.adapter as ItemsAdapter<*>
|
||||
|
||||
when (adapter) {
|
||||
is ItemCardAdapter -> adapter.removeItemAtIndex(position)
|
||||
is ItemListAdapter -> adapter.removeItemAtIndex(position)
|
||||
val wasItemUnread = adapter.unreadItemStatusAtIndex(position)
|
||||
|
||||
adapter.handleItemAtIndex(position)
|
||||
|
||||
if (wasItemUnread) {
|
||||
badgeNew--
|
||||
} else {
|
||||
badgeNew++
|
||||
}
|
||||
|
||||
badgeNew--
|
||||
reloadBadgeContent()
|
||||
|
||||
val tagHashes = i.tags.tags.split(",").map { it.longHash() }
|
||||
@ -307,19 +305,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
|
||||
val tabNew =
|
||||
BottomNavigationItem(
|
||||
R.drawable.ic_fiber_new_black_24dp,
|
||||
R.drawable.ic_tab_fiber_new_black_24dp,
|
||||
getString(R.string.tab_new)
|
||||
).setActiveColor(appColors.colorAccent)
|
||||
.setBadgeItem(tabNewBadge)
|
||||
val tabArchive =
|
||||
BottomNavigationItem(
|
||||
R.drawable.ic_archive_black_24dp,
|
||||
R.drawable.ic_tab_archive_black_24dp,
|
||||
getString(R.string.tab_read)
|
||||
).setActiveColor(appColors.colorAccentDark)
|
||||
.setBadgeItem(tabArchiveBadge)
|
||||
val tabStarred =
|
||||
BottomNavigationItem(
|
||||
R.drawable.ic_favorite_black_24dp,
|
||||
R.drawable.ic_tab_favorite_black_24dp,
|
||||
getString(R.string.tab_favs)
|
||||
).setActiveColorResource(R.color.pink)
|
||||
.setBadgeItem(tabStarredBadge)
|
||||
@ -481,7 +479,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
|
||||
footer {
|
||||
primaryItem(R.string.drawer_report_bug) {
|
||||
icon = R.drawable.ic_bug_report
|
||||
icon = R.drawable.ic_bug_report_black_24dp
|
||||
iconTintingEnabled = true
|
||||
onClick { _ ->
|
||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(Config.trackerUrl))
|
||||
@ -491,7 +489,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
}
|
||||
|
||||
primaryItem(R.string.title_activity_settings) {
|
||||
icon = R.drawable.ic_settings
|
||||
icon = R.drawable.ic_settings_black_24dp
|
||||
iconTintingEnabled = true
|
||||
onClick { _ ->
|
||||
startActivityForResult(
|
||||
@ -691,7 +689,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
PrimaryDrawerItem()
|
||||
.withName(R.string.action_about)
|
||||
.withSelectable(false)
|
||||
.withIcon(R.drawable.ic_info_outline)
|
||||
.withIcon(R.drawable.ic_info_outline_white_24dp)
|
||||
.withIconTintingEnabled(true)
|
||||
.withOnDrawerItemClickListener { _, _, _ ->
|
||||
LibsBuilder()
|
||||
@ -1354,12 +1352,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
||||
).show()
|
||||
tabNewBadge.removeBadge()
|
||||
|
||||
|
||||
tagsBadge = itemsByTag.map {
|
||||
(it.key to ((tagsBadge[it.key] ?: it.value) - it.value))
|
||||
}.toMap()
|
||||
|
||||
reloadTagsBadges()
|
||||
handleDrawerItems()
|
||||
|
||||
getElementsAccordingToTab()
|
||||
} else {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package apps.amine.bou.readerforselfoss
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Build
|
||||
@ -27,6 +28,7 @@ import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_2_3
|
||||
import apps.amine.bou.readerforselfoss.themes.AppColors
|
||||
import apps.amine.bou.readerforselfoss.themes.Toppings
|
||||
import apps.amine.bou.readerforselfoss.transformers.DepthPageTransformer
|
||||
import apps.amine.bou.readerforselfoss.utils.Config
|
||||
import apps.amine.bou.readerforselfoss.utils.maybeHandleSilentException
|
||||
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
|
||||
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
|
||||
@ -94,6 +96,9 @@ class ReaderActivity : AppCompatActivity() {
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||
|
||||
val settings =
|
||||
getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
editor = prefs.edit()
|
||||
|
||||
@ -105,7 +110,7 @@ class ReaderActivity : AppCompatActivity() {
|
||||
api = SelfossApi(
|
||||
this,
|
||||
this@ReaderActivity,
|
||||
prefs.getBoolean("isSelfSignedCert", false),
|
||||
settings.getBoolean("isSelfSignedCert", false),
|
||||
prefs.getString("api_timeout", "-1").toLong(),
|
||||
prefs.getBoolean("should_log_everything", false)
|
||||
)
|
||||
|
@ -1,5 +1,6 @@
|
||||
package apps.amine.bou.readerforselfoss
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Build
|
||||
@ -13,6 +14,7 @@ import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
||||
import apps.amine.bou.readerforselfoss.api.selfoss.Source
|
||||
import apps.amine.bou.readerforselfoss.themes.AppColors
|
||||
import apps.amine.bou.readerforselfoss.themes.Toppings
|
||||
import apps.amine.bou.readerforselfoss.utils.Config
|
||||
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
|
||||
import com.ftinc.scoop.Scoop
|
||||
import kotlinx.android.synthetic.main.activity_sources.*
|
||||
@ -54,12 +56,14 @@ class SourcesActivity : AppCompatActivity() {
|
||||
super.onResume()
|
||||
val mLayoutManager = LinearLayoutManager(this)
|
||||
|
||||
val settings =
|
||||
getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
|
||||
val api = SelfossApi(
|
||||
this,
|
||||
this@SourcesActivity,
|
||||
prefs.getBoolean("isSelfSignedCert", false),
|
||||
settings.getBoolean("isSelfSignedCert", false),
|
||||
prefs.getString("api_timeout", "-1").toLong(),
|
||||
prefs.getBoolean("should_log_everything", false)
|
||||
)
|
||||
|
@ -41,7 +41,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
updateItems(items)
|
||||
}
|
||||
|
||||
private fun doUnmark(i: Item, position: Int) {
|
||||
private fun unmarkSnackbar(i: Item, position: Int) {
|
||||
val s = Snackbar
|
||||
.make(
|
||||
app.findViewById(R.id.coordLayout),
|
||||
@ -71,12 +71,11 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
}
|
||||
notifyItemRemoved(position)
|
||||
updateItems(items)
|
||||
doUnmark(i, position)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
thread {
|
||||
db.actionsDao().deleteReadActionForArticle(i.id)
|
||||
db.actionsDao().insertAllActions(ActionEntity(i.id, false, true, false, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -87,7 +86,64 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
s.show()
|
||||
}
|
||||
|
||||
fun removeItemAtIndex(position: Int) {
|
||||
private fun markSnackbar(i: Item, position: Int) {
|
||||
val s = Snackbar
|
||||
.make(
|
||||
app.findViewById(R.id.coordLayout),
|
||||
R.string.marked_as_unread,
|
||||
Snackbar.LENGTH_LONG
|
||||
)
|
||||
.setAction(R.string.undo_string) {
|
||||
items.add(position, i)
|
||||
thread {
|
||||
db.itemsDao().delete(i.toEntity())
|
||||
}
|
||||
notifyItemInserted(position)
|
||||
updateItems(items)
|
||||
|
||||
if (app.isNetworkAccessible(null)) {
|
||||
api.markItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
||||
override fun onResponse(
|
||||
call: Call<SuccessResponse>,
|
||||
response: Response<SuccessResponse>
|
||||
) {
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
||||
items.remove(i)
|
||||
thread {
|
||||
db.itemsDao().insertAllItems(i.toEntity())
|
||||
}
|
||||
notifyItemRemoved(position)
|
||||
updateItems(items)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
thread {
|
||||
db.actionsDao().insertAllActions(ActionEntity(i.id, true, false, false, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val view = s.view
|
||||
val tv: TextView = view.findViewById(com.google.android.material.R.id.snackbar_text)
|
||||
tv.setTextColor(Color.WHITE)
|
||||
s.show()
|
||||
}
|
||||
|
||||
fun handleItemAtIndex(position: Int) {
|
||||
if (unreadItemStatusAtIndex(position)) {
|
||||
readItemAtIndex(position)
|
||||
} else {
|
||||
unreadItemAtIndex(position)
|
||||
}
|
||||
}
|
||||
|
||||
fun unreadItemStatusAtIndex(position: Int): Boolean {
|
||||
return items[position].unread
|
||||
}
|
||||
|
||||
private fun readItemAtIndex(position: Int) {
|
||||
val i = items[position]
|
||||
items.remove(i)
|
||||
notifyItemRemoved(position)
|
||||
@ -105,7 +161,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
) {
|
||||
if (!response.succeeded() && debugReadingItems) {
|
||||
val message =
|
||||
"message: ${response.message()} " +
|
||||
"MARK message: ${response.message()} " +
|
||||
"response isSuccess: ${response.isSuccessful} " +
|
||||
"response code: ${response.code()} " +
|
||||
"response message: ${response.message()} " +
|
||||
@ -116,7 +172,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
Toast.makeText(app.baseContext, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
doUnmark(i, position)
|
||||
unmarkSnackbar(i, position)
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
||||
@ -129,7 +185,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
app.getString(R.string.cant_mark_read),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
items.add(i)
|
||||
items.add(position, i)
|
||||
notifyItemInserted(position)
|
||||
updateItems(items)
|
||||
|
||||
@ -141,7 +197,64 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
||||
} else {
|
||||
thread {
|
||||
db.actionsDao().insertAllActions(ActionEntity(i.id, true, false, false, false))
|
||||
doUnmark(i, position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun unreadItemAtIndex(position: Int) {
|
||||
val i = items[position]
|
||||
items.remove(i)
|
||||
notifyItemRemoved(position)
|
||||
updateItems(items)
|
||||
|
||||
thread {
|
||||
db.itemsDao().insertAllItems(i.toEntity())
|
||||
}
|
||||
|
||||
if (app.isNetworkAccessible(null)) {
|
||||
api.unmarkItem(i.id).enqueue(object : Callback<SuccessResponse> {
|
||||
override fun onResponse(
|
||||
call: Call<SuccessResponse>,
|
||||
response: Response<SuccessResponse>
|
||||
) {
|
||||
if (!response.succeeded() && debugReadingItems) {
|
||||
val message =
|
||||
"UNMARK message: ${response.message()} " +
|
||||
"response isSuccess: ${response.isSuccessful} " +
|
||||
"response code: ${response.code()} " +
|
||||
"response message: ${response.message()} " +
|
||||
"response errorBody: ${response.errorBody()?.string()} " +
|
||||
"body success: ${response.body()?.success} " +
|
||||
"body isSuccess: ${response.body()?.isSuccess}"
|
||||
ACRA.getErrorReporter().maybeHandleSilentException(Exception(message), app)
|
||||
Toast.makeText(app.baseContext, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
markSnackbar(i, position)
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
||||
if (debugReadingItems) {
|
||||
ACRA.getErrorReporter().maybeHandleSilentException(t, app)
|
||||
Toast.makeText(app.baseContext, t.message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
Toast.makeText(
|
||||
app,
|
||||
app.getString(R.string.cant_mark_unread),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
items.add(i)
|
||||
notifyItemInserted(position)
|
||||
updateItems(items)
|
||||
|
||||
thread {
|
||||
db.itemsDao().delete(i.toEntity())
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
thread {
|
||||
db.actionsDao().insertAllActions(ActionEntity(i.id, false, true, false, false))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class LoadingWorker(val context: Context, params: WorkerParameters) : Worker(con
|
||||
.setOngoing(true)
|
||||
.setPriority(PRIORITY_LOW)
|
||||
.setChannelId(Config.syncChannelId)
|
||||
.setSmallIcon(R.drawable.ic_cloud_download)
|
||||
.setSmallIcon(R.drawable.ic_stat_cloud_download_black_24dp)
|
||||
|
||||
notificationManager.notify(1, notification.build())
|
||||
|
||||
@ -101,7 +101,7 @@ class LoadingWorker(val context: Context, params: WorkerParameters) : Worker(con
|
||||
.setChannelId(Config.newItemsChannelId)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true)
|
||||
.setSmallIcon(R.drawable.ic_fiber_new_black_24dp)
|
||||
.setSmallIcon(R.drawable.ic_tab_fiber_new_black_24dp)
|
||||
|
||||
Timer("", false).schedule(4000) {
|
||||
notificationManager.notify(2, newItemsNotification.build())
|
||||
|
@ -3,6 +3,8 @@ package apps.amine.bou.readerforselfoss.fragments
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.TypedArray
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@ -19,6 +21,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.WebSettings
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.room.Room
|
||||
import apps.amine.bou.readerforselfoss.R
|
||||
import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi
|
||||
@ -45,6 +48,7 @@ import apps.amine.bou.readerforselfoss.utils.succeeded
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.github.rubensousa.floatingtoolbar.FloatingToolbar
|
||||
import kotlinx.android.synthetic.main.fragment_article.*
|
||||
import kotlinx.android.synthetic.main.fragment_article.view.*
|
||||
import org.acra.ACRA
|
||||
import retrofit2.Call
|
||||
@ -71,6 +75,14 @@ class ArticleFragment : Fragment() {
|
||||
private lateinit var textAlignment: String
|
||||
private lateinit var config: Config
|
||||
|
||||
private var rootView: ViewGroup? = null
|
||||
|
||||
private lateinit var prefs: SharedPreferences
|
||||
|
||||
private var typeface: Typeface? = null
|
||||
private var resId: Int = 0
|
||||
private var font = ""
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
if (mCustomTabActivityHelper != null) {
|
||||
@ -93,10 +105,6 @@ class ArticleFragment : Fragment() {
|
||||
).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3).build()
|
||||
}
|
||||
|
||||
private var rootView: ViewGroup? = null
|
||||
|
||||
private lateinit var prefs: SharedPreferences
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
@ -115,6 +123,19 @@ class ArticleFragment : Fragment() {
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
editor = prefs.edit()
|
||||
fontSize = prefs.getString("reader_font_size", "16").toInt()
|
||||
|
||||
font = prefs.getString("reader_font", "")
|
||||
if (font.isNotEmpty()) {
|
||||
resId = context!!.resources.getIdentifier(font, "font", context!!.packageName)
|
||||
typeface = try {
|
||||
ResourcesCompat.getFont(context!!, resId)!!
|
||||
} catch (e: java.lang.Exception) {
|
||||
ACRA.getErrorReporter().maybeHandleSilentException(Throwable("Font loading issue: ${e.message}"), context!!)
|
||||
// Just to be sure
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
refreshAlignment()
|
||||
|
||||
val settings = activity!!.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||
@ -204,11 +225,17 @@ class ArticleFragment : Fragment() {
|
||||
)
|
||||
|
||||
rootView!!.source.text = contentSource
|
||||
if (typeface != null) {
|
||||
rootView!!.source.typeface = typeface
|
||||
}
|
||||
|
||||
if (contentText.isEmptyOrNullOrNullString()) {
|
||||
getContentFromMercury(customTabsIntent, prefs)
|
||||
} else {
|
||||
rootView!!.titleView.text = contentTitle
|
||||
if (typeface != null) {
|
||||
rootView!!.titleView.typeface = typeface
|
||||
}
|
||||
|
||||
htmlToWebview()
|
||||
|
||||
@ -283,6 +310,9 @@ class ArticleFragment : Fragment() {
|
||||
if (response.body() != null && response.body()!!.content != null && !response.body()!!.content.isNullOrEmpty()) {
|
||||
try {
|
||||
rootView!!.titleView.text = response.body()!!.title
|
||||
if (typeface != null) {
|
||||
rootView!!.titleView.typeface = typeface
|
||||
}
|
||||
try {
|
||||
// Note: Mercury may return relative urls... If it does the url val will not be changed.
|
||||
URL(response.body()!!.url)
|
||||
@ -364,6 +394,11 @@ class ArticleFragment : Fragment() {
|
||||
private fun htmlToWebview() {
|
||||
val stringColor = String.format("#%06X", 0xFFFFFF and appColors.colorAccent)
|
||||
|
||||
val attrs: IntArray = intArrayOf(android.R.attr.fontFamily)
|
||||
val a: TypedArray = context!!.obtainStyledAttributes(resId, attrs)
|
||||
|
||||
|
||||
rootView!!.webcontent.settings.standardFontFamily = a.getString(0)
|
||||
rootView!!.webcontent.visibility = View.VISIBLE
|
||||
val (textColor, backgroundColor) = if (appColors.isDarkTheme) {
|
||||
if (context != null) {
|
||||
@ -423,6 +458,24 @@ class ArticleFragment : Fragment() {
|
||||
ACRA.getErrorReporter().maybeHandleSilentException(e, activity!!)
|
||||
}
|
||||
|
||||
val fontName = when (font) {
|
||||
getString(R.string.open_sans_font_id) -> "Open Sans"
|
||||
getString(R.string.roboto_font_id) -> "Roboto"
|
||||
else -> ""
|
||||
}
|
||||
|
||||
val fontLinkAndStyle = if (font.isNotEmpty()) {
|
||||
"""<link href="https://fonts.googleapis.com/css?family=${fontName.replace(" ", "+")}" rel="stylesheet">
|
||||
|<style>
|
||||
| * {
|
||||
| font-family: '$fontName';
|
||||
| }
|
||||
|</style>
|
||||
""".trimMargin()
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
rootView!!.webcontent.loadDataWithBaseURL(
|
||||
baseUrl,
|
||||
"""<html>
|
||||
@ -446,6 +499,7 @@ class ArticleFragment : Fragment() {
|
||||
| text-align: $textAlignment;
|
||||
| word-break: break-word;
|
||||
| overflow:hidden;
|
||||
| line-height: 1.5em;
|
||||
| }
|
||||
| a, pre, code {
|
||||
| text-align: $textAlignment;
|
||||
@ -456,6 +510,7 @@ class ArticleFragment : Fragment() {
|
||||
| background-color: $stringBackgroundColor;
|
||||
| }
|
||||
| </style>
|
||||
| $fontLinkAndStyle
|
||||
|</head>
|
||||
|<body>
|
||||
| $contentText
|
||||
|
@ -8,6 +8,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
@ -24,6 +25,7 @@ import android.text.Editable;
|
||||
import android.text.InputFilter;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
@ -124,6 +126,27 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public void onBuildHeaders(List<Header> target) {
|
||||
loadHeadersFromResource(R.xml.pref_headers, target);
|
||||
|
||||
AppColors appColors = new AppColors(this);
|
||||
if (appColors != null && appColors.isDarkTheme()) {
|
||||
for (Header header : target) {
|
||||
tryLoadIconDark(header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void tryLoadIconDark(Header header){
|
||||
try{
|
||||
if (header.fragmentArguments != null) {
|
||||
String iconDark = header.fragmentArguments.getString("iconDark");
|
||||
int iconDarkId = getResources().getIdentifier(iconDark, "drawable", getPackageName());
|
||||
if (iconDarkId != 0) {
|
||||
header.iconRes = iconDarkId;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e("SettingsActivity", "Can not load dark icon", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
Before Width: | Height: | Size: 683 B |
Before Width: | Height: | Size: 680 B |
Before Width: | Height: | Size: 134 B |
Before Width: | Height: | Size: 239 B |
Before Width: | Height: | Size: 271 B |
Before Width: | Height: | Size: 216 B |
Before Width: | Height: | Size: 206 B |
Before Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 334 B |
Before Width: | Height: | Size: 458 B |
Before Width: | Height: | Size: 275 B |
Before Width: | Height: | Size: 361 B |
Before Width: | Height: | Size: 324 B |
Before Width: | Height: | Size: 301 B |
Before Width: | Height: | Size: 551 B |
Before Width: | Height: | Size: 355 B |
Before Width: | Height: | Size: 551 B |
Before Width: | Height: | Size: 204 B |
Before Width: | Height: | Size: 187 B |
Before Width: | Height: | Size: 422 B |
Before Width: | Height: | Size: 473 B |
Before Width: | Height: | Size: 498 B |
Before Width: | Height: | Size: 453 B |
Before Width: | Height: | Size: 398 B |
Before Width: | Height: | Size: 397 B |
Before Width: | Height: | Size: 523 B |
Before Width: | Height: | Size: 409 B |
Before Width: | Height: | Size: 442 B |
Before Width: | Height: | Size: 116 B |
Before Width: | Height: | Size: 174 B |
Before Width: | Height: | Size: 212 B |
Before Width: | Height: | Size: 136 B |
Before Width: | Height: | Size: 134 B |
Before Width: | Height: | Size: 175 B |
Before Width: | Height: | Size: 228 B |
Before Width: | Height: | Size: 268 B |
Before Width: | Height: | Size: 213 B |
Before Width: | Height: | Size: 247 B |
Before Width: | Height: | Size: 215 B |
Before Width: | Height: | Size: 208 B |
Before Width: | Height: | Size: 352 B |
Before Width: | Height: | Size: 241 B |
Before Width: | Height: | Size: 355 B |
Before Width: | Height: | Size: 157 B |
Before Width: | Height: | Size: 144 B |
Before Width: | Height: | Size: 276 B |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 339 B |
Before Width: | Height: | Size: 322 B |
Before Width: | Height: | Size: 262 B |
Before Width: | Height: | Size: 268 B |
Before Width: | Height: | Size: 361 B |
Before Width: | Height: | Size: 871 B |
Before Width: | Height: | Size: 634 B |
Before Width: | Height: | Size: 168 B |
Before Width: | Height: | Size: 261 B |
Before Width: | Height: | Size: 312 B |
Before Width: | Height: | Size: 171 B |
Before Width: | Height: | Size: 174 B |
Before Width: | Height: | Size: 257 B |
Before Width: | Height: | Size: 380 B |
Before Width: | Height: | Size: 504 B |
Before Width: | Height: | Size: 300 B |
Before Width: | Height: | Size: 437 B |
Before Width: | Height: | Size: 327 B |
Before Width: | Height: | Size: 308 B |
Before Width: | Height: | Size: 684 B |
Before Width: | Height: | Size: 464 B |
Before Width: | Height: | Size: 725 B |
Before Width: | Height: | Size: 230 B |
Before Width: | Height: | Size: 208 B |
Before Width: | Height: | Size: 557 B |
Before Width: | Height: | Size: 625 B |
Before Width: | Height: | Size: 606 B |
Before Width: | Height: | Size: 557 B |
Before Width: | Height: | Size: 483 B |
Before Width: | Height: | Size: 496 B |
Before Width: | Height: | Size: 660 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 242 B |
Before Width: | Height: | Size: 377 B |
Before Width: | Height: | Size: 466 B |
Before Width: | Height: | Size: 263 B |
Before Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 347 B |
Before Width: | Height: | Size: 547 B |
Before Width: | Height: | Size: 741 B |
Before Width: | Height: | Size: 398 B |
Before Width: | Height: | Size: 636 B |