Skip to content

Commit

Permalink
Edit feed (#46)
Browse files Browse the repository at this point in the history
* Move feed unsubscribe button to dropdown

* Add dialog to edit feed
  • Loading branch information
jocmp authored Jan 14, 2024
1 parent 171ef25 commit 530c0d3
Show file tree
Hide file tree
Showing 32 changed files with 796 additions and 137 deletions.
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

0 comments on commit 530c0d3

Please sign in to comment.