Compare commits
	
		
			9 Commits
		
	
	
		
			v172201007
			...
			da0696cac0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | da0696cac0 | ||
| 288970483b | |||
| 5b540dbc38 | |||
| def75b6431 | |||
| 4826ed0355 | |||
| 3b47a4a2f0 | |||
| 9693dec807 | |||
| ca5186d20a | |||
| 78d5744139 | 
| @@ -44,8 +44,12 @@ | ||||
|  | ||||
| - 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. | ||||
|   | ||||
							
								
								
									
										48
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,47 +1 @@ | ||||
| # ReaderForSelfoss **(Only available from F-Droid)** | ||||
|  | ||||
| [](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) | ||||
| # Project moved to https://github.com/aminecmi/ReaderforSelfoss-multiplatform | ||||
|   | ||||
| @@ -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.0-beta01" | ||||
|     implementation 'com.google.android.material:material:1.5.0-alpha04' | ||||
|     implementation 'androidx.appcompat:appcompat:1.4.1' | ||||
|     implementation 'com.google.android.material:material:1.5.0' | ||||
|     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.3.0" | ||||
|     implementation 'androidx.browser:browser:1.4.0' | ||||
|     implementation "androidx.cardview:cardview:$android_version" | ||||
|     implementation "androidx.annotation:annotation:1.2.0" | ||||
|     implementation 'androidx.work:work-runtime-ktx:2.7.0' | ||||
|     implementation 'androidx.constraintlayout:constraintlayout:2.1.1' | ||||
|     implementation 'androidx.annotation:annotation:1.3.0' | ||||
|     implementation 'androidx.work:work-runtime-ktx:2.7.1' | ||||
|     implementation 'androidx.constraintlayout:constraintlayout:2.1.3' | ||||
|     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.5.2' | ||||
|     implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0' | ||||
|  | ||||
|     // Retrofit + http logging + okhttp | ||||
|     implementation 'com.squareup.retrofit2:retrofit:2.9.0' | ||||
|     implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1' | ||||
|     implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.3' | ||||
|     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.4' | ||||
|     implementation 'com.mikepenz:materialdrawer:8.4.5' | ||||
|  | ||||
|     // Themes | ||||
|     implementation 'com.52inc:scoops:1.0.0' | ||||
| @@ -160,10 +160,10 @@ dependencies { | ||||
|     //PhotoView | ||||
|     implementation 'com.github.chrisbanes:PhotoView:2.3.0' | ||||
|  | ||||
|     implementation 'androidx.core:core-ktx:1.7.0-rc01' | ||||
|     implementation 'androidx.core:core-ktx:1.7.0' | ||||
|  | ||||
|     implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.4.0-rc01" | ||||
|     implementation "androidx.lifecycle:lifecycle-common-java8:2.4.0-rc01" | ||||
|     implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.0' | ||||
|     implementation 'androidx.lifecycle:lifecycle-common-java8:2.4.0' | ||||
|  | ||||
|     implementation "androidx.room:room-ktx:2.4.0-beta01" | ||||
|     kapt "androidx.room:room-compiler:2.4.0-beta01" | ||||
|   | ||||
| @@ -7,23 +7,20 @@ 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 | ||||
| @@ -84,11 +81,14 @@ 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), times(1)) | ||||
|         intended(hasComponent(LoginActivity::class.java.name)) | ||||
|     } | ||||
|  | ||||
|     // TODO: test articles opening and actions for cards and lists | ||||
|   | ||||
| @@ -85,7 +85,7 @@ class LoginActivityEspressoTest { | ||||
|  | ||||
|         onView(withId(R.id.signInButton)).perform(click()) | ||||
|  | ||||
|         onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled())) | ||||
|         onView(withId(R.id.urlView)).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.loginLayout)).check(matches(isHintOrErrorEnabled())) | ||||
|         onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled())) | ||||
|         onView(withId(R.id.loginView)).check(matches(isHintOrErrorEnabled())) | ||||
|         onView(withId(R.id.passwordView)).check(matches(isHintOrErrorEnabled())) | ||||
|  | ||||
|         onView(withId(R.id.loginView)).perform(click()).perform( | ||||
|                 typeText(username), | ||||
|                 closeSoftKeyboard() | ||||
|         ) | ||||
|  | ||||
|         onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled())) | ||||
|         onView(withId(R.id.passwordView)).check(matches(isHintOrErrorEnabled())) | ||||
|  | ||||
|         onView(withId(R.id.signInButton)).perform(click()) | ||||
|  | ||||
|         onView(withId(R.id.passwordLayout)).check( | ||||
|         onView(withId(R.id.passwordView)).check( | ||||
|                 matches( | ||||
|                         isHintOrErrorEnabled() | ||||
|                 ) | ||||
| @@ -141,9 +141,9 @@ class LoginActivityEspressoTest { | ||||
|  | ||||
|         onView(withId(R.id.signInButton)).perform(click()) | ||||
|  | ||||
|         onView(withId(R.id.urlLayout)).check(matches(isHintOrErrorEnabled())) | ||||
|         onView(withId(R.id.loginLayout)).check(matches(isHintOrErrorEnabled())) | ||||
|         onView(withId(R.id.passwordLayout)).check(matches(isHintOrErrorEnabled())) | ||||
|         onView(withId(R.id.urlView)).check(matches(isHintOrErrorEnabled())) | ||||
|         onView(withId(R.id.loginView)).check(matches(isHintOrErrorEnabled())) | ||||
|         onView(withId(R.id.passwordView)).check(matches(isHintOrErrorEnabled())) | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
| @@ -167,6 +167,7 @@ class LoginActivityEspressoTest { | ||||
|  | ||||
|         onView(withId(R.id.signInButton)).perform(click()) | ||||
|  | ||||
|         Thread.sleep(2000) | ||||
|         intended(hasComponent(HomeActivity::class.java.name)) | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| package apps.amine.bou.readerforselfoss | ||||
|  | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.content.SharedPreferences | ||||
| import android.preference.PreferenceManager | ||||
| @@ -10,6 +11,7 @@ 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 | ||||
| @@ -22,6 +24,9 @@ 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) | ||||
| @@ -32,31 +37,39 @@ class MainActivityEspressoTest { | ||||
|         val context = getInstrumentation().targetContext | ||||
|  | ||||
|         // create a SharedPreferences editor | ||||
|         preferencesEditor = PreferenceManager.getDefaultSharedPreferences(context).edit() | ||||
|         preferencesEditor = context.getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE).edit() | ||||
|  | ||||
|         url = BuildConfig.LOGIN_URL | ||||
|         username = BuildConfig.LOGIN_USERNAME | ||||
|         password = BuildConfig.LOGIN_PASSWORD | ||||
|  | ||||
|         Intents.init() | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     fun checkFirstOpenLaunchesIntro() { | ||||
|         preferencesEditor.putBoolean("firstStart", true) | ||||
|         preferencesEditor.putString("url", "") | ||||
|         preferencesEditor.putString("password", "") | ||||
|         preferencesEditor.putString("login", "") | ||||
|         preferencesEditor.commit() | ||||
|  | ||||
|         rule.launchActivity(intent) | ||||
|  | ||||
|         intended(hasComponent(MainActivity::class.java.name)) | ||||
|         intended(hasComponent(LoginActivity::class.java.name), times(0)) | ||||
|         intended(hasComponent(LoginActivity::class.java.name)) | ||||
|         intended(hasComponent(HomeActivity::class.java.name), times(0)) | ||||
|     } | ||||
|  | ||||
|     @Test | ||||
|     fun checkNotFirstOpenLaunchesLogin() { | ||||
|         preferencesEditor.putBoolean("firstStart", false) | ||||
|         preferencesEditor.putString("url", url) | ||||
|         preferencesEditor.putString("password", password) | ||||
|         preferencesEditor.putString("login", username) | ||||
|         preferencesEditor.commit() | ||||
|  | ||||
|         rule.launchActivity(intent) | ||||
|  | ||||
|         intended(hasComponent(MainActivity::class.java.name)) | ||||
|         intended(hasComponent(LoginActivity::class.java.name)) | ||||
|         intended(hasComponent(HomeActivity::class.java.name)) | ||||
|     } | ||||
|  | ||||
|     @After | ||||
|   | ||||
| @@ -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 TextInputLayout) { | ||||
|                 if (item !is EditText) { | ||||
|                     return false | ||||
|                 } | ||||
|  | ||||
|                 return item.isHintEnabled || item.isErrorEnabled | ||||
|                 return item.error.isNotEmpty() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| package apps.amine.bou.readerforselfoss | ||||
| package apps.amine.bou.readerforselfoss.utils | ||||
| 
 | ||||
| import apps.amine.bou.readerforselfoss.utils.Config | ||||
| import apps.amine.bou.readerforselfoss.utils.parseDate | ||||
| import org.junit.Test | ||||
| 
 | ||||
| class DateUtilsTest { | ||||
| @@ -18,7 +18,6 @@ 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.* | ||||
| @@ -100,10 +99,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { | ||||
|     private var displayAllCount = false | ||||
|     private var fullHeightCards: Boolean = false | ||||
|     private var itemsNumber: Int = 200 | ||||
|     private var elementsShown: Int = 0 | ||||
|     private var maybeTagFilter: Tag? = null | ||||
|     private var maybeSourceFilter: Source? = null | ||||
|     private var maybeSearchFilter: String? = null | ||||
|     private var elementsShown: Int = 1 | ||||
|     private var userIdentifier: String = "" | ||||
|     private var displayAccountHeader: Boolean = false | ||||
|     private var infiniteScroll: Boolean = false | ||||
| @@ -220,7 +216,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { | ||||
|             lastFetchDone = false | ||||
|             handleDrawerItems() | ||||
|             CoroutineScope(Dispatchers.Main).launch { | ||||
|                 refreshFocusedItems(applicationContext, api, db) | ||||
|                 refreshFocusedItems(applicationContext, api, db, itemsNumber) | ||||
|                 getElementsAccordingToTab() | ||||
|                 binding.swipeRefreshLayout.isRefreshing = false | ||||
|             } | ||||
| @@ -251,7 +247,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { | ||||
|                 ): Boolean = false | ||||
|  | ||||
|                 override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) { | ||||
|                     val position = viewHolder.adapterPosition | ||||
|                     val position = viewHolder.bindingAdapterPosition | ||||
|                     val i = items.elementAtOrNull(position) | ||||
|  | ||||
|                     if (i != null) { | ||||
| @@ -563,8 +559,9 @@ 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 | ||||
| @@ -615,8 +612,9 @@ 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 | ||||
| @@ -650,9 +648,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 | ||||
| @@ -673,11 +671,10 @@ 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 | ||||
| @@ -984,7 +981,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { | ||||
|         CoroutineScope(Dispatchers.Main).launch { | ||||
|             if (appendResults || !SharedItems.fetchedUnread) { | ||||
|                 binding.swipeRefreshLayout.isRefreshing = true | ||||
|                 getUnreadItems(applicationContext, api, db, offset) | ||||
|                 getUnreadItems(applicationContext, api, db, itemsNumber, offset) | ||||
|                 binding.swipeRefreshLayout.isRefreshing = false | ||||
|             } | ||||
|             SharedItems.getUnRead() | ||||
| @@ -997,7 +994,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { | ||||
|         CoroutineScope(Dispatchers.Main).launch { | ||||
|             if (appendResults || !SharedItems.fetchedAll) { | ||||
|                 binding.swipeRefreshLayout.isRefreshing = true | ||||
|                 getReadItems(applicationContext, api, db, offset) | ||||
|                 getReadItems(applicationContext, api, db, itemsNumber, offset) | ||||
|                 binding.swipeRefreshLayout.isRefreshing = false | ||||
|             } | ||||
|             SharedItems.getAll() | ||||
| @@ -1010,7 +1007,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { | ||||
|         CoroutineScope(Dispatchers.Main).launch { | ||||
|             if (appendResults || !SharedItems.fetchedStarred) { | ||||
|                 binding.swipeRefreshLayout.isRefreshing = true | ||||
|                 getStarredItems(applicationContext, api, db, offset) | ||||
|                 getStarredItems(applicationContext, api, db, itemsNumber, offset) | ||||
|                 binding.swipeRefreshLayout.isRefreshing = false | ||||
|             } | ||||
|             SharedItems.getStarred() | ||||
| @@ -1122,7 +1119,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { | ||||
|  | ||||
|     override fun onQueryTextChange(p0: String?): Boolean { | ||||
|         if (p0.isNullOrBlank()) { | ||||
|             maybeSearchFilter = null | ||||
|             SharedItems.searchFilter = null | ||||
|             getElementsAccordingToTab() | ||||
|             fetchOnEmptyList() | ||||
| @@ -1131,29 +1127,18 @@ 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 = MenuItemCompat.getActionView(searchItem) as SearchView | ||||
|         val searchView = searchItem.getActionView() as SearchView | ||||
|         searchView.setOnQueryTextListener(this) | ||||
|  | ||||
|         return true | ||||
| @@ -1268,8 +1253,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener { | ||||
|                     .addTag("selfoss-loading") | ||||
|                     .build() | ||||
|  | ||||
|  | ||||
|             WorkManager.getInstance().enqueueUniquePeriodicWork("selfoss-loading", ExistingPeriodicWorkPolicy.KEEP, backgroundWork) | ||||
|             WorkManager.getInstance(baseContext).enqueueUniquePeriodicWork("selfoss-loading", ExistingPeriodicWorkPolicy.KEEP, backgroundWork) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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 = getSharedPreferences(Config.settingsName, Context.MODE_PRIVATE) | ||||
|         settings = PreferenceManager.getDefaultSharedPreferences(applicationContext) | ||||
|         userIdentifier = settings.getString("unique_id", "")!! | ||||
|  | ||||
|         editor = settings.edit() | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import android.content.Context | ||||
| import android.content.SharedPreferences | ||||
| import android.graphics.Color | ||||
| import android.os.Bundle | ||||
| import android.view.KeyEvent | ||||
| import androidx.preference.PreferenceManager | ||||
| import androidx.appcompat.app.AppCompatActivity | ||||
| import android.view.Menu | ||||
| @@ -135,13 +136,30 @@ class ReaderActivity : AppCompatActivity() { | ||||
|     private inner class ScreenSlidePagerAdapter(fa: FragmentActivity) : | ||||
|         FragmentStateAdapter(fa) { | ||||
|  | ||||
|  | ||||
|         override fun getItemCount(): Int = allItems.size | ||||
|  | ||||
|         override fun createFragment(position: Int): Fragment = ArticleFragment.newInstance(allItems[position]) | ||||
|  | ||||
|     } | ||||
|  | ||||
|     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) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun alignmentMenu(showJustify: Boolean) { | ||||
|         toolbarMenu.findItem(R.id.align_left).isVisible = !showJustify | ||||
|         toolbarMenu.findItem(R.id.align_justify).isVisible = showJustify | ||||
|   | ||||
| @@ -39,13 +39,13 @@ suspend fun updateItems(context: Context, api: SelfossApi, db: AppDatabase) = co | ||||
|     } | ||||
| } | ||||
|  | ||||
| suspend fun refreshFocusedItems(context: Context, api: SelfossApi, db: AppDatabase) = withContext(Dispatchers.IO) { | ||||
| suspend fun refreshFocusedItems(context: Context, api: SelfossApi, db: AppDatabase, itemsNumber: Int) = withContext(Dispatchers.IO) { | ||||
|     if (isNetworkAvailable(context)) { | ||||
|         val response = when (SharedItems.displayedItems) { | ||||
|             "read" -> api.readItems(200, 0) | ||||
|             "unread" -> api.newItems(200, 0) | ||||
|             "starred" -> api.starredItems(200, 0) | ||||
|             else -> api.readItems(200, 0) | ||||
|             "read" -> api.readItems(itemsNumber, 0) | ||||
|             "unread" -> api.newItems(itemsNumber, 0) | ||||
|             "starred" -> api.starredItems(itemsNumber, 0) | ||||
|             else -> api.readItems(itemsNumber, 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, offset: Int) = withContext(Dispatchers.IO) { | ||||
| suspend fun getReadItems(context: Context, api: SelfossApi, db: AppDatabase, itemsNumber: Int, offset: Int) = withContext(Dispatchers.IO) { | ||||
|     if (isNetworkAvailable(context)) { | ||||
|             try { | ||||
|                 enqueueArticles(api.readItems( 200, offset), db, false) | ||||
|                 enqueueArticles(api.readItems( itemsNumber, offset), db, false) | ||||
|                 SharedItems.fetchedAll = true | ||||
|                 SharedItems.updateDatabase(db) | ||||
|             } catch (e: Throwable) {} | ||||
|     } | ||||
| } | ||||
|  | ||||
| suspend fun getUnreadItems(context: Context, api: SelfossApi, db: AppDatabase, offset: Int) = withContext(Dispatchers.IO) { | ||||
| suspend fun getUnreadItems(context: Context, api: SelfossApi, db: AppDatabase, itemsNumber: Int, offset: Int) = withContext(Dispatchers.IO) { | ||||
|     if (isNetworkAvailable(context)) { | ||||
|         try { | ||||
|             if (!SharedItems.fetchedUnread) { | ||||
|                 SharedItems.clearDBItems(db) | ||||
|             } | ||||
|             enqueueArticles(api.newItems(200, offset), db, false) | ||||
|             enqueueArticles(api.newItems(itemsNumber, offset), db, false) | ||||
|             SharedItems.fetchedUnread = true | ||||
|         } catch (e: Throwable) {} | ||||
|     } | ||||
|     SharedItems.updateDatabase(db) | ||||
| } | ||||
|  | ||||
| suspend fun getStarredItems(context: Context, api: SelfossApi, db: AppDatabase, offset: Int) = withContext(Dispatchers.IO) { | ||||
| suspend fun getStarredItems(context: Context, api: SelfossApi, db: AppDatabase, itemsNumber: Int, offset: Int) = withContext(Dispatchers.IO) { | ||||
|     if (isNetworkAvailable(context)) { | ||||
|         try { | ||||
|             enqueueArticles(api.starredItems(200, offset), db, false) | ||||
|             enqueueArticles(api.starredItems(itemsNumber, offset), db, false) | ||||
|             SharedItems.fetchedStarred = true | ||||
|             SharedItems.updateDatabase(db) | ||||
|         } catch (e: Throwable) { | ||||
|   | ||||
| @@ -511,6 +511,16 @@ 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( | ||||
|   | ||||
| @@ -4,11 +4,12 @@ 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 = c.getSharedPreferences(settingsName, Context.MODE_PRIVATE) | ||||
|     val settings: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(c) | ||||
|  | ||||
|     val baseUrl: String | ||||
|         get() = settings.getString("url", "")!! | ||||
| @@ -42,17 +43,15 @@ 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 { | ||||
|             editor.remove("url") | ||||
|             editor.remove("login") | ||||
|             editor.remove("password") | ||||
|             editor.remove("apiVersionMajor") | ||||
|             editor.apply() | ||||
|             val settings = PreferenceManager.getDefaultSharedPreferences(c) | ||||
|             settings.edit().clear().commit() | ||||
|             val intent = Intent(c, LoginActivity::class.java) | ||||
|             if (baseUrlFail) { | ||||
|                 intent.putExtra("baseUrlFail", baseUrlFail) | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
| buildscript { | ||||
|     ext { | ||||
|         kotlin_version = '1.5.31' | ||||
|         kotlin_version = '1.6.10' | ||||
|         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.3' | ||||
|         classpath 'com.android.tools.build:gradle:7.0.4' | ||||
|         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() | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user