add following tab property in datastore
This commit is contained in:
@ -0,0 +1,18 @@
|
||||
package app.omnivore.omnivore.core.datastore
|
||||
|
||||
const val omnivoreSelfHostedApiServer = "omnivoreSelfHostedAPIServer"
|
||||
const val omnivoreSelfHostedWebServer = "omnivoreSelfHostedWebServer"
|
||||
const val omnivoreAuthToken = "omnivoreAuthToken"
|
||||
const val omnivoreAuthCookieString = "omnivoreAuthCookieString"
|
||||
const val omnivorePendingUserToken = "omnivorePendingUserToken"
|
||||
const val libraryLastSyncTimestamp = "libraryLastSyncTimestamp"
|
||||
const val preferredWebFontSize = "preferredWebFontSize"
|
||||
const val preferredWebLineHeight = "preferredWebLineHeight"
|
||||
const val preferredWebMaxWidthPercentage = "preferredWebMaxWidthPercentage"
|
||||
const val preferredWebFontFamily = "preferredWebFontFamily"
|
||||
const val prefersWebHighContrastText = "prefersWebHighContrastText"
|
||||
const val prefersJustifyText = "prefersJustifyText"
|
||||
const val lastUsedSavedItemFilter = "lastUsedSavedItemFilter"
|
||||
const val lastUsedSavedItemSortFilter = "lastUsedSavedItemSortFilter"
|
||||
const val preferredTheme = "preferredTheme"
|
||||
const val followingTabActive = "followingTabActive"
|
||||
@ -2,79 +2,96 @@ package app.omnivore.omnivore.core.datastore
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.*
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import app.omnivore.omnivore.utils.Constants
|
||||
import app.omnivore.omnivore.utils.DatastoreKeys
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
|
||||
interface DatastoreRepository {
|
||||
val hasAuthTokenFlow: Flow<Boolean>
|
||||
val themeKeyFlow: Flow<String>
|
||||
val hasAuthTokenFlow: Flow<Boolean>
|
||||
val themeKeyFlow: Flow<String>
|
||||
|
||||
suspend fun clear()
|
||||
suspend fun putString(key: String, value: String)
|
||||
suspend fun putInt(key: String, value: Int)
|
||||
suspend fun getString(key: String): String?
|
||||
suspend fun getInt(key: String): Int?
|
||||
suspend fun clearValue(key: String)
|
||||
suspend fun clear()
|
||||
suspend fun putBoolean(key: String, value: Boolean)
|
||||
fun getBoolean(key: String): Flow<Boolean>
|
||||
suspend fun putString(key: String, value: String)
|
||||
suspend fun putInt(key: String, value: Int)
|
||||
suspend fun getString(key: String): String?
|
||||
suspend fun getInt(key: String): Int?
|
||||
suspend fun clearValue(key: String)
|
||||
}
|
||||
|
||||
class OmnivoreDatastore @Inject constructor(
|
||||
private val context: Context
|
||||
private val context: Context
|
||||
) : DatastoreRepository {
|
||||
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(
|
||||
name = Constants.dataStoreName
|
||||
)
|
||||
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(
|
||||
name = Constants.dataStoreName
|
||||
)
|
||||
|
||||
override suspend fun putString(key: String, value: String) {
|
||||
val preferencesKey = stringPreferencesKey(key)
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[preferencesKey] = value
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun putInt(key: String, value: Int) {
|
||||
val preferencesKey = intPreferencesKey(key)
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[preferencesKey] = value
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getString(key: String): String? {
|
||||
val preferencesKey = stringPreferencesKey(key)
|
||||
val preferences = context.dataStore.data.first()
|
||||
return preferences[preferencesKey]
|
||||
}
|
||||
|
||||
override suspend fun getInt(key: String): Int? {
|
||||
val preferencesKey = intPreferencesKey(key)
|
||||
val preferences = context.dataStore.data.first()
|
||||
return preferences[preferencesKey]
|
||||
}
|
||||
|
||||
override suspend fun clear() {
|
||||
context.dataStore.edit { it.clear() }
|
||||
}
|
||||
|
||||
override suspend fun clearValue(key: String) {
|
||||
val preferencesKey = stringPreferencesKey(key)
|
||||
context.dataStore.edit { it.remove(preferencesKey) }
|
||||
}
|
||||
|
||||
override val hasAuthTokenFlow: Flow<Boolean> = context
|
||||
.dataStore.data.map { preferences ->
|
||||
val key = stringPreferencesKey(DatastoreKeys.omnivoreAuthToken)
|
||||
val token = preferences[key]
|
||||
token != null
|
||||
override suspend fun putBoolean(key: String, value: Boolean) {
|
||||
val preferencesKey = booleanPreferencesKey(key)
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[preferencesKey] = value
|
||||
}
|
||||
}
|
||||
|
||||
override val themeKeyFlow: Flow<String> = context
|
||||
.dataStore.data.map { preferences ->
|
||||
val key = stringPreferencesKey(DatastoreKeys.preferredTheme)
|
||||
preferences[key] ?: "System"
|
||||
override fun getBoolean(key: String): Flow<Boolean> {
|
||||
val preferencesKey = booleanPreferencesKey(key)
|
||||
return context.dataStore.data.map { preferences ->
|
||||
preferences[preferencesKey] ?: false
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun putString(key: String, value: String) {
|
||||
val preferencesKey = stringPreferencesKey(key)
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[preferencesKey] = value
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun putInt(key: String, value: Int) {
|
||||
val preferencesKey = intPreferencesKey(key)
|
||||
context.dataStore.edit { preferences ->
|
||||
preferences[preferencesKey] = value
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getString(key: String): String? {
|
||||
val preferencesKey = stringPreferencesKey(key)
|
||||
val preferences = context.dataStore.data.first()
|
||||
return preferences[preferencesKey]
|
||||
}
|
||||
|
||||
override suspend fun getInt(key: String): Int? {
|
||||
val preferencesKey = intPreferencesKey(key)
|
||||
val preferences = context.dataStore.data.first()
|
||||
return preferences[preferencesKey]
|
||||
}
|
||||
|
||||
override suspend fun clear() {
|
||||
context.dataStore.edit { it.clear() }
|
||||
}
|
||||
|
||||
override suspend fun clearValue(key: String) {
|
||||
val preferencesKey = stringPreferencesKey(key)
|
||||
context.dataStore.edit { it.remove(preferencesKey) }
|
||||
}
|
||||
|
||||
override val hasAuthTokenFlow: Flow<Boolean> = context.dataStore.data.map { preferences ->
|
||||
val key = stringPreferencesKey(omnivoreAuthToken)
|
||||
val token = preferences[key]
|
||||
token != null
|
||||
}
|
||||
|
||||
override val themeKeyFlow: Flow<String> = context.dataStore.data.map { preferences ->
|
||||
val key = stringPreferencesKey(preferredTheme)
|
||||
preferences[key] ?: "System"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
package app.omnivore.omnivore.core.network
|
||||
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.core.datastore.omnivoreAuthToken
|
||||
import app.omnivore.omnivore.core.datastore.omnivoreSelfHostedApiServer
|
||||
import app.omnivore.omnivore.utils.Constants
|
||||
import app.omnivore.omnivore.utils.DatastoreKeys
|
||||
import com.apollographql.apollo3.ApolloClient
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -10,10 +11,10 @@ class Networker @Inject constructor(
|
||||
private val datastoreRepo: DatastoreRepository
|
||||
) {
|
||||
suspend fun baseUrl() =
|
||||
datastoreRepo.getString(DatastoreKeys.omnivoreSelfHostedAPIServer) ?: Constants.apiURL
|
||||
datastoreRepo.getString(omnivoreSelfHostedApiServer) ?: Constants.apiURL
|
||||
|
||||
private suspend fun serverUrl() = "${baseUrl()}/api/graphql"
|
||||
private suspend fun authToken() = datastoreRepo.getString(DatastoreKeys.omnivoreAuthToken) ?: ""
|
||||
private suspend fun authToken() = datastoreRepo.getString(omnivoreAuthToken) ?: ""
|
||||
|
||||
suspend fun authenticatedApolloClient() = ApolloClient.Builder().serverUrl(serverUrl())
|
||||
.addHttpHeader("Authorization", value = authToken()).build()
|
||||
|
||||
@ -5,11 +5,21 @@ import android.widget.Toast
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.*
|
||||
import app.omnivore.omnivore.*
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.omnivore.omnivore.BuildConfig
|
||||
import app.omnivore.omnivore.R
|
||||
import app.omnivore.omnivore.core.analytics.EventTracker
|
||||
import app.omnivore.omnivore.core.data.DataService
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.core.datastore.omnivoreAuthCookieString
|
||||
import app.omnivore.omnivore.core.datastore.omnivoreAuthToken
|
||||
import app.omnivore.omnivore.core.datastore.omnivorePendingUserToken
|
||||
import app.omnivore.omnivore.core.datastore.omnivoreSelfHostedApiServer
|
||||
import app.omnivore.omnivore.core.datastore.omnivoreSelfHostedWebServer
|
||||
import app.omnivore.omnivore.core.network.AuthProviderLoginSubmit
|
||||
import app.omnivore.omnivore.core.network.CreateAccountParams
|
||||
import app.omnivore.omnivore.core.network.CreateAccountSubmit
|
||||
@ -17,24 +27,26 @@ import app.omnivore.omnivore.core.network.CreateEmailAccountSubmit
|
||||
import app.omnivore.omnivore.core.network.EmailLoginCredentials
|
||||
import app.omnivore.omnivore.core.network.EmailLoginSubmit
|
||||
import app.omnivore.omnivore.core.network.EmailSignUpParams
|
||||
import app.omnivore.omnivore.graphql.generated.ValidateUsernameQuery
|
||||
import app.omnivore.omnivore.core.network.Networker
|
||||
import app.omnivore.omnivore.core.network.PendingUserSubmit
|
||||
import app.omnivore.omnivore.core.network.RetrofitHelper
|
||||
import app.omnivore.omnivore.core.network.SignInParams
|
||||
import app.omnivore.omnivore.core.network.UserProfile
|
||||
import app.omnivore.omnivore.core.network.viewer
|
||||
import app.omnivore.omnivore.utils.ResourceProvider
|
||||
import app.omnivore.omnivore.graphql.generated.ValidateUsernameQuery
|
||||
import app.omnivore.omnivore.utils.Constants
|
||||
import app.omnivore.omnivore.utils.DatastoreKeys
|
||||
import app.omnivore.omnivore.utils.ResourceProvider
|
||||
import com.apollographql.apollo3.ApolloClient
|
||||
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
|
||||
import com.google.android.gms.common.api.ApiException
|
||||
import com.google.android.gms.tasks.Task
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import io.intercom.android.sdk.Intercom
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.regex.Pattern
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -84,13 +96,13 @@ class LoginViewModel @Inject constructor(
|
||||
val registrationStateLiveData = MutableLiveData(RegistrationState.SocialLogin)
|
||||
|
||||
fun getAuthCookieString(): String? = runBlocking {
|
||||
datastoreRepo.getString(DatastoreKeys.omnivoreAuthCookieString)
|
||||
datastoreRepo.getString(omnivoreAuthCookieString)
|
||||
}
|
||||
|
||||
fun setSelfHostingDetails(context: Context, apiServer: String, webServer: String) {
|
||||
viewModelScope.launch {
|
||||
datastoreRepo.putString(DatastoreKeys.omnivoreSelfHostedAPIServer, apiServer)
|
||||
datastoreRepo.putString(DatastoreKeys.omnivoreSelfHostedWebServer, webServer)
|
||||
datastoreRepo.putString(omnivoreSelfHostedApiServer, apiServer)
|
||||
datastoreRepo.putString(omnivoreSelfHostedWebServer, webServer)
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.login_view_model_self_hosting_settings_updated),
|
||||
@ -101,8 +113,8 @@ class LoginViewModel @Inject constructor(
|
||||
|
||||
fun resetSelfHostingDetails(context: Context) {
|
||||
viewModelScope.launch {
|
||||
datastoreRepo.clearValue(DatastoreKeys.omnivoreSelfHostedAPIServer)
|
||||
datastoreRepo.clearValue(DatastoreKeys.omnivoreSelfHostedWebServer)
|
||||
datastoreRepo.clearValue(omnivoreSelfHostedApiServer)
|
||||
datastoreRepo.clearValue(omnivoreSelfHostedWebServer)
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.login_view_model_self_hosting_settings_reset),
|
||||
@ -136,7 +148,7 @@ class LoginViewModel @Inject constructor(
|
||||
fun cancelNewUserSignUp() {
|
||||
resetState()
|
||||
viewModelScope.launch {
|
||||
datastoreRepo.clearValue(DatastoreKeys.omnivorePendingUserToken)
|
||||
datastoreRepo.clearValue(omnivorePendingUserToken)
|
||||
}
|
||||
showSocialLogin()
|
||||
}
|
||||
@ -235,7 +247,7 @@ class LoginViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
if (result.body()?.authToken != null) {
|
||||
datastoreRepo.putString(DatastoreKeys.omnivoreAuthToken, result.body()?.authToken!!)
|
||||
datastoreRepo.putString(omnivoreAuthToken, result.body()?.authToken!!)
|
||||
} else {
|
||||
errorMessage = resourceProvider.getString(
|
||||
R.string.login_view_model_something_went_wrong_error_msg)
|
||||
@ -243,7 +255,7 @@ class LoginViewModel @Inject constructor(
|
||||
|
||||
if (result.body()?.authCookieString != null) {
|
||||
datastoreRepo.putString(
|
||||
DatastoreKeys.omnivoreAuthCookieString, result.body()?.authCookieString!!
|
||||
omnivoreAuthCookieString, result.body()?.authCookieString!!
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -282,7 +294,7 @@ class LoginViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun getPendingAuthToken(): String? = runBlocking {
|
||||
datastoreRepo.getString(DatastoreKeys.omnivorePendingUserToken)
|
||||
datastoreRepo.getString(omnivorePendingUserToken)
|
||||
}
|
||||
|
||||
fun submitProfile(username: String, name: String) {
|
||||
@ -305,7 +317,7 @@ class LoginViewModel @Inject constructor(
|
||||
isLoading = false
|
||||
|
||||
if (result.body()?.authToken != null) {
|
||||
datastoreRepo.putString(DatastoreKeys.omnivoreAuthToken, result.body()?.authToken!!)
|
||||
datastoreRepo.putString(omnivoreAuthToken, result.body()?.authToken!!)
|
||||
} else {
|
||||
errorMessage = resourceProvider.getString(
|
||||
R.string.login_view_model_something_went_wrong_error_msg)
|
||||
@ -313,7 +325,7 @@ class LoginViewModel @Inject constructor(
|
||||
|
||||
if (result.body()?.authCookieString != null) {
|
||||
datastoreRepo.putString(
|
||||
DatastoreKeys.omnivoreAuthCookieString, result.body()?.authCookieString!!
|
||||
omnivoreAuthCookieString, result.body()?.authCookieString!!
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -371,11 +383,11 @@ class LoginViewModel @Inject constructor(
|
||||
isLoading = false
|
||||
|
||||
if (result.body()?.authToken != null) {
|
||||
datastoreRepo.putString(DatastoreKeys.omnivoreAuthToken, result.body()?.authToken!!)
|
||||
datastoreRepo.putString(omnivoreAuthToken, result.body()?.authToken!!)
|
||||
|
||||
if (result.body()?.authCookieString != null) {
|
||||
datastoreRepo.putString(
|
||||
DatastoreKeys.omnivoreAuthCookieString, result.body()?.authCookieString!!
|
||||
omnivoreAuthCookieString, result.body()?.authCookieString!!
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@ -409,7 +421,7 @@ class LoginViewModel @Inject constructor(
|
||||
|
||||
if (result.body()?.pendingUserToken != null) {
|
||||
datastoreRepo.putString(
|
||||
DatastoreKeys.omnivorePendingUserToken, result.body()?.pendingUserToken!!
|
||||
omnivorePendingUserToken, result.body()?.pendingUserToken!!
|
||||
)
|
||||
registrationStateLiveData.value = RegistrationState.PendingUser
|
||||
} else {
|
||||
|
||||
@ -6,13 +6,13 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.omnivore.omnivore.utils.Constants
|
||||
import app.omnivore.omnivore.utils.DatastoreKeys
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.R
|
||||
import app.omnivore.omnivore.core.data.DataService
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.core.datastore.omnivoreAuthToken
|
||||
import app.omnivore.omnivore.graphql.generated.UpdatePageMutation
|
||||
import app.omnivore.omnivore.graphql.generated.type.UpdatePageInput
|
||||
import app.omnivore.omnivore.utils.Constants
|
||||
import app.omnivore.omnivore.utils.ResourceProvider
|
||||
import com.apollographql.apollo3.ApolloClient
|
||||
import com.apollographql.apollo3.api.Optional
|
||||
@ -45,7 +45,7 @@ class EditInfoViewModel @Inject constructor(
|
||||
private set
|
||||
|
||||
private fun getAuthToken(): String? = runBlocking {
|
||||
datastoreRepo.getString(DatastoreKeys.omnivoreAuthToken)
|
||||
datastoreRepo.getString(omnivoreAuthToken)
|
||||
}
|
||||
|
||||
fun editInfo(itemId: String, title: String, author: String?, description: String?) {
|
||||
|
||||
@ -13,12 +13,14 @@ import app.omnivore.omnivore.core.data.repository.LibraryRepository
|
||||
import app.omnivore.omnivore.core.database.entities.SavedItemLabel
|
||||
import app.omnivore.omnivore.core.database.entities.SavedItemWithLabelsAndHighlights
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.core.datastore.lastUsedSavedItemFilter
|
||||
import app.omnivore.omnivore.core.datastore.lastUsedSavedItemSortFilter
|
||||
import app.omnivore.omnivore.core.datastore.libraryLastSyncTimestamp
|
||||
import app.omnivore.omnivore.feature.library.LibraryBottomSheetState
|
||||
import app.omnivore.omnivore.feature.library.SavedItemAction
|
||||
import app.omnivore.omnivore.feature.library.SavedItemFilter
|
||||
import app.omnivore.omnivore.feature.library.SavedItemSortFilter
|
||||
import app.omnivore.omnivore.feature.library.SavedItemViewModel
|
||||
import app.omnivore.omnivore.utils.DatastoreKeys
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -118,7 +120,7 @@ class FollowingViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun getLastSyncTime(): Instant? = runBlocking {
|
||||
datastoreRepo.getString(DatastoreKeys.libraryLastSyncTimestamp)?.let {
|
||||
datastoreRepo.getString(libraryLastSyncTimestamp)?.let {
|
||||
try {
|
||||
return@let Instant.parse(it)
|
||||
} catch (e: Exception) {
|
||||
@ -164,7 +166,7 @@ class FollowingViewModel @Inject constructor(
|
||||
|
||||
fun updateSavedItemFilter(filter: SavedItemFilter) {
|
||||
viewModelScope.launch {
|
||||
datastoreRepo.putString(DatastoreKeys.lastUsedSavedItemFilter, filter.rawValue)
|
||||
datastoreRepo.putString(lastUsedSavedItemFilter, filter.rawValue)
|
||||
appliedFilterState.value = filter
|
||||
handleFilterChanges()
|
||||
}
|
||||
@ -172,7 +174,7 @@ class FollowingViewModel @Inject constructor(
|
||||
|
||||
fun updateSavedItemSortFilter(filter: SavedItemSortFilter) {
|
||||
viewModelScope.launch {
|
||||
datastoreRepo.putString(DatastoreKeys.lastUsedSavedItemSortFilter, filter.rawValue)
|
||||
datastoreRepo.putString(lastUsedSavedItemSortFilter, filter.rawValue)
|
||||
appliedSortFilterLiveData.value = filter
|
||||
handleFilterChanges()
|
||||
}
|
||||
@ -225,7 +227,7 @@ class FollowingViewModel @Inject constructor(
|
||||
_libraryQuery.value = LibraryQuery(
|
||||
allowedArchiveStates = allowedArchiveStates,
|
||||
sortKey = sortKey,
|
||||
requiredLabels = requiredLabels + listOf("Newsletter", "RSS"),
|
||||
requiredLabels = requiredLabels,
|
||||
excludedLabels = excludeLabels,
|
||||
allowedContentReaders = allowedContentReaders
|
||||
)
|
||||
@ -274,7 +276,7 @@ class FollowingViewModel @Inject constructor(
|
||||
isInitialBatch = false
|
||||
)
|
||||
} else {
|
||||
datastoreRepo.putString(DatastoreKeys.libraryLastSyncTimestamp, startTime)
|
||||
datastoreRepo.putString(libraryLastSyncTimestamp, startTime)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,9 @@ import app.omnivore.omnivore.core.data.repository.LibraryRepository
|
||||
import app.omnivore.omnivore.core.database.entities.SavedItemLabel
|
||||
import app.omnivore.omnivore.core.database.entities.SavedItemWithLabelsAndHighlights
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.utils.DatastoreKeys
|
||||
import app.omnivore.omnivore.core.datastore.lastUsedSavedItemFilter
|
||||
import app.omnivore.omnivore.core.datastore.lastUsedSavedItemSortFilter
|
||||
import app.omnivore.omnivore.core.datastore.libraryLastSyncTimestamp
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -112,7 +114,7 @@ class LibraryViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
private fun getLastSyncTime(): Instant? = runBlocking {
|
||||
datastoreRepo.getString(DatastoreKeys.libraryLastSyncTimestamp)?.let {
|
||||
datastoreRepo.getString(libraryLastSyncTimestamp)?.let {
|
||||
try {
|
||||
return@let Instant.parse(it)
|
||||
} catch (e: Exception) {
|
||||
@ -158,7 +160,7 @@ class LibraryViewModel @Inject constructor(
|
||||
|
||||
fun updateSavedItemFilter(filter: SavedItemFilter) {
|
||||
viewModelScope.launch {
|
||||
datastoreRepo.putString(DatastoreKeys.lastUsedSavedItemFilter, filter.rawValue)
|
||||
datastoreRepo.putString(lastUsedSavedItemFilter, filter.rawValue)
|
||||
appliedFilterState.value = filter
|
||||
handleFilterChanges()
|
||||
}
|
||||
@ -166,7 +168,7 @@ class LibraryViewModel @Inject constructor(
|
||||
|
||||
fun updateSavedItemSortFilter(filter: SavedItemSortFilter) {
|
||||
viewModelScope.launch {
|
||||
datastoreRepo.putString(DatastoreKeys.lastUsedSavedItemSortFilter, filter.rawValue)
|
||||
datastoreRepo.putString(lastUsedSavedItemSortFilter, filter.rawValue)
|
||||
appliedSortFilterLiveData.value = filter
|
||||
handleFilterChanges()
|
||||
}
|
||||
@ -182,49 +184,46 @@ class LibraryViewModel @Inject constructor(
|
||||
private fun handleFilterChanges() {
|
||||
librarySearchCursor = null
|
||||
|
||||
if (appliedSortFilterLiveData.value != null && appliedFilterState.value != null) {
|
||||
val sortKey = when (appliedSortFilterLiveData.value) {
|
||||
SavedItemSortFilter.NEWEST -> "newest"
|
||||
SavedItemSortFilter.OLDEST -> "oldest"
|
||||
SavedItemSortFilter.RECENTLY_READ -> "recentlyRead"
|
||||
SavedItemSortFilter.RECENTLY_PUBLISHED -> "recentlyPublished"
|
||||
else -> "newest"
|
||||
}
|
||||
|
||||
val allowedArchiveStates = when (appliedFilterState.value) {
|
||||
SavedItemFilter.ALL -> listOf(0, 1)
|
||||
SavedItemFilter.ARCHIVED -> listOf(1)
|
||||
else -> listOf(0)
|
||||
}
|
||||
|
||||
val allowedContentReaders = when (appliedFilterState.value) {
|
||||
SavedItemFilter.FILES -> listOf("PDF", "EPUB")
|
||||
else -> listOf("WEB", "PDF", "EPUB")
|
||||
}
|
||||
|
||||
var requiredLabels = when (appliedFilterState.value) {
|
||||
SavedItemFilter.NEWSLETTERS -> listOf("Newsletter")
|
||||
SavedItemFilter.FEEDS -> listOf("RSS")
|
||||
else -> activeLabels.value.map { it.name }
|
||||
}
|
||||
|
||||
activeLabels.value.let { it ->
|
||||
requiredLabels = requiredLabels + it.map { it.name }
|
||||
}
|
||||
|
||||
val excludeLabels = when (appliedFilterState.value) {
|
||||
SavedItemFilter.NON_FEED -> listOf("Newsletter", "RSS")
|
||||
else -> listOf("Newsletter", "RSS")
|
||||
}
|
||||
|
||||
_libraryQuery.value = LibraryQuery(
|
||||
allowedArchiveStates = allowedArchiveStates,
|
||||
sortKey = sortKey,
|
||||
requiredLabels = requiredLabels,
|
||||
excludedLabels = excludeLabels,
|
||||
allowedContentReaders = allowedContentReaders
|
||||
)
|
||||
val sortKey = when (appliedSortFilterLiveData.value) {
|
||||
SavedItemSortFilter.NEWEST -> "newest"
|
||||
SavedItemSortFilter.OLDEST -> "oldest"
|
||||
SavedItemSortFilter.RECENTLY_READ -> "recentlyRead"
|
||||
SavedItemSortFilter.RECENTLY_PUBLISHED -> "recentlyPublished"
|
||||
}
|
||||
|
||||
val allowedArchiveStates = when (appliedFilterState.value) {
|
||||
SavedItemFilter.ALL -> listOf(0, 1)
|
||||
SavedItemFilter.ARCHIVED -> listOf(1)
|
||||
else -> listOf(0)
|
||||
}
|
||||
|
||||
val allowedContentReaders = when (appliedFilterState.value) {
|
||||
SavedItemFilter.FILES -> listOf("PDF", "EPUB")
|
||||
else -> listOf("WEB", "PDF", "EPUB")
|
||||
}
|
||||
|
||||
var requiredLabels = when (appliedFilterState.value) {
|
||||
SavedItemFilter.NEWSLETTERS -> listOf("Newsletter")
|
||||
SavedItemFilter.FEEDS -> listOf("RSS")
|
||||
else -> activeLabels.value.map { it.name }
|
||||
}
|
||||
|
||||
activeLabels.value.let { it ->
|
||||
requiredLabels = requiredLabels + it.map { it.name }
|
||||
}
|
||||
|
||||
val excludeLabels = when (appliedFilterState.value) {
|
||||
SavedItemFilter.NON_FEED -> listOf("Newsletter", "RSS")
|
||||
else -> listOf("Newsletter", "RSS")
|
||||
}
|
||||
|
||||
_libraryQuery.value = LibraryQuery(
|
||||
allowedArchiveStates = allowedArchiveStates,
|
||||
sortKey = sortKey,
|
||||
requiredLabels = requiredLabels,
|
||||
excludedLabels = excludeLabels,
|
||||
allowedContentReaders = allowedContentReaders
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun syncItems() {
|
||||
@ -270,7 +269,7 @@ class LibraryViewModel @Inject constructor(
|
||||
isInitialBatch = false
|
||||
)
|
||||
} else {
|
||||
datastoreRepo.putString(DatastoreKeys.libraryLastSyncTimestamp, startTime)
|
||||
datastoreRepo.putString(libraryLastSyncTimestamp, startTime)
|
||||
}
|
||||
}
|
||||
|
||||
@ -360,7 +359,7 @@ class LibraryViewModel @Inject constructor(
|
||||
|
||||
private fun searchQueryString(): String {
|
||||
var query =
|
||||
"${appliedFilterState.value?.queryString} ${appliedSortFilterLiveData.value?.queryString}"
|
||||
"${appliedFilterState.value.queryString} ${appliedSortFilterLiveData.value.queryString}"
|
||||
|
||||
activeLabels.value.let {
|
||||
if (it.isNotEmpty()) {
|
||||
|
||||
@ -7,9 +7,9 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.omnivore.omnivore.core.data.DataService
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.core.datastore.libraryLastSyncTimestamp
|
||||
import app.omnivore.omnivore.core.network.Networker
|
||||
import app.omnivore.omnivore.core.network.viewer
|
||||
import app.omnivore.omnivore.utils.DatastoreKeys
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import io.intercom.android.sdk.Intercom
|
||||
import io.intercom.android.sdk.IntercomSpace
|
||||
@ -33,7 +33,7 @@ class ProfileViewModel @Inject constructor(
|
||||
isResettingData = true
|
||||
|
||||
viewModelScope.launch {
|
||||
datastoreRepo.clearValue(DatastoreKeys.libraryLastSyncTimestamp)
|
||||
datastoreRepo.clearValue(libraryLastSyncTimestamp)
|
||||
dataService.clearDatabase()
|
||||
delay(1000)
|
||||
isResettingData = false
|
||||
|
||||
@ -13,21 +13,18 @@ import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavHostController
|
||||
import app.omnivore.omnivore.R
|
||||
import app.omnivore.omnivore.core.designsystem.component.SwitchPreferenceWidget
|
||||
import app.omnivore.omnivore.feature.profile.ProfileViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
internal fun FiltersScreen(
|
||||
navController: NavHostController,
|
||||
settingsViewModel: ProfileViewModel = hiltViewModel()
|
||||
filtersViewModel: FiltersViewModel = hiltViewModel()
|
||||
) {
|
||||
|
||||
Scaffold(
|
||||
@ -52,12 +49,12 @@ internal fun FiltersScreen(
|
||||
contentPadding = contentPadding,
|
||||
) {
|
||||
item {
|
||||
var checked by remember { mutableStateOf(true) }
|
||||
val followingTabActive by filtersViewModel.followingTabActiveState.collectAsStateWithLifecycle()
|
||||
|
||||
SwitchPreferenceWidget(
|
||||
title = stringResource(R.string.hide_following_tab),
|
||||
checked = checked,
|
||||
onCheckedChanged = { checked = it },
|
||||
checked = followingTabActive,
|
||||
onCheckedChanged = { filtersViewModel.setFollowingTabActiveState(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
package app.omnivore.omnivore.feature.profile.filters
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.core.datastore.followingTabActive
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class FiltersViewModel @Inject constructor(
|
||||
private val datastoreRepository: DatastoreRepository
|
||||
) : ViewModel() {
|
||||
|
||||
val followingTabActiveState: StateFlow<Boolean> = datastoreRepository.getBoolean(followingTabActive).stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(),
|
||||
initialValue = false
|
||||
)
|
||||
|
||||
fun setFollowingTabActiveState(value: Boolean) {
|
||||
viewModelScope.launch {
|
||||
datastoreRepository.putBoolean(followingTabActive, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -28,6 +28,13 @@ import app.omnivore.omnivore.core.database.dao.SavedItemDao
|
||||
import app.omnivore.omnivore.core.database.entities.SavedItem
|
||||
import app.omnivore.omnivore.core.database.entities.SavedItemLabel
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.core.datastore.preferredTheme
|
||||
import app.omnivore.omnivore.core.datastore.preferredWebFontFamily
|
||||
import app.omnivore.omnivore.core.datastore.preferredWebFontSize
|
||||
import app.omnivore.omnivore.core.datastore.preferredWebLineHeight
|
||||
import app.omnivore.omnivore.core.datastore.preferredWebMaxWidthPercentage
|
||||
import app.omnivore.omnivore.core.datastore.prefersJustifyText
|
||||
import app.omnivore.omnivore.core.datastore.prefersWebHighContrastText
|
||||
import app.omnivore.omnivore.core.network.Networker
|
||||
import app.omnivore.omnivore.core.network.createNewLabel
|
||||
import app.omnivore.omnivore.core.network.saveUrl
|
||||
@ -35,7 +42,6 @@ import app.omnivore.omnivore.core.network.savedItem
|
||||
import app.omnivore.omnivore.feature.components.HighlightColor
|
||||
import app.omnivore.omnivore.feature.library.SavedItemAction
|
||||
import app.omnivore.omnivore.graphql.generated.type.CreateLabelInput
|
||||
import app.omnivore.omnivore.utils.DatastoreKeys
|
||||
import com.apollographql.apollo3.api.Optional.Companion.presentIfNotNull
|
||||
import com.google.gson.Gson
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
@ -454,21 +460,21 @@ class WebReaderViewModel @Inject constructor(
|
||||
.asLiveData()
|
||||
|
||||
fun storedWebPreferences(isDarkMode: Boolean): WebPreferences = runBlocking {
|
||||
val storedFontSize = datastoreRepo.getInt(DatastoreKeys.preferredWebFontSize)
|
||||
val storedLineHeight = datastoreRepo.getInt(DatastoreKeys.preferredWebLineHeight)
|
||||
val storedMaxWidth = datastoreRepo.getInt(DatastoreKeys.preferredWebMaxWidthPercentage)
|
||||
val storedFontSize = datastoreRepo.getInt(preferredWebFontSize)
|
||||
val storedLineHeight = datastoreRepo.getInt(preferredWebLineHeight)
|
||||
val storedMaxWidth = datastoreRepo.getInt(preferredWebMaxWidthPercentage)
|
||||
|
||||
val storedFontFamily =
|
||||
datastoreRepo.getString(DatastoreKeys.preferredWebFontFamily) ?: WebFont.SYSTEM.rawValue
|
||||
datastoreRepo.getString(preferredWebFontFamily) ?: WebFont.SYSTEM.rawValue
|
||||
val storedThemePreference =
|
||||
datastoreRepo.getString(DatastoreKeys.preferredTheme) ?: "System"
|
||||
datastoreRepo.getString(preferredTheme) ?: "System"
|
||||
val storedWebFont =
|
||||
WebFont.entries.firstOrNull { it.rawValue == storedFontFamily } ?: WebFont.entries
|
||||
.first()
|
||||
|
||||
val prefersHighContrastFont =
|
||||
datastoreRepo.getString(DatastoreKeys.prefersWebHighContrastText) == "true"
|
||||
val prefersJustifyText = datastoreRepo.getString(DatastoreKeys.prefersJustifyText) == "true"
|
||||
datastoreRepo.getString(prefersWebHighContrastText) == "true"
|
||||
val prefersJustifyText = datastoreRepo.getString(prefersJustifyText) == "true"
|
||||
|
||||
WebPreferences(
|
||||
textFontSize = storedFontSize ?: 12,
|
||||
@ -494,7 +500,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
Log.d("theme", "Setting theme key: $newThemeKey")
|
||||
|
||||
runBlocking {
|
||||
datastoreRepo.putString(DatastoreKeys.preferredTheme, newThemeKey)
|
||||
datastoreRepo.putString(preferredTheme, newThemeKey)
|
||||
}
|
||||
|
||||
val script =
|
||||
@ -504,7 +510,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
|
||||
fun setFontSize(newFontSize: Int) {
|
||||
runBlocking {
|
||||
datastoreRepo.putInt(DatastoreKeys.preferredWebFontSize, newFontSize)
|
||||
datastoreRepo.putInt(preferredWebFontSize, newFontSize)
|
||||
}
|
||||
val script =
|
||||
"var event = new Event('updateFontSize');event.fontSize = '$newFontSize';document.dispatchEvent(event);"
|
||||
@ -514,7 +520,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
fun setMaxWidthPercentage(newMaxWidthPercentageValue: Int) {
|
||||
runBlocking {
|
||||
datastoreRepo.putInt(
|
||||
DatastoreKeys.preferredWebMaxWidthPercentage,
|
||||
preferredWebMaxWidthPercentage,
|
||||
newMaxWidthPercentageValue
|
||||
)
|
||||
}
|
||||
@ -525,7 +531,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
|
||||
fun setLineHeight(newLineHeight: Int) {
|
||||
runBlocking {
|
||||
datastoreRepo.putInt(DatastoreKeys.preferredWebLineHeight, newLineHeight)
|
||||
datastoreRepo.putInt(preferredWebLineHeight, newLineHeight)
|
||||
}
|
||||
val script =
|
||||
"var event = new Event('updateLineHeight');event.lineHeight = '$newLineHeight';document.dispatchEvent(event);"
|
||||
@ -535,7 +541,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
fun updateHighContrastTextPreference(prefersHighContrastText: Boolean) {
|
||||
runBlocking {
|
||||
datastoreRepo.putString(
|
||||
DatastoreKeys.prefersWebHighContrastText,
|
||||
prefersWebHighContrastText,
|
||||
prefersHighContrastText.toString()
|
||||
)
|
||||
}
|
||||
@ -547,7 +553,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
|
||||
fun updateJustifyText(justifyText: Boolean) {
|
||||
runBlocking {
|
||||
datastoreRepo.putString(DatastoreKeys.prefersJustifyText, justifyText.toString())
|
||||
datastoreRepo.putString(prefersJustifyText, justifyText.toString())
|
||||
}
|
||||
val script =
|
||||
"var event = new Event('updateJustifyText');event.justifyText = $justifyText;document.dispatchEvent(event);"
|
||||
@ -556,7 +562,7 @@ class WebReaderViewModel @Inject constructor(
|
||||
|
||||
fun applyWebFont(font: WebFont) {
|
||||
runBlocking {
|
||||
datastoreRepo.putString(DatastoreKeys.preferredWebFontFamily, font.rawValue)
|
||||
datastoreRepo.putString(preferredWebFontFamily, font.rawValue)
|
||||
}
|
||||
|
||||
val script =
|
||||
|
||||
@ -8,19 +8,20 @@ import androidx.compose.ui.text.intl.Locale
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import app.omnivore.omnivore.utils.Constants
|
||||
import app.omnivore.omnivore.utils.DatastoreKeys
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.R
|
||||
import app.omnivore.omnivore.core.datastore.DatastoreRepository
|
||||
import app.omnivore.omnivore.core.datastore.omnivoreAuthToken
|
||||
import app.omnivore.omnivore.graphql.generated.SaveUrlMutation
|
||||
import app.omnivore.omnivore.graphql.generated.type.SaveUrlInput
|
||||
import app.omnivore.omnivore.utils.Constants
|
||||
import app.omnivore.omnivore.utils.ResourceProvider
|
||||
import com.apollographql.apollo3.ApolloClient
|
||||
import com.apollographql.apollo3.api.Optional
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.*
|
||||
import java.util.TimeZone
|
||||
import java.util.UUID
|
||||
import java.util.regex.Pattern
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -48,7 +49,7 @@ class SaveViewModel @Inject constructor(
|
||||
private set
|
||||
|
||||
private fun getAuthToken(): String? = runBlocking {
|
||||
datastoreRepo.getString(DatastoreKeys.omnivoreAuthToken)
|
||||
datastoreRepo.getString(omnivoreAuthToken)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -3,31 +3,13 @@ package app.omnivore.omnivore.utils
|
||||
import app.omnivore.omnivore.BuildConfig
|
||||
|
||||
object Constants {
|
||||
const val apiURL = BuildConfig.OMNIVORE_API_URL
|
||||
const val dataStoreName = "omnivore-datastore"
|
||||
}
|
||||
|
||||
object DatastoreKeys {
|
||||
const val omnivoreSelfHostedAPIServer = "omnivoreSelfHostedAPIServer"
|
||||
const val omnivoreSelfHostedWebServer = "omnivoreSelfHostedWebServer"
|
||||
const val omnivoreAuthToken = "omnivoreAuthToken"
|
||||
const val omnivoreAuthCookieString = "omnivoreAuthCookieString"
|
||||
const val omnivorePendingUserToken = "omnivorePendingUserToken"
|
||||
const val libraryLastSyncTimestamp = "libraryLastSyncTimestamp"
|
||||
const val preferredWebFontSize = "preferredWebFontSize"
|
||||
const val preferredWebLineHeight = "preferredWebLineHeight"
|
||||
const val preferredWebMaxWidthPercentage = "preferredWebMaxWidthPercentage"
|
||||
const val preferredWebFontFamily = "preferredWebFontFamily"
|
||||
const val prefersWebHighContrastText = "prefersWebHighContrastText"
|
||||
const val prefersJustifyText = "prefersJustifyText"
|
||||
const val lastUsedSavedItemFilter = "lastUsedSavedItemFilter"
|
||||
const val lastUsedSavedItemSortFilter = "lastUsedSavedItemSortFilter"
|
||||
const val preferredTheme = "preferredTheme"
|
||||
const val apiURL = BuildConfig.OMNIVORE_API_URL
|
||||
const val dataStoreName = "omnivore-datastore"
|
||||
}
|
||||
|
||||
object AppleConstants {
|
||||
const val clientId = "app.omnivore"
|
||||
const val redirectURI = BuildConfig.OMNIVORE_API_URL + "/api/mobile-auth/android-apple-redirect"
|
||||
const val scope = "name%20email"
|
||||
const val authUrl = "https://appleid.apple.com/auth/authorize"
|
||||
const val clientId = "app.omnivore"
|
||||
const val redirectURI = BuildConfig.OMNIVORE_API_URL + "/api/mobile-auth/android-apple-redirect"
|
||||
const val scope = "name%20email"
|
||||
const val authUrl = "https://appleid.apple.com/auth/authorize"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user