Compare commits

..

7 Commits

29 changed files with 371 additions and 262 deletions

View File

@ -44,12 +44,8 @@
- Closing #236. New sources can be added in Selfoss 2.19.
- Closing #397 and #355. Tag and Sources filters are now exclusive.
- Dropped support for android 4, the last version supporting it is v1721030811
- Added ability to scroll articles up and down using the volume keys #400
**1.6.x**
- Handling hidden tags.

View File

@ -1 +1,47 @@
# Project moved to https://github.com/aminecmi/ReaderforSelfoss-multiplatform
# ReaderForSelfoss **(Only available from F-Droid)**
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/readerforselfoss/localized.svg)](https://crowdin.com/project/readerforselfoss)
It's an RSS Reader for Android, that **only** works with [Selfoss](https://selfoss.aditu.de/)
**The project is not dead at all.**
I still want to work on it, but for the last few months, I didn't have that much time to do so.
If you are a developer, don't hesitate to help with PRs.
If you are a user, you can still create new issues. I'll fix them when I can.
<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>
## Screen captures
<img src="res//fr-card.png?raw=true" alt="card view" width="400"/> <img src="res//fr-list.png?raw=true" alt="list view" width="400"/>
## Like my app ?
<a href="https://www.buymeacoffee.com/aminecmi" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/lato-orange.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></a>
## Want to help ?
1. **You'll have to have a Selfoss instance running.** You'll find everything you need to install it [here](https://selfoss.aditu.de/).
2. Check the [Contribution guide](https://github.com/aminecmi/ReaderforSelfoss/blob/master/.github/CONTRIBUTING.md).
3. Build the project by following [these steps](https://github.com/aminecmi/ReaderforSelfoss/blob/master/.github/CONTRIBUTING.md#build-the-project) (you should have read them after the contribution guide)
## Useful links
- [Check what changed](https://github.com/aminecmi/ReaderforSelfoss/blob/master/CHANGELOG.md)
- [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)
- [Help translation the app](https://crowdin.com/project/readerforselfoss)
## Contributors (Alphabetical order) ❤️
- [@aancel](https://github.com/aancel)
- [@Binnette](https://github.com/Binnette)
- [@davidoskky](https://github.com/davidoskky)
- [@hectorgabucio](https://github.com/hectorgabucio)
- [@licaon-kter](https://github.com/licaon-kter)
- [@sergey-babkin](https://github.com/sergey-babkin)

View File

@ -104,18 +104,18 @@ dependencies {
// Espresso-intents for validation and stubbing of Intents
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0-alpha02'
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
// Android Support
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation "androidx.appcompat:appcompat:1.4.0-beta01"
implementation 'com.google.android.material:material:1.5.0-alpha04'
implementation 'androidx.recyclerview:recyclerview:1.3.0-alpha01'
implementation "androidx.legacy:legacy-support-v4:$android_version"
implementation 'androidx.vectordrawable:vectordrawable:1.2.0-alpha02'
implementation 'androidx.browser:browser:1.4.0'
implementation "androidx.browser:browser:1.3.0"
implementation "androidx.cardview:cardview:$android_version"
implementation 'androidx.annotation:annotation:1.3.0'
implementation 'androidx.work:work-runtime-ktx:2.7.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation "androidx.annotation:annotation:1.2.0"
implementation 'androidx.work:work-runtime-ktx:2.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
implementation 'org.jsoup:jsoup:1.14.3'
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5")
@ -129,11 +129,11 @@ dependencies {
implementation "com.mikepenz:aboutlibraries-definitions:8.9.4"
// Async
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
// Retrofit + http logging + okhttp
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.3'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.burgstaller:okhttp-digest:2.5'
@ -146,7 +146,7 @@ dependencies {
implementation 'com.github.bumptech.glide:okhttp3-integration:4.1.1'
// Drawer
implementation 'com.mikepenz:materialdrawer:8.4.5'
implementation 'com.mikepenz:materialdrawer:8.4.4'
// Themes
implementation 'com.52inc:scoops:1.0.0'
@ -155,15 +155,14 @@ dependencies {
// Pager
implementation 'me.relex:circleindicator:2.1.6'
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
//PhotoView
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.core:core-ktx:1.7.0-rc01'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.4.0'
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0-rc01"
implementation "androidx.lifecycle:lifecycle-common-java8:2.4.0-rc01"
implementation "androidx.room:room-ktx:2.4.0-beta01"
kapt "androidx.room:room-compiler:2.4.0-beta01"

View File

@ -1,5 +1,7 @@
package apps.amine.bou.readerforselfoss.utils
package apps.amine.bou.readerforselfoss
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.parseDate
import org.junit.Test
class DateUtilsTest {

View File

@ -7,20 +7,23 @@ import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.closeSoftKeyboard
import androidx.test.espresso.action.ViewActions.pressBack
import androidx.test.espresso.action.ViewActions.pressKey
import androidx.test.espresso.action.ViewActions.typeText
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.DrawerActions
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.Intents.times
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.rule.ActivityTestRule
import androidx.test.runner.AndroidJUnit4
import android.view.KeyEvent
import androidx.test.espresso.matcher.RootMatchers.isDialog
import apps.amine.bou.readerforselfoss.utils.Config
import org.junit.After
import org.junit.Before
@ -81,14 +84,11 @@ class HomeActivityEspressoTest {
onView(withMenu(id = R.id.refresh, titleId = R.string.menu_home_refresh))
.perform(click())
onView(withText(android.R.string.ok))
.inRoot(isDialog()).check(matches(isDisplayed())).perform(click())
openActionBarOverflowOrOptionsMenu(context)
onView(withText(R.string.action_disconnect)).perform(click())
intended(hasComponent(LoginActivity::class.java.name))
intended(hasComponent(LoginActivity::class.java.name), times(1))
}
// TODO: test articles opening and actions for cards and lists

View File

@ -85,7 +85,7 @@ class LoginActivityEspressoTest {
onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.urlView)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled()))
}
// TODO: Add tests for multiple false urls with dialog
@ -101,19 +101,19 @@ class LoginActivityEspressoTest {
onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.loginView)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.passwordView)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.loginLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.loginView)).perform(click()).perform(
typeText(username),
closeSoftKeyboard()
)
onView(withId(R.id.passwordView)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.passwordView)).check(
onView(withId(R.id.passwordLayout)).check(
matches(
isHintOrErrorEnabled()
)
@ -141,9 +141,9 @@ class LoginActivityEspressoTest {
onView(withId(R.id.signInButton)).perform(click())
onView(withId(R.id.urlView)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.loginView)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.passwordView)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.loginLayout)).check(matches(isHintOrErrorEnabled()))
onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled()))
}
@Test
@ -167,7 +167,6 @@ class LoginActivityEspressoTest {
onView(withId(R.id.signInButton)).perform(click())
Thread.sleep(2000)
intended(hasComponent(HomeActivity::class.java.name))
}

View File

@ -1,6 +1,5 @@
package apps.amine.bou.readerforselfoss
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.preference.PreferenceManager
@ -11,7 +10,6 @@ import androidx.test.espresso.intent.Intents.times
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
import androidx.test.rule.ActivityTestRule
import androidx.test.runner.AndroidJUnit4
import apps.amine.bou.readerforselfoss.utils.Config
import org.junit.After
import org.junit.Before
@ -24,9 +22,6 @@ class MainActivityEspressoTest {
lateinit var intent: Intent
lateinit var preferencesEditor: SharedPreferences.Editor
private lateinit var url: String
private lateinit var username: String
private lateinit var password: String
@Rule @JvmField
val rule = ActivityTestRule(MainActivity::class.java, true, false)
@ -37,39 +32,31 @@ class MainActivityEspressoTest {
val context = getInstrumentation().targetContext
// create a SharedPreferences editor
preferencesEditor = context.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE).edit()
url = BuildConfig.LOGIN_URL
username = BuildConfig.LOGIN_USERNAME
password = BuildConfig.LOGIN_PASSWORD
preferencesEditor = PreferenceManager.getDefaultSharedPreferences(context).edit()
Intents.init()
}
@Test
fun checkFirstOpenLaunchesIntro() {
preferencesEditor.putString("url", "")
preferencesEditor.putString("password", "")
preferencesEditor.putString("login", "")
preferencesEditor.commit()
rule.launchActivity(intent)
intended(hasComponent(LoginActivity::class.java.name))
intended(hasComponent(HomeActivity::class.java.name), times(0))
}
@Test
fun checkNotFirstOpenLaunchesLogin() {
preferencesEditor.putString("url", url)
preferencesEditor.putString("password", password)
preferencesEditor.putString("login", username)
preferencesEditor.putBoolean("firstStart", true)
preferencesEditor.commit()
rule.launchActivity(intent)
intended(hasComponent(MainActivity::class.java.name))
intended(hasComponent(HomeActivity::class.java.name))
intended(hasComponent(LoginActivity::class.java.name), times(0))
}
@Test
fun checkNotFirstOpenLaunchesLogin() {
preferencesEditor.putBoolean("firstStart", false)
preferencesEditor.commit()
rule.launchActivity(intent)
intended(hasComponent(MainActivity::class.java.name))
intended(hasComponent(LoginActivity::class.java.name))
}
@After

View File

@ -1,8 +1,8 @@
package apps.amine.bou.readerforselfoss
import com.google.android.material.textfield.TextInputLayout
import androidx.test.espresso.matcher.ViewMatchers
import android.view.View
import android.widget.EditText
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.hamcrest.Matchers
@ -14,11 +14,11 @@ fun isHintOrErrorEnabled(): Matcher<View> =
}
override fun matchesSafely(item: View?): Boolean {
if (item !is EditText) {
if (item !is TextInputLayout) {
return false
}
return item.error.isNotEmpty()
return item.isHintEnabled || item.isErrorEnabled
}
}

View File

@ -52,19 +52,19 @@ class AddSourceActivity : AppCompatActivity() {
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
val drawable = binding.nameInput.background
drawable.setTint(appColors.colorAccent)
drawable.setColorFilter(appColors.colorAccent, PorterDuff.Mode.SRC_ATOP)
// TODO: clean
binding.nameInput.background = drawable
val drawable1 = binding.sourceUri.background
drawable1.setTint(appColors.colorAccent)
drawable1.setColorFilter(appColors.colorAccent, PorterDuff.Mode.SRC_ATOP)
binding.sourceUri.background = drawable1
val drawable2 = binding.tags.background
drawable2.setTint(appColors.colorAccent)
drawable2.setColorFilter(appColors.colorAccent, PorterDuff.Mode.SRC_ATOP)
binding.tags.background = drawable2

View File

@ -18,6 +18,7 @@ import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.core.view.MenuItemCompat
import androidx.core.view.doOnNextLayout
import androidx.drawerlayout.widget.DrawerLayout
import androidx.recyclerview.widget.*
@ -99,7 +100,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
private var displayAllCount = false
private var fullHeightCards: Boolean = false
private var itemsNumber: Int = 200
private var elementsShown: Int = 1
private var elementsShown: Int = 0
private var maybeTagFilter: Tag? = null
private var maybeSourceFilter: Source? = null
private var maybeSearchFilter: String? = null
private var userIdentifier: String = ""
private var displayAccountHeader: Boolean = false
private var infiniteScroll: Boolean = false
@ -216,7 +220,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
lastFetchDone = false
handleDrawerItems()
CoroutineScope(Dispatchers.Main).launch {
refreshFocusedItems(applicationContext, api, db, itemsNumber)
refreshFocusedItems(applicationContext, api, db)
getElementsAccordingToTab()
binding.swipeRefreshLayout.isRefreshing = false
}
@ -247,7 +251,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
): Boolean = false
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) {
val position = viewHolder.bindingAdapterPosition
val position = viewHolder.adapterPosition
val i = items.elementAtOrNull(position)
if (i != null) {
@ -559,9 +563,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
color = ColorHolder.fromColor(appColors.colorAccent) }
onDrawerItemClickListener = { _,_,_ ->
allItems = ArrayList()
maybeTagFilter = it
SharedItems.tagFilter = it.tag
SharedItems.sourceFilter = null
SharedItems.sourceIDFilter = null
getElementsAccordingToTab()
fetchOnEmptyList()
false
@ -612,9 +615,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
color = ColorHolder.fromColor(appColors.colorAccent) }
onDrawerItemClickListener = { _,_,_ ->
allItems = ArrayList()
maybeTagFilter = it
SharedItems.tagFilter = it.tag
SharedItems.sourceFilter = null
SharedItems.sourceIDFilter = null
getElementsAccordingToTab()
fetchOnEmptyList()
false
@ -648,9 +650,9 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
iconUrl = source.getIcon(this@HomeActivity)
onDrawerItemClickListener = { _,_,_ ->
allItems = ArrayList()
maybeSourceFilter = source
SharedItems.sourceIDFilter = source.id.toLong()
SharedItems.sourceFilter = source.title
SharedItems.tagFilter = null
getElementsAccordingToTab()
fetchOnEmptyList()
false
@ -671,10 +673,11 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
badgeRes = R.string.drawer_action_clear
onDrawerItemClickListener = { _,_,_ ->
allItems = ArrayList()
maybeSourceFilter = null
SharedItems.sourceFilter = null
SharedItems.sourceIDFilter = null
maybeTagFilter = null
SharedItems.tagFilter = null
binding.mainDrawer.setSelectionAtPosition(-1)
getElementsAccordingToTab()
fetchOnEmptyList()
false
@ -981,7 +984,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
CoroutineScope(Dispatchers.Main).launch {
if (appendResults || !SharedItems.fetchedUnread) {
binding.swipeRefreshLayout.isRefreshing = true
getUnreadItems(applicationContext, api, db, itemsNumber, offset)
getUnreadItems(applicationContext, api, db, offset)
binding.swipeRefreshLayout.isRefreshing = false
}
SharedItems.getUnRead()
@ -994,7 +997,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
CoroutineScope(Dispatchers.Main).launch {
if (appendResults || !SharedItems.fetchedAll) {
binding.swipeRefreshLayout.isRefreshing = true
getReadItems(applicationContext, api, db, itemsNumber, offset)
getReadItems(applicationContext, api, db, offset)
binding.swipeRefreshLayout.isRefreshing = false
}
SharedItems.getAll()
@ -1007,7 +1010,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
CoroutineScope(Dispatchers.Main).launch {
if (appendResults || !SharedItems.fetchedStarred) {
binding.swipeRefreshLayout.isRefreshing = true
getStarredItems(applicationContext, api, db, itemsNumber, offset)
getStarredItems(applicationContext, api, db, offset)
binding.swipeRefreshLayout.isRefreshing = false
}
SharedItems.getStarred()
@ -1119,6 +1122,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
override fun onQueryTextChange(p0: String?): Boolean {
if (p0.isNullOrBlank()) {
maybeSearchFilter = null
SharedItems.searchFilter = null
getElementsAccordingToTab()
fetchOnEmptyList()
@ -1127,18 +1131,29 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
}
override fun onQueryTextSubmit(p0: String?): Boolean {
maybeSearchFilter = p0
SharedItems.searchFilter = p0
getElementsAccordingToTab()
fetchOnEmptyList()
return false
}
override fun onActivityResult(req: Int, result: Int, data: Intent?) {
when (req) {
MENU_PREFERENCES -> {
//drawer.closeDrawer()
recreate()
}
else -> super.onActivityResult(req, result, data)
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.home_menu, menu)
val searchItem = menu.findItem(R.id.action_search)
val searchView = searchItem.getActionView() as SearchView
val searchView = MenuItemCompat.getActionView(searchItem) as SearchView
searchView.setOnQueryTextListener(this)
return true
@ -1253,7 +1268,8 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener {
.addTag("selfoss-loading")
.build()
WorkManager.getInstance(baseContext).enqueueUniquePeriodicWork("selfoss-loading", ExistingPeriodicWorkPolicy.KEEP, backgroundWork)
WorkManager.getInstance().enqueueUniquePeriodicWork("selfoss-loading", ExistingPeriodicWorkPolicy.KEEP, backgroundWork)
}
}

View File

@ -3,9 +3,8 @@ package apps.amine.bou.readerforselfoss
import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import apps.amine.bou.readerforselfoss.databinding.ActivityImageBinding
import apps.amine.bou.readerforselfoss.fragments.ImageFragment
@ -29,8 +28,8 @@ class ImageActivity : AppCompatActivity() {
allImages = intent.getStringArrayListExtra("allImages") as ArrayList<String>
position = intent.getIntExtra("position", 0)
binding.pager.adapter = ScreenSlidePagerAdapter(this)
binding.pager.setCurrentItem(position, false)
binding.pager.adapter = ScreenSlidePagerAdapter(supportFragmentManager)
binding.pager.currentItem = position
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
@ -44,10 +43,14 @@ class ImageActivity : AppCompatActivity() {
return super.onOptionsItemSelected(item)
}
private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
private inner class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm, FragmentStatePagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
override fun getItemCount(): Int = allImages.size
override fun getCount(): Int {
return allImages.size
}
override fun createFragment(position: Int): Fragment = ImageFragment.newInstance(allImages[position])
override fun getItem(position: Int): ImageFragment {
return ImageFragment.newInstance(allImages[position])
}
}
}

View File

@ -14,11 +14,11 @@ import android.view.MenuItem
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.TextView
import androidx.preference.PreferenceManager
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.api.selfoss.SuccessResponse
import apps.amine.bou.readerforselfoss.databinding.ActivityLoginBinding
import apps.amine.bou.readerforselfoss.themes.AppColors
import apps.amine.bou.readerforselfoss.utils.Config
import apps.amine.bou.readerforselfoss.utils.isBaseUrlValid
import apps.amine.bou.readerforselfoss.utils.network.isNetworkAccessible
import com.mikepenz.aboutlibraries.LibsBuilder
@ -52,7 +52,7 @@ class LoginActivity : AppCompatActivity() {
handleBaseUrlFail()
settings = PreferenceManager.getDefaultSharedPreferences(applicationContext)
settings = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE)
userIdentifier = settings.getString("unique_id", "")!!
editor = settings.edit()

View File

@ -61,14 +61,14 @@ class MyApp : MultiDexApplication() {
private fun initDrawerImageLoader() {
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) {
Glide.with(imageView.context)
Glide.with(imageView?.context)
.loadMaybeBasicAuth(config, uri.toString())
.apply(RequestOptions.fitCenterTransform().placeholder(placeholder))
.into(imageView)
}
override fun cancel(imageView: ImageView) {
Glide.with(imageView.context).clear(imageView)
Glide.with(imageView?.context).clear(imageView)
}
override fun placeholder(ctx: Context, tag: String?): Drawable {

View File

@ -3,17 +3,21 @@ package apps.amine.bou.readerforselfoss
import android.content.Context
import android.content.SharedPreferences
import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Bundle
import android.view.KeyEvent
import androidx.preference.PreferenceManager
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.core.content.ContextCompat
import androidx.viewpager.widget.ViewPager
import androidx.appcompat.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import android.view.ViewGroup
import androidx.room.Room
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import apps.amine.bou.readerforselfoss.api.selfoss.Item
import apps.amine.bou.readerforselfoss.api.selfoss.SelfossApi
import apps.amine.bou.readerforselfoss.databinding.ActivityReaderBinding
@ -24,17 +28,18 @@ import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_2_3
import apps.amine.bou.readerforselfoss.persistence.migrations.MIGRATION_3_4
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.SharedItems
import apps.amine.bou.readerforselfoss.utils.toggleStar
import com.ftinc.scoop.Scoop
import me.relex.circleindicator.CircleIndicator
class ReaderActivity : AppCompatActivity() {
private var markOnScroll: Boolean = false
private var currentItem: Int = 0
private lateinit var userIdentifier: String
private lateinit var appColors: AppColors
private lateinit var api: SelfossApi
@ -45,14 +50,14 @@ class ReaderActivity : AppCompatActivity() {
private lateinit var binding: ActivityReaderBinding
private var activeAlignment: Int = 1
private val JUSTIFY = 1
private val ALIGN_LEFT = 2
val JUSTIFY = 1
val ALIGN_LEFT = 2
private fun showMenuItem(willAddToFavorite: Boolean) {
if (willAddToFavorite) {
toolbarMenu.findItem(R.id.star).icon.setTint(Color.WHITE)
toolbarMenu.findItem(R.id.star).icon.colorFilter = PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP)
} else {
toolbarMenu.findItem(R.id.star).icon.setTint(Color.RED)
toolbarMenu.findItem(R.id.star).icon.colorFilter = PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_ATOP)
}
}
@ -68,7 +73,6 @@ class ReaderActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
appColors = AppColors(this)
binding = ActivityReaderBinding.inflate(layoutInflater)
val view = binding.root
@ -112,14 +116,33 @@ class ReaderActivity : AppCompatActivity() {
readItem(allItems[currentItem])
binding.pager.adapter = ScreenSlidePagerAdapter(this)
binding.pager.setCurrentItem(currentItem, false)
binding.pager.adapter =
ScreenSlidePagerAdapter(supportFragmentManager, AppColors(this@ReaderActivity))
binding.pager.currentItem = currentItem
}
override fun onResume() {
super.onResume()
binding.indicator.setViewPager(binding.pager)
notifyAdapter()
binding.pager.setPageTransformer(true, DepthPageTransformer())
(binding.indicator as CircleIndicator).setViewPager(binding.pager)
binding.pager.addOnPageChangeListener(
object : ViewPager.SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
if (allItems[position].starred) {
canRemoveFromFavorite()
} else {
canFavorite()
}
readItem(allItems[position])
}
}
)
}
private fun readItem(item: Item) {
@ -128,39 +151,46 @@ class ReaderActivity : AppCompatActivity() {
}
}
private fun notifyAdapter() {
(binding.pager.adapter as ScreenSlidePagerAdapter).notifyDataSetChanged()
}
override fun onPause() {
super.onPause()
if (markOnScroll) {
binding.pager.clearOnPageChangeListeners()
}
}
override fun onSaveInstanceState(oldInstanceState: Bundle) {
super.onSaveInstanceState(oldInstanceState)
oldInstanceState.clear()
}
private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) :
FragmentStateAdapter(fa) {
private inner class ScreenSlidePagerAdapter(fm: FragmentManager, val appColors: AppColors) :
FragmentStatePagerAdapter(fm) {
override fun getItemCount(): Int = allItems.size
override fun getCount(): Int {
return allItems.size
}
override fun createFragment(position: Int): Fragment = ArticleFragment.newInstance(allItems[position])
override fun getItem(position: Int): ArticleFragment {
return ArticleFragment.newInstance(position, allItems)
}
}
override fun startUpdate(container: ViewGroup) {
super.startUpdate(container)
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
return when (keyCode) {
KeyEvent.KEYCODE_VOLUME_DOWN -> {
val currentFragment = supportFragmentManager.findFragmentByTag("f" + binding.pager.currentItem) as ArticleFragment
currentFragment.scrollDown()
true
}
KeyEvent.KEYCODE_VOLUME_UP -> {
val currentFragment = supportFragmentManager.findFragmentByTag("f" + binding.pager.currentItem) as ArticleFragment
currentFragment.scrollUp()
true
}
else -> {
super.onKeyDown(keyCode, event)
}
container.background = ColorDrawable(
ContextCompat.getColor(
this@ReaderActivity,
appColors.colorBackground
)
)
}
}
private fun alignmentMenu(showJustify: Boolean) {
fun alignmentMenu(showJustify: Boolean) {
toolbarMenu.findItem(R.id.align_left).isVisible = !showJustify
toolbarMenu.findItem(R.id.align_justify).isVisible = showJustify
}
@ -170,7 +200,7 @@ class ReaderActivity : AppCompatActivity() {
inflater.inflate(R.menu.reader_menu, menu)
toolbarMenu = menu
if (allItems.isNotEmpty() && allItems[currentItem].starred) {
if (!allItems.isEmpty() && allItems[currentItem].starred) {
canRemoveFromFavorite()
} else {
canFavorite()
@ -181,22 +211,6 @@ class ReaderActivity : AppCompatActivity() {
alignmentMenu(true)
}
binding.pager.registerOnPageChangeCallback(
object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if (allItems[position].starred) {
canRemoveFromFavorite()
} else {
canFavorite()
}
readItem(allItems[position])
}
}
)
return true
}
@ -204,11 +218,13 @@ class ReaderActivity : AppCompatActivity() {
fun afterSave() {
allItems[binding.pager.currentItem] =
allItems[binding.pager.currentItem].toggleStar()
notifyAdapter()
canRemoveFromFavorite()
}
fun afterUnsave() {
allItems[binding.pager.currentItem] = allItems[binding.pager.currentItem].toggleStar()
notifyAdapter()
canFavorite()
}

View File

@ -28,14 +28,14 @@ class SourcesActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
appColors = AppColors(this@SourcesActivity)
binding = ActivitySourcesBinding.inflate(layoutInflater)
val view = binding.root
val scoop = Scoop.getInstance()
scoop.bind(this, Toppings.PRIMARY.value, binding.toolbar)
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
super.onCreate(savedInstanceState)
binding = ActivitySourcesBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)

View File

@ -39,13 +39,13 @@ suspend fun updateItems(context: Context, api: SelfossApi, db: AppDatabase) = co
}
}
suspend fun refreshFocusedItems(context: Context, api: SelfossApi, db: AppDatabase, itemsNumber: Int) = withContext(Dispatchers.IO) {
suspend fun refreshFocusedItems(context: Context, api: SelfossApi, db: AppDatabase) = withContext(Dispatchers.IO) {
if (isNetworkAvailable(context)) {
val response = when (SharedItems.displayedItems) {
"read" -> api.readItems(itemsNumber, 0)
"unread" -> api.newItems(itemsNumber, 0)
"starred" -> api.starredItems(itemsNumber, 0)
else -> api.readItems(itemsNumber, 0)
"read" -> api.readItems(200, 0)
"unread" -> api.newItems(200, 0)
"starred" -> api.starredItems(200, 0)
else -> api.readItems(200, 0)
}
if (response.isSuccessful) {
@ -55,33 +55,33 @@ suspend fun refreshFocusedItems(context: Context, api: SelfossApi, db: AppDataba
}
}
suspend fun getReadItems(context: Context, api: SelfossApi, db: AppDatabase, itemsNumber: Int, offset: Int) = withContext(Dispatchers.IO) {
suspend fun getReadItems(context: Context, api: SelfossApi, db: AppDatabase, offset: Int) = withContext(Dispatchers.IO) {
if (isNetworkAvailable(context)) {
try {
enqueueArticles(api.readItems( itemsNumber, offset), db, false)
enqueueArticles(api.readItems( 200, offset), db, false)
SharedItems.fetchedAll = true
SharedItems.updateDatabase(db)
} catch (e: Throwable) {}
}
}
suspend fun getUnreadItems(context: Context, api: SelfossApi, db: AppDatabase, itemsNumber: Int, offset: Int) = withContext(Dispatchers.IO) {
suspend fun getUnreadItems(context: Context, api: SelfossApi, db: AppDatabase, offset: Int) = withContext(Dispatchers.IO) {
if (isNetworkAvailable(context)) {
try {
if (!SharedItems.fetchedUnread) {
SharedItems.clearDBItems(db)
}
enqueueArticles(api.newItems(itemsNumber, offset), db, false)
enqueueArticles(api.newItems(200, offset), db, false)
SharedItems.fetchedUnread = true
} catch (e: Throwable) {}
}
SharedItems.updateDatabase(db)
}
suspend fun getStarredItems(context: Context, api: SelfossApi, db: AppDatabase, itemsNumber: Int, offset: Int) = withContext(Dispatchers.IO) {
suspend fun getStarredItems(context: Context, api: SelfossApi, db: AppDatabase, offset: Int) = withContext(Dispatchers.IO) {
if (isNetworkAvailable(context)) {
try {
enqueueArticles(api.starredItems(itemsNumber, offset), db, false)
enqueueArticles(api.starredItems(200, offset), db, false)
SharedItems.fetchedStarred = true
SharedItems.updateDatabase(db)
} catch (e: Throwable) {

View File

@ -14,8 +14,6 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.RequestOptions
import com.google.gson.annotations.SerializedName
import java.util.*
import kotlin.collections.ArrayList
private fun constructUrl(config: Config?, path: String, file: String?): String {
return if (file.isEmptyOrNullOrNullString()) {
@ -157,14 +155,14 @@ data class Item(
}
fun getImages() : ArrayList<String> {
val allImages = ArrayList<String>()
var allImages = ArrayList<String>()
for ( image in Jsoup.parse(content).getElementsByTag("img")) {
val url = image.attr("src")
if (url.lowercase(Locale.US).contains(".jpg") ||
url.lowercase(Locale.US).contains(".jpeg") ||
url.lowercase(Locale.US).contains(".png") ||
url.lowercase(Locale.US).contains(".webp"))
if (url.toLowerCase().contains(".jpg") ||
url.toLowerCase().contains(".jpeg") ||
url.toLowerCase().contains(".png") ||
url.toLowerCase().contains(".webp"))
{
allImages.add(url)
}

View File

@ -14,11 +14,12 @@ import androidx.preference.PreferenceManager
import android.view.*
import android.webkit.*
import android.widget.Toast
import androidx.browser.customtabs.CustomTabsIntent
import com.google.android.material.floatingactionbutton.FloatingActionButton
import androidx.fragment.app.Fragment
import androidx.core.content.ContextCompat
import androidx.core.widget.NestedScrollView
import androidx.appcompat.app.AlertDialog
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.res.ResourcesCompat
import androidx.room.Room
import apps.amine.bou.readerforselfoss.ImageActivity
@ -47,14 +48,14 @@ import retrofit2.Callback
import retrofit2.Response
import java.net.MalformedURLException
import java.net.URL
import java.util.*
import java.util.concurrent.ExecutionException
import kotlin.collections.ArrayList
class ArticleFragment : Fragment() {
private lateinit var pageNumber: Number
private var fontSize: Int = 16
private lateinit var item: Item
private var mCustomTabActivityHelper: CustomTabActivityHelper? = null
private lateinit var allItems: ArrayList<Item>
private var mCustomTabActivityHelper: CustomTabActivityHelper? = null;
private lateinit var url: String
private lateinit var contentText: String
private lateinit var contentSource: String
@ -90,7 +91,8 @@ class ArticleFragment : Fragment() {
super.onCreate(savedInstanceState)
item = requireArguments().getParcelable(ARG_ITEMS)!!
pageNumber = requireArguments().getInt(ARG_POSITION)
allItems = requireArguments().getParcelableArrayList<Item>(ARG_ITEMS) as ArrayList<Item>
db = Room.databaseBuilder(
requireContext(),
@ -102,16 +104,16 @@ class ArticleFragment : Fragment() {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
): View? {
try {
_binding = FragmentArticleBinding.inflate(inflater, container, false)
url = item.getLinkDecoded()
contentText = item.content
contentTitle = item.getTitleDecoded()
contentImage = item.getThumbnail(requireActivity())
contentSource = item.sourceAndDateText()
allImages = item.getImages()
url = allItems[pageNumber.toInt()].getLinkDecoded()
contentText = allItems[pageNumber.toInt()].content
contentTitle = allItems[pageNumber.toInt()].getTitleDecoded()
contentImage = allItems[pageNumber.toInt()].getThumbnail(requireActivity())
contentSource = allItems[pageNumber.toInt()].sourceAndDateText()
allImages = allItems[pageNumber.toInt()].getImages()
prefs = PreferenceManager.getDefaultSharedPreferences(activity)
editor = prefs.edit()
@ -161,18 +163,26 @@ class ArticleFragment : Fragment() {
object : FloatingToolbar.ItemClickListener {
override fun onItemClick(item: MenuItem) {
when (item.itemId) {
R.id.more_action -> getContentFromMercury(customTabsIntent)
R.id.more_action -> getContentFromMercury(customTabsIntent, prefs)
R.id.share_action -> requireActivity().shareLink(url, contentTitle)
R.id.open_action -> requireActivity().openInBrowserAsNewTask(this@ArticleFragment.item)
R.id.open_action -> requireActivity().openItemUrl(
allItems,
pageNumber.toInt(),
url,
customTabsIntent,
false,
false,
requireActivity()
)
R.id.unread_action -> if (context != null) {
if (this@ArticleFragment.item.unread) {
if (allItems[pageNumber.toInt()].unread) {
SharedItems.readItem(
context!!,
api,
db,
this@ArticleFragment.item
allItems[pageNumber.toInt()]
)
this@ArticleFragment.item.unread = false
allItems[pageNumber.toInt()].unread = false
Toast.makeText(
context,
R.string.marked_as_read,
@ -183,9 +193,9 @@ class ArticleFragment : Fragment() {
context!!,
api,
db,
this@ArticleFragment.item
allItems[pageNumber.toInt()]
)
this@ArticleFragment.item.unread = true
allItems[pageNumber.toInt()].unread = true
Toast.makeText(
context,
R.string.marked_as_unread,
@ -213,7 +223,7 @@ class ArticleFragment : Fragment() {
}
if (contentText.isEmptyOrNullOrNullString()) {
getContentFromMercury(customTabsIntent)
getContentFromMercury(customTabsIntent, prefs)
} else {
binding.titleView.text = contentTitle
if (typeface != null) {
@ -255,11 +265,11 @@ class ArticleFragment : Fragment() {
.setMessage(requireContext().getString(R.string.webview_dialog_issue_message))
.setTitle(requireContext().getString(R.string.webview_dialog_issue_title))
.setPositiveButton(android.R.string.ok
) { _, _ ->
) { dialog, which ->
val sharedPref = PreferenceManager.getDefaultSharedPreferences(requireContext())
val editor = sharedPref.edit()
editor.putBoolean("prefer_article_viewer", false)
editor.apply()
editor.commit()
requireActivity().finish()
}
.create()
@ -282,7 +292,10 @@ class ArticleFragment : Fragment() {
}
}
private fun getContentFromMercury(customTabsIntent: CustomTabsIntent) {
private fun getContentFromMercury(
customTabsIntent: CustomTabsIntent,
prefs: SharedPreferences
) {
if ((context != null && requireContext().isNetworkAccessible(null)) || context == null) {
binding.progressBar.visibility = View.VISIBLE
val parser = MercuryApi()
@ -377,12 +390,30 @@ class ArticleFragment : Fragment() {
binding.webcontent.settings.standardFontFamily = a.getString(0)
binding.webcontent.visibility = View.VISIBLE
// TODO: Set the color strings programmatically
val (stringTextColor, stringBackgroundColor) = if (appColors.isDarkTheme) {
Pair("#FFFFFF", "#303030")
val (textColor, backgroundColor) = if (appColors.isDarkTheme) {
if (context != null) {
Pair(ContextCompat.getColor(requireContext(), R.color.dark_webview_text), ContextCompat.getColor(requireContext(), R.color.dark_webview))
} else {
Pair(null, null)
}
} else {
Pair("#212121", "#FAFAFA")
if (context != null) {
Pair(ContextCompat.getColor(requireContext(), R.color.light_webview_text), ContextCompat.getColor(requireContext(), R.color.light_webview))
} else {
Pair(null, null)
}
}
val stringTextColor: String = if (textColor != null) {
String.format("#%06X", 0xFFFFFF and textColor)
} else {
"#000000"
}
val stringBackgroundColor = if (backgroundColor != null) {
String.format("#%06X", 0xFFFFFF and backgroundColor)
} else {
"#FFFFFF"
}
binding.webcontent.settings.useWideViewPort = true
@ -399,19 +430,19 @@ class ArticleFragment : Fragment() {
override fun shouldInterceptRequest(view: WebView?, url: String): WebResourceResponse? {
val glideOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL)
if (url.lowercase(Locale.US).contains(".jpg") || url.lowercase(Locale.US).contains(".jpeg")) {
if (url.toLowerCase().contains(".jpg") || url.toLowerCase().contains(".jpeg")) {
try {
val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.JPEG))
}catch ( e : ExecutionException) {}
}
else if (url.lowercase(Locale.US).contains(".png")) {
else if (url.toLowerCase().contains(".png")) {
try {
val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.PNG))
}catch ( e : ExecutionException) {}
}
else if (url.lowercase(Locale.US).contains(".webp")) {
else if (url.toLowerCase().contains(".webp")) {
try {
val image = Glide.with(view).asBitmap().apply(glideOptions).load(url).submit().get()
return WebResourceResponse("image/jpg", "UTF-8", getBitmapInputStream(image, Bitmap.CompressFormat.WEBP))
@ -511,34 +542,31 @@ class ArticleFragment : Fragment() {
)
}
fun scrollDown() {
val height = binding.nestedScrollView.measuredHeight
binding.nestedScrollView.smoothScrollBy(0, height/2)
}
fun scrollUp() {
val height = binding.nestedScrollView.measuredHeight
binding.nestedScrollView.smoothScrollBy(0, -height/2)
}
private fun openInBrowserAfterFailing(customTabsIntent: CustomTabsIntent) {
binding.progressBar.visibility = View.GONE
requireActivity().openItemUrlInternalBrowser(
url,
customTabsIntent,
requireActivity()
requireActivity().openItemUrl(
allItems,
pageNumber.toInt(),
url,
customTabsIntent,
true,
false,
requireActivity()
)
}
companion object {
private const val ARG_POSITION = "position"
private const val ARG_ITEMS = "items"
fun newInstance(
item: Item
position: Int,
allItems: ArrayList<Item>
): ArticleFragment {
val fragment = ArticleFragment()
val args = Bundle()
args.putParcelable(ARG_ITEMS, item)
args.putInt(ARG_POSITION, position)
args.putParcelableArrayList(ARG_ITEMS, allItems)
fragment.arguments = args
return fragment
}

View File

@ -49,7 +49,7 @@ class AppColors(a: Activity) {
R.color.darkBackground
} else {
a.setTheme(R.style.NoBar)
R.color.grey_50
android.R.color.background_light
}
textColor = if (isDarkTheme) {

View File

@ -0,0 +1,43 @@
package apps.amine.bou.readerforselfoss.transformers
import androidx.viewpager.widget.ViewPager
import android.view.View
class DepthPageTransformer : ViewPager.PageTransformer {
override fun transformPage(view: View, position: Float) {
val pageWidth = view.width
when {
position < -1 -> // [-Infinity,-1)
// This page is way off-screen to the left.
view.alpha = 0F
position <= 0 -> { // [-1,0]
// Use the default slide transition when moving to the left page
view.alpha = 1F
view.translationX = 0F
view.scaleX = 1F
view.scaleY = 1F
}
position <= 1 -> { // (0,1]
// Fade the page out.
view.alpha = 1 - position
// Counteract the default slide transition
view.translationX = pageWidth * -position
// Scale the page down (between MIN_SCALE and 1)
val scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position))
view.scaleX = scaleFactor
view.scaleY = scaleFactor
}
else -> // (1,+Infinity]
// This page is way off-screen to the right.
view.alpha = 0F
}
}
companion object {
private val MIN_SCALE = 0.75f
}
}

View File

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

View File

@ -4,12 +4,11 @@ import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import androidx.preference.PreferenceManager
import apps.amine.bou.readerforselfoss.LoginActivity
class Config(c: Context) {
val settings: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(c)
val settings: SharedPreferences = c.getSharedPreferences(settingsName, Context.MODE_PRIVATE)
val baseUrl: String
get() = settings.getString("url", "")!!
@ -43,15 +42,17 @@ class Config(c: Context) {
var apiVersion = 0
/* Execute logout and clear all settings to default */
fun logoutAndRedirect(
c: Context,
callingActivity: Activity,
editor: SharedPreferences.Editor,
baseUrlFail: Boolean = false
): Boolean {
val settings = PreferenceManager.getDefaultSharedPreferences(c)
settings.edit().clear().commit()
editor.remove("url")
editor.remove("login")
editor.remove("password")
editor.remove("apiVersionMajor")
editor.apply()
val intent = Intent(c, LoginActivity::class.java)
if (baseUrlFail) {
intent.putExtra("baseUrlFail", baseUrlFail)

View File

@ -86,30 +86,19 @@ fun Context.openItemUrlInternally(
intent.putExtra("currentItem", currentItem)
app.startActivity(intent)
} else {
this.openItemUrlInternalBrowser(
linkDecoded,
customTabsIntent,
app)
}
}
fun Context.openItemUrlInternalBrowser(
linkDecoded: String,
customTabsIntent: CustomTabsIntent,
app: Activity
) {
try {
CustomTabActivityHelper.openCustomTab(
try {
CustomTabActivityHelper.openCustomTab(
app,
customTabsIntent,
Uri.parse(linkDecoded)
) { _, uri ->
val intent = Intent(Intent.ACTION_VIEW, uri)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
) { _, uri ->
val intent = Intent(Intent.ACTION_VIEW, uri)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
} catch (e: Exception) {
openInBrowser(linkDecoded, app)
}
} catch (e: Exception) {
openInBrowser(linkDecoded, app)
}
}
@ -132,7 +121,7 @@ fun Context.openItemUrl(
} else {
if (!internalBrowser) {
openInBrowser(linkDecoded, app)
} else if (articleViewer) {
} else {
this.openItemUrlInternally(
allItems,
currentItem,
@ -141,12 +130,6 @@ fun Context.openItemUrl(
articleViewer,
app
)
} else {
this.openItemUrlInternalBrowser(
linkDecoded,
customTabsIntent,
app
)
}
}
}

View File

@ -21,7 +21,7 @@
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
<androidx.viewpager.widget.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"

View File

@ -22,7 +22,7 @@
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
<androidx.viewpager.widget.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
@ -33,7 +33,7 @@
app:layout_constraintTop_toBottomOf="@+id/appBarLayout" />
<me.relex.circleindicator.CircleIndicator3
<me.relex.circleindicator.CircleIndicator
android:id="@+id/indicator"
android:layout_width="match_parent"
android:layout_height="20dp"

View File

@ -4,7 +4,6 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:colorBackground"
android:descendantFocusability="blocksDescendants">
<androidx.core.widget.NestedScrollView

View File

@ -5,7 +5,7 @@
<color name="colorAccent">#FFff5722</color>
<color name="colorAccentDark">#FFbf360c</color>
<color name="pink">#FFe91e63</color>
<color name="white">#FFFFFF</color>
<color name="white">#FFFFFFFF</color>
<color name="black">#FF000000</color>
<color name="red">#FF0000</color>
<color name="refresh_progress_1">@color/colorAccentDark</color>
@ -20,5 +20,5 @@
<color name="cardBackgroundColor">#FFFFFFFF</color>
<color name="materialDrawerHeaderSelectionText">#212121</color>
<color name="darkBackground">#303030</color>
<color name="darkBackground">#FF303030</color>
</resources>

View File

@ -28,7 +28,6 @@
<item name="cardBackgroundColor">@color/grey_800</item>
<item name="android:colorBackground">@color/darkBackground</item>
<item name="colorSurface">@color/darkBackground</item>
<item name="alertDialogTheme">@style/AlertDialogDark</item>
<item name="bnbBackgroundColor">@color/grey_900</item>
<item name="android:textColorPrimary">@color/white</item>
<item name="android:textColorSecondary">@color/grey_600</item>
@ -64,10 +63,4 @@
<item name="android:textColor">?android:textColorPrimary</item>
</style>
<!-- Alert dialog Theme -->
<style name="AlertDialogDark" parent="Theme.MaterialComponents.Dialog">
<item name="android:background">@color/darkBackground</item>
</style>
</resources>

View File

@ -2,7 +2,7 @@
buildscript {
ext {
kotlin_version = '1.6.10'
kotlin_version = '1.5.31'
android_version = '1.0.0'
androidx_version = '1.1.0-alpha05'
lifecycle_version = '2.2.0-alpha01'
@ -15,7 +15,7 @@ buildscript {
maven { url "https://www.jitpack.io" }
}
dependencies {
classpath 'com.android.tools.build:gradle:7.0.4'
classpath 'com.android.tools.build:gradle:7.0.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@ -23,9 +23,9 @@ buildscript {
allprojects {
repositories {
google()
mavenCentral()
jcenter()
maven { url "https://www.jitpack.io" }
mavenCentral()
}
}