forked from Louvorg/ReaderForSelfoss-multiplatform
Compare commits
22 Commits
cleaning
...
v123010281
Author | SHA1 | Date | |
---|---|---|---|
3e46e2ff29 | |||
f28e702549 | |||
fc31a4399c | |||
9b23053b66 | |||
389a04d250 | |||
40e1d1478b | |||
2154ff3c33 | |||
2245565f95 | |||
014858f06b | |||
3f1f86a78e | |||
a549169a7c | |||
be7cae365a | |||
cef3b2e593 | |||
ae927ebc57 | |||
90532cf501 | |||
ab0678d61e | |||
a1b7d22d26 | |||
29eae4b1f6 | |||
f5bbc63481 | |||
ddc72d85b0 | |||
68bbf5b2d3 | |||
2b6659f4ec |
@ -35,6 +35,7 @@ steps:
|
|||||||
trigger:
|
trigger:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
|
- pull_request
|
||||||
|
|
||||||
---
|
---
|
||||||
kind: pipeline
|
kind: pipeline
|
||||||
|
35
CHANGELOG.md
35
CHANGELOG.md
@ -1,3 +1,38 @@
|
|||||||
|
**v123010261**
|
||||||
|
|
||||||
|
- feat: Handle public instances (#126) Co-authored-by: davidoskky <davidoskky@hidden.hidden> Co-committed-by: davidoskky <davidoskky@hidden.hidden>
|
||||||
|
- ci: Pull request should trigger ci.
|
||||||
|
- fix: Complete the disconnection before redirecting to the login screen
|
||||||
|
- Complete the disconnection before redirecting to the login screen
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123010241**
|
||||||
|
|
||||||
|
- Merge pull request 'feat: swipe down to close images' (#122) from davidoskky/ReaderForSelfoss-multiplatform:swipe_down into master
|
||||||
|
- Remove unnecessary definition
|
||||||
|
- Remove unused import
|
||||||
|
- Adjust the image closing animation
|
||||||
|
- Add a dark hue to the underlying article when swiping to close images
|
||||||
|
- Rename activity style to avoid interferences
|
||||||
|
- Adapt the style of the image activity to the rest of the application
|
||||||
|
- Resolve issues when swiping down to close images
|
||||||
|
- Close the image fragment only if the image has been dragged down
|
||||||
|
- Animate swipe down to close images
|
||||||
|
- Swipe down to close images
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
**v123010041**
|
||||||
|
|
||||||
|
- Merge pull request 'scroll-tag-filters' (#124) from scroll-tag-filters into master
|
||||||
|
- fix: added POST_NOTIFICATIONS to fix notifications issues.
|
||||||
|
- fix: scrollable filter sheet.
|
||||||
|
- enhancement: Ellipsize chips text.
|
||||||
|
- Cleaning.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
**v122123641**
|
**v122123641**
|
||||||
|
|
||||||
- feat: Disable the failing source in the filter sheet.
|
- feat: Disable the failing source in the filter sheet.
|
||||||
|
@ -66,7 +66,7 @@ android {
|
|||||||
jvmTarget = "11"
|
jvmTarget = "11"
|
||||||
}
|
}
|
||||||
compileSdk = 33
|
compileSdk = 33
|
||||||
buildToolsVersion = "31.0.0"
|
buildToolsVersion = "33.0.0"
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
}
|
}
|
||||||
@ -115,7 +115,6 @@ dependencies {
|
|||||||
implementation(project(":shared"))
|
implementation(project(":shared"))
|
||||||
implementation("com.google.android.material:material:1.5.0")
|
implementation("com.google.android.material:material:1.5.0")
|
||||||
implementation("androidx.appcompat:appcompat:1.4.1")
|
implementation("androidx.appcompat:appcompat:1.4.1")
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.3")
|
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0")
|
||||||
|
|
||||||
implementation("androidx.preference:preference-ktx:1.1.1")
|
implementation("androidx.preference:preference-ktx:1.1.1")
|
||||||
@ -131,7 +130,7 @@ dependencies {
|
|||||||
implementation("androidx.cardview:cardview:1.0.0")
|
implementation("androidx.cardview:cardview:1.0.0")
|
||||||
implementation("androidx.annotation:annotation:1.3.0")
|
implementation("androidx.annotation:annotation:1.3.0")
|
||||||
implementation("androidx.work:work-runtime-ktx:2.7.1")
|
implementation("androidx.work:work-runtime-ktx:2.7.1")
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.3")
|
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||||
implementation("org.jsoup:jsoup:1.14.3")
|
implementation("org.jsoup:jsoup:1.14.3")
|
||||||
|
|
||||||
//multidex
|
//multidex
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
@ -69,7 +70,8 @@
|
|||||||
android:name=".ReaderActivity">
|
android:name=".ReaderActivity">
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".ImageActivity">
|
android:name=".ImageActivity"
|
||||||
|
android:theme="@style/Theme.AppCompat.ImageActivity">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<meta-data android:name="android.webkit.WebView.MetricsOptOut"
|
<meta-data android:name="android.webkit.WebView.MetricsOptOut"
|
||||||
|
@ -36,6 +36,7 @@ import com.ashokvarma.bottomnavigation.TextBadgeItem
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.kodein.di.DIAware
|
import org.kodein.di.DIAware
|
||||||
import org.kodein.di.android.closestDI
|
import org.kodein.di.android.closestDI
|
||||||
import org.kodein.di.instance
|
import org.kodein.di.instance
|
||||||
@ -114,10 +115,16 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val swipeDirs = if (appSettingsService.getPublicAccess()) {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
|
||||||
|
}
|
||||||
|
|
||||||
val simpleItemTouchCallback =
|
val simpleItemTouchCallback =
|
||||||
object : ItemTouchHelper.SimpleCallback(
|
object : ItemTouchHelper.SimpleCallback(
|
||||||
0,
|
0,
|
||||||
ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
|
swipeDirs
|
||||||
) {
|
) {
|
||||||
override fun getSwipeDirs(
|
override fun getSwipeDirs(
|
||||||
recyclerView: RecyclerView,
|
recyclerView: RecyclerView,
|
||||||
@ -510,6 +517,10 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
val inflater = menuInflater
|
val inflater = menuInflater
|
||||||
inflater.inflate(R.menu.home_menu, menu)
|
inflater.inflate(R.menu.home_menu, menu)
|
||||||
|
if (appSettingsService.getPublicAccess()) {
|
||||||
|
menu.removeItem(R.id.readAll)
|
||||||
|
menu.removeItem(R.id.action_sources)
|
||||||
|
}
|
||||||
|
|
||||||
val searchItem = menu.findItem(R.id.action_search)
|
val searchItem = menu.findItem(R.id.action_search)
|
||||||
val searchView = searchItem.getActionView() as SearchView
|
val searchView = searchItem.getActionView() as SearchView
|
||||||
@ -588,12 +599,12 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_disconnect -> {
|
R.id.action_disconnect -> {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
runBlocking {
|
||||||
repository.logout()
|
repository.logout()
|
||||||
}
|
}
|
||||||
this@HomeActivity.finish()
|
|
||||||
val intent = Intent(this, LoginActivity::class.java)
|
val intent = Intent(this, LoginActivity::class.java)
|
||||||
this.startActivity(intent)
|
this.startActivity(intent)
|
||||||
|
finish()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_settings -> {
|
R.id.action_settings -> {
|
||||||
|
@ -3,6 +3,7 @@ package bou.amine.apps.readerforselfossv2.android
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
@ -23,7 +24,6 @@ class ImageActivity : AppCompatActivity() {
|
|||||||
setContentView(view)
|
setContentView(view)
|
||||||
|
|
||||||
setSupportActionBar(binding.toolBar)
|
setSupportActionBar(binding.toolBar)
|
||||||
supportActionBar?.setDisplayShowTitleEnabled(false)
|
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
|
|
||||||
allImages = intent.getStringArrayListExtra("allImages") as ArrayList<String>
|
allImages = intent.getStringArrayListExtra("allImages") as ArrayList<String>
|
||||||
@ -31,12 +31,35 @@ class ImageActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
binding.pager.adapter = ScreenSlidePagerAdapter(this)
|
binding.pager.adapter = ScreenSlidePagerAdapter(this)
|
||||||
binding.pager.setCurrentItem(position, false)
|
binding.pager.setCurrentItem(position, false)
|
||||||
|
|
||||||
|
val transitionListener = object : MotionLayout.TransitionListener {
|
||||||
|
override fun onTransitionStarted(motionLayout: MotionLayout?, startId: Int, endId: Int) {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTransitionChange(motionLayout: MotionLayout?, startId: Int, endId: Int, progress: Float
|
||||||
|
) {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {
|
||||||
|
if (motionLayout?.currentState == binding.root.endState) {
|
||||||
|
onBackPressedDispatcher.onBackPressed()
|
||||||
|
overridePendingTransition(0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onTransitionTrigger(motionLayout: MotionLayout?, triggerId: Int, positive: Boolean, progress: Float) {
|
||||||
|
// Nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.root.setTransitionListener(transitionListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
onBackPressed()
|
onBackPressedDispatcher.onBackPressed()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
|
|
||||||
private fun goToMain() {
|
private fun goToMain() {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
repository.updateApiVersion()
|
repository.updateApiInformation()
|
||||||
ACRA.errorReporter.putCustomData("SELFOSS_API_VERSION", appSettingsService.getApiVersion().toString())
|
ACRA.errorReporter.putCustomData("SELFOSS_API_VERSION", appSettingsService.getApiVersion().toString())
|
||||||
}
|
}
|
||||||
val intent = Intent(this, HomeActivity::class.java)
|
val intent = Intent(this, HomeActivity::class.java)
|
||||||
|
@ -84,7 +84,7 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun readItem(item: SelfossModel.Item) {
|
private fun readItem(item: SelfossModel.Item) {
|
||||||
if (appSettingsService.isMarkOnScrollEnabled()) {
|
if (appSettingsService.isMarkOnScrollEnabled() && !appSettingsService.getPublicAccess()) {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
repository.markAsRead(item)
|
repository.markAsRead(item)
|
||||||
}
|
}
|
||||||
@ -137,28 +137,34 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
inflater.inflate(R.menu.reader_menu, menu)
|
inflater.inflate(R.menu.reader_menu, menu)
|
||||||
toolbarMenu = menu
|
toolbarMenu = menu
|
||||||
|
|
||||||
if (allItems.isNotEmpty() && allItems[currentItem].starred) {
|
|
||||||
canRemoveFromFavorite()
|
|
||||||
} else {
|
|
||||||
canFavorite()
|
|
||||||
}
|
|
||||||
alignmentMenu()
|
alignmentMenu()
|
||||||
|
|
||||||
binding.pager.registerOnPageChangeCallback(
|
if (appSettingsService.getPublicAccess()) {
|
||||||
object : ViewPager2.OnPageChangeCallback() {
|
menu.removeItem(R.id.star)
|
||||||
|
} else {
|
||||||
override fun onPageSelected(position: Int) {
|
if (allItems.isNotEmpty() && allItems[currentItem].starred) {
|
||||||
super.onPageSelected(position)
|
canRemoveFromFavorite()
|
||||||
|
} else {
|
||||||
if (allItems[position].starred) {
|
canFavorite()
|
||||||
canRemoveFromFavorite()
|
|
||||||
} else {
|
|
||||||
canFavorite()
|
|
||||||
}
|
|
||||||
readItem(allItems[position])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
|
||||||
|
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
|
return true
|
||||||
}
|
}
|
||||||
@ -177,7 +183,7 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
|
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
onBackPressed()
|
onBackPressedDispatcher.onBackPressed()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.star -> {
|
R.id.star -> {
|
||||||
|
@ -56,6 +56,10 @@ class ItemCardAdapter(
|
|||||||
val itm = items[position]
|
val itm = items[position]
|
||||||
|
|
||||||
binding.favButton.isSelected = itm.starred
|
binding.favButton.isSelected = itm.starred
|
||||||
|
if (appSettingsService.getPublicAccess()) {
|
||||||
|
binding.favButton.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
binding.title.text = itm.title.getHtmlDecoded()
|
binding.title.text = itm.title.getHtmlDecoded()
|
||||||
|
|
||||||
binding.title.setOnTouchListener(LinkOnTouchListener())
|
binding.title.setOnTouchListener(LinkOnTouchListener())
|
||||||
|
@ -195,6 +195,9 @@ class ArticleFragment : Fragment(), DIAware {
|
|||||||
|
|
||||||
private fun handleFloatingToolbar(): FloatingToolbar {
|
private fun handleFloatingToolbar(): FloatingToolbar {
|
||||||
val floatingToolbar: FloatingToolbar = binding.floatingToolbar
|
val floatingToolbar: FloatingToolbar = binding.floatingToolbar
|
||||||
|
if (appSettingsService.getPublicAccess()) {
|
||||||
|
floatingToolbar.setMenu(R.menu.reader_toolbar_no_read)
|
||||||
|
}
|
||||||
floatingToolbar.attachFab(fab)
|
floatingToolbar.attachFab(fab)
|
||||||
|
|
||||||
floatingToolbar.background = ColorDrawable(resources.getColor(R.color.colorAccent))
|
floatingToolbar.background = ColorDrawable(resources.getColor(R.color.colorAccent))
|
||||||
|
@ -6,6 +6,7 @@ import android.graphics.drawable.Drawable
|
|||||||
import android.graphics.drawable.GradientDrawable
|
import android.graphics.drawable.GradientDrawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.TextUtils
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
@ -85,6 +86,7 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware {
|
|||||||
|
|
||||||
repository.getSources().forEach { source ->
|
repository.getSources().forEach { source ->
|
||||||
val c = Chip(context)
|
val c = Chip(context)
|
||||||
|
c.ellipsize = TextUtils.TruncateAt.END
|
||||||
|
|
||||||
Glide.with(context)
|
Glide.with(context)
|
||||||
.load(source.getIcon(repository.baseUrl))
|
.load(source.getIcon(repository.baseUrl))
|
||||||
@ -158,6 +160,7 @@ class FilterSheetFragment : BottomSheetDialogFragment(), DIAware {
|
|||||||
|
|
||||||
tags.forEach { tag ->
|
tags.forEach { tag ->
|
||||||
val c = Chip(context)
|
val c = Chip(context)
|
||||||
|
c.ellipsize = TextUtils.TruncateAt.END
|
||||||
c.text = tag.tag
|
c.text = tag.tag
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -1,33 +1,40 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
app:layoutDescription="@xml/image_close_scene">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appBarLayout"
|
android:id="@+id/appBarLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar android:theme="@style/ToolBarStyle"
|
||||||
android:id="@+id/toolBar"
|
android:id="@+id/toolBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<androidx.viewpager2.widget.ViewPager2
|
<androidx.core.widget.NestedScrollView
|
||||||
android:id="@+id/pager"
|
android:id="@+id/scrollView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="0dp"
|
android:layout_height="match_parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:fillViewport="true"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintTop_toBottomOf="@+id/appBarLayout">
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/appBarLayout" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
|
android:id="@+id/pager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.constraintlayout.motion.widget.MotionLayout>
|
||||||
|
@ -47,7 +47,6 @@
|
|||||||
android:id="@+id/sourceImage"
|
android:id="@+id/sourceImage"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
@ -85,41 +84,32 @@
|
|||||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||||
tools:text="Google Actualité Il y a 5h" />
|
tools:text="Google Actualité Il y a 5h" />
|
||||||
|
|
||||||
<RelativeLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/sourceTitleAndDate">
|
app:layout_constraintTop_toBottomOf="@+id/sourceTitleAndDate">
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/favButton"
|
android:id="@+id/browserBtn"
|
||||||
android:layout_width="35dp"
|
android:layout_width="35dp"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_alignParentEnd="true"
|
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:layout_marginRight="8dp"
|
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:elevation="5dp"
|
android:elevation="5dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
app:srcCompat="@drawable/ic_menu_heart_60dp"
|
app:srcCompat="@drawable/ic_open_in_browser_black_24dp"
|
||||||
app:tint="@color/ic_menu_heart_color" />
|
app:tint="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/shareBtn"
|
android:id="@+id/shareBtn"
|
||||||
android:layout_width="35dp"
|
android:layout_width="35dp"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_centerVertical="true"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:layout_toLeftOf="@+id/favButton"
|
|
||||||
android:layout_toStartOf="@+id/favButton"
|
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:elevation="5dp"
|
android:elevation="5dp"
|
||||||
@ -129,23 +119,21 @@
|
|||||||
app:tint="?android:attr/textColorPrimary" />
|
app:tint="?android:attr/textColorPrimary" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/browserBtn"
|
android:id="@+id/favButton"
|
||||||
android:layout_width="35dp"
|
android:layout_width="35dp"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_centerVertical="true"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:layout_toLeftOf="@+id/shareBtn"
|
|
||||||
android:layout_toStartOf="@+id/shareBtn"
|
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:elevation="5dp"
|
android:elevation="5dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
app:srcCompat="@drawable/ic_open_in_browser_black_24dp"
|
app:srcCompat="@drawable/ic_menu_heart_60dp"
|
||||||
app:tint="?android:attr/textColorPrimary" />
|
app:tint="@color/ic_menu_heart_color" />
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -17,73 +17,80 @@
|
|||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:visibility="gone" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.core.widget.NestedScrollView
|
||||||
android:id="@+id/filterView"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:visibility="gone"
|
android:fillViewport="true">
|
||||||
tools:visibility="visible">
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/floatingActionButton2"
|
android:id="@+id/filterView"
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:clickable="true"
|
|
||||||
app:backgroundTint="@color/colorAccent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:rippleColor="@color/colorAccentDark"
|
|
||||||
app:srcCompat="@drawable/ic_menu_search_white_24dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/filterTagsTitle"
|
|
||||||
style="@style/MaterialAlertDialog.MaterialComponents.Title.Text"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:text="@string/filter_item_tags"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
|
||||||
android:id="@+id/tagsGroup"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:visibility="gone"
|
||||||
android:layout_marginTop="24dp"
|
tools:visibility="visible">
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/filterTagsTitle"
|
|
||||||
app:singleSelection="true">
|
|
||||||
|
|
||||||
</com.google.android.material.chip.ChipGroup>
|
<TextView
|
||||||
|
android:id="@+id/filterTagsTitle"
|
||||||
|
style="@style/MaterialAlertDialog.MaterialComponents.Title.Text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/filter_item_tags"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/filterSourcesTitle"
|
android:id="@+id/filterSourcesTitle"
|
||||||
style="@style/MaterialAlertDialog.MaterialComponents.Title.Text"
|
style="@style/MaterialAlertDialog.MaterialComponents.Title.Text"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:text="@string/filter_item_sources"
|
android:text="@string/filter_item_sources"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/tagsGroup" />
|
app:layout_constraintTop_toBottomOf="@+id/tagsGroup" />
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
<com.google.android.material.chip.ChipGroup
|
||||||
android:id="@+id/sourcesGroup"
|
android:id="@+id/tagsGroup"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/filterSourcesTitle">
|
app:layout_constraintTop_toBottomOf="@+id/filterTagsTitle"
|
||||||
|
app:singleSelection="true">
|
||||||
|
|
||||||
</com.google.android.material.chip.ChipGroup>
|
</com.google.android.material.chip.ChipGroup>
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/sourcesGroup"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/filterSourcesTitle">
|
||||||
|
|
||||||
|
</com.google.android.material.chip.ChipGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/floatingActionButton2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:clickable="true"
|
||||||
|
app:backgroundTint="@color/colorAccent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:rippleColor="@color/colorAccentDark"
|
||||||
|
app:srcCompat="@drawable/ic_menu_search_white_24dp" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -83,7 +83,7 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
android:layout_gravity="end|bottom|right">
|
android:layout_gravity="end|bottom|end">
|
||||||
|
|
||||||
<com.github.rubensousa.floatingtoolbar.FloatingToolbar
|
<com.github.rubensousa.floatingtoolbar.FloatingToolbar
|
||||||
android:id="@+id/floatingToolbar"
|
android:id="@+id/floatingToolbar"
|
||||||
@ -96,10 +96,9 @@
|
|||||||
android:id="@+id/fab"
|
android:id="@+id/fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="end|bottom|right"
|
android:layout_gravity="end|bottom|end"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginRight="16dp"
|
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
android:src="@drawable/ic_add_white_24dp"
|
android:src="@drawable/ic_add_white_24dp"
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<com.github.chrisbanes.photoview.PhotoView
|
<com.github.chrisbanes.photoview.PhotoView
|
||||||
android:id="@+id/photoView"
|
android:id="@+id/photoView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_centerVertical="true"
|
android:layout_centerVertical="true"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:background="@drawable/checkerboard"
|
android:background="@drawable/checkerboard"
|
||||||
app:srcCompat="@android:drawable/screen_background_dark" />
|
app:srcCompat="@android:drawable/screen_background_dark" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
16
androidApp/src/main/res/menu/reader_toolbar_no_read.xml
Normal file
16
androidApp/src/main/res/menu/reader_toolbar_no_read.xml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/open_action"
|
||||||
|
android:icon="@drawable/ic_open_in_browser_white_24dp"
|
||||||
|
android:title="@string/reader_action_open"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/share_action"
|
||||||
|
android:icon="@drawable/ic_share_white_24dp"
|
||||||
|
android:title="@string/reader_action_share"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
</menu>
|
@ -12,4 +12,5 @@
|
|||||||
<color name="refresh_progress_2">@color/colorAccent</color>
|
<color name="refresh_progress_2">@color/colorAccent</color>
|
||||||
<color name="refresh_progress_3">@color/pink</color>
|
<color name="refresh_progress_3">@color/pink</color>
|
||||||
<color name="dark">#FF282828</color>
|
<color name="dark">#FF282828</color>
|
||||||
|
<color name="transparent_dark_background">#33000000</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -26,4 +26,10 @@
|
|||||||
<item name="android:textColorSecondary">@color/white</item>
|
<item name="android:textColorSecondary">@color/white</item>
|
||||||
<item name="actionMenuTextColor">@color/white</item>
|
<item name="actionMenuTextColor">@color/white</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="Theme.AppCompat.ImageActivity" parent="NoBar">
|
||||||
|
<item name="android:windowBackground">@color/transparent_dark_background</item>
|
||||||
|
<item name="android:colorBackgroundCacheHint">@null</item>
|
||||||
|
<item name="android:windowIsTranslucent">true</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
41
androidApp/src/main/res/xml/image_close_scene.xml
Normal file
41
androidApp/src/main/res/xml/image_close_scene.xml
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:motion="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/motionLayout">
|
||||||
|
|
||||||
|
<Transition
|
||||||
|
motion:constraintSetStart="@+id/start"
|
||||||
|
motion:constraintSetEnd="@+id/end"
|
||||||
|
motion:duration="500"
|
||||||
|
motion:motionInterpolator="linear">
|
||||||
|
|
||||||
|
<OnSwipe
|
||||||
|
motion:touchAnchorId="@+id/scrollView"
|
||||||
|
motion:touchAnchorSide="top"
|
||||||
|
motion:onTouchUp="autoCompleteToStart" />
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<ConstraintSet android:id="@+id/start">
|
||||||
|
|
||||||
|
<Constraint
|
||||||
|
android:id="@id/scrollView"
|
||||||
|
motion:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
motion:layout_constraintTop_toBottomOf="@+id/appBarLayout"
|
||||||
|
motion:layout_constraintEnd_toEndOf="parent"
|
||||||
|
motion:layout_constraintStart_toStartOf="parent">
|
||||||
|
</Constraint>
|
||||||
|
</ConstraintSet>
|
||||||
|
|
||||||
|
<ConstraintSet android:id="@+id/end">
|
||||||
|
|
||||||
|
<Constraint
|
||||||
|
android:id="@+id/scrollView"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:layout_marginBottom="0dp"
|
||||||
|
motion:layout_constraintStart_toStartOf="parent"
|
||||||
|
motion:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
motion:layout_constraintEnd_toEndOf="parent">
|
||||||
|
</Constraint>
|
||||||
|
</ConstraintSet>
|
||||||
|
</MotionScene>
|
@ -20,6 +20,8 @@ import org.junit.Test
|
|||||||
|
|
||||||
private const val BASE_URL = "https://test.com/selfoss/"
|
private const val BASE_URL = "https://test.com/selfoss/"
|
||||||
|
|
||||||
|
private const val USERNAME = "username"
|
||||||
|
|
||||||
private const val SPOUT = "spouts\\rss\\fulltextrss"
|
private const val SPOUT = "spouts\\rss\\fulltextrss"
|
||||||
|
|
||||||
private const val IMAGE_URL = "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"
|
private const val IMAGE_URL = "b3aa8a664d08eb15d6ff1db2fa83e0d9.png"
|
||||||
@ -49,7 +51,7 @@ class RepositoryTest {
|
|||||||
repository = Repository(api, appSettingsService, isConnectionAvailable, db)
|
repository = Repository(api, appSettingsService, isConnectionAvailable, db)
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
repository.updateApiVersion()
|
repository.updateApiInformation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,12 +60,13 @@ class RepositoryTest {
|
|||||||
clearAllMocks()
|
clearAllMocks()
|
||||||
every { appSettingsService.getApiVersion() } returns 4
|
every { appSettingsService.getApiVersion() } returns 4
|
||||||
every { appSettingsService.getBaseUrl() } returns BASE_URL
|
every { appSettingsService.getBaseUrl() } returns BASE_URL
|
||||||
|
every { appSettingsService.getUserName() } returns USERNAME
|
||||||
every { appSettingsService.isItemCachingEnabled() } returns false
|
every { appSettingsService.isItemCachingEnabled() } returns false
|
||||||
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
every { appSettingsService.isUpdateSourcesEnabled() } returns false
|
||||||
|
|
||||||
coEvery { api.version() } returns StatusAndData(
|
coEvery { api.apiInformation() } returns StatusAndData(
|
||||||
success = true,
|
success = true,
|
||||||
data = SelfossModel.ApiVersion("2.19-ba1e8e3", "4.0.0")
|
data = SelfossModel.ApiInformation("2.19-ba1e8e3", "4.0.0", SelfossModel.ApiConfiguration(false, true))
|
||||||
)
|
)
|
||||||
coEvery { api.stats() } returns StatusAndData(
|
coEvery { api.stats() } returns StatusAndData(
|
||||||
success = true,
|
success = true,
|
||||||
@ -81,7 +84,7 @@ class RepositoryTest {
|
|||||||
fun instantiate_repository() {
|
fun instantiate_repository() {
|
||||||
initializeRepository()
|
initializeRepository()
|
||||||
|
|
||||||
coVerify(exactly = 1) { api.version() }
|
coVerify(exactly = 1) { api.apiInformation() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -90,7 +93,7 @@ class RepositoryTest {
|
|||||||
|
|
||||||
initializeRepository(MutableStateFlow(false))
|
initializeRepository(MutableStateFlow(false))
|
||||||
|
|
||||||
coVerify(exactly = 0) { api.version() }
|
coVerify(exactly = 0) { api.apiInformation() }
|
||||||
coVerify(exactly = 0) { api.stats() }
|
coVerify(exactly = 0) { api.stats() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,10 +113,70 @@ class RepositoryTest {
|
|||||||
verify(exactly = 1) { appSettingsService.updateApiVersion(4) }
|
verify(exactly = 1) { appSettingsService.updateApiVersion(4) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun get_public_access() {
|
||||||
|
every { appSettingsService.updatePublicAccess(any()) } returns Unit
|
||||||
|
coEvery { api.apiInformation() } returns StatusAndData(
|
||||||
|
success = true,
|
||||||
|
data = SelfossModel.ApiInformation("2.19-ba1e8e3", "4.0.0", SelfossModel.ApiConfiguration(true, true))
|
||||||
|
)
|
||||||
|
every { appSettingsService.getUserName() } returns ""
|
||||||
|
|
||||||
|
initializeRepository()
|
||||||
|
|
||||||
|
coVerify(exactly = 1) { api.apiInformation() }
|
||||||
|
coVerify(exactly = 1) { appSettingsService.updatePublicAccess(true) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun get_public_access_username_not_empty() {
|
||||||
|
every { appSettingsService.updatePublicAccess(any()) } returns Unit
|
||||||
|
coEvery { api.apiInformation() } returns StatusAndData(
|
||||||
|
success = true,
|
||||||
|
data = SelfossModel.ApiInformation("2.19-ba1e8e3", "4.0.0", SelfossModel.ApiConfiguration(true, true))
|
||||||
|
)
|
||||||
|
every { appSettingsService.getUserName() } returns "username"
|
||||||
|
|
||||||
|
initializeRepository()
|
||||||
|
|
||||||
|
coVerify(exactly = 1) { api.apiInformation() }
|
||||||
|
coVerify(exactly = 0) { appSettingsService.updatePublicAccess(true) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun get_public_access_no_auth() {
|
||||||
|
every { appSettingsService.updatePublicAccess(any()) } returns Unit
|
||||||
|
coEvery { api.apiInformation() } returns StatusAndData(
|
||||||
|
success = true,
|
||||||
|
data = SelfossModel.ApiInformation("2.19-ba1e8e3", "4.0.0", SelfossModel.ApiConfiguration(true, false))
|
||||||
|
)
|
||||||
|
every { appSettingsService.getUserName() } returns ""
|
||||||
|
|
||||||
|
initializeRepository()
|
||||||
|
|
||||||
|
coVerify(exactly = 1) { api.apiInformation() }
|
||||||
|
coVerify(exactly = 0) { appSettingsService.updatePublicAccess(true) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun get_public_access_disabled() {
|
||||||
|
every { appSettingsService.updatePublicAccess(any()) } returns Unit
|
||||||
|
coEvery { api.apiInformation() } returns StatusAndData(
|
||||||
|
success = true,
|
||||||
|
data = SelfossModel.ApiInformation("2.19-ba1e8e3", "4.0.0", SelfossModel.ApiConfiguration(false, true))
|
||||||
|
)
|
||||||
|
every { appSettingsService.getUserName() } returns ""
|
||||||
|
|
||||||
|
initializeRepository()
|
||||||
|
|
||||||
|
coVerify(exactly = 1) { api.apiInformation() }
|
||||||
|
coVerify(exactly = 0) { appSettingsService.updatePublicAccess(true) }
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun get_api_1_date_with_api_4_version_stored() {
|
fun get_api_1_date_with_api_4_version_stored() {
|
||||||
every { appSettingsService.getApiVersion() } returns 4
|
every { appSettingsService.getApiVersion() } returns 4
|
||||||
coEvery { api.version() } returns StatusAndData(success = false, null)
|
coEvery { api.apiInformation() } returns StatusAndData(success = false, null)
|
||||||
val itemParameters = FakeItemParameters()
|
val itemParameters = FakeItemParameters()
|
||||||
itemParameters.datetime = "2021-04-23 11:45:32"
|
itemParameters.datetime = "2021-04-23 11:45:32"
|
||||||
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
coEvery { api.getItems(any(), any(), any(), any(), any(), any(), any()) } returns
|
||||||
|
@ -7,8 +7,8 @@ buildscript {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
//trick: for the same plugin versions in all sub-modules
|
//trick: for the same plugin versions in all sub-modules
|
||||||
id("com.android.application").version("7.3.1").apply(false)
|
id("com.android.application").version("7.4.0").apply(false)
|
||||||
id("com.android.library").version("7.3.1").apply(false)
|
id("com.android.library").version("7.4.0").apply(false)
|
||||||
kotlin("android").version("1.7.20").apply(false)
|
kotlin("android").version("1.7.20").apply(false)
|
||||||
kotlin("multiplatform").version("1.7.20").apply(false)
|
kotlin("multiplatform").version("1.7.20").apply(false)
|
||||||
id("com.mikepenz.aboutlibraries.plugin").version("10.5.1").apply(false)
|
id("com.mikepenz.aboutlibraries.plugin").version("10.5.1").apply(false)
|
||||||
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
|||||||
#Wed Feb 09 17:05:19 CET 2022
|
#Mon Jan 23 20:47:46 CET 2023
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
@ -35,17 +35,32 @@ class SelfossModel {
|
|||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ApiVersion(
|
data class ApiInformation(
|
||||||
val version: String?,
|
val version: String?,
|
||||||
val apiversion: String?
|
val apiversion: String?,
|
||||||
|
val configuration: ApiConfiguration?
|
||||||
) {
|
) {
|
||||||
fun getApiMajorVersion() : Int {
|
fun getApiMajorVersion(): Int {
|
||||||
var versionNumber = 0
|
var versionNumber = 0
|
||||||
if (apiversion != null) {
|
if (apiversion != null) {
|
||||||
versionNumber = apiversion.substringBefore(".").toInt()
|
versionNumber = apiversion.substringBefore(".").toInt()
|
||||||
}
|
}
|
||||||
return versionNumber
|
return versionNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getApiConfiguration() = configuration ?: ApiConfiguration(null, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ApiConfiguration(
|
||||||
|
@Serializable(with = BooleanSerializer::class)
|
||||||
|
val publicMode: Boolean?,
|
||||||
|
@Serializable(with = BooleanSerializer::class)
|
||||||
|
val authEnabled: Boolean?
|
||||||
|
) {
|
||||||
|
fun isAuthEnabled() = authEnabled ?: true
|
||||||
|
|
||||||
|
fun isPublicModeEnabled() = publicMode ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
|
@ -439,13 +439,23 @@ class Repository(
|
|||||||
api.refreshLoginInformation()
|
api.refreshLoginInformation()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun updateApiVersion() {
|
suspend fun updateApiInformation() {
|
||||||
val apiMajorVersion = appSettingsService.getApiVersion()
|
val apiMajorVersion = appSettingsService.getApiVersion()
|
||||||
|
|
||||||
if (isNetworkAvailable()) {
|
if (isNetworkAvailable()) {
|
||||||
val fetchedVersion = api.version()
|
val fetchedInformation = api.apiInformation()
|
||||||
if (fetchedVersion.success && fetchedVersion.data != null && fetchedVersion.data.getApiMajorVersion() != apiMajorVersion) {
|
if (fetchedInformation.success && fetchedInformation.data != null) {
|
||||||
appSettingsService.updateApiVersion(fetchedVersion.data.getApiMajorVersion())
|
if (fetchedInformation.data.getApiMajorVersion() != apiMajorVersion) {
|
||||||
|
appSettingsService.updateApiVersion(fetchedInformation.data.getApiMajorVersion())
|
||||||
|
}
|
||||||
|
// Check if we're accessing the instance in public mode
|
||||||
|
// This happens when auth and public mode are enabled but
|
||||||
|
// no credentials are provided to login
|
||||||
|
if (appSettingsService.getUserName().isEmpty()
|
||||||
|
&& fetchedInformation.data.getApiConfiguration().isAuthEnabled()
|
||||||
|
&& fetchedInformation.data.getApiConfiguration().isPublicModeEnabled()) {
|
||||||
|
appSettingsService.updatePublicAccess(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
suspend fun version(): StatusAndData<SelfossModel.ApiVersion> =
|
suspend fun apiInformation(): StatusAndData<SelfossModel.ApiInformation> =
|
||||||
bodyOrFailure(client.tryToGet(url("/api/about")))
|
bodyOrFailure(client.tryToGet(url("/api/about")))
|
||||||
|
|
||||||
suspend fun markAsRead(id: String): SuccessResponse =
|
suspend fun markAsRead(id: String): SuccessResponse =
|
||||||
|
@ -7,6 +7,7 @@ class AppSettingsService {
|
|||||||
|
|
||||||
// Api related
|
// Api related
|
||||||
private var _apiVersion: Int = -1
|
private var _apiVersion: Int = -1
|
||||||
|
private var _publicAccess: Boolean? = null
|
||||||
private var _baseUrl: String = ""
|
private var _baseUrl: String = ""
|
||||||
private var _userName: String = ""
|
private var _userName: String = ""
|
||||||
private var _password: String = ""
|
private var _password: String = ""
|
||||||
@ -48,10 +49,32 @@ class AppSettingsService {
|
|||||||
return _apiVersion
|
return _apiVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun updateApiVersion(apiMajorVersion: Int) {
|
||||||
|
settings.putInt(API_VERSION_MAJOR, apiMajorVersion)
|
||||||
|
refreshApiVersion()
|
||||||
|
}
|
||||||
|
|
||||||
private fun refreshApiVersion() {
|
private fun refreshApiVersion() {
|
||||||
_apiVersion = settings.getInt(API_VERSION_MAJOR, -1)
|
_apiVersion = settings.getInt(API_VERSION_MAJOR, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getPublicAccess(): Boolean {
|
||||||
|
if (_publicAccess == null) {
|
||||||
|
refreshPublicAccess()
|
||||||
|
}
|
||||||
|
return _publicAccess!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updatePublicAccess(publicAccess: Boolean) {
|
||||||
|
settings.putBoolean(API_PUBLIC_ACCESS, publicAccess)
|
||||||
|
refreshPublicAccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun refreshPublicAccess() {
|
||||||
|
_publicAccess = settings.getBoolean(API_PUBLIC_ACCESS, false)
|
||||||
|
}
|
||||||
|
|
||||||
fun getBaseUrl(): String {
|
fun getBaseUrl(): String {
|
||||||
if (_baseUrl.isEmpty()) {
|
if (_baseUrl.isEmpty()) {
|
||||||
refreshBaseUrl()
|
refreshBaseUrl()
|
||||||
@ -333,6 +356,7 @@ class AppSettingsService {
|
|||||||
refreshUsername()
|
refreshUsername()
|
||||||
refreshBaseUrl()
|
refreshBaseUrl()
|
||||||
refreshApiVersion()
|
refreshApiVersion()
|
||||||
|
refreshPublicAccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshUserSettings() {
|
fun refreshUserSettings() {
|
||||||
@ -376,11 +400,6 @@ class AppSettingsService {
|
|||||||
refreshApiSettings()
|
refreshApiSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateApiVersion(apiMajorVersion: Int) {
|
|
||||||
settings.putInt(API_VERSION_MAJOR, apiMajorVersion)
|
|
||||||
refreshApiVersion()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun clearAll() {
|
fun clearAll() {
|
||||||
settings.clear()
|
settings.clear()
|
||||||
refreshApiSettings()
|
refreshApiSettings()
|
||||||
@ -409,6 +428,8 @@ class AppSettingsService {
|
|||||||
|
|
||||||
const val API_VERSION_MAJOR = "apiVersionMajor"
|
const val API_VERSION_MAJOR = "apiVersionMajor"
|
||||||
|
|
||||||
|
const val API_PUBLIC_ACCESS = "apiPublicAccess"
|
||||||
|
|
||||||
const val API_ITEMS_NUMBER = "prefer_api_items_number"
|
const val API_ITEMS_NUMBER = "prefer_api_items_number"
|
||||||
|
|
||||||
const val API_TIMEOUT = "api_timeout"
|
const val API_TIMEOUT = "api_timeout"
|
||||||
|
Reference in New Issue
Block a user