Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edit feed #46

Merged
merged 2 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.serialization") version "1.9.21"
kotlin("plugin.serialization") version libs.versions.kotlin
}

android {
Expand Down Expand Up @@ -41,7 +41,7 @@ android {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.4"
kotlinCompilerExtensionVersion = "1.5.8"
}
packaging {
resources {
Expand Down
51 changes: 46 additions & 5 deletions app/src/main/java/com/jocmp/basilreader/ContextPreferencesExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,58 @@ import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import com.jocmp.basil.ArticleFilter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

val Context.settings by preferencesDataStore("settings")

fun Preferences.selectedAccount(): String? {
return get(stringPreferencesKey("account_id"))
val Preferences.selectedAccountID: String?
get() = get(stringPreferencesKey("account_id"))

val Preferences.filter: ArticleFilter?
get() = getSerializable("filter")

val Preferences.articleID: String?
get() = get(stringPreferencesKey("article_id"))

suspend fun DataStore<Preferences>.putAccountID(id: String) {
edit { preferences ->
preferences[stringPreferencesKey("account_id")] = id
}
}

suspend fun DataStore<Preferences>.selectAccount(id: String) {
val key = stringPreferencesKey("account_id")
suspend fun DataStore<Preferences>.putArticleID(id: String?) = withContext(Dispatchers.IO) {
val key = stringPreferencesKey("article_id")

edit { preferences ->
preferences[key] = id
if (id.isNullOrBlank()) {
preferences.remove(key)
} else {
preferences[key] = id
}
}
}

suspend fun DataStore<Preferences>.putFilter(articleFilter: ArticleFilter) {
putSerializable("filter", articleFilter)
}

private suspend inline fun <reified S> DataStore<Preferences>.putSerializable(
key: String,
value: S
) {
val jsonString = Json.encodeToString(value)

edit { preferences ->
preferences[stringPreferencesKey(key)] = jsonString
}
}

private inline fun <reified S> Preferences.getSerializable(key: String): S? {
return get(stringPreferencesKey(key))?.let {
Json.decodeFromString(it) as? S
}
}
2 changes: 1 addition & 1 deletion app/src/main/java/com/jocmp/basilreader/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class MainActivity : ComponentActivity() {
}

private fun startDestination(): String {
val accountID = runBlocking { baseContext.settings.data.first().selectedAccount() }
val accountID = runBlocking { baseContext.settings.data.first().selectedAccountID }

return if (accountID.isNullOrBlank()) {
"accounts"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import com.jocmp.basil.AccountManager
import com.jocmp.basil.AccountManager.AccountSummary
import com.jocmp.basilreader.selectAccount
import com.jocmp.basilreader.putAccountID
import com.jocmp.basilreader.settings
import kotlinx.coroutines.launch
import org.koin.compose.koinInject
Expand Down Expand Up @@ -46,7 +46,7 @@ fun AccountIndexView(
items(accounts, key = { it.id }) { account ->
Row(modifier = Modifier.clickable {
composableScope.launch {
context.settings.selectAccount(account.id)
context.settings.putAccountID(account.id)
onSelect()
}
}) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.jocmp.basilreader.AndroidDatabaseProvider
import com.jocmp.basilreader.AccountPreferencesProvider
import com.jocmp.basil.PreferencesProvider
import com.jocmp.basilreader.settings
import com.jocmp.basilreader.ui.articles.EditFeedViewModel
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
Expand All @@ -33,4 +34,11 @@ internal val accountModule = module {
settings = androidContext().settings
)
}
viewModel {
EditFeedViewModel(
savedStateHandle = get(),
accountManager = get(),
settings = androidContext().settings
)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.jocmp.basilreader.ui.accounts

import EditFeedForm
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.neverEqualPolicy
Expand All @@ -14,24 +15,28 @@ import com.jocmp.basil.Article
import com.jocmp.basil.ArticleFilter
import com.jocmp.basil.ArticleStatus
import com.jocmp.basil.Feed
import com.jocmp.basil.FeedFormEntry
import com.jocmp.basil.AddFeedForm
import com.jocmp.basil.Folder
import com.jocmp.basil.buildPager
import com.jocmp.basil.unreadCounts
import com.jocmp.basilreader.selectedAccount
import com.jocmp.basilreader.articleID
import com.jocmp.basilreader.filter
import com.jocmp.basilreader.putArticleID
import com.jocmp.basilreader.putFilter
import com.jocmp.basilreader.selectedAccountID
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

private const val TAG = "AccountViewModel"

class AccountViewModel(
private val accountManager: AccountManager,
accountManager: AccountManager,
private val settings: DataStore<Preferences>,
) : ViewModel() {
private val initialPreferences = runBlocking { settings.data.first() }

private val accountState: MutableState<Account> = mutableStateOf(
accountManager.findByID(runBlocking { settings.data.first() }.selectedAccount())!!,
accountManager.findByID(initialPreferences.selectedAccountID)!!,
policy = neverEqualPolicy()
)

Expand All @@ -41,7 +46,7 @@ class AccountViewModel(
refreshUnreadCounts()
}

private val filter = mutableStateOf<ArticleFilter>(ArticleFilter.default())
private val filter = mutableStateOf(ArticleFilter.findOrDefault(initialPreferences))

private val pager = mutableStateOf(account.buildPager(filter.value))

Expand All @@ -54,7 +59,7 @@ class AccountViewModel(
val folders: List<Folder>
get() = account.folders.map(::copyFolderUnreadCounts)

private val articleState = mutableStateOf<Article?>(null)
private val articleState = mutableStateOf(account.findArticleOrNull(initialPreferences))

val feeds: List<Feed>
get() = account.feeds.map(::copyFeedUnreadCounts)
Expand All @@ -65,22 +70,28 @@ class AccountViewModel(
val filterStatus: ArticleStatus
get() = filter.value.status

val feed: Feed?
get() = (filter.value as? ArticleFilter.Feeds)?.feed

val isFeedSelected: Boolean
get() = filter.value is ArticleFilter.Feeds

fun selectStatus(status: ArticleStatus) {
val nextFilter = filter.value.withStatus(status = status)
filter.value = nextFilter
pager.value = account.buildPager(nextFilter)

updateFilterValue(nextFilter)
}

fun selectFeed(feedID: String) {
val feed = account.findFeed(feedID) ?: return
val feedFilter = ArticleFilter.Feeds(feed = feed, status = filter.value.status)
val feedFilter = ArticleFilter.Feeds(feed = feed, feedStatus = filter.value.status)

selectFilter(feedFilter)
}

fun selectFolder(title: String) {
val folder = account.findFolder(title) ?: return
val feedFilter = ArticleFilter.Folders(folder = folder, status = filter.value.status)
val feedFilter = ArticleFilter.Folders(folder = folder, folderStatus = filter.value.status)

selectFilter(feedFilter)
}
Expand Down Expand Up @@ -109,6 +120,10 @@ class AccountViewModel(
account.markRead(articleID)
articleState.value = account.findArticle(articleID = articleID)

viewModelScope.launch {
settings.putArticleID(articleID)
}

refreshUnreadCounts()
}

Expand Down Expand Up @@ -140,12 +155,35 @@ class AccountViewModel(

fun clearArticle() {
articleState.value = null

viewModelScope.launch {
settings.putArticleID(null)
}
}

private fun selectFilter(nextFilter: ArticleFilter) {
fun addFeed(entry: AddFeedForm, onSuccess: () -> Unit) {
viewModelScope.launch {
val result = account.addFeed(entry)

result.onSuccess { feed ->
selectFeed(feed.id)
onSuccess()
}
}
}

private fun updateFilterValue(nextFilter: ArticleFilter) {
filter.value = nextFilter
pager.value = account.buildPager(nextFilter)

viewModelScope.launch {
settings.putFilter(nextFilter)
}
}

private fun selectFilter(nextFilter: ArticleFilter) {
updateFilterValue(nextFilter)

clearArticle()
}

Expand Down Expand Up @@ -179,13 +217,12 @@ class AccountViewModel(
_unreadCounts.value = accountState.value.unreadCounts
}
}
}

fun addFeed(entry: FeedFormEntry, onSuccess: () -> Unit) {
viewModelScope.launch {
account.addFeed(entry).onSuccess {
accountState.value = account
onSuccess()
}
}
}
private fun ArticleFilter.Companion.findOrDefault(preferences: Preferences): ArticleFilter {
return preferences.filter ?: default()
}

private fun Account.findArticleOrNull(preferences: Preferences): Article? {
return preferences.articleID?.let { findArticle(it) }
}
Loading