Compare commits
42 Commits
v171811333
...
v171904096
Author | SHA1 | Date | |
---|---|---|---|
1485cc05f4 | |||
d1dad3e61a | |||
e5024b0420 | |||
9b01692c55 | |||
33aa587d36 | |||
12e0766803 | |||
a8721ad7a4 | |||
bc5e882894 | |||
e3460322b1 | |||
7e3288a076 | |||
ddc754ec25 | |||
134a0766d6 | |||
69da932ab5 | |||
592fb6328a | |||
a0aead6491 | |||
722b6cc06d | |||
6d7c4b40f6 | |||
f538ed39fc | |||
65821492ad | |||
6ede718a9f | |||
f1757937a4 | |||
2bd2e0a953 | |||
b5aef28af0 | |||
45747a1506 | |||
c6e2e08bcb | |||
25bf18661e | |||
6b088dcd24 | |||
d2b18e1880 | |||
eec7c94e98 | |||
d1f8fcacc0 | |||
07e4a33cbd | |||
f6317f566e | |||
9f51e4e6a5 | |||
750604a31f | |||
392eee0ad4 | |||
37e7b987ee | |||
9eac51e729 | |||
fa9cce6783 | |||
f0d4b63a97 | |||
83eeb11388 | |||
01f746f33d | |||
200851894b |
@ -1,5 +1,13 @@
|
|||||||
**1.7.x**
|
**1.7.x**
|
||||||
|
|
||||||
|
- Hiding tags with 0 articles
|
||||||
|
|
||||||
|
- Fixed issue with basic auth and images loading
|
||||||
|
|
||||||
|
- Added the ability to justify or left align the reader text
|
||||||
|
|
||||||
|
- Fixed #251
|
||||||
|
|
||||||
- Added experimental issue to set a default timeout. Should work for #238.
|
- Added experimental issue to set a default timeout. Should work for #238.
|
||||||
|
|
||||||
- Closing #220.
|
- Closing #220.
|
||||||
|
17
README.md
@ -1,20 +1,10 @@
|
|||||||
# ReaderForSelfoss
|
# ReaderForSelfoss **(Only available from F-Droid)**
|
||||||
|
|
||||||
[](https://join.slack.com/t/readerforselfoss/shared_invite/enQtMjkyNzc3NjM2Mjc1LTUzZTZhOGM5YjQ1MTI5MWZiODRjMjE1ZDBmMzQxZmQ3NWZhYTNhMTBjNGEwNmE2ZGFjODU5NjUxZjBkMWJmMDQ) [](https://jenkins.amine-bou.fr/job/ReaderForSelfoss/) [](https://www.codetriage.com/aminecmi/readerforselfoss) [](https://crowdin.com/project/readerforselfoss)
|
[](https://crowdin.com/project/readerforselfoss)
|
||||||
|
|
||||||
It's an RSS Reader for Android, that **only** works with [Selfoss](https://selfoss.aditu.de/)
|
It's an RSS Reader for Android, that **only** works with [Selfoss](https://selfoss.aditu.de/)
|
||||||
|
|
||||||
<a href='https://play.google.com/store/apps/details?id=apps.amine.bou.readerforselfoss'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height="100"/></a> <a href="https://f-droid.org/packages/apps.amine.bou.readerforselfoss"><img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="100"></a>
|
<a href="https://f-droid.org/packages/apps.amine.bou.readerforselfoss"><img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="100"></a>
|
||||||
|
|
||||||
Also, the last APK built from source is available [here](https://jenkins.amine-bou.fr/job/ReaderForSelfoss/lastSuccessfulBuild/artifact/SignApksBuilder-out/selfoss-key/selfoss/app-githubConfig-release-unsigned.apk/app-githubConfig-release.apk).
|
|
||||||
|
|
||||||
## Join the alpha channel
|
|
||||||
|
|
||||||
**Keep in mind, it could be instable, but you'll have the new updates faster**
|
|
||||||
|
|
||||||
- First, join the google [group](https://groups.google.com/d/forum/reader-for-selfoss-alpha-testing).
|
|
||||||
- Then, join the [alpha channel](https://play.google.com/apps/testing/apps.amine.bou.readerforselfoss) of the app.
|
|
||||||
- You'll be able to update the app for the current alpha version.
|
|
||||||
|
|
||||||
## Want to help ?
|
## Want to help ?
|
||||||
|
|
||||||
@ -30,4 +20,3 @@ Also, the last APK built from source is available [here](https://jenkins.amine-b
|
|||||||
- [See what I'm doing](https://github.com/aminecmi/ReaderforSelfoss/projects/1)
|
- [See what I'm doing](https://github.com/aminecmi/ReaderforSelfoss/projects/1)
|
||||||
- [Create an issue, or request a new feature](https://github.com/aminecmi/ReaderforSelfoss/issues)
|
- [Create an issue, or request a new feature](https://github.com/aminecmi/ReaderforSelfoss/issues)
|
||||||
- [Help translation the app](https://crowdin.com/project/readerforselfoss)
|
- [Help translation the app](https://crowdin.com/project/readerforselfoss)
|
||||||
- [Ask for help](https://join.slack.com/t/readerforselfoss/shared_invite/enQtMjkyNzc3NjM2Mjc1LTUzZTZhOGM5YjQ1MTI5MWZiODRjMjE1ZDBmMzQxZmQ3NWZhYTNhMTBjNGEwNmE2ZGFjODU5NjUxZjBkMWJmMDQ)
|
|
||||||
|
@ -2,7 +2,15 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def gitVersion() {
|
def gitVersion() {
|
||||||
def process = "git for-each-ref refs/tags --sort=-authordate --format='%(refname:short)' --count=1".execute()
|
def process
|
||||||
|
def maybeTagOfCurrentCommit = 'git describe --contains HEAD'.execute()
|
||||||
|
if (maybeTagOfCurrentCommit.text.isEmpty()) {
|
||||||
|
println "No tag on current commit. Will take the latest one."
|
||||||
|
process = "git for-each-ref refs/tags --sort=-authordate --format='%(refname:short)' --count=1".execute()
|
||||||
|
} else {
|
||||||
|
println "Tag found on current commit"
|
||||||
|
process = 'git describe --contains HEAD'.execute()
|
||||||
|
}
|
||||||
return process.text.replaceAll("'", "").substring(1).replaceAll("\\.", "").trim()
|
return process.text.replaceAll("'", "").substring(1).replaceAll("\\.", "").trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,14 +67,11 @@ android {
|
|||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
shrinkResources true
|
shrinkResources false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
proguardFiles getDefaultProguardFile('proguard-android.txt'),
|
||||||
'proguard-rules.pro'
|
'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
debug {
|
debug {
|
||||||
buildConfigField "String", "LOGIN_URL", appLoginUrl
|
|
||||||
buildConfigField "String", "LOGIN_USERNAME", appLoginUsername
|
|
||||||
buildConfigField "String", "LOGIN_PASSWORD", appLoginPassword
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flavorDimensions "build"
|
flavorDimensions "build"
|
||||||
@ -75,11 +80,6 @@ android {
|
|||||||
versionNameSuffix '-github'
|
versionNameSuffix '-github'
|
||||||
dimension "build"
|
dimension "build"
|
||||||
}
|
}
|
||||||
storeConfig {
|
|
||||||
// As jenkins publishes to alpha first, this is the default suffix now.
|
|
||||||
versionNameSuffix '-store'
|
|
||||||
dimension "build"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,17 +94,17 @@ dependencies {
|
|||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
// Android Support
|
// Android Support
|
||||||
implementation "androidx.appcompat:appcompat:$android_version"
|
implementation "androidx.appcompat:appcompat:$androidx_version"
|
||||||
implementation "com.google.android.material:material:$android_version"
|
implementation "com.google.android.material:material:$android_version"
|
||||||
implementation "androidx.recyclerview:recyclerview:$android_version"
|
implementation "androidx.recyclerview:recyclerview:$android_version"
|
||||||
implementation "androidx.legacy:legacy-support-v4:$android_version"
|
implementation "androidx.legacy:legacy-support-v4:$android_version"
|
||||||
implementation "androidx.vectordrawable:vectordrawable:$android_version"
|
implementation "androidx.vectordrawable:vectordrawable:$android_version"
|
||||||
implementation "androidx.browser:browser:$android_version"
|
implementation "androidx.browser:browser:$android_version"
|
||||||
implementation "androidx.cardview:cardview:$android_version"
|
implementation "androidx.cardview:cardview:$android_version"
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha4'
|
||||||
|
|
||||||
//multidex
|
//multidex
|
||||||
implementation 'androidx.multidex:multidex:2.0.0'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
|
|
||||||
// About
|
// About
|
||||||
implementation('com.mikepenz:aboutlibraries:6.2.0@aar') {
|
implementation('com.mikepenz:aboutlibraries:6.2.0@aar') {
|
||||||
@ -126,9 +126,6 @@ dependencies {
|
|||||||
implementation 'com.github.bumptech.glide:glide:4.1.1'
|
implementation 'com.github.bumptech.glide:glide:4.1.1'
|
||||||
implementation 'com.github.bumptech.glide:okhttp3-integration:4.1.1'
|
implementation 'com.github.bumptech.glide:okhttp3-integration:4.1.1'
|
||||||
|
|
||||||
// Asking politely users to rate the app
|
|
||||||
implementation 'com.github.stkent:amplify:2.2.0'
|
|
||||||
|
|
||||||
// Drawer
|
// Drawer
|
||||||
implementation 'co.zsmb:materialdrawer-kt:2.0.1'
|
implementation 'co.zsmb:materialdrawer-kt:2.0.1'
|
||||||
|
|
||||||
@ -153,21 +150,4 @@ dependencies {
|
|||||||
kapt "androidx.room:room-compiler:$room_version"
|
kapt "androidx.room:room-compiler:$room_version"
|
||||||
|
|
||||||
implementation "android.arch.work:work-runtime-ktx:$work_version"
|
implementation "android.arch.work:work-runtime-ktx:$work_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
afterEvaluate {
|
|
||||||
initAppLoginPropertiesIfNeeded()
|
|
||||||
}
|
|
||||||
|
|
||||||
def initAppLoginPropertiesIfNeeded() {
|
|
||||||
def propertiesFile = file(System.getProperty("user.home") + '/.gradle/gradle.properties')
|
|
||||||
if (!propertiesFile.exists()) {
|
|
||||||
def commentMessage = "This is autogenerated local property from system environment to prevent key to be committed to source control."
|
|
||||||
ant.propertyfile(file: System.getProperty("user.home") + "/.gradle/gradle.properties", comment: commentMessage) {
|
|
||||||
entry(key: "appLoginUrl", value: System.getProperty("appLoginUrl"))
|
|
||||||
entry(key: "appLoginUsername", value: System.getProperty("appLoginUsername"))
|
|
||||||
entry(key: "appLoginPassword", value: System.getProperty("appLoginPassword"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="apps.amine.bou.readerforselfoss"
|
package="apps.amine.bou.readerforselfoss">
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
@ -19,11 +18,11 @@
|
|||||||
android:theme="@style/SplashTheme">
|
android:theme="@style/SplashTheme">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<meta-data android:name="android.app.shortcuts"
|
<meta-data
|
||||||
|
android:name="android.app.shortcuts"
|
||||||
android:resource="@xml/shortcuts" />
|
android:resource="@xml/shortcuts" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
@ -38,7 +37,7 @@
|
|||||||
android:parentActivityName=".HomeActivity">
|
android:parentActivityName=".HomeActivity">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="apps.amine.bou.readerforselfoss.HomeActivity" />
|
android:value=".HomeActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".SourcesActivity"
|
android:name=".SourcesActivity"
|
||||||
@ -56,9 +55,7 @@
|
|||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND" />
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
||||||
<data android:mimeType="text/plain" />
|
<data android:mimeType="text/plain" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
@ -77,6 +74,9 @@
|
|||||||
android:value="true" />
|
android:value="true" />
|
||||||
|
|
||||||
<meta-data android:name="android.max_aspect" android:value="2.1" />
|
<meta-data android:name="android.max_aspect" android:value="2.1" />
|
||||||
|
<meta-data
|
||||||
|
android:name="preloaded_fonts"
|
||||||
|
android:resource="@array/preloaded_fonts" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package apps.amine.bou.readerforselfoss
|
package apps.amine.bou.readerforselfoss
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -85,10 +86,12 @@ class AddSourceActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
val settings =
|
||||||
|
getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||||
api = SelfossApi(
|
api = SelfossApi(
|
||||||
this,
|
this,
|
||||||
this@AddSourceActivity,
|
this@AddSourceActivity,
|
||||||
prefs.getBoolean("isSelfSignedCert", false),
|
settings.getBoolean("isSelfSignedCert", false),
|
||||||
prefs.getString("api_timeout", "-1").toLong(),
|
prefs.getString("api_timeout", "-1").toLong(),
|
||||||
prefs.getBoolean("should_log_everything", false)
|
prefs.getBoolean("should_log_everything", false)
|
||||||
)
|
)
|
||||||
|
@ -18,17 +18,13 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
import androidx.recyclerview.widget.StaggeredGridLayoutManager
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import android.util.Log
|
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
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.work.Constraints
|
import androidx.work.Constraints
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy
|
import androidx.work.ExistingPeriodicWorkPolicy
|
||||||
import androidx.work.NetworkType
|
|
||||||
import androidx.work.OneTimeWorkRequestBuilder
|
|
||||||
import androidx.work.PeriodicWorkRequestBuilder
|
import androidx.work.PeriodicWorkRequestBuilder
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter
|
import apps.amine.bou.readerforselfoss.adapters.ItemCardAdapter
|
||||||
@ -68,8 +64,6 @@ import com.ashokvarma.bottomnavigation.BottomNavigationBar
|
|||||||
import com.ashokvarma.bottomnavigation.BottomNavigationItem
|
import com.ashokvarma.bottomnavigation.BottomNavigationItem
|
||||||
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
||||||
import com.ftinc.scoop.Scoop
|
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.Libs
|
||||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||||
import com.mikepenz.materialdrawer.Drawer
|
import com.mikepenz.materialdrawer.Drawer
|
||||||
@ -79,7 +73,6 @@ import com.mikepenz.materialdrawer.model.DividerDrawerItem
|
|||||||
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
|
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
|
||||||
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
|
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
|
||||||
import kotlinx.android.synthetic.main.activity_home.*
|
import kotlinx.android.synthetic.main.activity_home.*
|
||||||
import kotlinx.android.synthetic.main.fragment_article.*
|
|
||||||
import org.acra.ACRA
|
import org.acra.ACRA
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
@ -152,6 +145,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
|
|
||||||
private lateinit var db: AppDatabase
|
private lateinit var db: AppDatabase
|
||||||
|
|
||||||
|
private lateinit var config: Config
|
||||||
|
|
||||||
data class DrawerData(val tags: List<Tag>?, val sources: List<Source>?)
|
data class DrawerData(val tags: List<Tag>?, val sources: List<Source>?)
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
@ -161,6 +156,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
appColors = AppColors(this@HomeActivity)
|
appColors = AppColors(this@HomeActivity)
|
||||||
|
config = Config(this@HomeActivity)
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@ -176,9 +172,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
handleThemeBinding()
|
handleThemeBinding()
|
||||||
|
|
||||||
setSupportActionBar(toolBar)
|
setSupportActionBar(toolBar)
|
||||||
if (savedInstanceState == null) {
|
|
||||||
Amplify.getSharedInstance().promptIfReady(promptView)
|
|
||||||
}
|
|
||||||
|
|
||||||
db = Room.databaseBuilder(
|
db = Room.databaseBuilder(
|
||||||
applicationContext,
|
applicationContext,
|
||||||
@ -230,7 +223,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 && elementsShown != READ_SHOWN) {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
super.getSwipeDirs(
|
super.getSwipeDirs(
|
||||||
@ -250,14 +243,18 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
val i = items.elementAtOrNull(position)
|
val i = items.elementAtOrNull(position)
|
||||||
|
|
||||||
if (i != null) {
|
if (i != null) {
|
||||||
val adapter = recyclerView.adapter
|
val adapter = recyclerView.adapter as ItemsAdapter<*>
|
||||||
|
|
||||||
when (adapter) {
|
val wasItemUnread = adapter.unreadItemStatusAtIndex(position)
|
||||||
is ItemCardAdapter -> adapter.removeItemAtIndex(position)
|
|
||||||
is ItemListAdapter -> adapter.removeItemAtIndex(position)
|
adapter.handleItemAtIndex(position)
|
||||||
|
|
||||||
|
if (wasItemUnread) {
|
||||||
|
badgeNew--
|
||||||
|
} else {
|
||||||
|
badgeNew++
|
||||||
}
|
}
|
||||||
|
|
||||||
badgeNew--
|
|
||||||
reloadBadgeContent()
|
reloadBadgeContent()
|
||||||
|
|
||||||
val tagHashes = i.tags.tags.split(",").map { it.longHash() }
|
val tagHashes = i.tags.tags.split(",").map { it.longHash() }
|
||||||
@ -304,19 +301,19 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
|
|
||||||
val tabNew =
|
val tabNew =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
R.drawable.ic_fiber_new_black_24dp,
|
R.drawable.ic_tab_fiber_new_black_24dp,
|
||||||
getString(R.string.tab_new)
|
getString(R.string.tab_new)
|
||||||
).setActiveColor(appColors.colorAccent)
|
).setActiveColor(appColors.colorAccent)
|
||||||
.setBadgeItem(tabNewBadge)
|
.setBadgeItem(tabNewBadge)
|
||||||
val tabArchive =
|
val tabArchive =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
R.drawable.ic_archive_black_24dp,
|
R.drawable.ic_tab_archive_black_24dp,
|
||||||
getString(R.string.tab_read)
|
getString(R.string.tab_read)
|
||||||
).setActiveColor(appColors.colorAccentDark)
|
).setActiveColor(appColors.colorAccentDark)
|
||||||
.setBadgeItem(tabArchiveBadge)
|
.setBadgeItem(tabArchiveBadge)
|
||||||
val tabStarred =
|
val tabStarred =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
R.drawable.ic_favorite_black_24dp,
|
R.drawable.ic_tab_favorite_black_24dp,
|
||||||
getString(R.string.tab_favs)
|
getString(R.string.tab_favs)
|
||||||
).setActiveColorResource(R.color.pink)
|
).setActiveColorResource(R.color.pink)
|
||||||
.setBadgeItem(tabStarredBadge)
|
.setBadgeItem(tabStarredBadge)
|
||||||
@ -478,7 +475,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
|
|
||||||
footer {
|
footer {
|
||||||
primaryItem(R.string.drawer_report_bug) {
|
primaryItem(R.string.drawer_report_bug) {
|
||||||
icon = R.drawable.ic_bug_report
|
icon = R.drawable.ic_bug_report_black_24dp
|
||||||
iconTintingEnabled = true
|
iconTintingEnabled = true
|
||||||
onClick { _ ->
|
onClick { _ ->
|
||||||
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(Config.trackerUrl))
|
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(Config.trackerUrl))
|
||||||
@ -488,7 +485,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
primaryItem(R.string.title_activity_settings) {
|
primaryItem(R.string.title_activity_settings) {
|
||||||
icon = R.drawable.ic_settings
|
icon = R.drawable.ic_settings_black_24dp
|
||||||
iconTintingEnabled = true
|
iconTintingEnabled = true
|
||||||
onClick { _ ->
|
onClick { _ ->
|
||||||
startActivityForResult(
|
startActivityForResult(
|
||||||
@ -518,7 +515,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val filteredTags = maybeTags.filterNot { hiddenTags.contains(it.tag) }
|
val filteredTags = maybeTags
|
||||||
|
.filterNot { hiddenTags.contains(it.tag) }
|
||||||
|
.sortedBy { it.unread == 0 }
|
||||||
tagsBadge = filteredTags.map {
|
tagsBadge = filteredTags.map {
|
||||||
val gd = GradientDrawable()
|
val gd = GradientDrawable()
|
||||||
val color = try {
|
val color = try {
|
||||||
@ -531,12 +530,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
gd.shape = GradientDrawable.RECTANGLE
|
gd.shape = GradientDrawable.RECTANGLE
|
||||||
gd.setSize(30, 30)
|
gd.setSize(30, 30)
|
||||||
gd.cornerRadius = 30F
|
gd.cornerRadius = 30F
|
||||||
drawer.addItem(
|
var drawerItem =
|
||||||
PrimaryDrawerItem()
|
PrimaryDrawerItem()
|
||||||
.withName(it.tag)
|
.withName(it.tag)
|
||||||
.withIdentifier(it.tag.longHash())
|
.withIdentifier(it.tag.longHash())
|
||||||
.withIcon(gd)
|
.withIcon(gd)
|
||||||
.withBadge("${it.unread}")
|
|
||||||
.withBadgeStyle(
|
.withBadgeStyle(
|
||||||
BadgeStyle().withTextColor(Color.WHITE)
|
BadgeStyle().withTextColor(Color.WHITE)
|
||||||
.withColor(appColors.colorAccent)
|
.withColor(appColors.colorAccent)
|
||||||
@ -547,6 +545,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
if (it.unread > 0) {
|
||||||
|
drawerItem = drawerItem.withBadge("${it.unread}")
|
||||||
|
}
|
||||||
|
drawer.addItem(
|
||||||
|
drawerItem
|
||||||
)
|
)
|
||||||
|
|
||||||
(it.tag.longHash() to it.unread)
|
(it.tag.longHash() to it.unread)
|
||||||
@ -578,12 +581,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
gd.shape = GradientDrawable.RECTANGLE
|
gd.shape = GradientDrawable.RECTANGLE
|
||||||
gd.setSize(30, 30)
|
gd.setSize(30, 30)
|
||||||
gd.cornerRadius = 30F
|
gd.cornerRadius = 30F
|
||||||
drawer.addItem(
|
var drawerItem =
|
||||||
PrimaryDrawerItem()
|
PrimaryDrawerItem()
|
||||||
.withName(it.tag)
|
.withName(it.tag)
|
||||||
.withIdentifier(it.tag.longHash())
|
.withIdentifier(it.tag.longHash())
|
||||||
.withIcon(gd)
|
.withIcon(gd)
|
||||||
.withBadge("${it.unread}")
|
|
||||||
.withBadgeStyle(
|
.withBadgeStyle(
|
||||||
BadgeStyle().withTextColor(Color.WHITE)
|
BadgeStyle().withTextColor(Color.WHITE)
|
||||||
.withColor(appColors.colorAccent)
|
.withColor(appColors.colorAccent)
|
||||||
@ -594,6 +596,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
if (it.unread > 0) {
|
||||||
|
drawerItem = drawerItem.withBadge("${it.unread}")
|
||||||
|
}
|
||||||
|
drawer.addItem(
|
||||||
|
drawerItem
|
||||||
)
|
)
|
||||||
|
|
||||||
(it.tag.longHash() to it.unread)
|
(it.tag.longHash() to it.unread)
|
||||||
@ -680,7 +687,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
PrimaryDrawerItem()
|
PrimaryDrawerItem()
|
||||||
.withName(R.string.action_about)
|
.withName(R.string.action_about)
|
||||||
.withSelectable(false)
|
.withSelectable(false)
|
||||||
.withIcon(R.drawable.ic_info_outline)
|
.withIcon(R.drawable.ic_info_outline_white_24dp)
|
||||||
.withIconTintingEnabled(true)
|
.withIconTintingEnabled(true)
|
||||||
.withOnDrawerItemClickListener { _, _, _ ->
|
.withOnDrawerItemClickListener { _, _, _ ->
|
||||||
LibsBuilder()
|
LibsBuilder()
|
||||||
@ -1136,7 +1143,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
fullHeightCards,
|
fullHeightCards,
|
||||||
appColors,
|
appColors,
|
||||||
debugReadingItems,
|
debugReadingItems,
|
||||||
userIdentifier
|
userIdentifier,
|
||||||
|
config
|
||||||
) {
|
) {
|
||||||
updateItems(it)
|
updateItems(it)
|
||||||
}
|
}
|
||||||
@ -1152,7 +1160,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
articleViewer,
|
articleViewer,
|
||||||
debugReadingItems,
|
debugReadingItems,
|
||||||
userIdentifier,
|
userIdentifier,
|
||||||
appColors
|
appColors,
|
||||||
|
config
|
||||||
) {
|
) {
|
||||||
updateItems(it)
|
updateItems(it)
|
||||||
}
|
}
|
||||||
@ -1341,12 +1350,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
|
|||||||
).show()
|
).show()
|
||||||
tabNewBadge.removeBadge()
|
tabNewBadge.removeBadge()
|
||||||
|
|
||||||
|
handleDrawerItems()
|
||||||
tagsBadge = itemsByTag.map {
|
|
||||||
(it.key to ((tagsBadge[it.key] ?: it.value) - it.value))
|
|
||||||
}.toMap()
|
|
||||||
|
|
||||||
reloadTagsBadges()
|
|
||||||
|
|
||||||
getElementsAccordingToTab()
|
getElementsAccordingToTab()
|
||||||
} else {
|
} else {
|
||||||
|
@ -10,12 +10,10 @@ import android.preference.PreferenceManager
|
|||||||
import androidx.multidex.MultiDexApplication
|
import androidx.multidex.MultiDexApplication
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import apps.amine.bou.readerforselfoss.utils.Config
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.glide.loadMaybeBasicAuth
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
import com.ftinc.scoop.Scoop
|
import com.ftinc.scoop.Scoop
|
||||||
import com.github.stkent.amplify.feedback.DefaultEmailFeedbackCollector
|
|
||||||
import com.github.stkent.amplify.feedback.GooglePlayStoreFeedbackCollector
|
|
||||||
import com.github.stkent.amplify.tracking.Amplify
|
|
||||||
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
|
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
|
||||||
import com.mikepenz.materialdrawer.util.DrawerImageLoader
|
import com.mikepenz.materialdrawer.util.DrawerImageLoader
|
||||||
import org.acra.ACRA
|
import org.acra.ACRA
|
||||||
@ -24,7 +22,6 @@ import org.acra.annotation.AcraCore
|
|||||||
import org.acra.annotation.AcraDialog
|
import org.acra.annotation.AcraDialog
|
||||||
import org.acra.annotation.AcraHttpSender
|
import org.acra.annotation.AcraHttpSender
|
||||||
import org.acra.sender.HttpSender
|
import org.acra.sender.HttpSender
|
||||||
import java.io.IOException
|
|
||||||
import java.util.UUID.randomUUID
|
import java.util.UUID.randomUUID
|
||||||
|
|
||||||
|
|
||||||
@ -42,11 +39,11 @@ import java.util.UUID.randomUUID
|
|||||||
ReportField.USER_APP_START_DATE, ReportField.USER_COMMENT, ReportField.USER_CRASH_DATE, ReportField.USER_EMAIL, ReportField.CUSTOM_DATA],
|
ReportField.USER_APP_START_DATE, ReportField.USER_COMMENT, ReportField.USER_CRASH_DATE, ReportField.USER_EMAIL, ReportField.CUSTOM_DATA],
|
||||||
buildConfigClass = BuildConfig::class)
|
buildConfigClass = BuildConfig::class)
|
||||||
class MyApp : MultiDexApplication() {
|
class MyApp : MultiDexApplication() {
|
||||||
|
private lateinit var config: Config
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
config = Config(baseContext)
|
||||||
initAmplify()
|
|
||||||
|
|
||||||
val prefs = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
val prefs = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||||
if (prefs.getString("unique_id", "").isEmpty()) {
|
if (prefs.getString("unique_id", "").isEmpty()) {
|
||||||
@ -89,13 +86,6 @@ class MyApp : MultiDexApplication() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initAmplify() {
|
|
||||||
Amplify.initSharedInstance(this)
|
|
||||||
.setPositiveFeedbackCollectors(GooglePlayStoreFeedbackCollector())
|
|
||||||
.setCriticalFeedbackCollectors(DefaultEmailFeedbackCollector(Config.feedbackEmail))
|
|
||||||
.applyAllDefaultRules()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initDrawerImageLoader() {
|
private fun initDrawerImageLoader() {
|
||||||
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
|
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
|
||||||
override fun set(
|
override fun set(
|
||||||
@ -105,7 +95,7 @@ class MyApp : MultiDexApplication() {
|
|||||||
tag: String?
|
tag: String?
|
||||||
) {
|
) {
|
||||||
Glide.with(imageView?.context)
|
Glide.with(imageView?.context)
|
||||||
.load(uri)
|
.loadMaybeBasicAuth(config, uri.toString())
|
||||||
.apply(RequestOptions.fitCenterTransform().placeholder(placeholder))
|
.apply(RequestOptions.fitCenterTransform().placeholder(placeholder))
|
||||||
.into(imageView)
|
.into(imageView)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package apps.amine.bou.readerforselfoss
|
package apps.amine.bou.readerforselfoss
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -13,6 +15,7 @@ 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.fragment.app.Fragment
|
||||||
import androidx.room.Room
|
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
|
||||||
@ -25,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.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.Config
|
||||||
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.network.isNetworkAccessible
|
||||||
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
|
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
|
||||||
@ -51,6 +55,11 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
private lateinit var toolbarMenu: Menu
|
private lateinit var toolbarMenu: Menu
|
||||||
|
|
||||||
private lateinit var db: AppDatabase
|
private lateinit var db: AppDatabase
|
||||||
|
private lateinit var prefs: SharedPreferences
|
||||||
|
|
||||||
|
private var activeAlignment: Int = 1
|
||||||
|
val JUSTIFY = 1
|
||||||
|
val ALIGN_LEFT = 2
|
||||||
|
|
||||||
private fun showMenuItem(willAddToFavorite: Boolean) {
|
private fun showMenuItem(willAddToFavorite: Boolean) {
|
||||||
toolbarMenu.findItem(R.id.save).isVisible = willAddToFavorite
|
toolbarMenu.findItem(R.id.save).isVisible = willAddToFavorite
|
||||||
@ -65,6 +74,8 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
showMenuItem(false)
|
showMenuItem(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lateinit var editor: SharedPreferences.Editor
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@ -85,16 +96,21 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
|
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
val settings =
|
||||||
|
getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||||
|
|
||||||
|
prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
editor = prefs.edit()
|
||||||
|
|
||||||
debugReadingItems = prefs.getBoolean("read_debug", false)
|
debugReadingItems = prefs.getBoolean("read_debug", false)
|
||||||
userIdentifier = prefs.getString("unique_id", "")
|
userIdentifier = prefs.getString("unique_id", "")
|
||||||
markOnScroll = prefs.getBoolean("mark_on_scroll", false)
|
markOnScroll = prefs.getBoolean("mark_on_scroll", false)
|
||||||
|
activeAlignment = prefs.getInt("text_align", JUSTIFY)
|
||||||
|
|
||||||
api = SelfossApi(
|
api = SelfossApi(
|
||||||
this,
|
this,
|
||||||
this@ReaderActivity,
|
this@ReaderActivity,
|
||||||
prefs.getBoolean("isSelfSignedCert", false),
|
settings.getBoolean("isSelfSignedCert", false),
|
||||||
prefs.getString("api_timeout", "-1").toLong(),
|
prefs.getString("api_timeout", "-1").toLong(),
|
||||||
prefs.getBoolean("should_log_everything", false)
|
prefs.getBoolean("should_log_everything", false)
|
||||||
)
|
)
|
||||||
@ -223,6 +239,11 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun alignmentMenu(showJustify: Boolean) {
|
||||||
|
toolbarMenu.findItem(R.id.align_left).isVisible = !showJustify
|
||||||
|
toolbarMenu.findItem(R.id.align_justify).isVisible = showJustify
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
val inflater = menuInflater
|
val inflater = menuInflater
|
||||||
inflater.inflate(R.menu.reader_menu, menu)
|
inflater.inflate(R.menu.reader_menu, menu)
|
||||||
@ -233,6 +254,11 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
} else {
|
} else {
|
||||||
canFavorite()
|
canFavorite()
|
||||||
}
|
}
|
||||||
|
if (activeAlignment == JUSTIFY) {
|
||||||
|
alignmentMenu(false)
|
||||||
|
} else {
|
||||||
|
alignmentMenu(true)
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -314,10 +340,29 @@ class ReaderActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
R.id.align_left -> {
|
||||||
|
editor.putInt("text_align", ALIGN_LEFT)
|
||||||
|
editor.apply()
|
||||||
|
alignmentMenu(true)
|
||||||
|
refreshFragment()
|
||||||
|
}
|
||||||
|
R.id.align_justify -> {
|
||||||
|
editor.putInt("text_align", JUSTIFY)
|
||||||
|
editor.apply()
|
||||||
|
alignmentMenu(false)
|
||||||
|
refreshFragment()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item)
|
return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun refreshFragment() {
|
||||||
|
finish()
|
||||||
|
overridePendingTransition(0, 0)
|
||||||
|
startActivity(intent)
|
||||||
|
overridePendingTransition(0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var allItems: ArrayList<Item> = ArrayList()
|
var allItems: ArrayList<Item> = ArrayList()
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package apps.amine.bou.readerforselfoss
|
package apps.amine.bou.readerforselfoss
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.os.Build
|
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.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.Config
|
||||||
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
|
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.*
|
||||||
@ -54,12 +56,14 @@ class SourcesActivity : AppCompatActivity() {
|
|||||||
super.onResume()
|
super.onResume()
|
||||||
val mLayoutManager = LinearLayoutManager(this)
|
val mLayoutManager = LinearLayoutManager(this)
|
||||||
|
|
||||||
|
val settings =
|
||||||
|
getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
|
||||||
val api = SelfossApi(
|
val api = SelfossApi(
|
||||||
this,
|
this,
|
||||||
this@SourcesActivity,
|
this@SourcesActivity,
|
||||||
prefs.getBoolean("isSelfSignedCert", false),
|
settings.getBoolean("isSelfSignedCert", false),
|
||||||
prefs.getString("api_timeout", "-1").toLong(),
|
prefs.getString("api_timeout", "-1").toLong(),
|
||||||
prefs.getBoolean("should_log_everything", false)
|
prefs.getBoolean("should_log_everything", false)
|
||||||
)
|
)
|
||||||
|
@ -17,6 +17,7 @@ import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
|||||||
import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase
|
import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase
|
||||||
import apps.amine.bou.readerforselfoss.persistence.entities.ActionEntity
|
import apps.amine.bou.readerforselfoss.persistence.entities.ActionEntity
|
||||||
import apps.amine.bou.readerforselfoss.themes.AppColors
|
import apps.amine.bou.readerforselfoss.themes.AppColors
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
import apps.amine.bou.readerforselfoss.utils.LinkOnTouchListener
|
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
|
||||||
@ -51,6 +52,7 @@ class ItemCardAdapter(
|
|||||||
override val appColors: AppColors,
|
override val appColors: AppColors,
|
||||||
override val debugReadingItems: Boolean,
|
override val debugReadingItems: Boolean,
|
||||||
override val userIdentifier: String,
|
override val userIdentifier: String,
|
||||||
|
override val config: Config,
|
||||||
override val updateItems: (ArrayList<Item>) -> Unit
|
override val updateItems: (ArrayList<Item>) -> Unit
|
||||||
) : ItemsAdapter<ItemCardAdapter.ViewHolder>() {
|
) : ItemsAdapter<ItemCardAdapter.ViewHolder>() {
|
||||||
private val c: Context = app.baseContext
|
private val c: Context = app.baseContext
|
||||||
@ -86,7 +88,7 @@ class ItemCardAdapter(
|
|||||||
holder.mView.itemImage.setImageDrawable(null)
|
holder.mView.itemImage.setImageDrawable(null)
|
||||||
} else {
|
} else {
|
||||||
holder.mView.itemImage.visibility = View.VISIBLE
|
holder.mView.itemImage.visibility = View.VISIBLE
|
||||||
c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage)
|
c.bitmapCenterCrop(config, itm.getThumbnail(c), holder.mView.itemImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itm.getIcon(c).isEmpty()) {
|
if (itm.getIcon(c).isEmpty()) {
|
||||||
@ -99,7 +101,7 @@ class ItemCardAdapter(
|
|||||||
.build(itm.sourcetitle.toTextDrawableString(c), color)
|
.build(itm.sourcetitle.toTextDrawableString(c), color)
|
||||||
holder.mView.sourceImage.setImageDrawable(drawable)
|
holder.mView.sourceImage.setImageDrawable(drawable)
|
||||||
} else {
|
} else {
|
||||||
c.circularBitmapDrawable(itm.getIcon(c), holder.mView.sourceImage)
|
c.circularBitmapDrawable(config, itm.getIcon(c), holder.mView.sourceImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.mView.favButton.isLiked = itm.starred
|
holder.mView.favButton.isLiked = itm.starred
|
||||||
|
@ -20,6 +20,7 @@ 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.persistence.database.AppDatabase
|
||||||
import apps.amine.bou.readerforselfoss.themes.AppColors
|
import apps.amine.bou.readerforselfoss.themes.AppColors
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
import apps.amine.bou.readerforselfoss.utils.LinkOnTouchListener
|
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
|
||||||
@ -52,6 +53,7 @@ class ItemListAdapter(
|
|||||||
override val debugReadingItems: Boolean,
|
override val debugReadingItems: Boolean,
|
||||||
override val userIdentifier: String,
|
override val userIdentifier: String,
|
||||||
override val appColors: AppColors,
|
override val appColors: AppColors,
|
||||||
|
override val config: Config,
|
||||||
override val updateItems: (ArrayList<Item>) -> Unit
|
override val updateItems: (ArrayList<Item>) -> Unit
|
||||||
) : ItemsAdapter<ItemListAdapter.ViewHolder>() {
|
) : ItemsAdapter<ItemListAdapter.ViewHolder>() {
|
||||||
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
||||||
@ -108,10 +110,10 @@ class ItemListAdapter(
|
|||||||
|
|
||||||
holder.mView.itemImage.setImageDrawable(drawable)
|
holder.mView.itemImage.setImageDrawable(drawable)
|
||||||
} else {
|
} else {
|
||||||
c.circularBitmapDrawable(itm.getIcon(c), holder.mView.itemImage)
|
c.circularBitmapDrawable(config, itm.getIcon(c), holder.mView.itemImage)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.bitmapCenterCrop(itm.getThumbnail(c), holder.mView.itemImage)
|
c.bitmapCenterCrop(config, itm.getThumbnail(c), holder.mView.itemImage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
|
|||||||
import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase
|
import apps.amine.bou.readerforselfoss.persistence.database.AppDatabase
|
||||||
import apps.amine.bou.readerforselfoss.persistence.entities.ActionEntity
|
import apps.amine.bou.readerforselfoss.persistence.entities.ActionEntity
|
||||||
import apps.amine.bou.readerforselfoss.themes.AppColors
|
import apps.amine.bou.readerforselfoss.themes.AppColors
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
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.network.isNetworkAccessible
|
||||||
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
|
import apps.amine.bou.readerforselfoss.utils.persistence.toEntity
|
||||||
@ -31,6 +32,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
abstract val userIdentifier: String
|
abstract val userIdentifier: String
|
||||||
abstract val app: Activity
|
abstract val app: Activity
|
||||||
abstract val appColors: AppColors
|
abstract val appColors: AppColors
|
||||||
|
abstract val config: Config
|
||||||
abstract val updateItems: (ArrayList<Item>) -> Unit
|
abstract val updateItems: (ArrayList<Item>) -> Unit
|
||||||
|
|
||||||
fun updateAllItems(newItems: ArrayList<Item>) {
|
fun updateAllItems(newItems: ArrayList<Item>) {
|
||||||
@ -39,7 +41,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
updateItems(items)
|
updateItems(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doUnmark(i: Item, position: Int) {
|
private fun unmarkSnackbar(i: Item, position: Int) {
|
||||||
val s = Snackbar
|
val s = Snackbar
|
||||||
.make(
|
.make(
|
||||||
app.findViewById(R.id.coordLayout),
|
app.findViewById(R.id.coordLayout),
|
||||||
@ -69,12 +71,11 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
}
|
}
|
||||||
notifyItemRemoved(position)
|
notifyItemRemoved(position)
|
||||||
updateItems(items)
|
updateItems(items)
|
||||||
doUnmark(i, position)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
thread {
|
thread {
|
||||||
db.actionsDao().deleteReadActionForArticle(i.id)
|
db.actionsDao().insertAllActions(ActionEntity(i.id, false, true, false, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,7 +86,64 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
s.show()
|
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]
|
val i = items[position]
|
||||||
items.remove(i)
|
items.remove(i)
|
||||||
notifyItemRemoved(position)
|
notifyItemRemoved(position)
|
||||||
@ -103,7 +161,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
) {
|
) {
|
||||||
if (!response.succeeded() && debugReadingItems) {
|
if (!response.succeeded() && debugReadingItems) {
|
||||||
val message =
|
val message =
|
||||||
"message: ${response.message()} " +
|
"MARK message: ${response.message()} " +
|
||||||
"response isSuccess: ${response.isSuccessful} " +
|
"response isSuccess: ${response.isSuccessful} " +
|
||||||
"response code: ${response.code()} " +
|
"response code: ${response.code()} " +
|
||||||
"response message: ${response.message()} " +
|
"response message: ${response.message()} " +
|
||||||
@ -114,7 +172,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
Toast.makeText(app.baseContext, message, Toast.LENGTH_LONG).show()
|
Toast.makeText(app.baseContext, message, Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
doUnmark(i, position)
|
unmarkSnackbar(i, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
override fun onFailure(call: Call<SuccessResponse>, t: Throwable) {
|
||||||
@ -127,7 +185,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
app.getString(R.string.cant_mark_read),
|
app.getString(R.string.cant_mark_read),
|
||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
items.add(i)
|
items.add(position, i)
|
||||||
notifyItemInserted(position)
|
notifyItemInserted(position)
|
||||||
updateItems(items)
|
updateItems(items)
|
||||||
|
|
||||||
@ -139,7 +197,64 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
} else {
|
} else {
|
||||||
thread {
|
thread {
|
||||||
db.actionsDao().insertAllActions(ActionEntity(i.id, true, false, false, false))
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import apps.amine.bou.readerforselfoss.R
|
|||||||
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
|
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.Config
|
||||||
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.network.isNetworkAccessible
|
||||||
import apps.amine.bou.readerforselfoss.utils.toTextDrawableString
|
import apps.amine.bou.readerforselfoss.utils.toTextDrawableString
|
||||||
@ -29,6 +30,7 @@ class SourcesListAdapter(
|
|||||||
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>() {
|
) : RecyclerView.Adapter<SourcesListAdapter.ViewHolder>() {
|
||||||
private val c: Context = app.baseContext
|
private val c: Context = app.baseContext
|
||||||
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
private val generator: ColorGenerator = ColorGenerator.MATERIAL
|
||||||
|
private lateinit var config: Config
|
||||||
|
|
||||||
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(
|
||||||
@ -41,6 +43,7 @@ class SourcesListAdapter(
|
|||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val itm = items[position]
|
val itm = items[position]
|
||||||
|
config = Config(c)
|
||||||
|
|
||||||
if (itm.getIcon(c).isEmpty()) {
|
if (itm.getIcon(c).isEmpty()) {
|
||||||
val color = generator.getColor(itm.title)
|
val color = generator.getColor(itm.title)
|
||||||
@ -52,7 +55,7 @@ class SourcesListAdapter(
|
|||||||
.build(itm.title.toTextDrawableString(c), color)
|
.build(itm.title.toTextDrawableString(c), color)
|
||||||
holder.mView.itemImage.setImageDrawable(drawable)
|
holder.mView.itemImage.setImageDrawable(drawable)
|
||||||
} else {
|
} else {
|
||||||
c.circularBitmapDrawable(itm.getIcon(c), holder.mView.itemImage)
|
c.circularBitmapDrawable(config, itm.getIcon(c), holder.mView.itemImage)
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.mView.sourceTitle.text = itm.title
|
holder.mView.sourceTitle.text = itm.title
|
||||||
|
@ -12,7 +12,10 @@ import com.burgstaller.okhttp.digest.CachingAuthenticator
|
|||||||
import com.burgstaller.okhttp.digest.Credentials
|
import com.burgstaller.okhttp.digest.Credentials
|
||||||
import com.burgstaller.okhttp.digest.DigestAuthenticator
|
import com.burgstaller.okhttp.digest.DigestAuthenticator
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
|
import okhttp3.Interceptor
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
@ -62,6 +65,17 @@ class SelfossApi(
|
|||||||
.maybeWithSelfSigned(isWithSelfSignedCert)
|
.maybeWithSelfSigned(isWithSelfSignedCert)
|
||||||
.authenticator(CachingAuthenticatorDecorator(this, authCache))
|
.authenticator(CachingAuthenticatorDecorator(this, authCache))
|
||||||
.addInterceptor(AuthenticationCacheInterceptor(authCache))
|
.addInterceptor(AuthenticationCacheInterceptor(authCache))
|
||||||
|
.addInterceptor(object: Interceptor {
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val request: Request = chain.request()
|
||||||
|
val response: Response = chain.proceed(request)
|
||||||
|
|
||||||
|
if (response.code() == 408) {
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -46,7 +46,7 @@ class LoadingWorker(val context: Context, params: WorkerParameters) : Worker(con
|
|||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setPriority(PRIORITY_LOW)
|
.setPriority(PRIORITY_LOW)
|
||||||
.setChannelId(Config.syncChannelId)
|
.setChannelId(Config.syncChannelId)
|
||||||
.setSmallIcon(R.drawable.ic_cloud_download)
|
.setSmallIcon(R.drawable.ic_stat_cloud_download_black_24dp)
|
||||||
|
|
||||||
notificationManager.notify(1, notification.build())
|
notificationManager.notify(1, notification.build())
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ class LoadingWorker(val context: Context, params: WorkerParameters) : Worker(con
|
|||||||
.setChannelId(Config.newItemsChannelId)
|
.setChannelId(Config.newItemsChannelId)
|
||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(pendingIntent)
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setSmallIcon(R.drawable.ic_fiber_new_black_24dp)
|
.setSmallIcon(R.drawable.ic_tab_fiber_new_black_24dp)
|
||||||
|
|
||||||
Timer("", false).schedule(4000) {
|
Timer("", false).schedule(4000) {
|
||||||
notificationManager.notify(2, newItemsNotification.build())
|
notificationManager.notify(2, newItemsNotification.build())
|
||||||
@ -130,7 +130,7 @@ class LoadingWorker(val context: Context, params: WorkerParameters) : Worker(con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Result.SUCCESS
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T> doAndReportOnFail(call: Call<T>, action: ActionEntity) {
|
private fun <T> doAndReportOnFail(call: Call<T>, action: ActionEntity) {
|
||||||
|
@ -3,6 +3,8 @@ package apps.amine.bou.readerforselfoss.fragments
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
|
import android.content.res.TypedArray
|
||||||
|
import android.graphics.Typeface
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -19,6 +21,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.webkit.WebSettings
|
import android.webkit.WebSettings
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.room.Room
|
import androidx.room.Room
|
||||||
import apps.amine.bou.readerforselfoss.R
|
import apps.amine.bou.readerforselfoss.R
|
||||||
import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi
|
import apps.amine.bou.readerforselfoss.api.mercury.MercuryApi
|
||||||
@ -34,6 +37,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.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.loadMaybeBasicAuth
|
||||||
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.network.isNetworkAccessible
|
||||||
@ -67,6 +71,16 @@ class ArticleFragment : Fragment() {
|
|||||||
private lateinit var fab: FloatingActionButton
|
private lateinit var fab: FloatingActionButton
|
||||||
private lateinit var appColors: AppColors
|
private lateinit var appColors: AppColors
|
||||||
private lateinit var db: AppDatabase
|
private lateinit var db: AppDatabase
|
||||||
|
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() {
|
override fun onStop() {
|
||||||
super.onStop()
|
super.onStop()
|
||||||
@ -77,6 +91,7 @@ class ArticleFragment : Fragment() {
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
appColors = AppColors(activity!!)
|
appColors = AppColors(activity!!)
|
||||||
|
config = Config(activity!!)
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@ -89,9 +104,6 @@ class ArticleFragment : Fragment() {
|
|||||||
).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3).build()
|
).addMigrations(MIGRATION_1_2).addMigrations(MIGRATION_2_3).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var rootView: ViewGroup? = null
|
|
||||||
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
@ -107,10 +119,24 @@ class ArticleFragment : Fragment() {
|
|||||||
contentImage = allItems[pageNumber.toInt()].getThumbnail(activity!!)
|
contentImage = allItems[pageNumber.toInt()].getThumbnail(activity!!)
|
||||||
contentSource = allItems[pageNumber.toInt()].sourceAndDateText()
|
contentSource = allItems[pageNumber.toInt()].sourceAndDateText()
|
||||||
|
|
||||||
val prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
prefs = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
editor = prefs.edit()
|
editor = prefs.edit()
|
||||||
fontSize = prefs.getString("reader_font_size", "16").toInt()
|
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)
|
val settings = activity!!.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
|
||||||
val debugReadingItems = prefs.getBoolean("read_debug", false)
|
val debugReadingItems = prefs.getBoolean("read_debug", false)
|
||||||
|
|
||||||
@ -198,20 +224,26 @@ class ArticleFragment : Fragment() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
rootView!!.source.text = contentSource
|
rootView!!.source.text = contentSource
|
||||||
|
if (typeface != null) {
|
||||||
|
rootView!!.source.typeface = typeface
|
||||||
|
}
|
||||||
|
|
||||||
if (contentText.isEmptyOrNullOrNullString()) {
|
if (contentText.isEmptyOrNullOrNullString()) {
|
||||||
getContentFromMercury(customTabsIntent, prefs)
|
getContentFromMercury(customTabsIntent, prefs)
|
||||||
} else {
|
} else {
|
||||||
rootView!!.titleView.text = contentTitle
|
rootView!!.titleView.text = contentTitle
|
||||||
|
if (typeface != null) {
|
||||||
|
rootView!!.titleView.typeface = typeface
|
||||||
|
}
|
||||||
|
|
||||||
htmlToWebview(contentText, prefs)
|
htmlToWebview()
|
||||||
|
|
||||||
if (!contentImage.isEmptyOrNullOrNullString() && context != null) {
|
if (!contentImage.isEmptyOrNullOrNullString() && context != null) {
|
||||||
rootView!!.imageView.visibility = View.VISIBLE
|
rootView!!.imageView.visibility = View.VISIBLE
|
||||||
Glide
|
Glide
|
||||||
.with(context!!)
|
.with(context!!)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.load(contentImage)
|
.loadMaybeBasicAuth(config, contentImage)
|
||||||
.apply(RequestOptions.fitCenterTransform())
|
.apply(RequestOptions.fitCenterTransform())
|
||||||
.into(rootView!!.imageView)
|
.into(rootView!!.imageView)
|
||||||
} else {
|
} else {
|
||||||
@ -248,6 +280,14 @@ class ArticleFragment : Fragment() {
|
|||||||
return rootView
|
return rootView
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun refreshAlignment() {
|
||||||
|
textAlignment = when (prefs.getInt("text_align", 1)) {
|
||||||
|
1 -> "justify"
|
||||||
|
2 -> "left"
|
||||||
|
else -> "justify"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getContentFromMercury(
|
private fun getContentFromMercury(
|
||||||
customTabsIntent: CustomTabsIntent,
|
customTabsIntent: CustomTabsIntent,
|
||||||
prefs: SharedPreferences
|
prefs: SharedPreferences
|
||||||
@ -269,12 +309,15 @@ class ArticleFragment : Fragment() {
|
|||||||
if (response.body() != null && response.body()!!.content != null && !response.body()!!.content.isNullOrEmpty()) {
|
if (response.body() != null && response.body()!!.content != null && !response.body()!!.content.isNullOrEmpty()) {
|
||||||
try {
|
try {
|
||||||
rootView!!.titleView.text = response.body()!!.title
|
rootView!!.titleView.text = response.body()!!.title
|
||||||
|
if (typeface != null) {
|
||||||
|
rootView!!.titleView.typeface = typeface
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// Note: Mercury may return relative urls... If it does the url val will not be changed.
|
// Note: Mercury may return relative urls... If it does the url val will not be changed.
|
||||||
URL(response.body()!!.url)
|
URL(response.body()!!.url)
|
||||||
url = response.body()!!.url
|
url = response.body()!!.url
|
||||||
} catch (e: MalformedURLException) {
|
} catch (e: MalformedURLException) {
|
||||||
ACRA.getErrorReporter().maybeHandleSilentException(e, activity!!)
|
// Mercury returned a relative url. We do nothing.
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
@ -283,7 +326,8 @@ class ArticleFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
htmlToWebview(response.body()!!.content.orEmpty(), prefs)
|
contentText = response.body()!!.content.orEmpty()
|
||||||
|
htmlToWebview()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
ACRA.getErrorReporter().maybeHandleSilentException(e, context!!)
|
ACRA.getErrorReporter().maybeHandleSilentException(e, context!!)
|
||||||
@ -297,7 +341,7 @@ class ArticleFragment : Fragment() {
|
|||||||
Glide
|
Glide
|
||||||
.with(context!!)
|
.with(context!!)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.load(response.body()!!.lead_image_url)
|
.loadMaybeBasicAuth(config, response.body()!!.lead_image_url.orEmpty())
|
||||||
.apply(RequestOptions.fitCenterTransform())
|
.apply(RequestOptions.fitCenterTransform())
|
||||||
.into(rootView!!.imageView)
|
.into(rootView!!.imageView)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@ -346,9 +390,14 @@ class ArticleFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun htmlToWebview(c: String, prefs: SharedPreferences) {
|
private fun htmlToWebview() {
|
||||||
val stringColor = String.format("#%06X", 0xFFFFFF and appColors.colorAccent)
|
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
|
rootView!!.webcontent.visibility = View.VISIBLE
|
||||||
val (textColor, backgroundColor) = if (appColors.isDarkTheme) {
|
val (textColor, backgroundColor) = if (appColors.isDarkTheme) {
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
@ -408,6 +457,24 @@ class ArticleFragment : Fragment() {
|
|||||||
ACRA.getErrorReporter().maybeHandleSilentException(e, activity!!)
|
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(
|
rootView!!.webcontent.loadDataWithBaseURL(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
"""<html>
|
"""<html>
|
||||||
@ -428,12 +495,13 @@ class ArticleFragment : Fragment() {
|
|||||||
| }
|
| }
|
||||||
| * {
|
| * {
|
||||||
| font-size: ${fontSize}px;
|
| font-size: ${fontSize}px;
|
||||||
| text-align: justify;
|
| text-align: $textAlignment;
|
||||||
| word-break: break-word;
|
| word-break: break-word;
|
||||||
| overflow:hidden;
|
| overflow:hidden;
|
||||||
|
| line-height: 1.5em;
|
||||||
| }
|
| }
|
||||||
| a, pre, code {
|
| a, pre, code {
|
||||||
| text-align: left;
|
| text-align: $textAlignment;
|
||||||
| }
|
| }
|
||||||
| pre, code {
|
| pre, code {
|
||||||
| white-space: pre-wrap;
|
| white-space: pre-wrap;
|
||||||
@ -441,9 +509,10 @@ class ArticleFragment : Fragment() {
|
|||||||
| background-color: $stringBackgroundColor;
|
| background-color: $stringBackgroundColor;
|
||||||
| }
|
| }
|
||||||
| </style>
|
| </style>
|
||||||
|
| $fontLinkAndStyle
|
||||||
|</head>
|
|</head>
|
||||||
|<body>
|
|<body>
|
||||||
| $c
|
| $contentText
|
||||||
|</body>""".trimMargin(),
|
|</body>""".trimMargin(),
|
||||||
"text/html",
|
"text/html",
|
||||||
"utf-8",
|
"utf-8",
|
||||||
|
@ -8,6 +8,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -24,6 +25,7 @@ import android.text.Editable;
|
|||||||
import android.text.InputFilter;
|
import android.text.InputFilter;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@ -124,6 +126,27 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
|
|||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
public void onBuildHeaders(List<Header> target) {
|
public void onBuildHeaders(List<Header> target) {
|
||||||
loadHeadersFromResource(R.xml.pref_headers, 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,11 +148,7 @@ fun String.isBaseUrlValid(logErrors: Boolean, ctx: Context): Boolean {
|
|||||||
existsAndEndsWithSlash = "" == pathSegments[pathSegments.size - 1]
|
existsAndEndsWithSlash = "" == pathSegments[pathSegments.size - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
val isValid = Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash
|
return Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash
|
||||||
if (!isValid && logErrors) {
|
|
||||||
ACRA.getErrorReporter().doHandleSilentException(java.lang.Exception("Patterns.WEB_URL.matcher(this).matches() == ${Patterns.WEB_URL.matcher(this).matches()} && existsAndEndsWithSlash == $existsAndEndsWithSlash && baseUrl.pathSegments() == ${baseUrl?.pathSegments()}"), ctx)
|
|
||||||
}
|
|
||||||
return isValid
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.openInBrowserAsNewTask(i: Item) {
|
fun Context.openInBrowserAsNewTask(i: Item) {
|
||||||
|
@ -2,30 +2,30 @@ package apps.amine.bou.readerforselfoss.utils.glide
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.util.Base64
|
||||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import apps.amine.bou.readerforselfoss.utils.Config
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.RequestBuilder
|
||||||
|
import com.bumptech.glide.RequestManager
|
||||||
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
|
import com.bumptech.glide.load.model.LazyHeaders
|
||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
import com.bumptech.glide.request.target.BitmapImageViewTarget
|
import com.bumptech.glide.request.target.BitmapImageViewTarget
|
||||||
|
|
||||||
fun Context.bitmapCenterCrop(url: String, iv: ImageView) =
|
fun Context.bitmapCenterCrop(config: Config, url: String, iv: ImageView) =
|
||||||
Glide.with(this)
|
Glide.with(this)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.load(url)
|
.loadMaybeBasicAuth(config, url)
|
||||||
.apply(RequestOptions.centerCropTransform())
|
.apply(RequestOptions.centerCropTransform())
|
||||||
.into(iv)
|
.into(iv)
|
||||||
|
|
||||||
fun Context.bitmapFitCenter(url: String, iv: ImageView) =
|
fun Context.circularBitmapDrawable(config: Config, url: String, iv: ImageView) =
|
||||||
Glide.with(this)
|
Glide.with(this)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.load(url)
|
.loadMaybeBasicAuth(config, url)
|
||||||
.apply(RequestOptions.fitCenterTransform())
|
|
||||||
.into(iv)
|
|
||||||
|
|
||||||
fun Context.circularBitmapDrawable(url: String, iv: ImageView) =
|
|
||||||
Glide.with(this)
|
|
||||||
.asBitmap()
|
|
||||||
.load(url)
|
|
||||||
.apply(RequestOptions.centerCropTransform())
|
.apply(RequestOptions.centerCropTransform())
|
||||||
.into(object : BitmapImageViewTarget(iv) {
|
.into(object : BitmapImageViewTarget(iv) {
|
||||||
override fun setResource(resource: Bitmap?) {
|
override fun setResource(resource: Bitmap?) {
|
||||||
@ -36,4 +36,24 @@ fun Context.circularBitmapDrawable(url: String, iv: ImageView) =
|
|||||||
circularBitmapDrawable.isCircular = true
|
circularBitmapDrawable.isCircular = true
|
||||||
iv.setImageDrawable(circularBitmapDrawable)
|
iv.setImageDrawable(circularBitmapDrawable)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
fun RequestBuilder<Bitmap>.loadMaybeBasicAuth(config: Config, url: String): RequestBuilder<Bitmap> {
|
||||||
|
val builder: LazyHeaders.Builder = LazyHeaders.Builder()
|
||||||
|
if (config.httpUserLogin.isNotEmpty() || config.httpUserPassword.isNotEmpty()) {
|
||||||
|
val basicAuth = "Basic " + Base64.encodeToString("${config.httpUserLogin}:${config.httpUserPassword}".toByteArray(), Base64.NO_WRAP)
|
||||||
|
builder.addHeader("Authorization", basicAuth)
|
||||||
|
}
|
||||||
|
val glideUrl = GlideUrl(url, builder.build())
|
||||||
|
return this.load(glideUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RequestManager.loadMaybeBasicAuth(config: Config, url: String): RequestBuilder<Drawable> {
|
||||||
|
val builder: LazyHeaders.Builder = LazyHeaders.Builder()
|
||||||
|
if (config.httpUserLogin.isNotEmpty() || config.httpUserPassword.isNotEmpty()) {
|
||||||
|
val basicAuth = "Basic " + Base64.encodeToString("${config.httpUserLogin}:${config.httpUserPassword}".toByteArray(), Base64.NO_WRAP)
|
||||||
|
builder.addHeader("Authorization", basicAuth)
|
||||||
|
}
|
||||||
|
val glideUrl = GlideUrl(url, builder.build())
|
||||||
|
return this.load(glideUrl)
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M3,21h18v-2L3,19v2zM3,17h18v-2L3,15v2zM3,13h18v-2L3,11v2zM3,9h18L21,7L3,7v2zM3,3v2h18L21,3L3,3z"/>
|
||||||
|
</vector>
|
@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M15,15L3,15v2h12v-2zM15,7L3,7v2h12L15,7zM3,13h18v-2L3,11v2zM3,21h18v-2L3,19v2zM3,3v2h18L21,3L3,3z"/>
|
||||||
|
</vector>
|
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 |