refactor: improve community opening on other instances (#486)

This commit is contained in:
Diego Beraldin 2024-01-26 00:41:47 +01:00 committed by GitHub
parent 4fee7addfd
commit 1b1facbdfe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 56 additions and 96 deletions

View File

@ -45,6 +45,7 @@ kotlin {
implementation(projects.core.navigation)
implementation(projects.core.commonui.detailopenerApi)
implementation(projects.domain.identity)
implementation(projects.domain.lemmy.data)
implementation(projects.domain.lemmy.repository)

View File

@ -2,10 +2,14 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.detailopener.impl
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.detailopener.api.DetailOpener
import com.github.diegoberaldin.raccoonforlemmy.core.navigation.NavigationCoordinator
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommentModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.PostModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SearchResult
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SearchResultType
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.UserModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommunityRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.LemmyItemCache
import com.github.diegoberaldin.raccoonforlemmy.unit.communitydetail.CommunityDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.createcomment.CreateCommentScreen
@ -14,23 +18,35 @@ import com.github.diegoberaldin.raccoonforlemmy.unit.postdetail.PostDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.unit.userdetail.UserDetailScreen
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class DefaultDetailOpener(
private val navigationCoordinator: NavigationCoordinator,
private val itemCache: LemmyItemCache,
private val identityRepository: IdentityRepository,
private val communityRepository: CommunityRepository,
) : DetailOpener {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
override fun openCommunityDetail(community: CommunityModel, otherInstance: String) {
scope.launch {
itemCache.putCommunity(community)
val (actualCommunity, actualInstance) = withContext(Dispatchers.IO) {
val found = searchCommunity(community.name)
if (found != null) {
found to ""
} else {
community to otherInstance
}
}
itemCache.putCommunity(actualCommunity)
navigationCoordinator.pushScreen(
CommunityDetailScreen(
communityId = community.id,
otherInstance = otherInstance,
communityId = actualCommunity.id,
otherInstance = actualInstance,
),
)
}
@ -113,4 +129,31 @@ class DefaultDetailOpener(
navigationCoordinator.pushScreen(screen)
}
}
private suspend fun searchCommunity(name: String): CommunityModel? {
val auth = identityRepository.authToken.value
tailrec suspend fun searchRec(page: Int = 0): CommunityModel? {
val results = communityRepository.getAll(
auth = auth,
query = name,
resultType = SearchResultType.Communities,
page = page,
limit = 50,
)?.filterIsInstance<SearchResult.Community>().orEmpty()
val found = results.firstOrNull {
it.model.name == name
}?.model
// iterates for no more than 20 pages before giving up
if (found != null || page >= 20) {
return found
}
return searchRec(page + 1)
}
// start recursive search
return searchRec()
}
}

View File

@ -18,6 +18,8 @@ internal val internalSharedModule = module {
DefaultDetailOpener(
navigationCoordinator = get(),
itemCache = get(),
identityRepository = get(),
communityRepository = get(),
)
}
}

View File

@ -20,7 +20,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
@ -44,6 +43,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotific
import com.github.diegoberaldin.raccoonforlemmy.core.persistence.di.getSettingsRepository
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.onClick
import com.github.diegoberaldin.raccoonforlemmy.core.utils.compose.rememberCallback
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import com.github.diegoberaldin.raccoonforlemmy.unit.about.AboutConstants.CHANGELOG_URL
import com.github.diegoberaldin.raccoonforlemmy.unit.about.AboutConstants.REPORT_EMAIL_ADDRESS
@ -52,8 +52,6 @@ import com.github.diegoberaldin.raccoonforlemmy.unit.about.AboutConstants.WEBSIT
import com.github.diegoberaldin.raccoonforlemmy.unit.web.WebViewScreen
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
class AboutDialog : Screen {
@ -72,19 +70,6 @@ class AboutDialog : Screen {
val notificationCenter = remember { getNotificationCenter() }
val detailOpener = remember { getDetailOpener() }
LaunchedEffect(viewModel) {
viewModel.effects.onEach { effect ->
when (effect) {
is AboutDialogMviModel.Effect.OpenCommunity -> {
detailOpener.openCommunityDetail(
community = effect.community,
otherInstance = effect.instance,
)
}
}
}.launchIn(this)
}
AlertDialog(
onDismissRequest = {
notificationCenter.send(NotificationCenterEvent.CloseDialog)
@ -187,7 +172,10 @@ class AboutDialog : Screen {
text = stringResource(MR.strings.settings_about_view_lemmy),
textDecoration = TextDecoration.Underline,
onClick = {
viewModel.reduce(AboutDialogMviModel.Intent.OpenOwnCommunity)
detailOpener.openCommunityDetail(
community = CommunityModel(name = AboutConstants.LEMMY_COMMUNITY_NAME),
otherInstance = AboutConstants.LEMMY_COMMUNITY_INSTANCE
)
},
)
}
@ -199,7 +187,6 @@ class AboutDialog : Screen {
onClick = {
runCatching {
uriHandler.openUri(AboutConstants.MATRIX_URL)
viewModel.reduce(AboutDialogMviModel.Intent.OpenOwnCommunity)
}
},
)

View File

@ -2,25 +2,16 @@ package com.github.diegoberaldin.raccoonforlemmy.unit.about
import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
interface AboutDialogMviModel :
MviModel<AboutDialogMviModel.Intent, AboutDialogMviModel.UiState, AboutDialogMviModel.Effect>,
ScreenModel {
sealed interface Intent {
data object OpenOwnCommunity : Intent
}
sealed interface Intent
data class UiState(
val version: String = "",
)
sealed interface Effect {
data class OpenCommunity(
val community: CommunityModel,
val instance: String = "",
) : Effect
}
sealed interface Effect
}

View File

@ -3,23 +3,10 @@ package com.github.diegoberaldin.raccoonforlemmy.unit.about
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.DefaultMviModel
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.core.utils.debug.AppInfo
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository.IdentityRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SearchResult
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SearchResultType
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.CommunityRepository
import com.github.diegoberaldin.raccoonforlemmy.unit.about.AboutConstants.LEMMY_COMMUNITY_INSTANCE
import com.github.diegoberaldin.raccoonforlemmy.unit.about.AboutConstants.LEMMY_COMMUNITY_NAME
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeoutOrNull
class AboutDialogViewModel(
private val mvi: DefaultMviModel<AboutDialogMviModel.Intent, AboutDialogMviModel.UiState, AboutDialogMviModel.Effect>,
private val identityRepository: IdentityRepository,
private val communityRepository: CommunityRepository,
) : AboutDialogMviModel,
MviModel<AboutDialogMviModel.Intent, AboutDialogMviModel.UiState, AboutDialogMviModel.Effect> by mvi {
@ -31,53 +18,4 @@ class AboutDialogViewModel(
)
}
}
override fun reduce(intent: AboutDialogMviModel.Intent) {
when (intent) {
AboutDialogMviModel.Intent.OpenOwnCommunity -> {
mvi.scope?.launch(Dispatchers.IO) {
val (community, instance) = searchCommunity().let { community ->
if (community != null) {
community to ""
} else {
communityRepository.get(
name = LEMMY_COMMUNITY_NAME,
instance = LEMMY_COMMUNITY_INSTANCE
) to LEMMY_COMMUNITY_INSTANCE
}
}
if (community != null) {
mvi.emitEffect(
AboutDialogMviModel.Effect.OpenCommunity(
community = community,
instance = instance
)
)
}
}
}
}
}
private suspend fun searchCommunity(): CommunityModel? {
val auth = identityRepository.authToken.value
suspend fun searchRec(page: Int = 0): CommunityModel? {
return communityRepository.getAll(
auth = auth,
query = LEMMY_COMMUNITY_NAME,
resultType = SearchResultType.Communities,
page = page,
limit = 50,
)
?.filterIsInstance<SearchResult.Community>()
?.firstOrNull {
it.model.name == LEMMY_COMMUNITY_NAME
}?.model ?: searchRec(page + 1)
}
return withTimeoutOrNull(5000) {
// start recursive search
searchRec()
}
}
}

View File

@ -9,8 +9,6 @@ val aboutModule = module {
factory<AboutDialogMviModel> {
AboutDialogViewModel(
mvi = DefaultMviModel(AboutDialogMviModel.UiState()),
identityRepository = get(),
communityRepository = get(),
)
}
}