From c579c0137f9e045b109c2efa6dde69ba3de844a4 Mon Sep 17 00:00:00 2001 From: Ash Date: Thu, 18 Jan 2024 18:30:17 +0800 Subject: [PATCH] feat(greader): support groups and feeds --- .../ash/reader/domain/repository/FeedDao.kt | 9 ++ .../domain/service/AbstractRssRepository.kt | 35 +++++-- .../reader/domain/service/FeverRssService.kt | 34 ++++++- .../domain/service/GoogleReaderRssService.kt | 95 ++++++++++++++++--- .../rss/provider/greader/GoogleReaderAPI.kt | 62 ++++++++---- .../reader/ui/page/home/feeds/FeedsPage.kt | 2 +- .../feeds/drawer/feed/FeedOptionDrawer.kt | 8 +- .../feeds/drawer/feed/FeedOptionViewModel.kt | 13 ++- .../feeds/drawer/group/GroupOptionDrawer.kt | 6 +- .../drawer/group/GroupOptionViewModel.kt | 2 +- .../feeds/subscribe/SubscribeViewModel.kt | 3 +- 11 files changed, 207 insertions(+), 62 deletions(-) diff --git a/app/src/main/java/me/ash/reader/domain/repository/FeedDao.kt b/app/src/main/java/me/ash/reader/domain/repository/FeedDao.kt index 526dee6d0..8b004c640 100644 --- a/app/src/main/java/me/ash/reader/domain/repository/FeedDao.kt +++ b/app/src/main/java/me/ash/reader/domain/repository/FeedDao.kt @@ -45,6 +45,15 @@ interface FeedDao { isNotification: Boolean, ) + @Query( + """ + SELECT * FROM feed + WHERE groupId = :groupId + AND accountId = :accountId + """ + ) + suspend fun queryByGroupId(accountId: Int, groupId: String): List + @Query( """ DELETE FROM feed diff --git a/app/src/main/java/me/ash/reader/domain/service/AbstractRssRepository.kt b/app/src/main/java/me/ash/reader/domain/service/AbstractRssRepository.kt index 3274847d8..62bac31f3 100644 --- a/app/src/main/java/me/ash/reader/domain/service/AbstractRssRepository.kt +++ b/app/src/main/java/me/ash/reader/domain/service/AbstractRssRepository.kt @@ -44,10 +44,10 @@ abstract class AbstractRssRepository( private val dispatcherDefault: CoroutineDispatcher, ) { - open val subscribe: Boolean = true - open val move: Boolean = true - open val delete: Boolean = true - open val update: Boolean = true + open val addSubscription: Boolean = true + open val moveSubscription: Boolean = true + open val deleteSubscription: Boolean = true + open val updateSubscription: Boolean = true open suspend fun validCredentials(): Boolean = true @@ -73,13 +73,16 @@ abstract class AbstractRssRepository( }) } - open suspend fun addGroup(name: String): String { + open suspend fun addGroup( + destFeed: Feed?, + newGroupName: String + ): String { context.currentAccountId.let { accountId -> return accountId.spacerDollar(UUID.randomUUID().toString()).also { groupDao.insert( Group( id = it, - name = name, + name = newGroupName, accountId = accountId ) ) @@ -290,21 +293,33 @@ abstract class AbstractRssRepository( suspend fun isFeedExist(url: String): Boolean = feedDao.queryByLink(context.currentAccountId, url).isNotEmpty() - suspend fun updateGroup(group: Group) { + open suspend fun renameGroup(group: Group) { groupDao.update(group) } - suspend fun updateFeed(feed: Feed) { + open suspend fun renameFeed(feed: Feed) { + updateFeed(feed) + } + + open suspend fun moveFeed(originGroupId: String, feed: Feed) { + updateFeed(feed) + } + + open suspend fun changeFeedUrl(feed: Feed) { + updateFeed(feed) + } + + internal suspend fun updateFeed(feed: Feed) { feedDao.update(feed) } - suspend fun deleteGroup(group: Group) { + open suspend fun deleteGroup(group: Group) { deleteArticles(group = group) feedDao.deleteByGroupId(context.currentAccountId, group.id) groupDao.delete(group) } - suspend fun deleteFeed(feed: Feed) { + open suspend fun deleteFeed(feed: Feed) { deleteArticles(feed = feed) feedDao.delete(feed) } diff --git a/app/src/main/java/me/ash/reader/domain/service/FeverRssService.kt b/app/src/main/java/me/ash/reader/domain/service/FeverRssService.kt index cadde6a75..cd23f8fb4 100644 --- a/app/src/main/java/me/ash/reader/domain/service/FeverRssService.kt +++ b/app/src/main/java/me/ash/reader/domain/service/FeverRssService.kt @@ -57,10 +57,10 @@ class FeverRssService @Inject constructor( feedDao, workManager, rssHelper, notificationHelper, ioDispatcher, defaultDispatcher ) { - override val subscribe: Boolean = false - override val move: Boolean = false - override val delete: Boolean = false - override val update: Boolean = false + override val addSubscription: Boolean = false + override val moveSubscription: Boolean = false + override val deleteSubscription: Boolean = false + override val updateSubscription: Boolean = false private suspend fun getFeverAPI() = FeverSecurityKey(accountDao.queryById(context.currentAccountId)!!.securityKey).run { @@ -86,7 +86,31 @@ class FeverRssService @Inject constructor( throw Exception("Unsupported") } - override suspend fun addGroup(name: String): String { + override suspend fun addGroup(destFeed: Feed?, newGroupName: String): String { + throw Exception("Unsupported") + } + + override suspend fun renameGroup(group: Group) { + throw Exception("Unsupported") + } + + override suspend fun renameFeed(feed: Feed) { + throw Exception("Unsupported") + } + + override suspend fun deleteGroup(group: Group) { + throw Exception("Unsupported") + } + + override suspend fun deleteFeed(feed: Feed) { + throw Exception("Unsupported") + } + + override suspend fun moveFeed(originGroupId: String, feed: Feed) { + throw Exception("Unsupported") + } + + override suspend fun changeFeedUrl(feed: Feed) { throw Exception("Unsupported") } diff --git a/app/src/main/java/me/ash/reader/domain/service/GoogleReaderRssService.kt b/app/src/main/java/me/ash/reader/domain/service/GoogleReaderRssService.kt index 9c49c1346..74baed970 100644 --- a/app/src/main/java/me/ash/reader/domain/service/GoogleReaderRssService.kt +++ b/app/src/main/java/me/ash/reader/domain/service/GoogleReaderRssService.kt @@ -27,9 +27,9 @@ import me.ash.reader.infrastructure.di.IODispatcher import me.ash.reader.infrastructure.di.MainDispatcher import me.ash.reader.infrastructure.rss.RssHelper import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI -import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI.Companion.ofCategoryPathToId -import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI.Companion.ofFeedPathToId -import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI.Companion.ofItemPathToId +import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI.Companion.ofCategoryStreamIdToId +import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI.Companion.ofFeedStreamIdToId +import me.ash.reader.infrastructure.rss.provider.greader.GoogleReaderAPI.Companion.ofItemStreamIdToId import me.ash.reader.ui.ext.currentAccountId import me.ash.reader.ui.ext.dollarLast import me.ash.reader.ui.ext.showToast @@ -59,10 +59,10 @@ class GoogleReaderRssService @Inject constructor( feedDao, workManager, rssHelper, notificationHelper, ioDispatcher, defaultDispatcher ) { - // override val subscribe: Boolean = true - // override val move: Boolean = true - // override val delete: Boolean = true - // override val update: Boolean = true + override val addSubscription: Boolean = true + override val moveSubscription: Boolean = true + override val deleteSubscription: Boolean = true + override val updateSubscription: Boolean = true private suspend fun getGoogleReaderAPI() = GoogleReaderSecurityKey(accountDao.queryById(context.currentAccountId)!!.securityKey).run { @@ -87,9 +87,12 @@ class GoogleReaderRssService @Inject constructor( ) { val accountId = context.currentAccountId val quickAdd = getGoogleReaderAPI().subscriptionQuickAdd(feedLink) - val feedId = quickAdd.streamId?.ofFeedPathToId()!! - getGoogleReaderAPI().subscriptionEdit(feedId, groupId.dollarLast()) - // TODO: Support rename while adding a subscription + val feedId = quickAdd.streamId?.ofFeedStreamIdToId()!! + getGoogleReaderAPI().subscriptionEdit( + destFeedId = feedId, + destCategoryId = groupId.dollarLast(), + destFeedName = searchedFeed.title!! + ) feedDao.insert(Feed( id = accountId.spacerDollar(feedId), name = searchedFeed.title!!, @@ -102,10 +105,72 @@ class GoogleReaderRssService @Inject constructor( SyncWorker.enqueueOneTimeWork(workManager) } - override suspend fun addGroup(name: String): String { + override suspend fun addGroup( + destFeed: Feed?, + newGroupName: String, + ): String { + val accountId = context.currentAccountId + getGoogleReaderAPI().subscriptionEdit( + destFeedId = destFeed?.id?.dollarLast(), + destCategoryId = newGroupName + ) + val id = accountId.spacerDollar(newGroupName) + groupDao.insert( + Group( + id = id, + name = newGroupName, + accountId = accountId + ) + ) + return id + } + + override suspend fun renameGroup(group: Group) { + getGoogleReaderAPI().renameTag( + categoryId = group.id.dollarLast(), + renameToName = group.name + ) + // TODO: Whether to switch the old ID to the new ID? + super.renameGroup(group) + } + + override suspend fun moveFeed(originGroupId: String, feed: Feed) { + getGoogleReaderAPI().subscriptionEdit( + destFeedId = feed.id.dollarLast(), + destCategoryId = feed.groupId.dollarLast(), + originCategoryId = originGroupId.dollarLast(), + ) + super.moveFeed(originGroupId, feed) + } + + override suspend fun changeFeedUrl(feed: Feed) { throw Exception("Unsupported") } + override suspend fun renameFeed(feed: Feed) { + getGoogleReaderAPI().subscriptionEdit( + destFeedId = feed.id.dollarLast(), + destFeedName = feed.name + ) + // TODO: Whether to switch the old ID to the new ID? + super.renameFeed(feed) + } + + override suspend fun deleteGroup(group: Group) { + feedDao.queryByGroupId(context.currentAccountId, group.id) + .forEach { deleteFeed(it) } + getGoogleReaderAPI().disableTag(group.id.dollarLast()) + super.deleteGroup(group) + } + + override suspend fun deleteFeed(feed: Feed) { + getGoogleReaderAPI().subscriptionEdit( + action = "unsubscribe", + destFeedId = feed.id.dollarLast() + ) + super.deleteFeed(feed) + } + /** * Google Reader API synchronous processing with object's ID to ensure idempotence * and handle foreign key relationships such as read status, starred status, etc. @@ -141,7 +206,7 @@ class GoogleReaderRssService @Inject constructor( googleReaderAPI.getSubscriptionList() .subscriptions.groupBy { it.categories?.first() } .forEach { (category, feeds) -> - val groupId = accountId.spacerDollar(category?.id?.ofCategoryPathToId()!!) + val groupId = accountId.spacerDollar(category?.id?.ofCategoryStreamIdToId()!!) // Handle folders groupDao.insert( @@ -156,7 +221,7 @@ class GoogleReaderRssService @Inject constructor( // Handle feeds feedDao.insert( *feeds.map { - val feedId = accountId.spacerDollar(it.id?.ofFeedPathToId()!!) + val feedId = accountId.spacerDollar(it.id?.ofFeedStreamIdToId()!!) Feed( id = feedId, name = it.title ?: context.getString(R.string.empty), @@ -197,7 +262,7 @@ class GoogleReaderRssService @Inject constructor( readIds?.map { it.id!! }?.chunked(100)?.forEach { chunkedIds -> articleDao.insert( *googleReaderAPI.getItemsContents(chunkedIds).items?.map { - val articleId = it.id!!.ofItemPathToId() + val articleId = it.id!!.ofItemStreamIdToId() Article( id = accountId.spacerDollar(articleId), date = it.published?.run { Date(this * 1000) } ?: Date(), @@ -213,7 +278,7 @@ class GoogleReaderRssService @Inject constructor( link = it.canonical?.first()?.href ?: it.alternate?.first()?.href ?: it.origin?.htmlUrl ?: "", - feedId = accountId.spacerDollar(it.origin?.streamId?.ofFeedPathToId() ?: feedIds.first()), + feedId = accountId.spacerDollar(it.origin?.streamId?.ofFeedStreamIdToId() ?: feedIds.first()), accountId = accountId, isUnread = unreadIds?.contains(articleId) ?: true, isStarred = starredIds?.contains(articleId) ?: false, diff --git a/app/src/main/java/me/ash/reader/infrastructure/rss/provider/greader/GoogleReaderAPI.kt b/app/src/main/java/me/ash/reader/infrastructure/rss/provider/greader/GoogleReaderAPI.kt index 653798131..f50650583 100644 --- a/app/src/main/java/me/ash/reader/infrastructure/rss/provider/greader/GoogleReaderAPI.kt +++ b/app/src/main/java/me/ash/reader/infrastructure/rss/provider/greader/GoogleReaderAPI.kt @@ -24,11 +24,11 @@ class GoogleReaderAPI private constructor( private val authData = AuthData(null, null) suspend fun validCredentials(): Boolean { - reAuthentication() + reauthenticate() return authData.clientLoginToken?.isNotEmpty() ?: false } - private suspend fun reAuthentication() { + private suspend fun reauthenticate() { // Get client login token val clResponse = client.newCall( Request.Builder() @@ -109,7 +109,7 @@ class GoogleReaderAPI private constructor( params: List>? = null, ): T { if (authData.clientLoginToken.isNullOrEmpty()) { - reAuthentication() + reauthenticate() } val response = client.newCall( @@ -143,7 +143,7 @@ class GoogleReaderAPI private constructor( form: List>? = null, ): T { if (authData.clientLoginToken.isNullOrEmpty()) { - reAuthentication() + reauthenticate() } val response = client.newCall( Request.Builder() @@ -219,16 +219,42 @@ class GoogleReaderAPI private constructor( form = listOf(Pair("quickadd", feedUrl)) ) - suspend fun subscriptionEdit(feedId: String, categoryId: String): String = + enum class subscriptionOperationType + + suspend fun editTag(categoryName: String): String = + retryablePostRequest( + query = "reader/api/0/edit-tag", + form = listOf(Pair("a", categoryName.ofCategoryIdToStreamId())) + ) + + suspend fun disableTag(categoryId: String): String = + retryablePostRequest( + query = "reader/api/0/disable-tag", + form = listOf(Pair("s", categoryId.ofCategoryIdToStreamId())) + ) + + suspend fun renameTag(categoryId: String, renameToName: String): String = retryablePostRequest( - query = "reader/api/0/subscription/edit", + query = "reader/api/0/rename-tag", form = listOf( - Pair("ac", "edit"), - Pair("s", feedId.ofFeedIdToPath()), - Pair("a", categoryId.ofCategoryIdToPath()), + Pair("s", categoryId.ofCategoryIdToStreamId()), + Pair("dest", renameToName.ofCategoryIdToStreamId()), ) ) + suspend fun subscriptionEdit( + action: String = "edit", destFeedId: String? = null, destCategoryId: String? = null, + originCategoryId: String? = null, destFeedName: String? = null, + ): String = retryablePostRequest( + query = "reader/api/0/subscription/edit", + form = mutableListOf(Pair("ac", action)).apply { + if (destFeedId != null) add(Pair("s", destFeedId.ofFeedIdToStreamId())) + if (destCategoryId != null) add(Pair("a", destCategoryId.ofCategoryIdToStreamId())) + if (originCategoryId != null) add(Pair("r", originCategoryId.ofCategoryIdToStreamId())) + if (destFeedName?.isNotBlank() == true) add(Pair("t", destFeedName)) + } + ) + companion object { const val MAXIMUM_ITEMS_LIMIT = "10000" @@ -241,35 +267,35 @@ class GoogleReaderAPI private constructor( return toLong(16).toString() } - fun String.ofItemPathToHexId(): String { + fun String.ofItemStreamIdToHexId(): String { return replace("tag:google.com,2005:reader/item/", "") } - fun String.ofItemPathToId(): String { - return ofItemPathToHexId().ofItemHexIdToId() + fun String.ofItemStreamIdToId(): String { + return ofItemStreamIdToHexId().ofItemHexIdToId() } - fun String.ofItemHexIdToPath(): String { + fun String.ofItemHexIdToStreamId(): String { return "tag:google.com,2005:reader/item/$this" } - fun String.ofItemIdToPath(): String { + fun String.ofItemIdToStreamId(): String { return "tag:google.com,2005:reader/item/${ofItemIdToHexId()}" } - fun String.ofFeedIdToPath(): String { + fun String.ofFeedIdToStreamId(): String { return "feed/$this" } - fun String.ofFeedPathToId(): String { + fun String.ofFeedStreamIdToId(): String { return replace("feed/", "") } - fun String.ofCategoryIdToPath(): String { + fun String.ofCategoryIdToStreamId(): String { return "user/-/label/$this" } - fun String.ofCategoryPathToId(): String { + fun String.ofCategoryStreamIdToId(): String { return replace("user/-/label/", "") } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt index 3de0427a7..3bd96400d 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt @@ -148,7 +148,7 @@ fun FeedsPage( ) { if (!isSyncing) homeViewModel.sync() } - if (subscribeViewModel.rssService.get().subscribe) { + if (subscribeViewModel.rssService.get().addSubscription) { FeedbackIconButton( imageVector = Icons.Rounded.Add, contentDescription = stringResource(R.string.subscribe), diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionDrawer.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionDrawer.kt index c8e139a49..da0082111 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionDrawer.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionDrawer.kt @@ -73,7 +73,7 @@ fun FeedOptionDrawer( Spacer(modifier = Modifier.height(16.dp)) Text( modifier = Modifier.roundClick { - if (feedOptionViewModel.rssService.get().update) { + if (feedOptionViewModel.rssService.get().updateSubscription) { feedOptionViewModel.showRenameDialog() } }, @@ -92,8 +92,8 @@ fun FeedOptionDrawer( ?: false, selectedParseFullContentPreset = feedOptionUiState.feed?.isFullContent ?: false, isMoveToGroup = true, - showGroup = feedOptionViewModel.rssService.get().move, - showUnsubscribe = feedOptionViewModel.rssService.get().delete, + showGroup = feedOptionViewModel.rssService.get().moveSubscription, + showUnsubscribe = feedOptionViewModel.rssService.get().deleteSubscription, notSubscribeMode = true, selectedGroupId = feedOptionUiState.feed?.groupId ?: "", allowNotificationPresetOnClick = { @@ -118,7 +118,7 @@ fun FeedOptionDrawer( context.openURL(feed?.url, openLink, openLinkSpecificBrowser) }, onFeedUrlLongClick = { - if (feedOptionViewModel.rssService.get().update) { + if (feedOptionViewModel.rssService.get().updateSubscription) { view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) feedOptionViewModel.showFeedUrlDialog() } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionViewModel.kt index 098f9f12f..f87ac2f92 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/feed/FeedOptionViewModel.kt @@ -88,7 +88,9 @@ class FeedOptionViewModel @Inject constructor( fun addNewGroup() { if (_feedOptionUiState.value.newGroupContent.isNotBlank()) { viewModelScope.launch { - selectedGroup(rssService.get().addGroup(_feedOptionUiState.value.newGroupContent)) + selectedGroup(rssService.get().addGroup( + destFeed = _feedOptionUiState.value.feed, + newGroupName = _feedOptionUiState.value.newGroupContent)) hideNewGroupDialog() } } @@ -97,7 +99,10 @@ class FeedOptionViewModel @Inject constructor( fun selectedGroup(groupId: String) { viewModelScope.launch(ioDispatcher) { _feedOptionUiState.value.feed?.let { - rssService.get().updateFeed(it.copy(groupId = groupId)) + rssService.get().moveFeed( + originGroupId = it.groupId, + feed = it.copy(groupId = groupId) + ) fetchFeed(it.id) } } @@ -162,7 +167,7 @@ class FeedOptionViewModel @Inject constructor( fun renameFeed() { _feedOptionUiState.value.feed?.let { viewModelScope.launch { - rssService.get().updateFeed(it.copy(name = _feedOptionUiState.value.newName)) + rssService.get().renameFeed(it.copy(name = _feedOptionUiState.value.newName)) _feedOptionUiState.update { it.copy(renameDialogVisible = false) } } } @@ -215,7 +220,7 @@ class FeedOptionViewModel @Inject constructor( fun changeFeedUrl() { _feedOptionUiState.value.feed?.let { viewModelScope.launch { - rssService.get().updateFeed(it.copy(url = _feedOptionUiState.value.newUrl)) + rssService.get().changeFeedUrl(it.copy(url = _feedOptionUiState.value.newUrl)) _feedOptionUiState.update { it.copy(changeUrlDialogVisible = false) } } } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/group/GroupOptionDrawer.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/group/GroupOptionDrawer.kt index 9b1449677..0e5e24f6b 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/group/GroupOptionDrawer.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/group/GroupOptionDrawer.kt @@ -73,7 +73,7 @@ fun GroupOptionDrawer( Spacer(modifier = Modifier.height(16.dp)) Text( modifier = Modifier.roundClick { - if (viewModel.rssService.get().update) { + if (viewModel.rssService.get().updateSubscription) { viewModel.showRenameDialog() } }, @@ -106,7 +106,7 @@ fun GroupOptionDrawer( Spacer(modifier = Modifier.height(10.dp)) Preset(viewModel, group, context) - if (viewModel.rssService.get().move && groupOptionUiState.groups.size != 1) { + if (viewModel.rssService.get().moveSubscription && groupOptionUiState.groups.size != 1) { Spacer(modifier = Modifier.height(26.dp)) Subtitle(text = stringResource(R.string.move_to_group)) Spacer(modifier = Modifier.height(10.dp)) @@ -199,7 +199,7 @@ private fun Preset( ) { viewModel.showClearDialog() } - if (viewModel.rssService.get().delete && group?.id != context.currentAccountId.getDefaultGroupId()) { + if (viewModel.rssService.get().deleteSubscription && group?.id != context.currentAccountId.getDefaultGroupId()) { RYSelectionChip( modifier = Modifier.animateContentSize(), content = stringResource(R.string.delete_group), diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/group/GroupOptionViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/group/GroupOptionViewModel.kt index 2ae8ea11b..20bd78cd7 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/group/GroupOptionViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/drawer/group/GroupOptionViewModel.kt @@ -162,7 +162,7 @@ class GroupOptionViewModel @Inject constructor( fun rename() { _groupOptionUiState.value.group?.let { viewModelScope.launch { - rssService.get().updateGroup(it.copy(name = _groupOptionUiState.value.newName)) + rssService.get().renameGroup(it.copy(name = _groupOptionUiState.value.newName)) _groupOptionUiState.update { it.copy(renameDialogVisible = false) } } } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/SubscribeViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/SubscribeViewModel.kt index 92a95c80f..d735f3bdc 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/SubscribeViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/subscribe/SubscribeViewModel.kt @@ -65,7 +65,8 @@ class SubscribeViewModel @Inject constructor( fun addNewGroup() { if (_subscribeUiState.value.newGroupContent.isNotBlank()) { viewModelScope.launch { - selectedGroup(rssService.get().addGroup(_subscribeUiState.value.newGroupContent)) + // TODO: How to add a single group without no feeds via Google Reader API? + selectedGroup(rssService.get().addGroup(null, _subscribeUiState.value.newGroupContent)) hideNewGroupDialog() _subscribeUiState.update { it.copy(newGroupContent = "") } }