feat: change favorites from navigation drawer (#993)

This commit is contained in:
Diego Beraldin 2024-06-17 09:35:02 +02:00 committed by GitHub
parent 98ad71100a
commit 005b2cbdbc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
54 changed files with 742 additions and 419 deletions

View File

@ -416,4 +416,5 @@ internal val ArStrings =
override val noticeBannedUser = "تم حظر المستخدم الحالي من هذا المجتمع"
override val settingsHiddenPosts = "المشاركات المخفية"
override val settingsMediaList = "تحميلات الوسائط"
override val settingsEnableToggleFavoriteInNavDrawer = "إضافة/إزالة المفضلة في درج التنقل"
}

View File

@ -424,4 +424,6 @@ internal val BgStrings =
override val noticeBannedUser = "Настоящият потребител е забранен от тази общност"
override val settingsHiddenPosts = "Скрити публикации"
override val settingsMediaList = "Качване на мултимедия"
override val settingsEnableToggleFavoriteInNavDrawer =
"Добавяне/премахване на любими в чекмеджето за навигация"
}

View File

@ -420,4 +420,6 @@ internal val CsStrings =
override val noticeBannedUser = "Aktuálnímu uživateli byl zakázán přístup do této komunity"
override val settingsHiddenPosts = "Skryté příspěvky"
override val settingsMediaList = "Nahrávání médií"
override val settingsEnableToggleFavoriteInNavDrawer =
"Přidat/odebrat oblíbené položky v navigační zásuvce"
}

View File

@ -420,4 +420,6 @@ internal val DaStrings =
"Den nuværende bruger er blevet udelukket fra dette fællesskab"
override val settingsHiddenPosts = "Skjulte indlæg"
override val settingsMediaList = "Medieuploads"
override val settingsEnableToggleFavoriteInNavDrawer =
"Tilføj/fjern favoritter i navigationsskuffen"
}

View File

@ -423,4 +423,6 @@ internal val DeStrings =
override val contentScaleFit = "Angepasste Größe"
override val contentScaleFillWidth = "Breite füllen"
override val settingsMediaList = "Medien-Uploads"
override val settingsEnableToggleFavoriteInNavDrawer =
"Favoriten in der Navigationsleiste hinzufügen/entfernen"
}

View File

@ -427,4 +427,6 @@ internal val ElStrings =
override val noticeBannedUser = "Ο τρέχων χρήστης έχει αποκλειστεί από αυτήν την κοινότητα"
override val settingsHiddenPosts = "Κρυφές αναρτήσεις"
override val settingsMediaList = "Μεταφορτώσεις πολυμέσων"
override val settingsEnableToggleFavoriteInNavDrawer =
"Προσθήκη/αφαίρεση αγαπημένων στο συρτάρι πλοήγησης"
}

View File

@ -417,4 +417,5 @@ internal val EnStrings =
override val noticeBannedUser = "The current user has been banned from this community"
override val settingsHiddenPosts = "Hidden posts"
override val settingsMediaList = "Media uploads"
override val settingsEnableToggleFavoriteInNavDrawer = "Add/remove favorites in navigation drawer"
}

View File

@ -416,4 +416,5 @@ internal val EoStrings =
override val noticeBannedUser = "La nuna uzanto estas malpermesita de ĉi tiu komunumo"
override val settingsHiddenPosts = "Kaŝitaj afiŝoj"
override val settingsMediaList = "Amaskomunikiloj alŝutoj"
override val settingsEnableToggleFavoriteInNavDrawer = "Aldoni/forigi plej ŝatatajn en navigada tirkesto"
}

View File

@ -421,4 +421,6 @@ internal val EsStrings =
override val noticeBannedUser = "El usuario actual ha sido baneado de esta comunidad"
override val settingsHiddenPosts = "Publicaciones escondidas"
override val settingsMediaList = "Cargas de medios"
override val settingsEnableToggleFavoriteInNavDrawer =
"Agregar/eliminar favoritos en el cajón de navegación"
}

View File

@ -422,4 +422,6 @@ internal val EtStrings =
override val noticeBannedUser = "Praegune kasutaja on sellest kogukonnast keelatud"
override val settingsHiddenPosts = "Peidetud postitused"
override val settingsMediaList = "Meedia üleslaadimine"
override val settingsEnableToggleFavoriteInNavDrawer =
"Lemmikute lisamine/eemaldamine navigeerimissahtlis"
}

View File

@ -417,4 +417,6 @@ internal val FiStrings =
override val noticeBannedUser = "Nykyinen käyttäjä on estetty tästä yhteisöstä"
override val settingsHiddenPosts = "Piilotetut viestit"
override val settingsMediaList = "Median lataukset"
override val settingsEnableToggleFavoriteInNavDrawer =
"Lisää/poista suosikkeja navigointipaneelissa"
}

View File

@ -426,4 +426,6 @@ internal val FrStrings =
override val noticeBannedUser = "L\'utilisateur actuel a été banni de cette communauté"
override val settingsHiddenPosts = "Messages masqués"
override val settingsMediaList = "Téléchargements de médias"
override val settingsEnableToggleFavoriteInNavDrawer =
"Ajouter/supprimer des favoris dans le tiroir de navigation"
}

View File

@ -421,4 +421,6 @@ internal val GaStrings =
override val noticeBannedUser = "Tá cosc ar an úsáideoir reatha ón bpobal seo"
override val settingsHiddenPosts = "Poist i bhfolach"
override val settingsMediaList = "Uaslódálacha meáin"
override val settingsEnableToggleFavoriteInNavDrawer =
"Cuir leis/bain na ceanáin sa tarraiceán nascleanúna"
}

View File

@ -421,4 +421,6 @@ internal val HrStrings =
override val noticeBannedUser = "Trenutačni korisnik je zabranjen iz ove zajednice"
override val settingsHiddenPosts = "Skriveni postovi"
override val settingsMediaList = "Prijenos medija"
override val settingsEnableToggleFavoriteInNavDrawer =
"Dodajte/uklonite favorite u ladici za navigaciju"
}

View File

@ -425,4 +425,6 @@ internal val HuStrings =
override val noticeBannedUser = "A jelenlegi felhasználót kitiltották a közösségből"
override val settingsHiddenPosts = "Rejtett bejegyzések"
override val settingsMediaList = "Médiafeltöltések"
override val settingsEnableToggleFavoriteInNavDrawer =
"Kedvencek hozzáadása/eltávolítása a navigációs fiókban"
}

View File

@ -422,4 +422,5 @@ internal val ItStrings =
override val noticeBannedUser = "L\'utente corrente è stato bannato da questa comunità"
override val settingsHiddenPosts = "Post nascosti"
override val settingsMediaList = "Caricamenti multimediali"
override val settingsEnableToggleFavoriteInNavDrawer = "Aggiungi/rimuovi preferiti in menu laterale"
}

View File

@ -420,4 +420,6 @@ internal val LtStrings =
"Dabartinis vartotojas buvo uždraustas dalyvauti šioje bendruomenėje"
override val settingsHiddenPosts = "Paslėpti įrašai"
override val settingsMediaList = "Žiniasklaidos įkėlimai"
override val settingsEnableToggleFavoriteInNavDrawer =
"Pridėti / pašalinti mėgstamiausius naršymo skydelyje"
}

View File

@ -419,4 +419,6 @@ internal val LvStrings =
override val noticeBannedUser = "Pašreizējais lietotājs ir bloķēts no šīs kopienas"
override val settingsHiddenPosts = "Slēptās ziņas"
override val settingsMediaList = "Multivides augšupielādes"
override val settingsEnableToggleFavoriteInNavDrawer =
"Pievienojiet/noņemiet izlasi navigācijas atvilktnē"
}

View File

@ -421,4 +421,6 @@ internal val MtStrings =
override val noticeBannedUser = "L-utent attwali ġie pprojbit minn din il-komunità"
override val settingsHiddenPosts = "Postijiet moħbija"
override val settingsMediaList = "Uploads tal-midja"
override val settingsEnableToggleFavoriteInNavDrawer =
"Żid/neħħi l-favoriti fil-kexxun tan-navigazzjoni"
}

View File

@ -422,4 +422,6 @@ internal val NlStrings =
override val noticeBannedUser = "De huidige gebruiker is uitgesloten van deze community"
override val settingsHiddenPosts = "Verborgen berichten"
override val settingsMediaList = "Media-uploads"
override val settingsEnableToggleFavoriteInNavDrawer =
"Favorieten toevoegen/verwijderen in de navigatielade"
}

View File

@ -419,4 +419,6 @@ internal val NoStrings =
"Den nåværende brukeren har blitt utestengt fra dette fellesskapet"
override val settingsHiddenPosts = "Skjulte innlegg"
override val settingsMediaList = "Medieopplastinger"
override val settingsEnableToggleFavoriteInNavDrawer =
"Legg til/fjern favoritter i navigasjonsskuffen"
}

View File

@ -421,4 +421,5 @@ internal val PlStrings =
override val noticeBannedUser = "Bieżący użytkownik został zablokowany w tej społeczności"
override val settingsHiddenPosts = "Ukryte posty"
override val settingsMediaList = "Przesyłanie multimediów"
override val settingsEnableToggleFavoriteInNavDrawer = "Dodaj/usuń ulubione w szufladzie nawigacji"
}

View File

@ -419,4 +419,6 @@ internal val PtBrStrings =
override val noticeBannedUser = "O usuário atual foi banido desta comunidade"
override val settingsHiddenPosts = "Posts escondidos"
override val settingsMediaList = "Carregamentos de mídia"
override val settingsEnableToggleFavoriteInNavDrawer =
"Adicionar/remover favoritos na gaveta de navegação"
}

View File

@ -420,4 +420,6 @@ internal val PtStrings =
override val noticeBannedUser = "O usuário atual foi banido desta comunidade"
override val settingsHiddenPosts = "Postagens ocultadas"
override val settingsMediaList = "Carregamentos de mídia"
override val settingsEnableToggleFavoriteInNavDrawer =
"Adicionar/remover favoritos na gaveta de navegação"
}

View File

@ -420,4 +420,6 @@ internal val RoStrings =
override val noticeBannedUser = "Utilizatorul actual a fost exclus din această comunitate"
override val settingsHiddenPosts = "Postări ascunse"
override val settingsMediaList = "Încărcări media"
override val settingsEnableToggleFavoriteInNavDrawer =
"Adăugă/elimină favoritele din sertarul de navigare"
}

View File

@ -422,4 +422,6 @@ internal val RuStrings =
override val noticeBannedUser = "Текущий пользователь заблокирован в этом сообществе"
override val settingsHiddenPosts = "Скрытые сообщения"
override val settingsMediaList = "Загрузка мультимедиа"
override val settingsEnableToggleFavoriteInNavDrawer =
"Добавить/удалить избранное в панели навигации"
}

View File

@ -420,4 +420,6 @@ internal val SeStrings =
override val noticeBannedUser = "Den nuvarande användaren har blockerats från denna grupp"
override val settingsHiddenPosts = "Dolda inlägg"
override val settingsMediaList = "Mediauppladdningar"
override val settingsEnableToggleFavoriteInNavDrawer =
"Lägg till/ta bort favoriter i navigeringslådan"
}

View File

@ -422,4 +422,6 @@ internal val SkStrings =
override val noticeBannedUser = "Aktuálny používateľ má zakázaný prístup do tejto komunity"
override val settingsHiddenPosts = "Skryté príspevky"
override val settingsMediaList = "Nahrávanie médií"
override val settingsEnableToggleFavoriteInNavDrawer =
"Pridať/odstrániť obľúbené položky v navigačnej zásuvke"
}

View File

@ -420,4 +420,6 @@ internal val SlStrings =
override val noticeBannedUser = "Trenutni uporabnik je bil izključen iz te skupnosti"
override val settingsHiddenPosts = "Skrite objave"
override val settingsMediaList = "Nalaganje medijev"
override val settingsEnableToggleFavoriteInNavDrawer =
"Dodajte/odstranite priljubljene v predalu za krmarjenje"
}

View File

@ -422,4 +422,6 @@ internal val SqStrings =
override val noticeBannedUser = "Përdoruesi aktual është përjashtuar nga ky komunitet"
override val settingsHiddenPosts = "Postimet e fshehura"
override val settingsMediaList = "Ngarkimet e mediave"
override val settingsEnableToggleFavoriteInNavDrawer =
"Shto/hiq të preferuarat në sirtarin e navigimit"
}

View File

@ -422,4 +422,6 @@ internal val SrStrings =
override val noticeBannedUser = "Тренутном кориснику је забрањен приступ овој заједници"
override val settingsHiddenPosts = "Скривени постови"
override val settingsMediaList = "Учитавање медија"
override val settingsEnableToggleFavoriteInNavDrawer =
"Додајте/уклоните фаворите у фиоци за навигацију"
}

View File

@ -415,6 +415,7 @@ interface Strings {
val noticeBannedUser: String
val settingsHiddenPosts: String
val settingsMediaList: String
val settingsEnableToggleFavoriteInNavDrawer: String
}
object Locales {

View File

@ -416,4 +416,6 @@ internal val TokStrings =
override val noticeBannedUser = "sina ken lukin ala e lipu mute pi kulupu ni"
override val settingsHiddenPosts = "lipu pi lukin ala"
override val settingsMediaList = "sitelen linluwi"
override val settingsEnableToggleFavoriteInNavDrawer =
"o sin/o weka e ijo pona lon leko luka"
}

View File

@ -421,4 +421,6 @@ internal val TrStrings =
override val noticeBannedUser = "Mevcut kullanıcı bu topluluktan yasaklandı"
override val settingsHiddenPosts = "Gizli gönderiler"
override val settingsMediaList = "Medya yüklemeleri"
override val settingsEnableToggleFavoriteInNavDrawer =
"Gezinme çekmecesinde favorileri ekle/kaldır"
}

View File

@ -422,4 +422,6 @@ internal val UkStrings =
override val noticeBannedUser = "Поточний користувач був забанений у цій спільноті"
override val settingsHiddenPosts = "Приховані пости"
override val settingsMediaList = "Завантаження медіа"
override val settingsEnableToggleFavoriteInNavDrawer =
"Додати/видалити вибране в панелі навігації"
}

View File

@ -411,4 +411,6 @@ internal val ZhHkStrings =
override val noticeBannedUser = "呢個用戶已被呢個社區禁止"
override val settingsHiddenPosts = "隱藏帖子"
override val settingsMediaList = "媒體上傳"
override val settingsEnableToggleFavoriteInNavDrawer =
"Add/remove favorites in navigation drawer"
}

View File

@ -411,4 +411,6 @@ internal val ZhTwStrings =
override val settingsAboutLicences = "授權"
override val never = "從不"
override val appIconDefault = "默認"
override val settingsEnableToggleFavoriteInNavDrawer =
"Add/remove favorites in navigation drawer"
}

View File

@ -162,4 +162,6 @@ sealed interface NotificationCenterEvent {
data class ChangeCommunityVisibility(val value: CommunityVisibilityType) :
NotificationCenterEvent
data object FavoritesUpdated : NotificationCenterEvent
}

View File

@ -155,6 +155,7 @@ class DefaultSettingsRepositoryTest {
fullWidthImages = if (model.fullWidthImages) 1 else 0,
showUnreadComments = if (model.showUnreadComments) 1 else 0,
commentIndentAmount = model.commentIndentAmount.toLong(),
enableToggleFavoriteInNavDrawer = if (model.enableToggleFavoriteInNavDrawer) 1 else 0,
account_id = 1,
)
}
@ -226,6 +227,7 @@ class DefaultSettingsRepositoryTest {
fullWidthImages = if (model.fullWidthImages) 1 else 0,
showUnreadComments = if (model.showUnreadComments) 1 else 0,
commentIndentAmount = model.commentIndentAmount.toLong(),
enableToggleFavoriteInNavDrawer = if (model.enableToggleFavoriteInNavDrawer) 1 else 0,
account_id = 1,
)
}
@ -293,6 +295,7 @@ class DefaultSettingsRepositoryTest {
fullWidthImages: Boolean = false,
showUnreadComments: Boolean = true,
commentIndentAmount: Int = 2,
enableToggleFavoriteInNavDrawer: Boolean = false,
) = GetBy(
id = id,
theme = theme,
@ -353,5 +356,6 @@ class DefaultSettingsRepositoryTest {
fullWidthImages = if (fullWidthImages) 1 else 0,
showUnreadComments = if (showUnreadComments) 1 else 0,
commentIndentAmount = commentIndentAmount.toLong(),
enableToggleFavoriteInNavDrawer = if (enableToggleFavoriteInNavDrawer) 1 else 0,
)
}

View File

@ -62,4 +62,5 @@ data class SettingsModel(
val showUnreadComments: Boolean = false,
val enableButtonsToScrollBetweenComments: Boolean = false,
val commentIndentAmount: Int = 2,
val enableToggleFavoriteInNavDrawer: Boolean = false,
)

View File

@ -120,22 +120,28 @@ internal class DefaultSettingsRepository(
postBodyMaxLines = settings.postBodyMaxLines?.toLong(),
infiniteScrollEnabled = if (settings.infiniteScrollEnabled) 1 else 0,
actionsOnSwipeToStartPosts =
settings.actionsOnSwipeToStartPosts.map { it.toInt() }
settings.actionsOnSwipeToStartPosts
.map { it.toInt() }
.joinToString(","),
actionsOnSwipeToEndPosts =
settings.actionsOnSwipeToEndPosts.map { it.toInt() }
settings.actionsOnSwipeToEndPosts
.map { it.toInt() }
.joinToString(","),
actionsOnSwipeToStartComments =
settings.actionsOnSwipeToStartComments.map { it.toInt() }
settings.actionsOnSwipeToStartComments
.map { it.toInt() }
.joinToString(","),
actionsOnSwipeToEndComments =
settings.actionsOnSwipeToEndComments.map { it.toInt() }
settings.actionsOnSwipeToEndComments
.map { it.toInt() }
.joinToString(","),
actionsOnSwipeToStartInbox =
settings.actionsOnSwipeToStartInbox.map { it.toInt() }
settings.actionsOnSwipeToStartInbox
.map { it.toInt() }
.joinToString(","),
actionsOnSwipeToEndInbox =
settings.actionsOnSwipeToEndInbox.map { it.toInt() }
settings.actionsOnSwipeToEndInbox
.map { it.toInt() }
.joinToString(","),
opaqueSystemBars = if (settings.opaqueSystemBars) 1L else 0L,
showScores = if (settings.showScores) 1L else 0L,
@ -150,6 +156,7 @@ internal class DefaultSettingsRepository(
showUnreadComments = if (settings.showUnreadComments) 1L else 0L,
enableButtonsToScrollBetweenComments = if (settings.enableButtonsToScrollBetweenComments) 1L else 0L,
fullWidthImages = if (settings.fullWidthImages) 1L else 0L,
enableToggleFavoriteInNavDrawer = if (settings.enableToggleFavoriteInNavDrawer) 1L else 0L,
)
}
@ -387,22 +394,28 @@ internal class DefaultSettingsRepository(
postBodyMaxLines = settings.postBodyMaxLines?.toLong(),
infiniteScrollEnabled = if (settings.infiniteScrollEnabled) 1L else 0L,
actionsOnSwipeToStartPosts =
settings.actionsOnSwipeToStartPosts.map { it.toInt() }
settings.actionsOnSwipeToStartPosts
.map { it.toInt() }
.joinToString(","),
actionsOnSwipeToEndPosts =
settings.actionsOnSwipeToEndPosts.map { it.toInt() }
settings.actionsOnSwipeToEndPosts
.map { it.toInt() }
.joinToString(","),
actionsOnSwipeToStartComments =
settings.actionsOnSwipeToStartComments.map { it.toInt() }
settings.actionsOnSwipeToStartComments
.map { it.toInt() }
.joinToString(","),
actionsOnSwipeToEndComments =
settings.actionsOnSwipeToEndComments.map { it.toInt() }
settings.actionsOnSwipeToEndComments
.map { it.toInt() }
.joinToString(","),
actionsOnSwipeToStartInbox =
settings.actionsOnSwipeToStartInbox.map { it.toInt() }
settings.actionsOnSwipeToStartInbox
.map { it.toInt() }
.joinToString(","),
actionsOnSwipeToEndInbox =
settings.actionsOnSwipeToEndInbox.map { it.toInt() }
settings.actionsOnSwipeToEndInbox
.map { it.toInt() }
.joinToString(","),
opaqueSystemBars = if (settings.opaqueSystemBars) 1L else 0L,
showScores = if (settings.showScores) 1L else 0L,
@ -417,6 +430,7 @@ internal class DefaultSettingsRepository(
showUnreadComments = if (settings.showUnreadComments) 1L else 0L,
enableButtonsToScrollBetweenComments = if (settings.enableButtonsToScrollBetweenComments) 1L else 0L,
fullWidthImages = if (settings.fullWidthImages) 1L else 0L,
enableToggleFavoriteInNavDrawer = if (settings.enableToggleFavoriteInNavDrawer) 1L else 0L,
)
}
}
@ -472,27 +486,33 @@ private fun GetBy.toModel() =
postBodyMaxLines = postBodyMaxLines?.toInt(),
infiniteScrollEnabled = infiniteScrollEnabled != 0L,
actionsOnSwipeToStartPosts =
actionsOnSwipeToStartPosts?.split(",")
actionsOnSwipeToStartPosts
?.split(",")
?.mapNotNull { it.toIntOrNull()?.toActionOnSwipe() }
?: ActionOnSwipe.DEFAULT_SWIPE_TO_START_POSTS,
actionsOnSwipeToEndPosts =
actionsOnSwipeToEndPosts?.split(",")
actionsOnSwipeToEndPosts
?.split(",")
?.mapNotNull { it.toIntOrNull()?.toActionOnSwipe() }
?: ActionOnSwipe.DEFAULT_SWIPE_TO_END_POSTS,
actionsOnSwipeToStartComments =
actionsOnSwipeToStartComments?.split(",")
actionsOnSwipeToStartComments
?.split(",")
?.mapNotNull { it.toIntOrNull()?.toActionOnSwipe() }
?: ActionOnSwipe.DEFAULT_SWIPE_TO_START_COMMENTS,
actionsOnSwipeToEndComments =
actionsOnSwipeToEndComments?.split(",")
actionsOnSwipeToEndComments
?.split(",")
?.mapNotNull { it.toIntOrNull()?.toActionOnSwipe() }
?: ActionOnSwipe.DEFAULT_SWIPE_TO_END_COMMENTS,
actionsOnSwipeToStartInbox =
actionsOnSwipeToStartInbox?.split(",")
actionsOnSwipeToStartInbox
?.split(",")
?.mapNotNull { it.toIntOrNull()?.toActionOnSwipe() }
?: ActionOnSwipe.DEFAULT_SWIPE_TO_START_INBOX,
actionsOnSwipeToEndInbox =
actionsOnSwipeToEndInbox?.split(",")
actionsOnSwipeToEndInbox
?.split(",")
?.mapNotNull { it.toIntOrNull()?.toActionOnSwipe() }
?: ActionOnSwipe.DEFAULT_SWIPE_TO_END_INBOX,
opaqueSystemBars = opaqueSystemBars == 1L,
@ -508,4 +528,5 @@ private fun GetBy.toModel() =
showUnreadComments = showUnreadComments == 1L,
enableButtonsToScrollBetweenComments = enableButtonsToScrollBetweenComments == 1L,
fullWidthImages = fullWidthImages == 1L,
enableToggleFavoriteInNavDrawer = enableToggleFavoriteInNavDrawer == 1L,
)

View File

@ -74,6 +74,7 @@ internal data class SerializableSettings(
val showUnreadComments: Boolean = false,
val enableButtonsToScrollBetweenComments: Boolean = false,
val fullWidthImages: Boolean = false,
val enableToggleFavoriteInNavDrawer: Boolean = false,
)
internal fun SerializableSettings.toModel() =
@ -139,6 +140,7 @@ internal fun SerializableSettings.toModel() =
showUnreadComments = showUnreadComments,
enableButtonsToScrollBetweenComments = enableButtonsToScrollBetweenComments,
fullWidthImages = fullWidthImages,
enableToggleFavoriteInNavDrawer = enableToggleFavoriteInNavDrawer,
)
internal fun SettingsModel.toData() =
@ -198,4 +200,5 @@ internal fun SettingsModel.toData() =
showUnreadComments = showUnreadComments,
enableButtonsToScrollBetweenComments = enableButtonsToScrollBetweenComments,
fullWidthImages = fullWidthImages,
enableToggleFavoriteInNavDrawer = enableToggleFavoriteInNavDrawer,
)

View File

@ -59,6 +59,7 @@ CREATE TABLE SettingsEntity (
enableButtonsToScrollBetweenComments INTEGER NOT NULL DEFAULT 0,
fullWidthImages INTEGER NOT NULL DEFAULT 0,
commentIndentAmount INTEGER NOT NULL DEFAULT 2,
enableToggleFavoriteInNavDrawer INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY (account_id) REFERENCES AccountEntity(id) ON DELETE CASCADE,
UNIQUE(account_id)
);
@ -123,6 +124,7 @@ INSERT OR IGNORE INTO SettingsEntity (
enableButtonsToScrollBetweenComments,
fullWidthImages,
commentIndentAmount,
enableToggleFavoriteInNavDrawer,
account_id
) VALUES (
?,
@ -183,6 +185,7 @@ INSERT OR IGNORE INTO SettingsEntity (
?,
?,
?,
?,
?
);
@ -245,7 +248,8 @@ SET theme = ?,
showUnreadComments = ?,
enableButtonsToScrollBetweenComments = ?,
fullWidthImages = ?,
commentIndentAmount = ?
commentIndentAmount = ?,
enableToggleFavoriteInNavDrawer = ?
WHERE account_id = ?;
getBy:
@ -308,6 +312,7 @@ SELECT
showUnreadComments,
enableButtonsToScrollBetweenComments,
fullWidthImages,
commentIndentAmount
commentIndentAmount,
enableToggleFavoriteInNavDrawer
FROM SettingsEntity
WHERE account_id = ?;

View File

@ -0,0 +1,2 @@
ALTER TABLE SettingsEntity
ADD COLUMN enableToggleFavoriteInNavDrawer INTEGER NOT NULL DEFAULT 0;

View File

@ -14,7 +14,7 @@
{
"title": "NicKoehler",
"avatar": "https://avatars.githubusercontent.com/u/53040044?v=4",
"subtitle": "App icon and artwork",
"subtitle": "App icon designer, Code contributor",
"url": "https://github.com/NicKoehler"
},
{

View File

@ -11,37 +11,71 @@ interface AdvancedSettingsMviModel :
ScreenModel,
MviModel<AdvancedSettingsMviModel.Intent, AdvancedSettingsMviModel.UiState, AdvancedSettingsMviModel.Effect> {
sealed interface Intent {
data class ChangeEnableDoubleTapAction(val value: Boolean) : Intent
data class ChangeEnableDoubleTapAction(
val value: Boolean,
) : Intent
data class ChangeAutoLoadImages(val value: Boolean) : Intent
data class ChangeAutoLoadImages(
val value: Boolean,
) : Intent
data class ChangeAutoExpandComments(val value: Boolean) : Intent
data class ChangeAutoExpandComments(
val value: Boolean,
) : Intent
data class ChangeHideNavigationBarWhileScrolling(val value: Boolean) : Intent
data class ChangeHideNavigationBarWhileScrolling(
val value: Boolean,
) : Intent
data class ChangeMarkAsReadWhileScrolling(val value: Boolean) : Intent
data class ChangeMarkAsReadWhileScrolling(
val value: Boolean,
) : Intent
data class ChangeNavBarTitlesVisible(val value: Boolean) : Intent
data class ChangeNavBarTitlesVisible(
val value: Boolean,
) : Intent
data class ChangeSearchPostTitleOnly(val value: Boolean) : Intent
data class ChangeSearchPostTitleOnly(
val value: Boolean,
) : Intent
data class ChangeEdgeToEdge(val value: Boolean) : Intent
data class ChangeEdgeToEdge(
val value: Boolean,
) : Intent
data class ChangeInfiniteScrollDisabled(val value: Boolean) : Intent
data class ChangeInfiniteScrollDisabled(
val value: Boolean,
) : Intent
data class ChangeImageSourcePath(val value: Boolean) : Intent
data class ChangeImageSourcePath(
val value: Boolean,
) : Intent
data class ChangeDefaultLanguage(val value: Long?) : Intent
data class ChangeDefaultLanguage(
val value: Long?,
) : Intent
data class ChangeFadeReadPosts(val value: Boolean) : Intent
data class ChangeFadeReadPosts(
val value: Boolean,
) : Intent
data class ChangeShowUnreadComments(val value: Boolean) : Intent
data class ChangeShowUnreadComments(
val value: Boolean,
) : Intent
data object ExportSettings : Intent
data class ImportSettings(val content: String) : Intent
data class ImportSettings(
val content: String,
) : Intent
data class ChangeEnableButtonsToScrollBetweenComments(val value: Boolean) : Intent
data class ChangeEnableButtonsToScrollBetweenComments(
val value: Boolean,
) : Intent
data class ChangeEnableToggleFavoriteInNavDrawer(
val value: Boolean,
) : Intent
}
data class UiState(
@ -71,9 +105,12 @@ interface AdvancedSettingsMviModel :
val supportSettingsImportExport: Boolean = true,
val loading: Boolean = false,
val enableButtonsToScrollBetweenComments: Boolean = false,
val enableToggleFavoriteInNavDrawer: Boolean = false,
)
sealed interface Effect {
data class SaveSettings(val content: String) : Effect
data class SaveSettings(
val content: String,
) : Effect
}
}

View File

@ -97,13 +97,14 @@ class AdvancedSettingsScreen : Screen {
var settingsContent by remember { mutableStateOf<String?>(null) }
LaunchedEffect(model) {
model.effects.onEach { evt ->
when (evt) {
is AdvancedSettingsMviModel.Effect.SaveSettings -> {
settingsContent = evt.content
model.effects
.onEach { evt ->
when (evt) {
is AdvancedSettingsMviModel.Effect.SaveSettings -> {
settingsContent = evt.content
}
}
}
}.launchIn(this)
}.launchIn(this)
}
Scaffold(
@ -155,8 +156,7 @@ class AdvancedSettingsScreen : Screen {
Modifier
.padding(
top = padding.calculateTopPadding(),
)
.nestedScroll(scrollBehavior.nestedScrollConnection),
).nestedScroll(scrollBehavior.nestedScrollConnection),
) {
Column(
modifier = Modifier.fillMaxSize().verticalScroll(scrollState),
@ -287,11 +287,12 @@ class AdvancedSettingsScreen : Screen {
// default language
val languageValue =
uiState.availableLanguages.firstOrNull { l ->
l.id == uiState.defaultLanguageId
}?.takeIf { l ->
l.id > 0 // undetermined language
}?.name ?: LocalStrings.current.undetermined
uiState.availableLanguages
.firstOrNull { l ->
l.id == uiState.defaultLanguageId
}?.takeIf { l ->
l.id > 0 // undetermined language
}?.name ?: LocalStrings.current.undetermined
SettingsRow(
title = LocalStrings.current.advancedSettingsDefaultLanguage,
value = languageValue,
@ -365,7 +366,11 @@ class AdvancedSettingsScreen : Screen {
title = LocalStrings.current.settingsZombieModeScrollAmount,
value =
buildString {
val pt = uiState.zombieModeScrollAmount.toLocalDp().value.roundToInt()
val pt =
uiState.zombieModeScrollAmount
.toLocalDp()
.value
.roundToInt()
append(pt)
append(LocalStrings.current.settingsPointsShort)
},
@ -429,6 +434,20 @@ class AdvancedSettingsScreen : Screen {
icon = Icons.Default.Science,
)
if (uiState.isLogged) {
// edit favorites in navigation drawer
SettingsSwitchRow(
title = LocalStrings.current.settingsEnableToggleFavoriteInNavDrawer,
value = uiState.enableToggleFavoriteInNavDrawer,
onValueChanged =
rememberCallbackArgs(model) { value ->
model.reduce(
AdvancedSettingsMviModel.Intent.ChangeEnableToggleFavoriteInNavDrawer(
value,
),
)
},
)
// double tap
SettingsSwitchRow(
title = LocalStrings.current.settingsEnableDoubleTap,

View File

@ -40,44 +40,59 @@ class AdvancedSettingsViewModel(
private val fileSystemManager: FileSystemManager,
private val importSettings: ImportSettingsUseCase,
private val exportSettings: ExportSettingsUseCase,
) : AdvancedSettingsMviModel,
DefaultMviModel<AdvancedSettingsMviModel.Intent, AdvancedSettingsMviModel.UiState, AdvancedSettingsMviModel.Effect>(
) : DefaultMviModel<AdvancedSettingsMviModel.Intent, AdvancedSettingsMviModel.UiState, AdvancedSettingsMviModel.Effect>(
initialState = AdvancedSettingsMviModel.UiState(),
) {
),
AdvancedSettingsMviModel {
init {
screenModelScope.launch {
themeRepository.navItemTitles.onEach { value ->
updateState { it.copy(navBarTitlesVisible = value) }
}.launchIn(this)
themeRepository.navItemTitles
.onEach { value ->
updateState { it.copy(navBarTitlesVisible = value) }
}.launchIn(this)
identityRepository.isLogged.onEach { logged ->
updateState { it.copy(isLogged = logged ?: false) }
}.launchIn(this)
identityRepository.isLogged
.onEach { logged ->
updateState { it.copy(isLogged = logged ?: false) }
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeZombieInterval::class).onEach { evt ->
changeZombieModeInterval(evt.value)
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeFeedType::class).onEach { evt ->
if (evt.screenKey == "advancedSettings") {
changeExploreType(evt.value)
}
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeZombieScrollAmount::class).onEach { evt ->
changeZombieModeScrollAmount(evt.value)
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeInboxType::class).onEach { evt ->
changeDefaultInboxUnreadOnly(evt.unreadOnly)
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeSystemBarTheme::class).onEach { evt ->
changeSystemBarTheme(evt.value)
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.ChangeInboxBackgroundCheckPeriod::class)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeZombieInterval::class)
.onEach { evt ->
changeZombieModeInterval(evt.value)
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeFeedType::class)
.onEach { evt ->
if (evt.screenKey == "advancedSettings") {
changeExploreType(evt.value)
}
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeZombieScrollAmount::class)
.onEach { evt ->
changeZombieModeScrollAmount(evt.value)
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeInboxType::class)
.onEach { evt ->
changeDefaultInboxUnreadOnly(evt.unreadOnly)
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeSystemBarTheme::class)
.onEach { evt ->
changeSystemBarTheme(evt.value)
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeInboxBackgroundCheckPeriod::class)
.onEach { evt ->
changeInboxBackgroundCheckPeriod(evt.value)
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.AppIconVariantSelected::class).onEach { evt ->
changeAppIconVariant(evt.value.toAppIconVariant())
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.AppIconVariantSelected::class)
.onEach { evt ->
changeAppIconVariant(evt.value.toAppIconVariant())
}.launchIn(this)
updateAvailableLanguages()
@ -106,6 +121,7 @@ class AdvancedSettingsViewModel(
inboxBackgroundCheckPeriod = settings.inboxBackgroundCheckPeriod,
supportSettingsImportExport = fileSystemManager.isSupported,
enableButtonsToScrollBetweenComments = settings.enableButtonsToScrollBetweenComments,
enableToggleFavoriteInNavDrawer = settings.enableToggleFavoriteInNavDrawer,
)
}
}
@ -129,26 +145,44 @@ class AdvancedSettingsViewModel(
is AdvancedSettingsMviModel.Intent.ChangeMarkAsReadWhileScrolling ->
changeMarkAsReadWhileScrolling(intent.value)
is AdvancedSettingsMviModel.Intent.ChangeSearchPostTitleOnly -> changeSearchPostTitleOnly(intent.value)
is AdvancedSettingsMviModel.Intent.ChangeSearchPostTitleOnly ->
changeSearchPostTitleOnly(
intent.value,
)
is AdvancedSettingsMviModel.Intent.ChangeEdgeToEdge -> changeEdgeToEdge(intent.value)
is AdvancedSettingsMviModel.Intent.ChangeInfiniteScrollDisabled ->
changeInfiniteScrollDisabled(intent.value)
is AdvancedSettingsMviModel.Intent.ChangeImageSourcePath -> changeImageSourcePath(intent.value)
is AdvancedSettingsMviModel.Intent.ChangeDefaultLanguage -> changeDefaultLanguageId(intent.value)
is AdvancedSettingsMviModel.Intent.ChangeDefaultLanguage ->
changeDefaultLanguageId(
intent.value,
)
is AdvancedSettingsMviModel.Intent.ChangeFadeReadPosts -> changeFadeReadPosts(intent.value)
is AdvancedSettingsMviModel.Intent.ChangeShowUnreadComments -> changeShowUnreadPosts(intent.value)
is AdvancedSettingsMviModel.Intent.ChangeShowUnreadComments ->
changeShowUnreadPosts(
intent.value,
)
is AdvancedSettingsMviModel.Intent.ExportSettings -> handleExportSettings()
is AdvancedSettingsMviModel.Intent.ImportSettings -> handleImportSettings(intent.content)
is AdvancedSettingsMviModel.Intent.ChangeEnableButtonsToScrollBetweenComments ->
changeEnableButtonsToScrollBetweenComments(intent.value)
is AdvancedSettingsMviModel.Intent.ChangeEnableToggleFavoriteInNavDrawer ->
changeEnableToggleFavoriteInNavDrawer(
intent.value,
)
}
}
private fun changeNavBarTitlesVisible(value: Boolean) {
themeRepository.changeNavItemTitles(value)
screenModelScope.launch {
val settings = settingsRepository.currentSettings.value.copy(navigationTitlesVisible = value)
val settings =
settingsRepository.currentSettings.value.copy(navigationTitlesVisible = value)
saveSettings(settings)
}
}
@ -156,7 +190,8 @@ class AdvancedSettingsViewModel(
private fun changeEnableDoubleTapAction(value: Boolean) {
screenModelScope.launch {
updateState { it.copy(enableDoubleTapAction = value) }
val settings = settingsRepository.currentSettings.value.copy(enableDoubleTapAction = value)
val settings =
settingsRepository.currentSettings.value.copy(enableDoubleTapAction = value)
saveSettings(settings)
}
}
@ -180,7 +215,8 @@ class AdvancedSettingsViewModel(
private fun changeHideNavigationBarWhileScrolling(value: Boolean) {
screenModelScope.launch {
updateState { it.copy(hideNavigationBarWhileScrolling = value) }
val settings = settingsRepository.currentSettings.value.copy(hideNavigationBarWhileScrolling = value)
val settings =
settingsRepository.currentSettings.value.copy(hideNavigationBarWhileScrolling = value)
saveSettings(settings)
}
}
@ -188,7 +224,8 @@ class AdvancedSettingsViewModel(
private fun changeMarkAsReadWhileScrolling(value: Boolean) {
screenModelScope.launch {
updateState { it.copy(markAsReadWhileScrolling = value) }
val settings = settingsRepository.currentSettings.value.copy(markAsReadWhileScrolling = value)
val settings =
settingsRepository.currentSettings.value.copy(markAsReadWhileScrolling = value)
saveSettings(settings)
}
}
@ -204,7 +241,8 @@ class AdvancedSettingsViewModel(
private fun changeZombieModeScrollAmount(value: Float) {
screenModelScope.launch {
updateState { it.copy(zombieModeScrollAmount = value) }
val settings = settingsRepository.currentSettings.value.copy(zombieModeScrollAmount = value)
val settings =
settingsRepository.currentSettings.value.copy(zombieModeScrollAmount = value)
saveSettings(settings)
}
}
@ -212,7 +250,8 @@ class AdvancedSettingsViewModel(
private fun changeDefaultInboxUnreadOnly(value: Boolean) {
screenModelScope.launch {
updateState { it.copy(defaultInboxUnreadOnly = value) }
val settings = settingsRepository.currentSettings.value.copy(defaultInboxType = value.toInboxDefaultType())
val settings =
settingsRepository.currentSettings.value.copy(defaultInboxType = value.toInboxDefaultType())
saveSettings(settings)
notificationCenter.send(NotificationCenterEvent.ResetInbox)
}
@ -221,7 +260,8 @@ class AdvancedSettingsViewModel(
private fun changeSearchPostTitleOnly(value: Boolean) {
screenModelScope.launch {
updateState { it.copy(searchPostTitleOnly = value) }
val settings = settingsRepository.currentSettings.value.copy(searchPostTitleOnly = value)
val settings =
settingsRepository.currentSettings.value.copy(searchPostTitleOnly = value)
saveSettings(settings)
}
}
@ -229,7 +269,8 @@ class AdvancedSettingsViewModel(
private fun changeExploreType(value: ListingType) {
screenModelScope.launch {
updateState { it.copy(defaultExploreType = value) }
val settings = settingsRepository.currentSettings.value.copy(defaultExploreType = value.toInt())
val settings =
settingsRepository.currentSettings.value.copy(defaultExploreType = value.toInt())
saveSettings(settings)
}
}
@ -245,7 +286,8 @@ class AdvancedSettingsViewModel(
private fun changeInfiniteScrollDisabled(value: Boolean) {
screenModelScope.launch {
updateState { it.copy(infiniteScrollDisabled = value) }
val settings = settingsRepository.currentSettings.value.copy(infiniteScrollEnabled = !value)
val settings =
settingsRepository.currentSettings.value.copy(infiniteScrollEnabled = !value)
saveSettings(settings)
}
}
@ -290,7 +332,8 @@ class AdvancedSettingsViewModel(
private fun changeInboxBackgroundCheckPeriod(value: Duration) {
screenModelScope.launch {
updateState { it.copy(inboxBackgroundCheckPeriod = value) }
val settings = settingsRepository.currentSettings.value.copy(inboxBackgroundCheckPeriod = value)
val settings =
settingsRepository.currentSettings.value.copy(inboxBackgroundCheckPeriod = value)
saveSettings(settings)
}
}
@ -314,7 +357,17 @@ class AdvancedSettingsViewModel(
private fun changeEnableButtonsToScrollBetweenComments(value: Boolean) {
screenModelScope.launch {
updateState { it.copy(enableButtonsToScrollBetweenComments = value) }
val settings = settingsRepository.currentSettings.value.copy(enableButtonsToScrollBetweenComments = value)
val settings =
settingsRepository.currentSettings.value.copy(enableButtonsToScrollBetweenComments = value)
saveSettings(settings)
}
}
private fun changeEnableToggleFavoriteInNavDrawer(value: Boolean) {
screenModelScope.launch {
updateState { it.copy(enableToggleFavoriteInNavDrawer = value) }
val settings =
settingsRepository.currentSettings.value.copy(enableToggleFavoriteInNavDrawer = value)
saveSettings(settings)
}
}

View File

@ -67,10 +67,10 @@ class CommunityDetailViewModel(
private val communitySortRepository: CommunitySortRepository,
private val postNavigationManager: PostNavigationManager,
private val communityPreferredLanguageRepository: CommunityPreferredLanguageRepository,
) : CommunityDetailMviModel,
DefaultMviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect>(
) : DefaultMviModel<CommunityDetailMviModel.Intent, CommunityDetailMviModel.UiState, CommunityDetailMviModel.Effect>(
initialState = CommunityDetailMviModel.UiState(),
) {
),
CommunityDetailMviModel {
private var hideReadPosts = false
private val searchEventChannel = Channel<Unit>()
@ -88,47 +88,56 @@ class CommunityDetailViewModel(
}
}
themeRepository.postLayout.onEach { layout ->
updateState { it.copy(postLayout = layout) }
}.launchIn(this)
identityRepository.isLogged.onEach { logged ->
updateState { it.copy(isLogged = logged ?: false) }
updateAvailableSortTypes()
}.launchIn(this)
themeRepository.postLayout
.onEach { layout ->
updateState { it.copy(postLayout = layout) }
}.launchIn(this)
identityRepository.isLogged
.onEach { logged ->
updateState { it.copy(isLogged = logged ?: false) }
updateAvailableSortTypes()
}.launchIn(this)
settingsRepository.currentSettings.onEach { settings ->
updateState {
it.copy(
blurNsfw = settings.blurNsfw,
swipeActionsEnabled = settings.enableSwipeActions,
doubleTapActionEnabled = settings.enableDoubleTapAction,
fullHeightImages = settings.fullHeightImages,
fullWidthImages = settings.fullWidthImages,
voteFormat = settings.voteFormat,
autoLoadImages = settings.autoLoadImages,
preferNicknames = settings.preferUserNicknames,
actionsOnSwipeToStartPosts = settings.actionsOnSwipeToStartPosts,
actionsOnSwipeToEndPosts = settings.actionsOnSwipeToEndPosts,
showScores = settings.showScores,
fadeReadPosts = settings.fadeReadPosts,
showUnreadComments = settings.showUnreadComments,
)
}
}.launchIn(this)
settingsRepository.currentSettings
.onEach { settings ->
updateState {
it.copy(
blurNsfw = settings.blurNsfw,
swipeActionsEnabled = settings.enableSwipeActions,
doubleTapActionEnabled = settings.enableDoubleTapAction,
fullHeightImages = settings.fullHeightImages,
fullWidthImages = settings.fullWidthImages,
voteFormat = settings.voteFormat,
autoLoadImages = settings.autoLoadImages,
preferNicknames = settings.preferUserNicknames,
actionsOnSwipeToStartPosts = settings.actionsOnSwipeToStartPosts,
actionsOnSwipeToEndPosts = settings.actionsOnSwipeToEndPosts,
showScores = settings.showScores,
fadeReadPosts = settings.fadeReadPosts,
showUnreadComments = settings.showUnreadComments,
)
}
}.launchIn(this)
zombieModeHelper.index.onEach { index ->
if (uiState.value.zombieModeActive) {
emitEffect(CommunityDetailMviModel.Effect.ZombieModeTick(index))
}
}.launchIn(this)
zombieModeHelper.index
.onEach { index ->
if (uiState.value.zombieModeActive) {
emitEffect(CommunityDetailMviModel.Effect.ZombieModeTick(index))
}
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.PostUpdated::class).onEach { evt ->
handlePostUpdate(evt.model)
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.PostRemoved::class).onEach { evt ->
handlePostDelete(evt.model.id)
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.UserBannedPost::class)
notificationCenter
.subscribe(NotificationCenterEvent.PostUpdated::class)
.onEach { evt ->
handlePostUpdate(evt.model)
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.PostRemoved::class)
.onEach { evt ->
handlePostDelete(evt.model.id)
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.UserBannedPost::class)
.onEach { evt ->
val postId = evt.postId
val newUser = evt.user
@ -148,7 +157,8 @@ class CommunityDetailViewModel(
)
}
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.CommentRemoved::class)
notificationCenter
.subscribe(NotificationCenterEvent.CommentRemoved::class)
.onEach { evt ->
val postId = evt.model.postId
uiState.value.posts.firstOrNull { it.id == postId }?.also {
@ -157,7 +167,8 @@ class CommunityDetailViewModel(
}
}.launchIn(this)
val communityHandle = uiState.value.community.readableHandle
notificationCenter.subscribe(NotificationCenterEvent.ChangeSortType::class)
notificationCenter
.subscribe(NotificationCenterEvent.ChangeSortType::class)
.onEach { evt ->
if (evt.screenKey == communityHandle) {
if (evt.defaultForCommunity) {
@ -166,19 +177,26 @@ class CommunityDetailViewModel(
applySortType(evt.value)
}
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.Share::class).onEach { evt ->
shareHelper.share(evt.url)
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.CopyText::class).onEach {
emitEffect(CommunityDetailMviModel.Effect.TriggerCopy(it.value))
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.Share::class)
.onEach { evt ->
shareHelper.share(evt.url)
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.CopyText::class)
.onEach {
emitEffect(CommunityDetailMviModel.Effect.TriggerCopy(it.value))
}.launchIn(this)
searchEventChannel.receiveAsFlow().debounce(1_000).onEach {
updateState { it.copy(loading = false) }
emitEffect(CommunityDetailMviModel.Effect.BackToTop)
delay(50)
refresh()
}.launchIn(this)
searchEventChannel
.receiveAsFlow()
.debounce(1_000)
.onEach {
updateState { it.copy(loading = false) }
emitEffect(CommunityDetailMviModel.Effect.BackToTop)
delay(50)
refresh()
}.launchIn(this)
if (uiState.value.currentUserId == null) {
val auth = identityRepository.authToken.value.orEmpty()
@ -194,7 +212,8 @@ class CommunityDetailViewModel(
}
if (uiState.value.initial) {
val defaultPostSortType =
settingsRepository.currentSettings.value.defaultPostSortType.toSortType()
settingsRepository.currentSettings.value.defaultPostSortType
.toSortType()
val customPostSortType =
communitySortRepository.get(communityHandle)?.toSortType()
val preferredLanguageId = communityPreferredLanguageRepository.get(communityHandle)
@ -296,19 +315,22 @@ class CommunityDetailViewModel(
}
is CommunityDetailMviModel.Intent.ModFeaturePost ->
uiState.value.posts.firstOrNull { it.id == intent.id }
uiState.value.posts
.firstOrNull { it.id == intent.id }
?.also { post ->
feature(post = post)
}
is CommunityDetailMviModel.Intent.AdminFeaturePost ->
uiState.value.posts.firstOrNull { it.id == intent.id }
uiState.value.posts
.firstOrNull { it.id == intent.id }
?.also { post ->
featureLocal(post = post)
}
is CommunityDetailMviModel.Intent.ModLockPost ->
uiState.value.posts.firstOrNull { it.id == intent.id }
uiState.value.posts
.firstOrNull { it.id == intent.id }
?.also { post ->
lock(post = post)
}
@ -381,12 +403,13 @@ class CommunityDetailViewModel(
val isFavorite =
favoriteCommunityRepository.getBy(accountId, currentState.community.id) != null
val refreshedCommunity =
communityRepository.get(
auth = auth,
name = currentState.community.name,
id = currentState.community.id,
instance = otherInstance,
)?.copy(favorite = isFavorite)
communityRepository
.get(
auth = auth,
name = currentState.community.name,
id = currentState.community.id,
instance = otherInstance,
)?.copy(favorite = isFavorite)
val moderators =
communityRepository.getModerators(
auth = auth,
@ -436,26 +459,28 @@ class CommunityDetailViewModel(
}
updateState { it.copy(loading = true) }
val posts =
postPaginationManager.loadNextPage().let {
if (!hideReadPosts) {
it
} else {
it.filter { post -> !post.read }
}
}.let {
if (currentState.searching) {
it.filter { post ->
listOf(post.title, post.text).any { s ->
s.contains(
other = currentState.searchText,
ignoreCase = true,
)
}
postPaginationManager
.loadNextPage()
.let {
if (!hideReadPosts) {
it
} else {
it.filter { post -> !post.read }
}
}.let {
if (currentState.searching) {
it.filter { post ->
listOf(post.title, post.text).any { s ->
s.contains(
other = currentState.searchText,
ignoreCase = true,
)
}
}
} else {
it
}
} else {
it
}
}
if (uiState.value.autoLoadImages) {
posts.forEach { post ->
post.imageUrl.takeIf { i -> i.isNotEmpty() }?.also { url ->
@ -775,9 +800,11 @@ class CommunityDetailViewModel(
if (newValue) {
val model = FavoriteCommunityModel(communityId = communityId)
favoriteCommunityRepository.create(model, accountId)
notificationCenter.send(NotificationCenterEvent.FavoritesUpdated)
} else {
favoriteCommunityRepository.getBy(accountId, communityId)?.also { toDelete ->
favoriteCommunityRepository.delete(accountId, toDelete)
notificationCenter.send(NotificationCenterEvent.FavoritesUpdated)
}
}
val newCommunity = uiState.value.community.copy(favorite = newValue)

View File

@ -103,20 +103,24 @@ object ModalDrawerContent : Tab {
var uiFontSizeWorkaround by remember { mutableStateOf(true) }
LaunchedEffect(themeRepository) {
themeRepository.uiFontScale.drop(1).onEach {
uiFontSizeWorkaround = false
delay(50)
uiFontSizeWorkaround = true
}.launchIn(this)
themeRepository.uiFontScale
.drop(1)
.onEach {
uiFontSizeWorkaround = false
delay(50)
uiFontSizeWorkaround = true
}.launchIn(this)
}
if (!uiFontSizeWorkaround) {
return
}
LaunchedEffect(notificationCenter) {
notificationCenter.subscribe(NotificationCenterEvent.InstanceSelected::class).onEach {
// closes the navigation drawer after instance change
coordinator.closeDrawer()
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.InstanceSelected::class)
.onEach {
// closes the navigation drawer after instance change
coordinator.closeDrawer()
}.launchIn(this)
}
ModalDrawerSheet {
@ -125,21 +129,22 @@ object ModalDrawerContent : Tab {
instance = uiState.instance,
autoLoadImages = uiState.autoLoadImages,
onOpenChangeInstance =
rememberCallback(model) {
navigationCoordinator.showBottomSheet(SelectInstanceBottomSheet())
},
onOpenSwitchAccount = {
navigationCoordinator.showBottomSheet(ManageAccountsScreen())
},
rememberCallback(model) {
navigationCoordinator.showBottomSheet(SelectInstanceBottomSheet())
},
onOpenSwitchAccount =
rememberCallback {
navigationCoordinator.showBottomSheet(ManageAccountsScreen())
},
)
HorizontalDivider(
modifier =
Modifier
.padding(
top = Spacing.s,
bottom = Spacing.s,
),
Modifier
.padding(
top = Spacing.s,
bottom = Spacing.s,
),
)
if (uiState.user != null) {
@ -147,16 +152,16 @@ object ModalDrawerContent : Tab {
rememberPullRefreshState(
refreshing = uiState.refreshing,
onRefresh =
rememberCallback(model) {
model.reduce(ModalDrawerMviModel.Intent.Refresh)
},
rememberCallback(model) {
model.reduce(ModalDrawerMviModel.Intent.Refresh)
},
)
Box(
modifier =
Modifier
.weight(1f)
.nestedScroll(keyboardScrollConnection)
.pullRefresh(pullRefreshState),
Modifier
.weight(1f)
.nestedScroll(keyboardScrollConnection)
.pullRefresh(pullRefreshState),
) {
LazyColumn(
modifier = Modifier.fillMaxSize().padding(horizontal = Spacing.xxs),
@ -165,45 +170,45 @@ object ModalDrawerContent : Tab {
item {
TextField(
modifier =
Modifier
.scale(0.95f)
.padding(
horizontal = Spacing.xxs,
vertical = Spacing.xxs,
).fillMaxWidth(),
Modifier
.scale(0.95f)
.padding(
horizontal = Spacing.xxs,
vertical = Spacing.xxs,
).fillMaxWidth(),
label = {
Text(text = LocalStrings.current.exploreSearchPlaceholder)
},
singleLine = true,
value = uiState.searchText,
keyboardOptions =
KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Search,
),
KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Search,
),
onValueChange = { value ->
model.reduce(ModalDrawerMviModel.Intent.SetSearch(value))
},
trailingIcon = {
Icon(
modifier =
Modifier.onClick(
onClick = {
if (uiState.searchText.isNotEmpty()) {
model.reduce(
ModalDrawerMviModel.Intent.SetSearch(
"",
),
)
}
},
),
Modifier.onClick(
onClick = {
if (uiState.searchText.isNotEmpty()) {
model.reduce(
ModalDrawerMviModel.Intent.SetSearch(
"",
),
)
}
},
),
imageVector =
if (uiState.searchText.isEmpty()) {
Icons.Default.Search
} else {
Icons.Default.Clear
},
if (uiState.searchText.isEmpty()) {
Icons.Default.Search
} else {
Icons.Default.Clear
},
contentDescription = null,
)
},
@ -223,15 +228,15 @@ object ModalDrawerContent : Tab {
title = listingType.toReadableName(),
icon = listingType.toIcon(),
onSelected =
rememberCallback(coordinator) {
scope.launch {
focusManager.clearFocus()
coordinator.toggleDrawer()
coordinator.sendEvent(
DrawerEvent.ChangeListingType(listingType),
)
}
},
rememberCallback(coordinator) {
scope.launch {
focusManager.clearFocus()
coordinator.toggleDrawer()
coordinator.sendEvent(
DrawerEvent.ChangeListingType(listingType),
)
}
},
)
}
}
@ -259,7 +264,7 @@ object ModalDrawerContent : Tab {
items(
items = uiState.favorites,
key = { it.id.toString() },
key = { "${it.id}-favorite" },
) { community ->
DrawerCommunityItem(
title = community.readableName(uiState.preferNicknames),
@ -276,17 +281,28 @@ object ModalDrawerContent : Tab {
)
}
},
onToggleFavorite =
if (!uiState.enableToggleFavorite) {
null
} else {
rememberCallback(model) {
model.reduce(
ModalDrawerMviModel.Intent.ToggleFavorite(community.id),
)
}
},
)
}
items(
items = uiState.communities,
key = { it.id.toString() },
key = { "${it.id}-community" },
) { community ->
DrawerCommunityItem(
title = community.readableName(uiState.preferNicknames),
subtitle = community.readableHandle,
url = community.icon,
favorite = false,
autoLoadImages = uiState.autoLoadImages,
onSelected = {
scope.launch {
@ -297,6 +313,16 @@ object ModalDrawerContent : Tab {
)
}
},
onToggleFavorite =
if (!uiState.enableToggleFavorite) {
null
} else {
rememberCallback(model) {
model.reduce(
ModalDrawerMviModel.Intent.ToggleFavorite(community.id),
)
}
},
)
}

View File

@ -14,8 +14,15 @@ interface ModalDrawerMviModel :
sealed interface Intent {
data object Refresh : Intent
data class SetSearch(val value: String) : Intent
data class SetSearch(
val value: String,
) : Intent
data object LoadNextPage : Intent
data class ToggleFavorite(
val id: Long,
) : Intent
}
data class UiState(
@ -31,6 +38,7 @@ interface ModalDrawerMviModel :
val favorites: List<CommunityModel> = emptyList(),
val searchText: String = "",
val isFiltering: Boolean = false,
val enableToggleFavorite: Boolean = false,
)
sealed interface Effect

View File

@ -4,6 +4,7 @@ import cafe.adriel.voyager.core.model.screenModelScope
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterEvent
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.data.FavoriteCommunityModel
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.AccountRepository
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.FavoriteCommunityRepository
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.repository.MultiCommunityRepository
@ -12,21 +13,15 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.ApiCo
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommunityRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapConcat
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout
import kotlinx.coroutines.yield
@ -41,47 +36,60 @@ class ModalDrawerViewModel(
private val settingsRepository: SettingsRepository,
private val favoriteCommunityRepository: FavoriteCommunityRepository,
private val notificationCenter: NotificationCenter,
) : ModalDrawerMviModel,
DefaultMviModel<ModalDrawerMviModel.Intent, ModalDrawerMviModel.UiState, ModalDrawerMviModel.Effect>(
) : DefaultMviModel<ModalDrawerMviModel.Intent, ModalDrawerMviModel.UiState, ModalDrawerMviModel.Effect>(
initialState = ModalDrawerMviModel.UiState(),
) {
),
ModalDrawerMviModel {
private var currentPage = 1
private val searchEventChannel = Channel<Unit>()
init {
screenModelScope.launch {
apiConfigurationRepository.instance.onEach { instance ->
updateState {
it.copy(instance = instance)
}
}.launchIn(this)
apiConfigurationRepository.instance
.onEach { instance ->
updateState {
it.copy(instance = instance)
}
}.launchIn(this)
identityRepository.isLogged.onEach { _ ->
refreshUser()
refresh()
}.launchIn(this)
identityRepository.isLogged
.onEach { _ ->
refreshUser()
refresh()
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.Logout::class).onEach {
delay(250)
refreshUser()
refresh()
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.Logout::class)
.onEach {
delay(250)
refreshUser()
refresh()
}.launchIn(this)
settingsRepository.currentSettings.onEach { settings ->
updateState {
it.copy(
autoLoadImages = settings.autoLoadImages,
preferNicknames = settings.preferUserNicknames,
)
}
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.FavoritesUpdated::class)
.onEach {
refresh()
}.launchIn(this)
settingsRepository.currentSettings
.onEach { settings ->
updateState {
it.copy(
autoLoadImages = settings.autoLoadImages,
preferNicknames = settings.preferUserNicknames,
enableToggleFavorite = settings.enableToggleFavoriteInNavDrawer,
)
}
}.launchIn(this)
@OptIn(FlowPreview::class)
searchEventChannel.receiveAsFlow().debounce(1000).onEach {
refresh()
}.launchIn(this)
observeChangesInFavoriteCommunities()
searchEventChannel
.receiveAsFlow()
.debounce(1000)
.onEach {
refresh()
}.launchIn(this)
delay(250)
refreshUser()
@ -89,53 +97,25 @@ class ModalDrawerViewModel(
}
}
@OptIn(ExperimentalCoroutinesApi::class)
private fun CoroutineScope.observeChangesInFavoriteCommunities() {
channelFlow {
while (isActive) {
val accountId = accountRepository.getActive()?.id
trySend(accountId)
delay(1000)
}
}.distinctUntilChanged().flatMapConcat { accountId ->
channelFlow {
while (isActive) {
val communityIds =
favoriteCommunityRepository.getAll(accountId).map { it.communityId }
trySend(communityIds)
delay(1000)
}
}.distinctUntilChanged()
}.onEach { favoriteCommunityIds ->
val currentState = uiState.value
val newFavorites =
currentState.favorites.filter { it.id in favoriteCommunityIds } + currentState.communities.filter { it.id in favoriteCommunityIds }
val newCommunities =
(currentState.communities.filter { it.id !in favoriteCommunityIds } + currentState.favorites.filter { it.id !in favoriteCommunityIds })
updateState {
it.copy(
favorites = newFavorites,
communities = newCommunities,
)
}
}.launchIn(this)
}
override fun reduce(intent: ModalDrawerMviModel.Intent) {
when (intent) {
ModalDrawerMviModel.Intent.Refresh -> screenModelScope.launch {
refresh()
}
ModalDrawerMviModel.Intent.Refresh ->
screenModelScope.launch {
refresh()
}
is ModalDrawerMviModel.Intent.SetSearch -> screenModelScope.launch {
updateState { it.copy(searchText = intent.value) }
searchEventChannel.send(Unit)
}
is ModalDrawerMviModel.Intent.SetSearch ->
screenModelScope.launch {
updateState { it.copy(searchText = intent.value) }
searchEventChannel.send(Unit)
}
ModalDrawerMviModel.Intent.LoadNextPage -> screenModelScope.launch {
loadNextPage()
}
ModalDrawerMviModel.Intent.LoadNextPage ->
screenModelScope.launch {
loadNextPage()
}
is ModalDrawerMviModel.Intent.ToggleFavorite -> toggleFavorite(intent.id)
}
}
@ -175,46 +155,48 @@ class ModalDrawerViewModel(
val accountId = accountRepository.getActive()?.id
val searchText = uiState.value.searchText
val multiCommunities =
accountId?.let {
multiCommunityRepository.getAll(it)
.let { communities ->
if (searchText.isEmpty()) {
communities
} else {
communities.filter { c ->
c.name.contains(
other = searchText,
ignoreCase = true
)
accountId
?.let {
multiCommunityRepository
.getAll(it)
.let { communities ->
if (searchText.isEmpty()) {
communities
} else {
communities.filter { c ->
c.name.contains(
other = searchText,
ignoreCase = true,
)
}
}
}
}
.sortedBy { e -> e.name }
}.orEmpty()
}.sortedBy { e -> e.name }
}.orEmpty()
val favorites = coroutineScope {
val auth = identityRepository.authToken.value
favoriteCommunityRepository.getAll(accountId).mapNotNull { favorite ->
val communityId = favorite.communityId
async {
communityRepository.get(
auth = auth,
id = communityId,
)
}.await()
}
}.let { communities ->
if (searchText.isEmpty()) {
communities
} else {
communities.filter { c ->
c.name.contains(
other = searchText,
ignoreCase = true
)
val favorites =
coroutineScope {
val auth = identityRepository.authToken.value
favoriteCommunityRepository.getAll(accountId).mapNotNull { favorite ->
val communityId = favorite.communityId
async {
communityRepository.get(
auth = auth,
id = communityId,
)
}.await()
}
}.let { communities ->
if (searchText.isEmpty()) {
communities
} else {
communities.filter { c ->
c.name.contains(
other = searchText,
ignoreCase = true,
)
}
}
}
}
updateState {
it.copy(
@ -234,21 +216,23 @@ class ModalDrawerViewModel(
}
val auth = identityRepository.authToken.value
val searchText = uiState.value.searchText
val itemsToAdd = communityRepository.getSubscribed(
auth = auth,
page = currentPage,
query = searchText,
).filter { c1 ->
// exclude items already included in favorites
currentState.favorites.none { c2 -> c2.id == c1.id }
}.filter { c1 ->
// prevents accidental duplication
if (!currentState.refreshing) {
currentState.communities.none { c2 -> c2.id == c1.id }
} else {
true
}
}
val itemsToAdd =
communityRepository
.getSubscribed(
auth = auth,
page = currentPage,
query = searchText,
).filter { c1 ->
// exclude items already included in favorites
currentState.favorites.none { c2 -> c2.id == c1.id }
}.filter { c1 ->
// prevents accidental duplication
if (!currentState.refreshing) {
currentState.communities.none { c2 -> c2.id == c1.id }
} else {
true
}
}
if (itemsToAdd.isNotEmpty()) {
currentPage++
}
@ -256,14 +240,49 @@ class ModalDrawerViewModel(
it.copy(
isFiltering = searchText.isNotEmpty(),
refreshing = false,
communities = if (currentState.refreshing) {
itemsToAdd
} else {
currentState.communities + itemsToAdd
},
communities =
if (currentState.refreshing) {
itemsToAdd
} else {
currentState.communities + itemsToAdd
},
canFetchMore = itemsToAdd.isNotEmpty(),
loading = false,
)
}
}
private fun toggleFavorite(communityId: Long) {
screenModelScope.launch {
val currentState = uiState.value
val accountId = accountRepository.getActive()?.id ?: 0L
val isCurrentlyFavorite = currentState.favorites.any { it.id == communityId }
if (isCurrentlyFavorite) {
val community = currentState.favorites.first { it.id == communityId }
favoriteCommunityRepository.getBy(accountId, communityId)?.also { toDelete ->
favoriteCommunityRepository.delete(accountId, toDelete)
}
val newFavorites = currentState.favorites.filter { it.id != communityId }
val newCommunities = currentState.communities + community
updateState {
it.copy(
favorites = newFavorites,
communities = newCommunities,
)
}
} else {
val model = FavoriteCommunityModel(communityId = communityId)
favoriteCommunityRepository.create(model, accountId)
val community = currentState.communities.first { it.id == communityId }
val newFavorites = currentState.favorites + community
val newCommunities = currentState.communities.filter { it.id != communityId }
updateState {
it.copy(
favorites = newFavorites,
communities = newCommunities,
)
}
}
}
}
}

View File

@ -1,10 +1,12 @@
package com.github.diegoberaldin.raccoonforlemmy.unit.drawer.components
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Star
import androidx.compose.material.icons.filled.StarBorder
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationDrawerItem
@ -13,10 +15,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.IconSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.ancillaryTextAlpha
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CustomImage
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.PlaceholderImage
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
@Composable
internal fun DrawerCommunityItem(
@ -27,6 +31,7 @@ internal fun DrawerCommunityItem(
favorite: Boolean = false,
autoLoadImages: Boolean = true,
onSelected: (() -> Unit)? = null,
onToggleFavorite: (() -> Unit)? = null,
) {
NavigationDrawerItem(
modifier = modifier,
@ -51,7 +56,8 @@ internal fun DrawerCommunityItem(
},
label = {
val fullColor = MaterialTheme.colorScheme.onBackground
val ancillaryColor = MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha)
val ancillaryColor =
MaterialTheme.colorScheme.onBackground.copy(alpha = ancillaryTextAlpha)
Column {
Text(
text = title,
@ -70,13 +76,24 @@ internal fun DrawerCommunityItem(
}
},
badge =
if (favorite) {
if (onToggleFavorite != null || favorite) {
@Composable {
Icon(
modifier = Modifier.size(IconSize.s),
imageVector = Icons.Default.Star,
modifier =
Modifier
.size(IconSize.s)
.padding(start = 1.dp)
.onClick(onClick = { onToggleFavorite?.invoke() }),
imageVector = if (favorite) Icons.Default.Star else Icons.Default.StarBorder,
contentDescription = "",
tint = MaterialTheme.colorScheme.onBackground,
tint =
MaterialTheme.colorScheme.onBackground.let {
if (favorite) {
it
} else {
it.copy(alpha = 0.25f)
}
},
)
}
} else {

View File

@ -34,36 +34,42 @@ class ManageSubscriptionsViewModel(
private val siteRepository: SiteRepository,
private val hapticFeedback: HapticFeedback,
private val notificationCenter: NotificationCenter,
) : ManageSubscriptionsMviModel,
DefaultMviModel<ManageSubscriptionsMviModel.Intent, ManageSubscriptionsMviModel.UiState, ManageSubscriptionsMviModel.Effect>(
) : DefaultMviModel<ManageSubscriptionsMviModel.Intent, ManageSubscriptionsMviModel.UiState, ManageSubscriptionsMviModel.Effect>(
initialState = ManageSubscriptionsMviModel.UiState(),
) {
),
ManageSubscriptionsMviModel {
private var currentPage = 1
private val searchEventChannel = Channel<Unit>()
init {
screenModelScope.launch {
settingsRepository.currentSettings.onEach { settings ->
updateState {
it.copy(
autoLoadImages = settings.autoLoadImages,
preferNicknames = settings.preferUserNicknames,
)
}
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.MultiCommunityCreated::class)
settingsRepository.currentSettings
.onEach { settings ->
updateState {
it.copy(
autoLoadImages = settings.autoLoadImages,
preferNicknames = settings.preferUserNicknames,
)
}
}.launchIn(this)
notificationCenter
.subscribe(NotificationCenterEvent.MultiCommunityCreated::class)
.onEach { evt ->
handleMultiCommunityCreated(evt.model)
}.launchIn(this)
notificationCenter.subscribe(NotificationCenterEvent.CommunitySubscriptionChanged::class)
notificationCenter
.subscribe(NotificationCenterEvent.CommunitySubscriptionChanged::class)
.onEach { evt ->
handleCommunityUpdate(evt.value)
}.launchIn(this)
searchEventChannel.receiveAsFlow().debounce(1000).onEach {
emitEffect(ManageSubscriptionsMviModel.Effect.BackToTop)
refresh()
}.launchIn(this)
searchEventChannel
.receiveAsFlow()
.debounce(1000)
.onEach {
emitEffect(ManageSubscriptionsMviModel.Effect.BackToTop)
refresh()
}.launchIn(this)
if (uiState.value.communities.isEmpty()) {
// determine whether community creation is allowed
val isAdmin = identityRepository.cachedUser?.admin ?: false
@ -89,11 +95,12 @@ class ManageSubscriptionsViewModel(
}
is ManageSubscriptionsMviModel.Intent.DeleteMultiCommunity -> {
uiState.value.multiCommunities.firstOrNull {
(it.id ?: 0L) == intent.id
}?.also { community ->
deleteMultiCommunity(community)
}
uiState.value.multiCommunities
.firstOrNull {
(it.id ?: 0L) == intent.id
}?.also { community ->
deleteMultiCommunity(community)
}
}
is ManageSubscriptionsMviModel.Intent.ToggleFavorite -> {
@ -122,7 +129,8 @@ class ManageSubscriptionsViewModel(
currentPage = 1
val accountId = accountRepository.getActive()?.id ?: 0L
val multiCommunitites =
multiCommunityRepository.getAll(accountId)
multiCommunityRepository
.getAll(accountId)
.let {
val searchText = uiState.value.searchText
if (searchText.isNotEmpty()) {
@ -132,8 +140,7 @@ class ManageSubscriptionsViewModel(
} else {
it
}
}
.sortedBy { it.name }
}.sortedBy { it.name }
updateState {
it.copy(
@ -193,9 +200,11 @@ class ManageSubscriptionsViewModel(
if (newValue) {
val model = FavoriteCommunityModel(communityId = communityId)
favoriteCommunityRepository.create(model, accountId)
notificationCenter.send(NotificationCenterEvent.FavoritesUpdated)
} else {
favoriteCommunityRepository.getBy(accountId, communityId)?.also { toDelete ->
favoriteCommunityRepository.delete(accountId, toDelete)
notificationCenter.send(NotificationCenterEvent.FavoritesUpdated)
}
}
val newCommunity = community.copy(favorite = newValue)
@ -240,17 +249,19 @@ class ManageSubscriptionsViewModel(
val favoriteCommunityIds =
favoriteCommunityRepository.getAll(accountId).map { it.communityId }
val itemsToAdd =
communityRepository.getSubscribed(
auth = auth,
page = currentPage,
query = searchText,
).map { community ->
community.copy(favorite = community.id in favoriteCommunityIds)
}.sortedBy { it.name }.let {
val favorites = it.filter { e -> e.favorite }
val res = it - favorites.toSet()
favorites + res
}
communityRepository
.getSubscribed(
auth = auth,
page = currentPage,
query = searchText,
).map { community ->
community.copy(favorite = community.id in favoriteCommunityIds)
}.sortedBy { it.name }
.let {
val favorites = it.filter { e -> e.favorite }
val res = it - favorites.toSet()
favorites + res
}
if (itemsToAdd.isNotEmpty()) {
currentPage++
}