Compare commits
20
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf1b680b4a | ||
|
|
d81fb79b4f | ||
|
|
144067d5b6 | ||
|
|
8106faa45c | ||
|
|
d9ef301e0f | ||
|
|
90b52232ab | ||
|
|
0f000ea359 | ||
|
|
fb8f81a4c8 | ||
|
|
a76b3dd2a9 | ||
|
|
91aed5a777 | ||
|
|
8823cc6c6c | ||
|
|
74ef4da15b | ||
|
|
bd96c67788 | ||
|
|
da71de6806 | ||
|
|
0264da8ccc | ||
|
|
270d959ee0 | ||
|
|
6d11dfb80c | ||
|
|
4184bbb900 | ||
|
|
4c12c9d570 | ||
|
|
f4db02521d |
No files matched your search
+100
-4
@@ -1,21 +1,117 @@
|
|||||||
kind: pipeline
|
kind: pipeline
|
||||||
type: docker
|
type: docker
|
||||||
name: android
|
name: test
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: code-analysis
|
- name: AnylyseBuildTest
|
||||||
image: mingc/android-build-box:latest
|
image: mingc/android-build-box:latest
|
||||||
failure: ignore
|
failure: ignore
|
||||||
commands:
|
commands:
|
||||||
- ls -la
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Analysing..."
|
||||||
- ./gradlew sonarqube -Dsonar.projectKey=RFS2 -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\""
|
- ./gradlew sonarqube -Dsonar.projectKey=RFS2 -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$SONAR_LOGIN -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\""
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Building..."
|
||||||
|
- ./gradlew :androidApp:build -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Testing..."
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
environment:
|
environment:
|
||||||
SONAR_HOST_URL:
|
SONAR_HOST_URL:
|
||||||
from_secret: sonarScannerHostUrl
|
from_secret: sonarScannerHostUrl
|
||||||
SONAR_LOGIN:
|
SONAR_LOGIN:
|
||||||
from_secret: sonarScannerLogin
|
from_secret: sonarScannerLogin
|
||||||
|
trigger:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: Publish
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: createTag
|
||||||
|
image: ubuntu:latest
|
||||||
|
commands:
|
||||||
|
- apt-get update && apt-get install -y git
|
||||||
|
- ./build.sh --publish --from-ci
|
||||||
|
- git remote add pushing https://$GITEA_USR:$GITEA_PASS@gitea.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform.git
|
||||||
|
- git push pushing --tags
|
||||||
|
environment:
|
||||||
|
GITEA_USR:
|
||||||
|
from_secret: giteaUsr
|
||||||
|
GITEA_PASS:
|
||||||
|
from_secret: giteaPass
|
||||||
|
|
||||||
|
- name: scpFiles
|
||||||
|
image: appleboy/drone-scp
|
||||||
|
settings:
|
||||||
|
host: amine-louveau.fr
|
||||||
|
username: ubuntu
|
||||||
|
key:
|
||||||
|
from_secret: privateKey
|
||||||
|
port: 22
|
||||||
|
target: /home/ubuntu/
|
||||||
|
source: version.txt
|
||||||
|
|
||||||
|
- name: deploy
|
||||||
|
image: appleboy/drone-ssh
|
||||||
|
settings:
|
||||||
|
host: amine-louveau.fr
|
||||||
|
user: ubuntu
|
||||||
|
key:
|
||||||
|
from_secret: privateKey
|
||||||
|
command_timeout: 2m
|
||||||
|
script:
|
||||||
|
- cd /home/ubuntu
|
||||||
|
- sudo rm -rf /var/www/amine/version.txt
|
||||||
|
- sudo chown www-data:www-data ./version.txt
|
||||||
|
- sudo mv version.txt /var/www/amine/
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
event:
|
||||||
|
- promote
|
||||||
|
target:
|
||||||
|
- production
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: Release
|
||||||
|
|
||||||
|
steps:
|
||||||
- name: build
|
- name: build
|
||||||
image: mingc/android-build-box:latest
|
image: mingc/android-build-box:latest
|
||||||
commands:
|
commands:
|
||||||
- ./gradlew :androidApp:build -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
|
- echo "Generate APK"
|
||||||
|
- ./gradlew :androidApp:assembleGithubConfigRelease -PignoreGitVersion=true -P appLoginUrl="\"URL\"" -P appLoginUsername="\"LOGIN\"" -P appLoginPassword="\"PASS\"" -P pushCache=false
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Get Key"
|
||||||
|
- wget https://amine-louveau.fr/key
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Zipalign"
|
||||||
|
- $ANDROID_HOME/build-tools/31.0.0/zipalign -f -v 4 androidApp/build/outputs/apk/githubConfig/release/androidApp-githubConfig-release-unsigned.apk androidApp/build/outputs/apk/githubConfig/release/android-prod-released-ziped.apk
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Sign"
|
||||||
|
- $ANDROID_HOME/build-tools/31.0.0/apksigner sign -v --out signed.apk --ks ./key --ks-key-alias $YOUR_KEY_ALIAS --ks-pass pass:$YOUR_KEYSTORE_PASSWORD --v1-signing-enabled true --v2-signing-enabled true androidApp/build/outputs/apk/githubConfig/release/android-prod-released-ziped.apk
|
||||||
|
- echo "---------------------------------------------------------"
|
||||||
|
- echo "Verify"
|
||||||
|
- $ANDROID_HOME/build-tools/31.0.0/apksigner verify signed.apk
|
||||||
|
environment:
|
||||||
|
YOUR_KEYSTORE_PASSWORD:
|
||||||
|
from_secret: keyPass
|
||||||
|
YOUR_KEY_ALIAS:
|
||||||
|
from_secret: keyAlias
|
||||||
|
|
||||||
|
- name: gitea_release
|
||||||
|
image: plugins/gitea-release
|
||||||
|
settings:
|
||||||
|
api_key:
|
||||||
|
from_secret: giteaAPI
|
||||||
|
base_url: https://gitea.amine-louveau.fr
|
||||||
|
files: signed.apk
|
||||||
|
trigger:
|
||||||
|
event:
|
||||||
|
- tag
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
# ReaderForSelfoss-multiplatform
|
# ReaderForSelfoss-multiplatform [](https://build.amine-louveau.fr/Louvorg/ReaderForSelfoss-multiplatform)
|
||||||
|
|
||||||
[](https://crowdin.com/project/readerforselfoss)
|
[](https://crowdin.com/project/readerforselfoss)
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ fun gitVersion(): String {
|
|||||||
println("Tag found on current commit")
|
println("Tag found on current commit")
|
||||||
execWithOutput("git -C ../ describe --contains HEAD")
|
execWithOutput("git -C ../ describe --contains HEAD")
|
||||||
}
|
}
|
||||||
return process.replace("'", "").substring(1).replace("\\.", "").trim()
|
return process.replace("^0", "").replace("'", "").substring(1).replace("\\.", "").trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun versionCodeFromGit(): Int {
|
fun versionCodeFromGit(): Int {
|
||||||
@@ -101,6 +101,7 @@ android {
|
|||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = "1.8"
|
jvmTarget = "1.8"
|
||||||
}
|
}
|
||||||
|
namespace = "bou.amine.apps.readerforselfossv2.android"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,8 +167,6 @@ dependencies {
|
|||||||
implementation("com.mikepenz:materialdrawer:8.4.5")
|
implementation("com.mikepenz:materialdrawer:8.4.5")
|
||||||
|
|
||||||
// Themes
|
// Themes
|
||||||
implementation("com.52inc:scoops:1.0.0")
|
|
||||||
implementation("com.jaredrummler:colorpicker:1.1.0")
|
|
||||||
implementation("com.github.rubensousa:floatingtoolbar:1.5.1")
|
implementation("com.github.rubensousa:floatingtoolbar:1.5.1")
|
||||||
|
|
||||||
// Pager
|
// Pager
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
package="bou.amine.apps.readerforselfossv2.android">
|
|
||||||
|
|
||||||
<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" />
|
||||||
|
|||||||
+2
-7
@@ -9,11 +9,10 @@ import androidx.constraintlayout.widget.ConstraintLayout
|
|||||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityAddSourceBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityAddSourceBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid
|
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
|
||||||
import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException
|
import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import com.ftinc.scoop.Scoop
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -42,10 +41,6 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
|
|||||||
|
|
||||||
setContentView(view)
|
setContentView(view)
|
||||||
|
|
||||||
val scoop = Scoop.getInstance()
|
|
||||||
scoop.bind(this, Toppings.PRIMARY.value, binding.toolbar)
|
|
||||||
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
|
|
||||||
|
|
||||||
val drawable = binding.nameInput.background
|
val drawable = binding.nameInput.background
|
||||||
drawable.setTint(appColors.colorAccent)
|
drawable.setTint(appColors.colorAccent)
|
||||||
|
|
||||||
@@ -84,7 +79,7 @@ class AddSourceActivity : AppCompatActivity(), DIAware {
|
|||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
val baseUrl = appSettingsService.getBaseUrl()
|
val baseUrl = appSettingsService.getBaseUrl()
|
||||||
if (baseUrl.isEmpty() || !baseUrl.isBaseUrlValid(this@AddSourceActivity)) {
|
if (baseUrl.isEmpty() || baseUrl.isBaseUrlInvalid()) {
|
||||||
mustLoginToAddSource()
|
mustLoginToAddSource()
|
||||||
} else {
|
} else {
|
||||||
handleSpoutsSpinner(binding.spoutsSpinner, binding.progress, binding.formContainer)
|
handleSpoutsSpinner(binding.spoutsSpinner, binding.progress, binding.formContainer)
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||||||
import androidx.appcompat.app.ActionBarDrawerToggle
|
import androidx.appcompat.app.ActionBarDrawerToggle
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.core.view.doOnNextLayout
|
import androidx.core.view.doOnNextLayout
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
@@ -43,7 +46,6 @@ import com.ashokvarma.bottomnavigation.BottomNavigationItem
|
|||||||
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
import com.ashokvarma.bottomnavigation.TextBadgeItem
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
import com.ftinc.scoop.Scoop
|
|
||||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||||
import com.mikepenz.materialdrawer.holder.BadgeStyle
|
import com.mikepenz.materialdrawer.holder.BadgeStyle
|
||||||
import com.mikepenz.materialdrawer.holder.ColorHolder
|
import com.mikepenz.materialdrawer.holder.ColorHolder
|
||||||
@@ -95,6 +97,7 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
private val settingsLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
private val settingsLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
appSettingsService.refreshUserSettings()
|
appSettingsService.refreshUserSettings()
|
||||||
|
AppCompatDelegate.setDefaultNightMode(if (appSettingsService.isDarkThemeEnabled()) MODE_NIGHT_YES else MODE_NIGHT_NO)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val di by closestDI()
|
override val di by closestDI()
|
||||||
@@ -126,8 +129,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
setContentView(view)
|
setContentView(view)
|
||||||
|
|
||||||
handleThemeBinding()
|
|
||||||
|
|
||||||
setSupportActionBar(binding.toolBar)
|
setSupportActionBar(binding.toolBar)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
supportActionBar?.setHomeButtonEnabled(true)
|
supportActionBar?.setHomeButtonEnabled(true)
|
||||||
@@ -142,13 +143,13 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
handleSwipeRefreshLayout()
|
handleSwipeRefreshLayout()
|
||||||
|
|
||||||
getElementsAccordingToTab()
|
|
||||||
|
|
||||||
|
|
||||||
|
if (appSettingsService.isItemCachingEnabled()) {
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
repository.tryToCacheItemsAndGetNewOnes()
|
repository.tryToCacheItemsAndGetNewOnes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleSwipeRefreshLayout() {
|
private fun handleSwipeRefreshLayout() {
|
||||||
binding.swipeRefreshLayout.setColorSchemeResources(
|
binding.swipeRefreshLayout.setColorSchemeResources(
|
||||||
@@ -233,27 +234,24 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
tabNewBadge = TextBadgeItem()
|
tabNewBadge = TextBadgeItem()
|
||||||
.setText("")
|
.setText("")
|
||||||
.setHideOnSelect(false).hide(false)
|
.setHideOnSelect(false).hide(false)
|
||||||
.setBackgroundColor(appColors.colorPrimary)
|
|
||||||
tabArchiveBadge = TextBadgeItem()
|
tabArchiveBadge = TextBadgeItem()
|
||||||
.setText("")
|
.setText("")
|
||||||
.setHideOnSelect(false).hide(false)
|
.setHideOnSelect(false).hide(false)
|
||||||
.setBackgroundColor(appColors.colorPrimary)
|
|
||||||
tabStarredBadge = TextBadgeItem()
|
tabStarredBadge = TextBadgeItem()
|
||||||
.setText("")
|
.setText("")
|
||||||
.setHideOnSelect(false).hide(false)
|
.setHideOnSelect(false).hide(false)
|
||||||
.setBackgroundColor(appColors.colorPrimary)
|
|
||||||
|
|
||||||
val tabNew =
|
val tabNew =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
R.drawable.ic_tab_fiber_new_black_24dp,
|
R.drawable.ic_tab_fiber_new_black_24dp,
|
||||||
getString(R.string.tab_new)
|
getString(R.string.tab_new)
|
||||||
).setActiveColor(appColors.colorAccent)
|
)
|
||||||
.setBadgeItem(tabNewBadge)
|
.setBadgeItem(tabNewBadge)
|
||||||
val tabArchive =
|
val tabArchive =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
R.drawable.ic_tab_archive_black_24dp,
|
R.drawable.ic_tab_archive_black_24dp,
|
||||||
getString(R.string.tab_read)
|
getString(R.string.tab_read)
|
||||||
).setActiveColor(appColors.colorAccentDark)
|
)
|
||||||
.setBadgeItem(tabArchiveBadge)
|
.setBadgeItem(tabArchiveBadge)
|
||||||
val tabStarred =
|
val tabStarred =
|
||||||
BottomNavigationItem(
|
BottomNavigationItem(
|
||||||
@@ -269,7 +267,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
.setFirstSelectedPosition(0)
|
.setFirstSelectedPosition(0)
|
||||||
.initialise()
|
.initialise()
|
||||||
binding.bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING)
|
binding.bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING)
|
||||||
binding.bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_STATIC)
|
|
||||||
|
|
||||||
if (fromTabShortcut) {
|
if (fromTabShortcut) {
|
||||||
binding.bottomBar.selectTab(elementsShown.position - 1)
|
binding.bottomBar.selectTab(elementsShown.position - 1)
|
||||||
@@ -283,8 +280,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
|
|
||||||
handleDrawerItems()
|
handleDrawerItems()
|
||||||
|
|
||||||
handleThemeUpdate()
|
|
||||||
|
|
||||||
reloadLayoutManager()
|
reloadLayoutManager()
|
||||||
|
|
||||||
if (appSettingsService.isInfiniteLoadingEnabled()) {
|
if (appSettingsService.isInfiniteLoadingEnabled()) {
|
||||||
@@ -309,20 +304,6 @@ class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAwar
|
|||||||
customTabActivityHelper.unbindCustomTabsService(this)
|
customTabActivityHelper.unbindCustomTabsService(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleThemeBinding() {
|
|
||||||
val scoop = Scoop.getInstance()
|
|
||||||
scoop.bind(this, Toppings.PRIMARY.value, binding.toolBar)
|
|
||||||
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleThemeUpdate() {
|
|
||||||
|
|
||||||
val scoop = Scoop.getInstance()
|
|
||||||
scoop.update(Toppings.PRIMARY.value, appColors.colorPrimary)
|
|
||||||
|
|
||||||
scoop.update(Toppings.PRIMARY_DARK.value, appColors.colorPrimaryDark)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun initDrawer() {
|
private fun initDrawer() {
|
||||||
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
|
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
|
||||||
override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) {
|
override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) {
|
||||||
|
|||||||
@@ -12,9 +12,10 @@ import android.view.inputmethod.EditorInfo
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding
|
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
||||||
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlValid
|
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import com.mikepenz.aboutlibraries.LibsBuilder
|
import com.mikepenz.aboutlibraries.LibsBuilder
|
||||||
@@ -41,6 +42,8 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
appColors = AppColors(this@LoginActivity)
|
appColors = AppColors(this@LoginActivity)
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
AppCompatDelegate.setDefaultNightMode(if (appSettingsService.isDarkThemeEnabled()) AppCompatDelegate.MODE_NIGHT_YES else AppCompatDelegate.MODE_NIGHT_NO)
|
||||||
|
|
||||||
binding = ActivityLoginBinding.inflate(layoutInflater)
|
binding = ActivityLoginBinding.inflate(layoutInflater)
|
||||||
val view = binding.root
|
val view = binding.root
|
||||||
|
|
||||||
@@ -115,14 +118,14 @@ class LoginActivity : AppCompatActivity(), DIAware {
|
|||||||
binding.passwordView.error = null
|
binding.passwordView.error = null
|
||||||
|
|
||||||
// Store values at the time of the login attempt.
|
// Store values at the time of the login attempt.
|
||||||
val url = binding.urlView.text.toString()
|
val url = binding.urlView.text.toString().trim()
|
||||||
val login = binding.loginView.text.toString()
|
val login = binding.loginView.text.toString().trim()
|
||||||
val password = binding.passwordView.text.toString()
|
val password = binding.passwordView.text.toString().trim()
|
||||||
|
|
||||||
var cancel = false
|
var cancel = false
|
||||||
var focusView: View? = null
|
var focusView: View? = null
|
||||||
|
|
||||||
if (!url.isBaseUrlValid(this@LoginActivity)) {
|
if (url.isBaseUrlInvalid()) {
|
||||||
binding.urlView.error = getString(R.string.login_url_problem)
|
binding.urlView.error = getString(R.string.login_url_problem)
|
||||||
focusView = binding.urlView
|
focusView = binding.urlView
|
||||||
cancel = true
|
cancel = true
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import bou.amine.apps.readerforselfossv2.repository.Repository
|
|||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
import com.ftinc.scoop.Scoop
|
|
||||||
import com.github.ln_12.library.ConnectivityStatus
|
import com.github.ln_12.library.ConnectivityStatus
|
||||||
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
|
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
|
||||||
import com.mikepenz.materialdrawer.util.DrawerImageLoader
|
import com.mikepenz.materialdrawer.util.DrawerImageLoader
|
||||||
@@ -54,8 +53,6 @@ class MyApp : MultiDexApplication(), DIAware {
|
|||||||
|
|
||||||
initDrawerImageLoader()
|
initDrawerImageLoader()
|
||||||
|
|
||||||
initTheme()
|
|
||||||
|
|
||||||
tryToHandleBug()
|
tryToHandleBug()
|
||||||
|
|
||||||
handleNotificationChannels()
|
handleNotificationChannels()
|
||||||
@@ -117,14 +114,6 @@ class MyApp : MultiDexApplication(), DIAware {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initTheme() {
|
|
||||||
Scoop.waffleCone()
|
|
||||||
.addFlavor(getString(R.string.default_theme), R.style.NoBar, true)
|
|
||||||
.addFlavor(getString(R.string.default_dark_theme), R.style.NoBarDark, false)
|
|
||||||
.setSharedPreferences(PreferenceManager.getDefaultSharedPreferences(this))
|
|
||||||
.initialize()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun tryToHandleBug() {
|
private fun tryToHandleBug() {
|
||||||
val oldHandler = Thread.getDefaultUncaughtExceptionHandler()
|
val oldHandler = Thread.getDefaultUncaughtExceptionHandler()
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
|||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import com.ftinc.scoop.Scoop
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -62,10 +61,6 @@ class ReaderActivity : AppCompatActivity(), DIAware {
|
|||||||
|
|
||||||
setContentView(view)
|
setContentView(view)
|
||||||
|
|
||||||
val scoop = Scoop.getInstance()
|
|
||||||
scoop.bind(this, Toppings.PRIMARY.value, binding.toolBar)
|
|
||||||
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
|
|
||||||
|
|
||||||
setSupportActionBar(binding.toolBar)
|
setSupportActionBar(binding.toolBar)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
|||||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
||||||
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
import bou.amine.apps.readerforselfossv2.model.SelfossModel
|
||||||
import bou.amine.apps.readerforselfossv2.repository.Repository
|
import bou.amine.apps.readerforselfossv2.repository.Repository
|
||||||
import com.ftinc.scoop.Scoop
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -33,10 +32,6 @@ class SourcesActivity : AppCompatActivity(), DIAware {
|
|||||||
binding = ActivitySourcesBinding.inflate(layoutInflater)
|
binding = ActivitySourcesBinding.inflate(layoutInflater)
|
||||||
val view = binding.root
|
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)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
setContentView(view)
|
setContentView(view)
|
||||||
|
|||||||
+2
-2
@@ -30,7 +30,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
updateItems(this.items)
|
updateItems(this.items)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unmarkSnackbar(i: SelfossModel.Item, position: Int) {
|
private fun unmarkSnackbar(position: Int) {
|
||||||
val s = Snackbar
|
val s = Snackbar
|
||||||
.make(
|
.make(
|
||||||
app.findViewById(R.id.coordLayout),
|
app.findViewById(R.id.coordLayout),
|
||||||
@@ -87,7 +87,7 @@ abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapte
|
|||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
}
|
}
|
||||||
if (showSnackbar) {
|
if (showSnackbar) {
|
||||||
unmarkSnackbar(i, position)
|
unmarkSnackbar(position)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-22
@@ -22,7 +22,6 @@ import bou.amine.apps.readerforselfossv2.android.databinding.ActivitySettingsBin
|
|||||||
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
import bou.amine.apps.readerforselfossv2.android.themes.AppColors
|
||||||
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
import bou.amine.apps.readerforselfossv2.android.themes.Toppings
|
||||||
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
|
||||||
import com.ftinc.scoop.Scoop
|
|
||||||
|
|
||||||
private const val TITLE_TAG = "settingsActivityTitle"
|
private const val TITLE_TAG = "settingsActivityTitle"
|
||||||
|
|
||||||
@@ -31,15 +30,8 @@ class SettingsActivity : AppCompatActivity(),
|
|||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", false)) {
|
|
||||||
setTheme(R.style.NoBarDark)
|
|
||||||
}
|
|
||||||
val binding = ActivitySettingsBinding.inflate(layoutInflater)
|
val binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
val scoop = Scoop.getInstance()
|
|
||||||
scoop.bind(this, Toppings.PRIMARY.value, binding.toolbar)
|
|
||||||
scoop.bindStatusBar(this, Toppings.PRIMARY_DARK.value)
|
|
||||||
|
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
supportFragmentManager
|
supportFragmentManager
|
||||||
@@ -171,20 +163,6 @@ class SettingsActivity : AppCompatActivity(),
|
|||||||
setPreferencesFromResource(R.xml.pref_theme, rootKey)
|
setPreferencesFromResource(R.xml.pref_theme, rootKey)
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
|
||||||
inflater.inflate(R.menu.settings_theme, menu)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
||||||
val id = item.itemId
|
|
||||||
if (id == R.id.clear) {
|
|
||||||
AppColors.resetColors()
|
|
||||||
requireActivity().recreate()
|
|
||||||
}
|
|
||||||
return super.onOptionsItemSelected(item)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class LinksPreferenceFragment : PreferenceFragmentCompat() {
|
class LinksPreferenceFragment : PreferenceFragmentCompat() {
|
||||||
|
|||||||
+4
-50
@@ -7,66 +7,20 @@ import com.russhwolf.settings.Settings
|
|||||||
|
|
||||||
class AppColors(a: Activity) {
|
class AppColors(a: Activity) {
|
||||||
|
|
||||||
@ColorInt val colorPrimary: Int
|
@ColorInt val colorPrimary: Int = a.resources.getColor(R.color.colorPrimary)
|
||||||
@ColorInt val colorPrimaryDark: Int
|
@ColorInt val colorPrimaryDark: Int = a.resources.getColor(R.color.colorPrimaryDark)
|
||||||
@ColorInt val colorAccent: Int
|
@ColorInt val colorAccent: Int = a.resources.getColor(R.color.colorAccent)
|
||||||
@ColorInt val colorAccentDark: Int
|
@ColorInt val colorAccentDark: Int = a.resources.getColor(R.color.colorAccentDark)
|
||||||
@ColorInt val colorBackground: Int
|
|
||||||
@ColorInt val textColor: Int
|
|
||||||
val isDarkTheme: Boolean
|
val isDarkTheme: Boolean
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val settings = Settings()
|
val settings = Settings()
|
||||||
|
|
||||||
colorPrimary =
|
|
||||||
settings.getInt(
|
|
||||||
"color_primary",
|
|
||||||
a.resources.getColor(R.color.colorPrimary)
|
|
||||||
)
|
|
||||||
colorPrimaryDark =
|
|
||||||
settings.getInt(
|
|
||||||
"color_primary_dark",
|
|
||||||
a.resources.getColor(R.color.colorPrimaryDark)
|
|
||||||
)
|
|
||||||
colorAccent =
|
|
||||||
settings.getInt(
|
|
||||||
"color_accent",
|
|
||||||
a.resources.getColor(R.color.colorAccent)
|
|
||||||
)
|
|
||||||
colorAccentDark =
|
|
||||||
settings.getInt(
|
|
||||||
"color_accent_dark",
|
|
||||||
a.resources.getColor(R.color.colorAccentDark)
|
|
||||||
)
|
|
||||||
isDarkTheme =
|
isDarkTheme =
|
||||||
settings.getBoolean(
|
settings.getBoolean(
|
||||||
"dark_theme",
|
"dark_theme",
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
|
||||||
colorBackground = if (isDarkTheme) {
|
|
||||||
a.setTheme(R.style.NoBarDark)
|
|
||||||
a.resources.getColor(R.color.darkBackground)
|
|
||||||
} else {
|
|
||||||
a.setTheme(R.style.NoBar)
|
|
||||||
a.resources.getColor(R.color.grey_50)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
textColor = if (isDarkTheme) {
|
|
||||||
a.resources.getColor(R.color.white)
|
|
||||||
} else {
|
|
||||||
a.resources.getColor(R.color.grey_900)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun resetColors() {
|
|
||||||
val settings = Settings()
|
|
||||||
settings.remove("color_primary")
|
|
||||||
settings.remove("color_primary_dark")
|
|
||||||
settings.remove("color_accent")
|
|
||||||
settings.remove("color_accent_dark")
|
|
||||||
settings.remove("dark_theme")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+2
-2
@@ -163,7 +163,7 @@ private fun openInBrowser(linkDecoded: String, app: Activity) {
|
|||||||
fun String.isUrlValid(): Boolean =
|
fun String.isUrlValid(): Boolean =
|
||||||
this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches()
|
this.toHttpUrlOrNull() != null && Patterns.WEB_URL.matcher(this).matches()
|
||||||
|
|
||||||
fun String.isBaseUrlValid(ctx: Context): Boolean {
|
fun String.isBaseUrlInvalid(): Boolean {
|
||||||
val baseUrl = this.toHttpUrlOrNull()
|
val baseUrl = this.toHttpUrlOrNull()
|
||||||
var existsAndEndsWithSlash = false
|
var existsAndEndsWithSlash = false
|
||||||
if (baseUrl != null) {
|
if (baseUrl != null) {
|
||||||
@@ -171,7 +171,7 @@ fun String.isBaseUrlValid(ctx: Context): Boolean {
|
|||||||
existsAndEndsWithSlash = "" == pathSegments[pathSegments.size - 1]
|
existsAndEndsWithSlash = "" == pathSegments[pathSegments.size - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
return Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash
|
return !(Patterns.WEB_URL.matcher(this).matches() && existsAndEndsWithSlash)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.openInBrowserAsNewTask(i: SelfossModel.Item) {
|
fun Context.openInBrowserAsNewTask(i: SelfossModel.Item) {
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item
|
<item>
|
||||||
android:drawable="@color/ic_launcher_background"/>
|
<shape android:shape="rectangle" >
|
||||||
|
<solid android:color="?attr/colorSurface" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
|
||||||
<item>
|
<item>
|
||||||
<bitmap
|
<bitmap
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
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"
|
||||||
app:theme="@style/ToolBarStyle"
|
|
||||||
app:popupTheme="?attr/toolbarPopupTheme" />
|
/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
@@ -107,8 +107,7 @@
|
|||||||
app:layout_constraintTop_toBottomOf="@+id/tags"
|
app:layout_constraintTop_toBottomOf="@+id/tags"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"/>
|
||||||
android:theme="@style/App.Spinner"/>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:text="@string/add_source_save"
|
android:text="@string/add_source_save"
|
||||||
|
|||||||
@@ -32,8 +32,8 @@
|
|||||||
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"
|
||||||
app:theme="@style/ToolBarStyle"
|
|
||||||
app:popupTheme="?attr/toolbarPopupTheme" />
|
/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
@@ -78,10 +78,12 @@
|
|||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
<com.ashokvarma.bottomnavigation.BottomNavigationBar
|
<com.ashokvarma.bottomnavigation.BottomNavigationBar
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:id="@+id/bottomBar"
|
android:id="@+id/bottomBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="60dp"/>
|
android:layout_height="60dp"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
app:bnbActiveColor="@color/colorAccent"
|
||||||
|
app:bnbBackgroundColor="?attr/bottomBarBackground" />
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
|
<com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
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"
|
||||||
app:popupTheme="?attr/toolbarPopupTheme"
|
|
||||||
app:theme="@style/ToolBarStyle" />
|
/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
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"
|
||||||
app:theme="@style/ToolBarStyle"
|
|
||||||
app:popupTheme="?attr/toolbarPopupTheme" />
|
/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|||||||
@@ -17,8 +17,8 @@
|
|||||||
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"
|
||||||
app:popupTheme="?attr/toolbarPopupTheme"
|
|
||||||
app:theme="@style/ToolBarStyle" />
|
/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
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"
|
||||||
android:theme="@style/ToolBarStyle" />
|
/>
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
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"
|
||||||
app:theme="@style/ToolBarStyle"
|
|
||||||
app:popupTheme="?attr/toolbarPopupTheme" />
|
/>
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/clear"
|
|
||||||
android:icon="@drawable/ic_history_white_24dp"
|
|
||||||
android:title="@string/drawer_action_clear"
|
|
||||||
app:showAsAction="ifRoom" />
|
|
||||||
</menu>
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<resources>
|
||||||
|
<style name="NoBar" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||||
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
<item name="colorAccentDark">@color/colorAccentDark</item>
|
||||||
|
<item name="cardBackgroundColor">@color/white</item>
|
||||||
|
<item name="materialDrawerHeaderStyle">@style/Widget.MaterialDrawerHeaderStyle</item>
|
||||||
|
<item name="preferenceTheme">@style/PreferenceStyle</item>
|
||||||
|
<item name="android:statusBarColor">#282828</item>
|
||||||
|
<item name="bottomBarBackground">#282828</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
@@ -2,5 +2,6 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<declare-styleable name="Theme">
|
<declare-styleable name="Theme">
|
||||||
<attr name="colorAccentDark" format="reference|color" />
|
<attr name="colorAccentDark" format="reference|color" />
|
||||||
|
<attr name="bottomBarBackground" format="reference|color" />
|
||||||
</declare-styleable>
|
</declare-styleable>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -11,6 +11,4 @@
|
|||||||
<color name="refresh_progress_1">@color/colorAccentDark</color>
|
<color name="refresh_progress_1">@color/colorAccentDark</color>
|
||||||
<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="darkBackground">#303030</color>
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -4,70 +4,20 @@
|
|||||||
<item name="android:windowBackground">@drawable/background_splash</item>
|
<item name="android:windowBackground">@drawable/background_splash</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="NoBar" parent="Theme.MaterialComponents.Light.NoActionBar">
|
<style name="NoBar" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
||||||
<item name="colorPrimary">@color/colorPrimary</item>
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
<item name="colorAccent">@color/colorAccent</item>
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
<item name="colorAccentDark">@color/colorAccentDark</item>
|
<item name="colorAccentDark">@color/colorAccentDark</item>
|
||||||
<item name="cardBackgroundColor">@color/white</item>
|
<item name="cardBackgroundColor">@color/white</item>
|
||||||
<item name="android:colorBackground">@color/grey_50</item>
|
|
||||||
<item name="colorSurface">@color/grey_50</item>
|
|
||||||
<item name="android:textColorPrimary">@color/grey_900</item>
|
|
||||||
<item name="android:textColorSecondary">@color/grey_400</item>
|
|
||||||
<item name="materialDrawerStyle">@style/App.materialDrawerStyle</item>
|
|
||||||
<item name="materialDrawerHeaderStyle">@style/Widget.MaterialDrawerHeaderStyle</item>
|
<item name="materialDrawerHeaderStyle">@style/Widget.MaterialDrawerHeaderStyle</item>
|
||||||
<item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item>
|
|
||||||
<item name="preferenceTheme">@style/PreferenceStyle</item>
|
<item name="preferenceTheme">@style/PreferenceStyle</item>
|
||||||
</style>
|
<item name="android:statusBarColor">?attr/colorPrimary</item>
|
||||||
|
<item name="bottomBarBackground">@color/white</item>
|
||||||
<style name="NoBarDark" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
|
||||||
<item name="colorPrimary">@color/colorPrimary</item>
|
|
||||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
|
||||||
<item name="colorAccent">@color/colorAccent</item>
|
|
||||||
<item name="colorAccentDark">@color/colorAccentDark</item>
|
|
||||||
<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>
|
|
||||||
<item name="materialDrawerStyle">@style/App.materialDrawerStyle</item>
|
|
||||||
<item name="materialDrawerHeaderStyle">@style/Widget.MaterialDrawerHeaderStyle</item>
|
|
||||||
<item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat.Dark</item>
|
|
||||||
<item name="preferenceTheme">@style/PreferenceStyle</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!-- ToolBar -->
|
|
||||||
<style name="ToolBarStyle" parent="Theme.AppCompat">
|
|
||||||
<item name="android:textColorPrimary">@color/white</item>
|
|
||||||
<item name="android:textColorSecondary">@color/white</item>
|
|
||||||
<item name="actionMenuTextColor">@color/white</item>
|
|
||||||
<!--<item name="actionOverflowButtonStyle">@style/ActionButtonOverflowStyle</item>
|
|
||||||
<item name="drawerArrowStyle">@style/DrawerArrowStyle</item>-->
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!-- Material Drawer Theme -->
|
|
||||||
<style name="App.materialDrawerStyle" parent="@style/Widget.MaterialDrawerStyle">
|
|
||||||
<item name="materialDrawerPrimaryIcon">?android:textColorPrimary</item>
|
|
||||||
<item name="materialDrawerSecondaryIcon">?android:textColorPrimary</item>
|
|
||||||
<item name="materialDrawerSecondaryText">?android:textColorPrimary</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Preference Theme -->
|
<!-- Preference Theme -->
|
||||||
<style name="PreferenceStyle" parent="@style/PreferenceThemeOverlay">
|
<style name="PreferenceStyle" parent="@style/PreferenceThemeOverlay">
|
||||||
<item name="android:tint">?android:textColorPrimary</item>
|
<item name="android:tint">?attr/colorOnSurface</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Spinner Theme -->
|
|
||||||
<style name="App.Spinner" parent="Widget.AppCompat.Light.DropDownItem.Spinner">
|
|
||||||
<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>
|
</resources>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<EditTextPreference
|
<EditTextPreference
|
||||||
android:defaultValue="200"
|
android:defaultValue="20"
|
||||||
android:inputType="number"
|
android:inputType="number"
|
||||||
android:key="prefer_api_items_number"
|
android:key="prefer_api_items_number"
|
||||||
android:selectAllOnFocus="true"
|
android:selectAllOnFocus="true"
|
||||||
|
|||||||
@@ -8,28 +8,4 @@
|
|||||||
android:key="dark_theme"
|
android:key="dark_theme"
|
||||||
app:iconSpaceReserved="false"
|
app:iconSpaceReserved="false"
|
||||||
android:title="Dark theme" />
|
android:title="Dark theme" />
|
||||||
|
|
||||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
|
||||||
android:defaultValue="@color/colorPrimary"
|
|
||||||
android:key="color_primary"
|
|
||||||
app:iconSpaceReserved="false"
|
|
||||||
android:title="Primary color"/>
|
|
||||||
|
|
||||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
|
||||||
android:defaultValue="@color/colorPrimaryDark"
|
|
||||||
android:key="color_primary_dark"
|
|
||||||
app:iconSpaceReserved="false"
|
|
||||||
android:title="Primary dark color"/>
|
|
||||||
|
|
||||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
|
||||||
android:defaultValue="@color/colorAccent"
|
|
||||||
android:key="color_accent"
|
|
||||||
app:iconSpaceReserved="false"
|
|
||||||
android:title="Accent color"/>
|
|
||||||
|
|
||||||
<com.jaredrummler.android.colorpicker.ColorPreferenceCompat
|
|
||||||
android:defaultValue="@color/colorAccentDark"
|
|
||||||
android:key="color_accent_dark"
|
|
||||||
app:iconSpaceReserved="false"
|
|
||||||
android:title="Accent dark color"/>
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
+1
-1
@@ -6,7 +6,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
|
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
|
||||||
classpath("com.android.tools.build:gradle:7.2.2")
|
classpath("com.android.tools.build:gradle:7.3.0")
|
||||||
|
|
||||||
// sonarquve
|
// sonarquve
|
||||||
classpath("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513")
|
classpath("org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513")
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ VERSION="${INITIAL_VERSION}${TODAYS_VERSION}"
|
|||||||
|
|
||||||
PARAMS_EXCEPT_PUBLISH=$(echo $1 | sed 's/\-\-publish//')
|
PARAMS_EXCEPT_PUBLISH=$(echo $1 | sed 's/\-\-publish//')
|
||||||
|
|
||||||
./version.sh ${VERSION} ${PARAMS_EXCEPT_PUBLISH}
|
./version.sh ${VERSION} ${PARAMS_EXCEPT_PUBLISH} $@
|
||||||
|
|
||||||
if [[ "$@" == *'--publish'* ]]
|
if [[ "$@" == *'--publish'* ]]
|
||||||
then
|
then
|
||||||
./publish-version.sh ${VERSION}
|
./publish-version.sh ${VERSION} $@
|
||||||
else
|
else
|
||||||
echo "Did not publish. If you wanted to do so, call the script with \"--publish\" or \"--publish-local\"."
|
echo "Did not publish. If you wanted to do so, call the script with \"--publish\" or \"--publish-local\"."
|
||||||
fi
|
fi
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#Wed Feb 09 17:05:19 CET 2022
|
#Wed Feb 09 17:05:19 CET 2022
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
+5
-1
@@ -5,7 +5,11 @@
|
|||||||
rm -f version.txt
|
rm -f version.txt
|
||||||
printf "versionName=$1-github\nversionCode=$1" >> version.txt
|
printf "versionName=$1-github\nversionCode=$1" >> version.txt
|
||||||
|
|
||||||
|
if [[ "$@" == *'--from-ci'* ]]
|
||||||
|
then
|
||||||
|
echo "File created. HANDLE IN CI"
|
||||||
|
else
|
||||||
# You'll need to change server as your server and define a VERSION_PATH.
|
# You'll need to change server as your server and define a VERSION_PATH.
|
||||||
scp version.txt server:$VERSION_PATH
|
scp version.txt server:$VERSION_PATH
|
||||||
|
|
||||||
rm version.txt
|
rm version.txt
|
||||||
|
fi
|
||||||
@@ -28,12 +28,12 @@ kotlin {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
val commonMain by getting {
|
val commonMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("io.ktor:ktor-client-core:2.0.1")
|
implementation("io.ktor:ktor-client-core:2.1.1")
|
||||||
implementation("io.ktor:ktor-client-content-negotiation:2.0.1")
|
implementation("io.ktor:ktor-client-content-negotiation:2.1.1")
|
||||||
implementation("io.ktor:ktor-serialization-kotlinx-json:2.0.1")
|
implementation("io.ktor:ktor-serialization-kotlinx-json:2.1.1")
|
||||||
implementation("io.ktor:ktor-client-logging:2.0.1")
|
implementation("io.ktor:ktor-client-logging:2.1.1")
|
||||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
|
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0")
|
||||||
implementation("io.ktor:ktor-client-auth:2.0.1")
|
implementation("io.ktor:ktor-client-auth:2.1.1")
|
||||||
implementation("org.jsoup:jsoup:1.14.3")
|
implementation("org.jsoup:jsoup:1.14.3")
|
||||||
|
|
||||||
//Dependency Injection
|
//Dependency Injection
|
||||||
@@ -60,7 +60,7 @@ kotlin {
|
|||||||
}
|
}
|
||||||
val androidMain by getting {
|
val androidMain by getting {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("io.ktor:ktor-client-android:2.0.1")
|
implementation("io.ktor:ktor-client-okhttp:2.1.1")
|
||||||
|
|
||||||
// Sql
|
// Sql
|
||||||
implementation(SqlDelight.android)
|
implementation(SqlDelight.android)
|
||||||
@@ -94,7 +94,7 @@ kotlin {
|
|||||||
iosX64Test.dependsOn(this)
|
iosX64Test.dependsOn(this)
|
||||||
iosArm64Test.dependsOn(this)
|
iosArm64Test.dependsOn(this)
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("io.ktor:ktor-client-ios:2.0.1")
|
implementation("io.ktor:ktor-client-ios:2.1.1")
|
||||||
}
|
}
|
||||||
//iosSimulatorArm64Test.dependsOn(this)
|
//iosSimulatorArm64Test.dependsOn(this)
|
||||||
}
|
}
|
||||||
@@ -112,6 +112,7 @@ android {
|
|||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
namespace = "bou.amine.apps.readerforselfossv2"
|
||||||
}
|
}
|
||||||
|
|
||||||
sqldelight {
|
sqldelight {
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest package="bou.amine.apps.readerforselfossv2" />
|
<manifest />
|
||||||
@@ -2,7 +2,14 @@ package bou.amine.apps.readerforselfossv2.model
|
|||||||
|
|
||||||
import bou.amine.apps.readerforselfossv2.utils.DateUtils
|
import bou.amine.apps.readerforselfossv2.utils.DateUtils
|
||||||
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
import bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveKind
|
||||||
|
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlinx.serialization.json.*
|
||||||
|
|
||||||
class SelfossModel {
|
class SelfossModel {
|
||||||
|
|
||||||
@@ -50,6 +57,7 @@ class SelfossModel {
|
|||||||
data class Source(
|
data class Source(
|
||||||
val id: Int,
|
val id: Int,
|
||||||
val title: String,
|
val title: String,
|
||||||
|
@Serializable(with = TagsListSerializer::class)
|
||||||
val tags: List<String>,
|
val tags: List<String>,
|
||||||
val spout: String,
|
val spout: String,
|
||||||
val error: String,
|
val error: String,
|
||||||
@@ -62,12 +70,15 @@ class SelfossModel {
|
|||||||
val datetime: String,
|
val datetime: String,
|
||||||
val title: String,
|
val title: String,
|
||||||
val content: String,
|
val content: String,
|
||||||
|
@Serializable(with = BooleanSerializer::class)
|
||||||
var unread: Boolean,
|
var unread: Boolean,
|
||||||
|
@Serializable(with = BooleanSerializer::class)
|
||||||
var starred: Boolean,
|
var starred: Boolean,
|
||||||
val thumbnail: String?,
|
val thumbnail: String?,
|
||||||
val icon: String?,
|
val icon: String?,
|
||||||
val link: String,
|
val link: String,
|
||||||
val sourcetitle: String,
|
val sourcetitle: String,
|
||||||
|
@Serializable(with = TagsListSerializer::class)
|
||||||
val tags: List<String>
|
val tags: List<String>
|
||||||
) {
|
) {
|
||||||
// TODO: maybe find a better way to handle these kind of urls
|
// TODO: maybe find a better way to handle these kind of urls
|
||||||
@@ -105,4 +116,48 @@ class SelfossModel {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this seems to be super slow.
|
||||||
|
object TagsListSerializer : KSerializer<List<String>> {
|
||||||
|
override fun deserialize(decoder: Decoder): List<String> {
|
||||||
|
return when(val json = ((decoder as JsonDecoder).decodeJsonElement())) {
|
||||||
|
is JsonArray -> json.toList().map { it.toString() }
|
||||||
|
else -> json.toString().split(",")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override val descriptor: SerialDescriptor
|
||||||
|
get() = PrimitiveSerialDescriptor("tags", PrimitiveKind.STRING)
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: List<String>) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object BooleanSerializer : KSerializer<Boolean> {
|
||||||
|
override fun deserialize(decoder: Decoder): Boolean {
|
||||||
|
val json = ((decoder as JsonDecoder).decodeJsonElement()).jsonPrimitive
|
||||||
|
return json.booleanOrNull ?: json.int == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
override val descriptor: SerialDescriptor
|
||||||
|
get() = PrimitiveSerialDescriptor("b", PrimitiveKind.BOOLEAN)
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: Boolean) {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StatusAndData<T>(val success: Boolean, val data: T? = null) {
|
||||||
|
companion object {
|
||||||
|
fun <T> succes(d: T): StatusAndData<T> {
|
||||||
|
return StatusAndData(true, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> error(): StatusAndData<T> {
|
||||||
|
return StatusAndData(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+47
-36
@@ -47,7 +47,8 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
|
|
||||||
suspend fun getNewerItems(): ArrayList<SelfossModel.Item> {
|
suspend fun getNewerItems(): ArrayList<SelfossModel.Item> {
|
||||||
// TODO: Use the updatedSince parameter
|
// TODO: Use the updatedSince parameter
|
||||||
var fetchedItems: List<SelfossModel.Item>? = null
|
var fetchedItems: SelfossModel.StatusAndData<List<SelfossModel.Item>> = SelfossModel.StatusAndData.error()
|
||||||
|
var fromDB = false
|
||||||
if (isNetworkAvailable()) {
|
if (isNetworkAvailable()) {
|
||||||
fetchedItems = api.getItems(
|
fetchedItems = api.getItems(
|
||||||
displayedItems.type,
|
displayedItems.type,
|
||||||
@@ -59,23 +60,28 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
if (appSettingsService.isItemCachingEnabled()) {
|
if (appSettingsService.isItemCachingEnabled()) {
|
||||||
fetchedItems = getDBItems().filter {
|
fromDB = true
|
||||||
|
fetchedItems = SelfossModel.StatusAndData.succes(
|
||||||
|
getDBItems().filter {
|
||||||
displayedItems == ItemType.ALL ||
|
displayedItems == ItemType.ALL ||
|
||||||
(it.unread && displayedItems == ItemType.UNREAD) ||
|
(it.unread && displayedItems == ItemType.UNREAD) ||
|
||||||
(it.starred && displayedItems == ItemType.STARRED)
|
(it.starred && displayedItems == ItemType.STARRED)
|
||||||
}.map { it.toView() }
|
}.map { it.toView() }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fetchedItems != null) {
|
if (fetchedItems.success && fetchedItems.data != null) {
|
||||||
items = ArrayList(fetchedItems)
|
items = ArrayList(fetchedItems.data!!)
|
||||||
sortItems()
|
if (fromDB) {
|
||||||
|
items.sortByDescending { dateUtils.parseDate(it.datetime) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getOlderItems(): ArrayList<SelfossModel.Item> {
|
suspend fun getOlderItems(): ArrayList<SelfossModel.Item> {
|
||||||
var fetchedItems: List<SelfossModel.Item>? = null
|
var fetchedItems: SelfossModel.StatusAndData<List<SelfossModel.Item>> = SelfossModel.StatusAndData.error()
|
||||||
if (isNetworkAvailable()) {
|
if (isNetworkAvailable()) {
|
||||||
val offset = items.size
|
val offset = items.size
|
||||||
fetchedItems = api.getItems(
|
fetchedItems = api.getItems(
|
||||||
@@ -88,16 +94,15 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
)
|
)
|
||||||
} // When using the db cache, we load everything the first time, so there should be nothing more to load.
|
} // When using the db cache, we load everything the first time, so there should be nothing more to load.
|
||||||
|
|
||||||
if (fetchedItems != null) {
|
if (fetchedItems.success && fetchedItems.data != null) {
|
||||||
items.addAll(fetchedItems)
|
items.addAll(fetchedItems.data!!)
|
||||||
sortItems()
|
|
||||||
}
|
}
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getMaxItemsForBackground(itemType: ItemType): List<SelfossModel.Item>? {
|
private suspend fun getMaxItemsForBackground(itemType: ItemType): List<SelfossModel.Item> {
|
||||||
return if (isNetworkAvailable()) {
|
return if (isNetworkAvailable()) {
|
||||||
api.getItems(
|
val items = api.getItems(
|
||||||
itemType.type,
|
itemType.type,
|
||||||
0,
|
0,
|
||||||
tagFilter?.tag,
|
tagFilter?.tag,
|
||||||
@@ -106,23 +111,24 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
null,
|
null,
|
||||||
200
|
200
|
||||||
)
|
)
|
||||||
|
return if (items.success && items.data != null) {
|
||||||
|
items.data
|
||||||
} else {
|
} else {
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sortItems() {
|
|
||||||
items.sortByDescending { dateUtils.parseDate(it.datetime) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun reloadBadges(): Boolean {
|
suspend fun reloadBadges(): Boolean {
|
||||||
var success = false
|
var success = false
|
||||||
if (isNetworkAvailable()) {
|
if (isNetworkAvailable()) {
|
||||||
val response = api.stats()
|
val response = api.stats()
|
||||||
if (response != null) {
|
if (response.success && response.data != null) {
|
||||||
badgeUnread = response.unread
|
badgeUnread = response.data.unread
|
||||||
badgeAll = response.total
|
badgeAll = response.data.total
|
||||||
badgeStarred = response.starred
|
badgeStarred = response.data.starred
|
||||||
success = true
|
success = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -138,10 +144,10 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
suspend fun getTags(): List<SelfossModel.Tag>? {
|
suspend fun getTags(): List<SelfossModel.Tag>? {
|
||||||
return if (isNetworkAvailable()) {
|
return if (isNetworkAvailable()) {
|
||||||
val apiTags = api.tags()
|
val apiTags = api.tags()
|
||||||
if (apiTags != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
|
if (apiTags.success && apiTags.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
|
||||||
resetDBTagsWithData(apiTags)
|
resetDBTagsWithData(apiTags.data)
|
||||||
}
|
}
|
||||||
apiTags
|
apiTags.data
|
||||||
} else {
|
} else {
|
||||||
getDBTags().map { it.toView() }
|
getDBTags().map { it.toView() }
|
||||||
}
|
}
|
||||||
@@ -149,7 +155,12 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
|
|
||||||
suspend fun getSpouts(): Map<String, SelfossModel.Spout>? {
|
suspend fun getSpouts(): Map<String, SelfossModel.Spout>? {
|
||||||
return if (isNetworkAvailable()) {
|
return if (isNetworkAvailable()) {
|
||||||
api.spouts()
|
val spouts = api.spouts()
|
||||||
|
return if (spouts.success && spouts.data != null) {
|
||||||
|
spouts.data
|
||||||
|
} else {
|
||||||
|
emptyMap() // TODO: do something here
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw NetworkUnavailableException()
|
throw NetworkUnavailableException()
|
||||||
}
|
}
|
||||||
@@ -158,10 +169,10 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
suspend fun getSources(): ArrayList<SelfossModel.Source>? {
|
suspend fun getSources(): ArrayList<SelfossModel.Source>? {
|
||||||
return if (isNetworkAvailable()) {
|
return if (isNetworkAvailable()) {
|
||||||
val apiSources = api.sources()
|
val apiSources = api.sources()
|
||||||
if (apiSources != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
|
if (apiSources.success && apiSources.data != null && (appSettingsService.isItemCachingEnabled() || !appSettingsService.isUpdateSourcesEnabled())) {
|
||||||
resetDBSourcesWithData(apiSources)
|
resetDBSourcesWithData(apiSources.data)
|
||||||
}
|
}
|
||||||
apiSources
|
apiSources.data
|
||||||
} else {
|
} else {
|
||||||
ArrayList(getDBSources().map { it.toView() })
|
ArrayList(getDBSources().map { it.toView() })
|
||||||
}
|
}
|
||||||
@@ -178,7 +189,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
|
|
||||||
private suspend fun markAsReadById(id: Int): Boolean {
|
private suspend fun markAsReadById(id: Int): Boolean {
|
||||||
return if (isNetworkAvailable()) {
|
return if (isNetworkAvailable()) {
|
||||||
api.markAsRead(id.toString())?.isSuccess == true
|
api.markAsRead(id.toString())?.isSuccess
|
||||||
} else {
|
} else {
|
||||||
insertDBAction(id.toString(), read = true)
|
insertDBAction(id.toString(), read = true)
|
||||||
true
|
true
|
||||||
@@ -197,7 +208,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
|
|
||||||
private suspend fun unmarkAsReadById(id: Int): Boolean {
|
private suspend fun unmarkAsReadById(id: Int): Boolean {
|
||||||
return if (isNetworkAvailable()) {
|
return if (isNetworkAvailable()) {
|
||||||
api.unmarkAsRead(id.toString())?.isSuccess == true
|
api.unmarkAsRead(id.toString())?.isSuccess
|
||||||
} else {
|
} else {
|
||||||
insertDBAction(id.toString(), unread = true)
|
insertDBAction(id.toString(), unread = true)
|
||||||
true
|
true
|
||||||
@@ -215,7 +226,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
|
|
||||||
private suspend fun starrById(id: Int): Boolean {
|
private suspend fun starrById(id: Int): Boolean {
|
||||||
return if (isNetworkAvailable()) {
|
return if (isNetworkAvailable()) {
|
||||||
api.starr(id.toString())?.isSuccess == true
|
api.starr(id.toString())?.isSuccess
|
||||||
} else {
|
} else {
|
||||||
insertDBAction(id.toString(), starred = true)
|
insertDBAction(id.toString(), starred = true)
|
||||||
true
|
true
|
||||||
@@ -233,7 +244,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
|
|
||||||
private suspend fun unstarrById(id: Int): Boolean {
|
private suspend fun unstarrById(id: Int): Boolean {
|
||||||
return if (isNetworkAvailable()) {
|
return if (isNetworkAvailable()) {
|
||||||
api.unstarr(id.toString())?.isSuccess == true
|
api.unstarr(id.toString())?.isSuccess
|
||||||
} else {
|
} else {
|
||||||
insertDBAction(id.toString(), starred = true)
|
insertDBAction(id.toString(), starred = true)
|
||||||
true
|
true
|
||||||
@@ -243,7 +254,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
suspend fun markAllAsRead(items: ArrayList<SelfossModel.Item>): Boolean {
|
suspend fun markAllAsRead(items: ArrayList<SelfossModel.Item>): Boolean {
|
||||||
var success = false
|
var success = false
|
||||||
|
|
||||||
if (isNetworkAvailable() && api.markAllAsRead(items.map { it.id.toString() })?.isSuccess == true) {
|
if (isNetworkAvailable() && api.markAllAsRead(items.map { it.id.toString() })?.isSuccess) {
|
||||||
success = true
|
success = true
|
||||||
for (item in items) {
|
for (item in items) {
|
||||||
markAsReadLocally(item)
|
markAsReadLocally(item)
|
||||||
@@ -332,7 +343,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
|
|
||||||
suspend fun updateRemote(): Boolean {
|
suspend fun updateRemote(): Boolean {
|
||||||
return if (isNetworkAvailable()) {
|
return if (isNetworkAvailable()) {
|
||||||
api.update()?.equals("finished") ?: false
|
api.update()?.equals("finished")
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@@ -365,8 +376,8 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
|
|
||||||
if (isNetworkAvailable()) {
|
if (isNetworkAvailable()) {
|
||||||
val fetchedVersion = api.version()
|
val fetchedVersion = api.version()
|
||||||
if (fetchedVersion != null && fetchedVersion.getApiMajorVersion() != apiMajorVersion) {
|
if (fetchedVersion.success && fetchedVersion.data != null && fetchedVersion.data.getApiMajorVersion() != apiMajorVersion) {
|
||||||
appSettingsService.updateApiVersion(fetchedVersion.getApiMajorVersion())
|
appSettingsService.updateApiVersion(fetchedVersion.data.getApiMajorVersion())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -383,7 +394,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
|
|
||||||
fun getDBSources(): List<SOURCE> = db.sourcesQueries.sources().executeAsList()
|
fun getDBSources(): List<SOURCE> = db.sourcesQueries.sources().executeAsList()
|
||||||
|
|
||||||
fun resetDBTagsWithData(tagEntities: List<SelfossModel.Tag>) {
|
private fun resetDBTagsWithData(tagEntities: List<SelfossModel.Tag>) {
|
||||||
db.tagsQueries.deleteAllTags()
|
db.tagsQueries.deleteAllTags()
|
||||||
|
|
||||||
db.tagsQueries.transaction {
|
db.tagsQueries.transaction {
|
||||||
@@ -393,7 +404,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resetDBSourcesWithData(sources: List<SelfossModel.Source>) {
|
private fun resetDBSourcesWithData(sources: List<SelfossModel.Source>) {
|
||||||
db.sourcesQueries.deleteAllSources()
|
db.sourcesQueries.deleteAllSources()
|
||||||
|
|
||||||
db.sourcesQueries.transaction {
|
db.sourcesQueries.transaction {
|
||||||
@@ -425,7 +436,7 @@ class Repository(private val api: SelfossApi, private val appSettingsService: Ap
|
|||||||
val newItems = getMaxItemsForBackground(ItemType.UNREAD)
|
val newItems = getMaxItemsForBackground(ItemType.UNREAD)
|
||||||
val allItems = getMaxItemsForBackground(ItemType.ALL)
|
val allItems = getMaxItemsForBackground(ItemType.ALL)
|
||||||
val starredItems = getMaxItemsForBackground(ItemType.STARRED)
|
val starredItems = getMaxItemsForBackground(ItemType.STARRED)
|
||||||
insertDBItems(newItems.orEmpty() + allItems.orEmpty() + starredItems.orEmpty())
|
insertDBItems(newItems + allItems + starredItems)
|
||||||
return newItems
|
return newItems
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
// We do nothing
|
// We do nothing
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import io.ktor.client.plugins.contentnegotiation.*
|
|||||||
import io.ktor.client.plugins.logging.*
|
import io.ktor.client.plugins.logging.*
|
||||||
import io.ktor.client.request.*
|
import io.ktor.client.request.*
|
||||||
import io.ktor.client.request.forms.*
|
import io.ktor.client.request.forms.*
|
||||||
|
import io.ktor.client.statement.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.serialization.kotlinx.json.*
|
import io.ktor.serialization.kotlinx.json.*
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@@ -34,7 +35,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
appSettingsService.logApiCalls(message)
|
appSettingsService.logApiCalls(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
level = LogLevel.ALL
|
level = LogLevel.INFO
|
||||||
}
|
}
|
||||||
install(HttpTimeout) {
|
install(HttpTimeout) {
|
||||||
requestTimeoutMillis = appSettingsService.getApiTimeout()
|
requestTimeoutMillis = appSettingsService.getApiTimeout()
|
||||||
@@ -65,11 +66,11 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
client = createHttpClient()
|
client = createHttpClient()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun login(): SelfossModel.SuccessResponse? =
|
suspend fun login(): SelfossModel.SuccessResponse =
|
||||||
client.get(url("/login")) {
|
maybeResponse(client.get(url("/login")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
suspend fun getItems(
|
suspend fun getItems(
|
||||||
type: String,
|
type: String,
|
||||||
@@ -79,8 +80,8 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
search: String?,
|
search: String?,
|
||||||
updatedSince: String?,
|
updatedSince: String?,
|
||||||
items: Int? = null
|
items: Int? = null
|
||||||
): List<SelfossModel.Item>? =
|
): SelfossModel.StatusAndData<List<SelfossModel.Item>> =
|
||||||
client.get(url("/items")) {
|
bodyOrFailure(client.get(url("/items")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
parameter("type", type)
|
parameter("type", type)
|
||||||
@@ -90,74 +91,74 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
parameter("updatedsince", updatedSince)
|
parameter("updatedsince", updatedSince)
|
||||||
parameter("items", items ?: appSettingsService.getItemsNumber())
|
parameter("items", items ?: appSettingsService.getItemsNumber())
|
||||||
parameter("offset", offset)
|
parameter("offset", offset)
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
suspend fun stats(): SelfossModel.Stats? =
|
suspend fun stats(): SelfossModel.StatusAndData<SelfossModel.Stats> =
|
||||||
client.get(url("/stats")) {
|
bodyOrFailure(client.get(url("/stats")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
suspend fun tags(): List<SelfossModel.Tag>? =
|
suspend fun tags(): SelfossModel.StatusAndData<List<SelfossModel.Tag>> =
|
||||||
client.get(url("/tags")) {
|
bodyOrFailure(client.get(url("/tags")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
suspend fun update(): String? =
|
suspend fun update(): SelfossModel.StatusAndData<String> =
|
||||||
client.get(url("/update")) {
|
bodyOrFailure(client.get(url("/update")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
suspend fun spouts(): Map<String, SelfossModel.Spout>? =
|
suspend fun spouts(): SelfossModel.StatusAndData<Map<String, SelfossModel.Spout>> =
|
||||||
client.get(url("/sources/spouts")) {
|
bodyOrFailure(client.get(url("/sources/spouts")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
suspend fun sources(): ArrayList<SelfossModel.Source>? =
|
suspend fun sources(): SelfossModel.StatusAndData<ArrayList<SelfossModel.Source>> =
|
||||||
client.get(url("/sources/list")) {
|
bodyOrFailure(client.get(url("/sources/list")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
suspend fun version(): SelfossModel.ApiVersion? =
|
suspend fun version(): SelfossModel.StatusAndData<SelfossModel.ApiVersion> =
|
||||||
client.get(url("/api/about")).body()
|
bodyOrFailure(client.get(url("/api/about")))
|
||||||
|
|
||||||
suspend fun markAsRead(id: String): SelfossModel.SuccessResponse? =
|
suspend fun markAsRead(id: String): SelfossModel.SuccessResponse =
|
||||||
client.post(url("/mark/$id")) {
|
maybeResponse(client.post(url("/mark/$id")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
suspend fun unmarkAsRead(id: String): SelfossModel.SuccessResponse? =
|
suspend fun unmarkAsRead(id: String): SelfossModel.SuccessResponse =
|
||||||
client.post(url("/unmark/$id")) {
|
maybeResponse(client.post(url("/unmark/$id")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
suspend fun starr(id: String): SelfossModel.SuccessResponse? =
|
suspend fun starr(id: String): SelfossModel.SuccessResponse =
|
||||||
client.post(url("/starr/$id")) {
|
maybeResponse(client.post(url("/starr/$id")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
suspend fun unstarr(id: String): SelfossModel.SuccessResponse? =
|
suspend fun unstarr(id: String): SelfossModel.SuccessResponse =
|
||||||
client.post(url("/unstarr/$id")) {
|
maybeResponse(client.post(url("/unstarr/$id")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
suspend fun markAllAsRead(ids: List<String>): SelfossModel.SuccessResponse? =
|
suspend fun markAllAsRead(ids: List<String>): SelfossModel.SuccessResponse =
|
||||||
client.submitForm(
|
maybeResponse(client.submitForm(
|
||||||
url = url("/mark"),
|
url = url("/mark"),
|
||||||
formParameters = Parameters.build {
|
formParameters = Parameters.build {
|
||||||
append("username", appSettingsService.getUserName())
|
append("username", appSettingsService.getUserName())
|
||||||
append("password", appSettingsService.getPassword())
|
append("password", appSettingsService.getPassword())
|
||||||
ids.map { append("ids[]", it) }
|
ids.map { append("ids[]", it) }
|
||||||
}
|
}
|
||||||
).body()
|
))
|
||||||
|
|
||||||
suspend fun createSourceForVersion(
|
suspend fun createSourceForVersion(
|
||||||
title: String,
|
title: String,
|
||||||
@@ -166,12 +167,14 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
tags: String,
|
tags: String,
|
||||||
filter: String,
|
filter: String,
|
||||||
version: Int
|
version: Int
|
||||||
): SelfossModel.SuccessResponse? =
|
): SelfossModel.SuccessResponse =
|
||||||
|
maybeResponse(
|
||||||
if (version > 1) {
|
if (version > 1) {
|
||||||
createSource2(title, url, spout, tags, filter)
|
createSource2(title, url, spout, tags, filter)
|
||||||
} else {
|
} else {
|
||||||
createSource(title, url, spout, tags, filter)
|
createSource(title, url, spout, tags, filter)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
suspend fun createSource(
|
suspend fun createSource(
|
||||||
title: String,
|
title: String,
|
||||||
@@ -179,7 +182,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
spout: String,
|
spout: String,
|
||||||
tags: String,
|
tags: String,
|
||||||
filter: String
|
filter: String
|
||||||
): SelfossModel.SuccessResponse? =
|
): HttpResponse =
|
||||||
client.submitForm(
|
client.submitForm(
|
||||||
url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"),
|
url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"),
|
||||||
formParameters = Parameters.build {
|
formParameters = Parameters.build {
|
||||||
@@ -189,7 +192,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
append("tags", tags)
|
append("tags", tags)
|
||||||
append("filter", filter)
|
append("filter", filter)
|
||||||
}
|
}
|
||||||
).body()
|
)
|
||||||
|
|
||||||
suspend fun createSource2(
|
suspend fun createSource2(
|
||||||
title: String,
|
title: String,
|
||||||
@@ -197,7 +200,7 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
spout: String,
|
spout: String,
|
||||||
tags: String,
|
tags: String,
|
||||||
filter: String
|
filter: String
|
||||||
): SelfossModel.SuccessResponse? =
|
): HttpResponse =
|
||||||
client.submitForm(
|
client.submitForm(
|
||||||
url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"),
|
url = url("/source?username=${appSettingsService.getUserName()}&password=${appSettingsService.getPassword()}"),
|
||||||
formParameters = Parameters.build {
|
formParameters = Parameters.build {
|
||||||
@@ -207,11 +210,27 @@ class SelfossApi(private val appSettingsService: AppSettingsService) {
|
|||||||
append("tags[]", tags)
|
append("tags[]", tags)
|
||||||
append("filter", filter)
|
append("filter", filter)
|
||||||
}
|
}
|
||||||
).body()
|
)
|
||||||
|
|
||||||
suspend fun deleteSource(id: Int): SelfossModel.SuccessResponse? =
|
suspend fun deleteSource(id: Int): SelfossModel.SuccessResponse =
|
||||||
client.delete(url("/source/$id")) {
|
maybeResponse(client.delete(url("/source/$id")) {
|
||||||
parameter("username", appSettingsService.getUserName())
|
parameter("username", appSettingsService.getUserName())
|
||||||
parameter("password", appSettingsService.getPassword())
|
parameter("password", appSettingsService.getPassword())
|
||||||
}.body()
|
})
|
||||||
|
|
||||||
|
suspend fun maybeResponse(r: HttpResponse): SelfossModel.SuccessResponse {
|
||||||
|
return if (r.status.isSuccess()) {
|
||||||
|
r.body()
|
||||||
|
} else {
|
||||||
|
SelfossModel.SuccessResponse(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend inline fun <reified T> bodyOrFailure(r: HttpResponse): SelfossModel.StatusAndData<T> {
|
||||||
|
return if (r.status.isSuccess()) {
|
||||||
|
SelfossModel.StatusAndData.succes(r.body())
|
||||||
|
} else {
|
||||||
|
SelfossModel.StatusAndData.error()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+14
-1
@@ -35,6 +35,7 @@ class AppSettingsService {
|
|||||||
|
|
||||||
private var _fontSize: Int? = null
|
private var _fontSize: Int? = null
|
||||||
private var _staticBar: Boolean? = null
|
private var _staticBar: Boolean? = null
|
||||||
|
private var _darkTheme: Boolean? = null
|
||||||
private var _font: String = ""
|
private var _font: String = ""
|
||||||
|
|
||||||
|
|
||||||
@@ -88,7 +89,7 @@ class AppSettingsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun refreshItemsNumber() {
|
fun refreshItemsNumber() {
|
||||||
_itemsNumber = settings.getString("prefer_api_items_number", "200").toInt()
|
_itemsNumber = settings.getString("prefer_api_items_number", "20").toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getApiTimeout(): Long {
|
fun getApiTimeout(): Long {
|
||||||
@@ -319,6 +320,17 @@ class AppSettingsService {
|
|||||||
return _staticBar == true
|
return _staticBar == true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun refreshDarkThemeEnabled() {
|
||||||
|
_darkTheme = settings.getBoolean("dark_theme", false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isDarkThemeEnabled(): Boolean {
|
||||||
|
if (_darkTheme != null) {
|
||||||
|
refreshDarkThemeEnabled()
|
||||||
|
}
|
||||||
|
return _darkTheme == true
|
||||||
|
}
|
||||||
|
|
||||||
private fun refreshFont() {
|
private fun refreshFont() {
|
||||||
_font = settings.getString("reader_font", "")
|
_font = settings.getString("reader_font", "")
|
||||||
}
|
}
|
||||||
@@ -359,6 +371,7 @@ class AppSettingsService {
|
|||||||
refreshFontSize()
|
refreshFontSize()
|
||||||
refreshFont()
|
refreshFont()
|
||||||
refreshStaticBarEnabled()
|
refreshStaticBarEnabled()
|
||||||
|
refreshDarkThemeEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshLoginInformation(
|
fun refreshLoginInformation(
|
||||||
|
|||||||
+8
-5
@@ -1,11 +1,14 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# You can pass --force as first parameter to force push and tag creation.
|
|
||||||
|
|
||||||
echo "Creating tag $@"
|
echo "Creating tag $1"
|
||||||
|
|
||||||
TAG="v$@"
|
TAG="v$1"
|
||||||
git tag ${TAG}
|
git tag -a ${TAG} -m ${TAG}
|
||||||
|
|
||||||
|
if [[ "$@" == *'--from-ci'* ]]
|
||||||
|
then
|
||||||
|
echo "Tag created. HANDLE IN CI"
|
||||||
|
else
|
||||||
echo "Pushing tag"
|
echo "Pushing tag"
|
||||||
|
|
||||||
git push origin ${TAG}
|
git push origin ${TAG}
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user