fix: deep link (and hide back button if not possible)

This commit is contained in:
Diego Beraldin 2023-10-21 20:04:38 +02:00
parent e168ab2396
commit ba7c197957
20 changed files with 224 additions and 190 deletions

View File

@ -6,7 +6,7 @@ import org.koin.core.qualifier.named
import org.koin.dsl.module
val coreApiModule = module {
single<ServiceProvider> {
single<ServiceProvider>(named("default")) {
DefaultServiceProvider()
}
single<ServiceProvider>(named("custom")) {

View File

@ -57,26 +57,6 @@ internal class DefaultServiceProvider : ServiceProvider {
private val factory = provideHttpClientEngineFactory()
private val client = HttpClient(factory) {
defaultRequest {
url {
host = currentInstance
}
}
install(HttpTimeout) {
requestTimeoutMillis = 600_000
connectTimeoutMillis = 30_000
socketTimeoutMillis = 30_000
}
install(Logging) {
logger = defaultLogger
level = LogLevel.ALL
}
install(ContentNegotiation) {
json(Json { isLenient = true; ignoreUnknownKeys = true })
}
}
init {
reinitialize()
}
@ -87,6 +67,25 @@ internal class DefaultServiceProvider : ServiceProvider {
}
private fun reinitialize() {
val client = HttpClient(factory) {
defaultRequest {
url {
host = currentInstance
}
}
install(HttpTimeout) {
requestTimeoutMillis = 600_000
connectTimeoutMillis = 30_000
socketTimeoutMillis = 30_000
}
install(Logging) {
logger = defaultLogger
level = LogLevel.ALL
}
install(ContentNegotiation) {
json(Json { isLenient = true; ignoreUnknownKeys = true })
}
}
val ktorfit = Ktorfit.Builder()
.baseUrl(baseUrl)
.httpClient(client)

View File

@ -213,14 +213,16 @@ class CommunityDetailScreen(
)
},
navigationIcon = {
Image(
modifier = Modifier.onClick {
navigator?.pop()
},
imageVector = Icons.Default.ArrowBack,
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
)
if (navigator?.canPop == true) {
Image(
modifier = Modifier.onClick {
navigator.pop()
},
imageVector = Icons.Default.ArrowBack,
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
)
}
},
)
}, floatingActionButton = {

View File

@ -9,7 +9,7 @@ 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.UserModel
fun getCommmunityFromUrl(url: String): CommunityModel? {
fun getCommunityFromUrl(url: String?): CommunityModel? {
val (normalizedUrl, instance) = normalizeUrl(url)
val res = extractCommunity(normalizedUrl)
return if (res != null && res.host.isEmpty()) {
@ -19,7 +19,7 @@ fun getCommmunityFromUrl(url: String): CommunityModel? {
}
}
fun getUserFromUrl(url: String): UserModel? {
fun getUserFromUrl(url: String?): UserModel? {
val (normalizedUrl, instance) = normalizeUrl(url)
val res = extractUser(normalizedUrl)
return if (res != null && res.host.isEmpty()) {
@ -29,10 +29,10 @@ fun getUserFromUrl(url: String): UserModel? {
}
}
fun getPostFromUrl(url: String): Pair<PostModel, String>? {
fun getPostFromUrl(url: String?): Pair<PostModel, String>? {
val (normalizedUrl, instance) = normalizeUrl(url)
val post = extractPost(normalizedUrl)
return if (post != null && instance != null) {
return if (post != null && instance.isNotEmpty()) {
post to instance
} else {
null
@ -45,7 +45,7 @@ fun handleUrl(
uriHandler: UriHandler,
navigator: Navigator? = null,
) {
val community = getCommmunityFromUrl(url)
val community = getCommunityFromUrl(url)
val user = getUserFromUrl(url)
when {
@ -79,8 +79,8 @@ fun handleUrl(
}
}
private fun normalizeUrl(url: String): Pair<String, String> {
val matches = Regex("https?://(?<instance>.*?)(?<pathAndQuery>/.*)").findAll(url)
private fun normalizeUrl(url: String?): Pair<String, String> {
val matches = Regex("https?://(?<instance>.*?)(?<pathAndQuery>/.*)").findAll(url.orEmpty())
var instance = ""
val res = buildString {
if (matches.count() > 0) {

View File

@ -7,12 +7,13 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.getAndUpdate
import kotlinx.coroutines.launch
internal class DefaultNavigationCoordinator : NavigationCoordinator {
override val onDoubleTabSelection = MutableSharedFlow<Tab>()
override val deeplinkUrl = MutableStateFlow<String?>(null)
override val deepLinkUrl = MutableStateFlow<String?>(null)
private var connection: NestedScrollConnection? = null
private var navigator: Navigator? = null
@ -43,8 +44,10 @@ internal class DefaultNavigationCoordinator : NavigationCoordinator {
}
}
override fun submitDeeplink(url: String?) {
deeplinkUrl.value = url
override fun consumeDeeplink(): String? = deepLinkUrl.getAndUpdate { null }
override fun submitDeeplink(url: String) {
deepLinkUrl.value = url
}
override fun setCanGoBackCallback(value: (() -> Boolean)?) {

View File

@ -3,18 +3,20 @@ package com.github.diegoberaldin.raccoonforlemmy.core.commonui.navigation
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.tab.Tab
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
interface NavigationCoordinator {
val deeplinkUrl: StateFlow<String?>
val onDoubleTabSelection: SharedFlow<Tab>
val onDoubleTabSelection: Flow<Tab>
val inboxUnread: StateFlow<Int>
val deepLinkUrl: StateFlow<String?>
fun setCurrentSection(tab: Tab)
fun submitDeeplink(url: String?)
fun consumeDeeplink(): String?
fun submitDeeplink(url: String)
fun setRootNavigator(value: Navigator?)

View File

@ -127,7 +127,8 @@ class PostDetailScreen(
model.bindToLifecycle(key)
val uiState by model.uiState.collectAsState()
val isOnOtherInstance = otherInstance.isNotEmpty()
val navigator = remember { getNavigationCoordinator().getRootNavigator() }
val navigationCoordinator = remember { getNavigationCoordinator() }
val navigator = remember { navigationCoordinator.getRootNavigator() }
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val topAppBarState = rememberTopAppBarState()
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(topAppBarState)
@ -207,14 +208,16 @@ class PostDetailScreen(
)
},
navigationIcon = {
Image(
modifier = Modifier.onClick {
navigator?.pop()
},
imageVector = Icons.Default.ArrowBack,
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
)
if (navigator?.canPop == true) {
Image(
modifier = Modifier.onClick {
navigator.pop()
},
imageVector = Icons.Default.ArrowBack,
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
)
}
},
)
},

View File

@ -107,7 +107,6 @@ class PostDetailViewModel(
}
if (highlightCommentId != null) {
val auth = identityRepository.authToken.value
val comment = commentRepository.getBy(
id = highlightCommentId,
auth = auth,

View File

@ -192,14 +192,16 @@ class UserDetailScreen(
)
},
navigationIcon = {
Image(
modifier = Modifier.onClick {
navigator?.pop()
},
imageVector = Icons.Default.ArrowBack,
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
)
if (navigator?.canPop == true) {
Image(
modifier = Modifier.onClick {
navigator.pop()
},
imageVector = Icons.Default.ArrowBack,
contentDescription = null,
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onBackground),
)
}
},
)
},

View File

@ -12,12 +12,13 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase.DefaultS
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase.LoginUseCase
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase.LogoutUseCase
import com.github.diegoberaldin.raccoonforlemmy.domain.identity.usecase.SwitchAccountUseCase
import org.koin.core.qualifier.named
import org.koin.dsl.module
val coreIdentityModule = module {
single<ApiConfigurationRepository> {
DefaultApiConfigurationRepository(
serviceProvider = get(),
serviceProvider = get(named("default")),
)
}
single<IdentityRepository> {
@ -27,7 +28,7 @@ val coreIdentityModule = module {
}
single<AuthRepository> {
DefaultAuthRepository(
services = get(),
services = get(named("default")),
)
}
single<LoginUseCase> {
@ -52,7 +53,7 @@ val coreIdentityModule = module {
identityRepository = get(),
accountRepository = get(),
settingsRepository = get(),
serviceProvider = get(),
serviceProvider = get(named("default")),
notificationCenter = get(),
)
}

View File

@ -1,12 +1,10 @@
package com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
interface ApiConfigurationRepository {
val instance: Flow<String>
fun getInstance(): String
val instance: StateFlow<String>
fun changeInstance(value: String)
}

View File

@ -1,25 +1,32 @@
package com.github.diegoberaldin.raccoonforlemmy.domain.identity.repository
import com.github.diegoberaldin.raccoonforlemmy.core.api.provider.ServiceProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.isActive
internal class DefaultApiConfigurationRepository(
private val serviceProvider: ServiceProvider,
) : ApiConfigurationRepository {
override val instance: Flow<String> = channelFlow {
private val scope = CoroutineScope(SupervisorJob())
override val instance = channelFlow {
while (isActive) {
val value = getInstance()
val value = serviceProvider.currentInstance
trySend(value)
delay(1000)
}
}.distinctUntilChanged()
override fun getInstance() = serviceProvider.currentInstance
}.distinctUntilChanged().stateIn(
scope = scope,
started = SharingStarted.Lazily,
initialValue = "",
)
override fun changeInstance(value: String) {
serviceProvider.changeInstance(value)

View File

@ -23,7 +23,7 @@ internal class DefaultLoginUseCase(
password: String,
totp2faToken: String?,
): Result<Unit> {
val oldInstance = apiConfigurationRepository.getInstance()
val oldInstance = apiConfigurationRepository.instance.value
apiConfigurationRepository.changeInstance(instance)
val response = authRepository.login(

View File

@ -8,7 +8,7 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.to
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel
class PrivateMessageRepository(
private val serviceProvider: ServiceProvider,
private val services: ServiceProvider,
) {
suspend fun getAll(
auth: String? = null,
@ -16,7 +16,7 @@ class PrivateMessageRepository(
limit: Int = PostRepository.DEFAULT_PAGE_SIZE,
unreadOnly: Boolean = true,
): List<PrivateMessageModel>? = runCatching {
val response = serviceProvider.privateMessages.getPrivateMessages(
val response = services.privateMessages.getPrivateMessages(
authHeader = auth.toAuthHeader(),
auth = auth,
limit = limit,
@ -37,7 +37,7 @@ class PrivateMessageRepository(
auth = auth.orEmpty(),
recipientId = recipiendId,
)
serviceProvider.privateMessages.createPrivateMessage(
services.privateMessages.createPrivateMessage(
authHeader = auth.toAuthHeader(),
form = data,
)
@ -53,7 +53,7 @@ class PrivateMessageRepository(
auth = auth.orEmpty(),
read = read,
)
serviceProvider.privateMessages.markPrivateMessageAsRead(
services.privateMessages.markPrivateMessageAsRead(
authHeader = auth.toAuthHeader(),
form = data,
)

View File

@ -9,10 +9,10 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.to
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel
class SiteRepository(
private val serviceProvider: ServiceProvider,
private val services: ServiceProvider,
) {
suspend fun getCurrentUser(auth: String): UserModel? = runCatching {
val response = serviceProvider.site.get(
val response = services.site.get(
auth = auth,
authHeader = auth.toAuthHeader(),
)
@ -28,14 +28,14 @@ class SiteRepository(
instanceId = id,
block = blocked,
)
serviceProvider.site.block(
services.site.block(
authHeader = auth.toAuthHeader(),
form = data,
)
}
suspend fun getMetadata(url: String): MetadataModel? = runCatching {
val response = serviceProvider.site.getSiteMetadata(
val response = services.site.getSiteMetadata(
url = url,
)
response.body()?.metadata?.toModel()

View File

@ -16,8 +16,8 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.to
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.utils.toModel
class UserRepository(
private val serviceProvider: ServiceProvider,
private val customServiceProvider: ServiceProvider,
private val services: ServiceProvider,
private val customServices: ServiceProvider,
) {
suspend fun get(
@ -25,7 +25,7 @@ class UserRepository(
auth: String? = null,
username: String? = null,
): UserModel? = runCatching {
val response = serviceProvider.user.getDetails(
val response = services.user.getDetails(
authHeader = auth.toAuthHeader(),
auth = auth,
personId = id,
@ -48,8 +48,8 @@ class UserRepository(
username: String? = null,
auth: String? = null,
): UserModel? = runCatching {
customServiceProvider.changeInstance(instance)
val response = customServiceProvider.user.getDetails(
customServices.changeInstance(instance)
val response = customServices.user.getDetails(
authHeader = auth.toAuthHeader(),
auth = auth,
username = username,
@ -73,7 +73,7 @@ class UserRepository(
limit: Int = PostRepository.DEFAULT_PAGE_SIZE,
sort: SortType = SortType.Active,
): List<PostModel>? = runCatching {
val response = serviceProvider.user.getDetails(
val response = services.user.getDetails(
authHeader = auth.toAuthHeader(),
auth = auth,
personId = id,
@ -92,7 +92,7 @@ class UserRepository(
limit: Int = PostRepository.DEFAULT_PAGE_SIZE,
sort: SortType = SortType.Active,
): List<PostModel>? = runCatching {
val response = serviceProvider.user.getDetails(
val response = services.user.getDetails(
authHeader = auth.toAuthHeader(),
auth = auth,
personId = id,
@ -112,7 +112,7 @@ class UserRepository(
limit: Int = PostRepository.DEFAULT_PAGE_SIZE,
sort: SortType = SortType.Active,
): List<CommentModel>? = runCatching {
val response = serviceProvider.user.getDetails(
val response = services.user.getDetails(
authHeader = auth.toAuthHeader(),
auth = auth,
personId = id,
@ -131,7 +131,7 @@ class UserRepository(
limit: Int = PostRepository.DEFAULT_PAGE_SIZE,
sort: SortType = SortType.Active,
): List<CommentModel>? = runCatching {
val response = serviceProvider.user.getDetails(
val response = services.user.getDetails(
authHeader = auth.toAuthHeader(),
auth = auth,
personId = id,
@ -151,7 +151,7 @@ class UserRepository(
sort: SortType = SortType.New,
unreadOnly: Boolean = true,
): List<PersonMentionModel>? = runCatching {
val response = serviceProvider.user.getMentions(
val response = services.user.getMentions(
authHeader = auth.toAuthHeader(),
auth = auth,
limit = limit,
@ -170,7 +170,7 @@ class UserRepository(
sort: SortType = SortType.New,
unreadOnly: Boolean = true,
): List<PersonMentionModel>? = runCatching {
val response = serviceProvider.user.getReplies(
val response = services.user.getReplies(
authHeader = auth.toAuthHeader(),
auth = auth,
limit = limit,
@ -186,7 +186,7 @@ class UserRepository(
auth: String? = null,
) {
val data = MarkAllAsReadForm(auth.orEmpty())
serviceProvider.user.markAllAsRead(
services.user.markAllAsRead(
authHeader = auth.toAuthHeader(),
form = data,
)
@ -198,7 +198,7 @@ class UserRepository(
read = read,
auth = auth.orEmpty(),
)
serviceProvider.user.markPersonMentionAsRead(
services.user.markPersonMentionAsRead(
authHeader = auth.toAuthHeader(),
form = data,
)
@ -210,7 +210,7 @@ class UserRepository(
read = read,
auth = auth.orEmpty(),
)
serviceProvider.user.markCommentReplyAsRead(
services.user.markCommentReplyAsRead(
authHeader = auth.toAuthHeader(),
form = data,
)
@ -222,7 +222,7 @@ class UserRepository(
block = blocked,
auth = auth.orEmpty(),
)
serviceProvider.user.block(
services.user.block(
authHeader = auth.toAuthHeader(),
form = data,
)

View File

@ -6,25 +6,42 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PostRepo
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.PrivateMessageRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.SiteRepository
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.repository.UserRepository
import org.koin.core.module.dsl.singleOf
import org.koin.core.qualifier.named
import org.koin.dsl.module
val repositoryModule = module {
single {
PostRepository(
services = get(),
services = get(named("default")),
customServices = get(named("custom")),
)
}
single {
CommunityRepository(
services = get(),
services = get(named("default")),
customServices = get(named("custom")),
)
}
singleOf(::UserRepository)
singleOf(::SiteRepository)
singleOf(::CommentRepository)
singleOf(::PrivateMessageRepository)
single {
UserRepository(
services = get(named("default")),
customServices = get(named("custom")),
)
}
single {
SiteRepository(
services = get(named("default")),
)
}
single {
CommentRepository(
services = get(named("default")),
customServices = get(named("custom")),
)
}
single {
PrivateMessageRepository(
services = get(named("default")),
)
}
}

View File

@ -66,7 +66,7 @@ class ExploreViewModel(
mvi.onStarted()
mvi.updateState {
it.copy(
instance = apiConfigRepository.getInstance(),
instance = apiConfigRepository.instance.value,
)
}
mvi.scope?.launch(Dispatchers.Main) {

View File

@ -31,9 +31,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.CurrentScreen
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator
import cafe.adriel.voyager.navigator.tab.TabNavigator
@ -47,7 +45,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.AppTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.CornerSize
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.getCommmunityFromUrl
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.getCommunityFromUrl
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.getPostFromUrl
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.getUserFromUrl
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getDrawerCoordinator
@ -77,12 +75,20 @@ fun App() {
val settingsRepository = remember { getSettingsRepository() }
val settings by settingsRepository.currentSettings.collectAsState()
var hasBeenInitialized by remember { mutableStateOf(false) }
LaunchedEffect(settingsRepository) {
val apiConfigurationRepository = remember { getApiConfigurationRepository() }
LaunchedEffect(accountRepository) {
val accountId = accountRepository.getActive()?.id
val currentSettings = settingsRepository.getSettings(accountId)
settingsRepository.changeCurrentSettings(currentSettings)
val lastActiveAccount = accountRepository.getActive()
val lastInstance = lastActiveAccount?.instance
if (lastInstance != null) {
apiConfigurationRepository.changeInstance(lastInstance)
}
hasBeenInitialized = true
}
val defaultTheme = if (isSystemInDarkTheme()) {
UiTheme.Dark.toInt()
} else {
@ -100,15 +106,6 @@ fun App() {
StringDesc.localeType = StringDesc.LocaleType.Custom(lang)
}.launchIn(scope)
val apiConfigurationRepository = remember { getApiConfigurationRepository() }
LaunchedEffect(Unit) {
val lastActiveAccount = accountRepository.getActive()
val lastInstance = lastActiveAccount?.instance
if (lastInstance != null) {
apiConfigurationRepository.changeInstance(lastInstance)
}
}
val themeRepository = remember { getThemeRepository() }
LaunchedEffect(settings) {
with(themeRepository) {
@ -136,6 +133,73 @@ fun App() {
val lang by languageRepository.currentLanguage.collectAsState()
LaunchedEffect(lang) {}
val url = navigationCoordinator.consumeDeeplink()
LaunchedEffect(navigationCoordinator, url) {
val community = getCommunityFromUrl(url)
val user = getUserFromUrl(url)
val postAndInstance = getPostFromUrl(url)
val newScreen = when {
community != null -> {
CommunityDetailScreen(
community = community,
otherInstance = community.host,
)
}
user != null -> {
UserDetailScreen(
user = user,
otherInstance = user.host,
)
}
postAndInstance != null -> {
val (post, otherInstance) = postAndInstance
PostDetailScreen(
post = post,
otherInstance = otherInstance,
)
}
else -> null
}
if (newScreen != null) {
navigationCoordinator.getRootNavigator()?.push(newScreen)
}
}
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val drawerCoordinator = remember { getDrawerCoordinator() }
LaunchedEffect(drawerCoordinator) {
drawerCoordinator.toggleEvents.onEach { evt ->
val navigator = navigationCoordinator.getRootNavigator()
when (evt) {
DrawerEvent.Toggled -> {
drawerState.apply {
if (isClosed) open() else close()
}
}
is DrawerEvent.OpenCommunity -> {
navigator?.push(CommunityDetailScreen(evt.community))
}
is DrawerEvent.OpenMultiCommunity -> {
navigator?.push(MultiCommunityScreen(evt.community))
}
DrawerEvent.ManageSubscriptions -> {
navigator?.push(ManageSubscriptionsScreen())
}
DrawerEvent.OpenBookmarks -> {
navigator?.push(SavedItemsScreen())
}
}
}.launchIn(this)
}
val drawerGestureEnabled by drawerCoordinator.gesturesEnabled.collectAsState()
CompositionLocalProvider(
LocalDensity provides Density(
density = LocalDensity.current.density,
@ -143,73 +207,12 @@ fun App() {
),
) {
BottomSheetNavigator(
sheetShape = RoundedCornerShape(topStart = CornerSize.xl, topEnd = CornerSize.xl),
sheetShape = RoundedCornerShape(
topStart = CornerSize.xl,
topEnd = CornerSize.xl
),
sheetBackgroundColor = MaterialTheme.colorScheme.background,
) {
val screens: List<Screen> = remember(navigationCoordinator.deeplinkUrl) {
val url = navigationCoordinator.deeplinkUrl.value.orEmpty()
val community = getCommmunityFromUrl(url)
val user = getUserFromUrl(url)
val postAndInstance = getPostFromUrl(url)
buildList {
if (community != null) {
add(
CommunityDetailScreen(
community = community,
otherInstance = community.host,
)
)
} else if (user != null) {
add(
UserDetailScreen(
user = user,
otherInstance = user.host,
)
)
} else if (postAndInstance != null) {
val (post, otherInstance) = postAndInstance
add(
PostDetailScreen(
post = post,
otherInstance = otherInstance,
)
)
} else {
add(MainScreen())
}
}
}
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val drawerCoordinator = remember { getDrawerCoordinator() }
LaunchedEffect(drawerCoordinator) {
drawerCoordinator.toggleEvents.onEach { evt ->
val navigator = navigationCoordinator.getRootNavigator()
when (evt) {
DrawerEvent.Toggled -> {
drawerState.apply {
if (isClosed) open() else close()
}
}
is DrawerEvent.OpenCommunity -> {
navigator?.push(CommunityDetailScreen(evt.community))
}
is DrawerEvent.OpenMultiCommunity -> {
navigator?.push(MultiCommunityScreen(evt.community))
}
DrawerEvent.ManageSubscriptions -> {
navigator?.push(ManageSubscriptionsScreen())
}
DrawerEvent.OpenBookmarks -> {
navigator?.push(SavedItemsScreen())
}
}
}.launchIn(this)
}
val drawerGestureEnabled by drawerCoordinator.gesturesEnabled.collectAsState()
ModalNavigationDrawer(
drawerState = drawerState,
gesturesEnabled = drawerGestureEnabled,
@ -217,21 +220,19 @@ fun App() {
ModalDrawerSheet {
TabNavigator(ModalDrawerContent)
}
}
},
) {
Navigator(
screens = screens,
screen = MainScreen,
onBackPressed = {
val callback = navigationCoordinator.getCanGoBackCallback()
callback?.let { it() } ?: true
}
) {
val navigator = LocalNavigator.current
) { navigator ->
navigationCoordinator.setRootNavigator(navigator)
if (hasBeenInitialized) {
CurrentScreen()
} else {
// loading screen
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,

View File

@ -43,7 +43,7 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlin.math.roundToInt
internal class MainScreen : Screen {
internal object MainScreen : Screen {
@Composable
override fun Content() {