Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Proposal] ♻️ Added the ability to go to the floor map from the session details. #1127

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import io.github.droidkaigi.confsched2023.data.di.AppAndroidBuildConfig
import io.github.droidkaigi.confsched2023.model.BuildConfigProvider
import io.github.droidkaigi.confsched2023.model.NavigationRequester
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Singleton

@InstallIn(SingletonComponent::class)
Expand All @@ -15,8 +18,25 @@ class AppModule {
@Singleton
@AppAndroidBuildConfig
fun provideBuildConfigProvider(): BuildConfigProvider = AppBuildConfigProvider()

@Provides
@Singleton
fun provideNavigationRequester(): NavigationRequester = DefaultNavigationRequester()
}

class AppBuildConfigProvider(
override val versionName: String = BuildConfig.VERSION_NAME,
) : BuildConfigProvider

class DefaultNavigationRequester : NavigationRequester {
private val _navigateRequestStateFlow = MutableStateFlow("")
override fun getNavigationRouteFlow(): Flow<String> = _navigateRequestStateFlow

override fun navigateTo(route: String) {
_navigateRequestStateFlow.value = route
}

override fun navigated() {
_navigateRequestStateFlow.value = ""
}
}
Copy link
Contributor Author

@Corvus400 Corvus400 Sep 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We did this to operate between different NavHosts.
I don't think this is the best way to do it, so if you have a better idea, I'm open to it.
I doubt if the name NavigationRequester is appropriate either.

Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ private fun KaigiNavHost(
onTimetableItemClick = navController::navigateToTimetableItemDetailScreen,
onNavigateToBookmarkScreenRequested = navController::navigateToBookmarkScreen,
onLinkClick = externalNavController::navigate,
onRoomClick = {
navController.popBackStack(navController.graph.startDestinationId, false)
Copy link
Member

@takahirom takahirom Sep 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it's difficult to think but what if we create navController::navigateToMainFloorMapScreen?
I think we can see parent navController to access getBackStackEntry 👀

Copy link
Contributor Author

@Corvus400 Corvus400 Sep 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once I was able to return to the start destination with the following code.

fun NavController.navigateToMainFloorMapScreen() {
    getBackStackEntry(timetableItemDetailScreenRoute).destination.parent?.startDestinationId?.let {
        navigate(it)
        // TODO navigateMainFloorMap
    }
}

However, I have not figured out how to move to FloorMapScreen from here without having to make any major changes.
Do you already have any ideas? 🙇

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this. But I think we can pass the route parameter to NavHost and we may be able to pass /main/floorMap.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@takahirom
I have tried the suggested method, but unfortunately the app crashes. 🙇
We still think that as long as NavHost is split into two, it is unfortunately difficult to achieve this functionality other than this current implementation. 🙇

},
onCalendarRegistrationClick = externalNavController::navigateToCalendarRegistration,
onShareClick = externalNavController::onShareClick,
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.github.droidkaigi.confsched2023.model

import kotlinx.coroutines.flow.Flow

interface NavigationRequester {
fun getNavigationRouteFlow(): Flow<String>
fun navigateTo(route: String)
fun navigated()
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
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
Expand Down Expand Up @@ -108,6 +109,7 @@ fun MainScreen(
navigationType = navigationType,
routeToTab = mainNestedGraphStateHolder::routeToTab,
onTabSelected = mainNestedGraphStateHolder::onTabSelected,
onNavigated = viewModel::onNavigated,
mainNestedNavGraph = mainNestedNavGraph,
)
}
Expand Down Expand Up @@ -152,6 +154,7 @@ enum class MainScreenTab(

data class MainScreenUiState(
val isAchievementsEnabled: Boolean = false,
val navigationRoute: String,
)

@Composable
Expand All @@ -161,11 +164,18 @@ private fun MainScreen(
navigationType: NavigationType,
routeToTab: String.() -> MainScreenTab?,
onTabSelected: (NavController, MainScreenTab) -> Unit,
onNavigated: () -> Unit,
mainNestedNavGraph: NavGraphBuilder.(NavController, PaddingValues) -> Unit,
) {
val mainNestedNavController = rememberNavController()
val navBackStackEntry by mainNestedNavController.currentBackStackEntryAsState()
val currentTab = navBackStackEntry?.destination?.route?.routeToTab()
LaunchedEffect(uiState.navigationRoute) {
if (uiState.navigationRoute.isNotBlank()) {
mainNestedNavController.navigate(uiState.navigationRoute)
onNavigated()
}
}
Row(modifier = Modifier.fillMaxSize()) {
AnimatedVisibility(visible = navigationType == NAVIGATION_RAIL) {
KaigiNavigationRail(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import io.github.droidkaigi.confsched2023.data.contributors.AchievementRepository
import io.github.droidkaigi.confsched2023.designsystem.strings.AppStrings
import io.github.droidkaigi.confsched2023.model.NavigationRequester
import io.github.droidkaigi.confsched2023.ui.UserMessageStateHolder
import io.github.droidkaigi.confsched2023.ui.buildUiState
import io.github.droidkaigi.confsched2023.ui.handleErrorAndRetry
Expand All @@ -16,6 +17,7 @@ import javax.inject.Inject
@HiltViewModel
class MainScreenViewModel @Inject constructor(
val userMessageStateHolder: UserMessageStateHolder,
private val navigationRequester: NavigationRequester,
achievementRepository: AchievementRepository,
) : ViewModel(),
UserMessageStateHolder by userMessageStateHolder {
Expand All @@ -30,11 +32,24 @@ class MainScreenViewModel @Inject constructor(
initialValue = false,
)

private val navigationRouteStateFlow: StateFlow<String> = navigationRequester.getNavigationRouteFlow()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = "",
)

val uiState: StateFlow<MainScreenUiState> = buildUiState(
isAchievementsEnabledStateFlow,
) { isAchievementsEnabled ->
navigationRouteStateFlow,
) { isAchievementsEnabled, navigationRoute ->
MainScreenUiState(
isAchievementsEnabled = isAchievementsEnabled,
navigationRoute = navigationRoute,
)
}

fun onNavigated() {
navigationRequester.navigated()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@ fun NavGraphBuilder.sessionScreens(
onTimetableItemClick: (TimetableItem) -> Unit,
onNavigateToBookmarkScreenRequested: () -> Unit,
onLinkClick: (url: String) -> Unit,
onRoomClick: () -> Unit,
onCalendarRegistrationClick: (TimetableItem) -> Unit,
onShareClick: (TimetableItem) -> Unit,
) {
composable(timetableItemDetailScreenRoute) {
TimetableItemDetailScreen(
onNavigationIconClick = onNavigationIconClick,
onLinkClick = onLinkClick,
onRoomClick = onRoomClick,
onCalendarRegistrationClick = onCalendarRegistrationClick,
onNavigateToBookmarkScreenRequested = onNavigateToBookmarkScreenRequested,
onShareClick = onShareClick,
Expand Down Expand Up @@ -84,6 +86,7 @@ fun NavController.navigateToTimetableItemDetailScreen(
fun TimetableItemDetailScreen(
onNavigationIconClick: () -> Unit,
onLinkClick: (url: String) -> Unit,
onRoomClick: () -> Unit,
onCalendarRegistrationClick: (TimetableItem) -> Unit,
onNavigateToBookmarkScreenRequested: () -> Unit,
onShareClick: (TimetableItem) -> Unit,
Expand All @@ -109,6 +112,10 @@ fun TimetableItemDetailScreen(
onNavigationIconClick = onNavigationIconClick,
onBookmarkClick = viewModel::onBookmarkClick,
onLinkClick = onLinkClick,
onRoomClick = {
viewModel.navigateTo("floorMap")
Copy link
Contributor Author

@Corvus400 Corvus400 Sep 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to change this part if possible since it is directly specified.
It would be helpful if FloorMapScreenRoute could be referenced in this case.

onRoomClick()
},
onCalendarRegistrationClick = onCalendarRegistrationClick,
onShareClick = onShareClick,
onSelectedLanguage = viewModel::onSelectDescriptionLanguage,
Expand Down Expand Up @@ -145,6 +152,7 @@ private fun TimetableItemDetailScreen(
onLinkClick: (url: String) -> Unit,
onCalendarRegistrationClick: (TimetableItem) -> Unit,
onShareClick: (TimetableItem) -> Unit,
onRoomClick: () -> Unit,
onSelectedLanguage: (Lang) -> Unit,
snackbarHostState: SnackbarHostState,
) {
Expand Down Expand Up @@ -194,6 +202,7 @@ private fun TimetableItemDetailScreen(
uiState = it.timetableItemDetailSectionUiState,
selectedLanguage = it.currentLang,
onLinkClick = onLinkClick,
onRoomClick = onRoomClick,
contentPadding = innerPadding,
)
}
Expand All @@ -214,7 +223,9 @@ fun TimetableItemDetailScreenPreview() {
TimetableItemDetailScreen(
uiState = Loaded(
timetableItem = fakeSession,
timetableItemDetailSectionUiState = TimetableItemDetailSectionUiState(fakeSession),
timetableItemDetailSectionUiState = TimetableItemDetailSectionUiState(
fakeSession,
),
isBookmarked = isBookMarked,
isLangSelectable = true,
viewBookmarkListRequestState = ViewBookmarkListRequestState.NotRequested,
Expand All @@ -225,6 +236,7 @@ fun TimetableItemDetailScreenPreview() {
isBookMarked = !isBookMarked
},
onLinkClick = {},
onRoomClick = {},
onCalendarRegistrationClick = {},
onShareClick = {},
onSelectedLanguage = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import io.github.droidkaigi.confsched2023.designsystem.strings.AppStrings
import io.github.droidkaigi.confsched2023.model.Lang
import io.github.droidkaigi.confsched2023.model.NavigationRequester
import io.github.droidkaigi.confsched2023.model.SessionsRepository
import io.github.droidkaigi.confsched2023.model.TimetableItem
import io.github.droidkaigi.confsched2023.model.TimetableItemId
Expand All @@ -29,6 +30,7 @@ import javax.inject.Inject
@HiltViewModel
class TimetableItemDetailViewModel @Inject constructor(
private val sessionsRepository: SessionsRepository,
private val navigationRequester: NavigationRequester,
val userMessageStateHolder: UserMessageStateHolder,
savedStateHandle: SavedStateHandle,
) : ViewModel(),
Expand Down Expand Up @@ -108,4 +110,10 @@ class TimetableItemDetailViewModel @Inject constructor(
) {
selectedDescriptionLanguageStateFlow.value = language
}

fun navigateTo(
route: String,
) {
navigationRequester.navigateTo(route)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import java.util.Locale
@Composable
fun TimetableItemDetailSummaryCard(
timetableItem: TimetableItem,
onRoomClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(modifier = modifier) {
Expand Down Expand Up @@ -88,6 +89,7 @@ fun TimetableItemDetailSummaryCard(
leadingIcon = Icons.Outlined.Place,
label = SessionsStrings.Place.asString(),
content = timetableItem.room.nameAndFloor,
onContentClick = onRoomClick,
)
TimetableItemDetailSummaryCardRow(
leadingIcon = Icons.Outlined.Language,
Expand All @@ -110,7 +112,10 @@ fun TimetableItemDetailSummaryCard(
fun TimetableItemDetailSummaryPreview() {
KaigiTheme {
Surface {
TimetableItemDetailSummaryCard(timetableItem = Session.fake())
TimetableItemDetailSummaryCard(
timetableItem = Session.fake(),
onRoomClick = {},
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import io.github.droidkaigi.confsched2023.designsystem.component.ClickableLinkText
import io.github.droidkaigi.confsched2023.designsystem.preview.MultiLanguagePreviews
import io.github.droidkaigi.confsched2023.designsystem.preview.MultiThemePreviews
import io.github.droidkaigi.confsched2023.designsystem.theme.KaigiTheme
import io.github.droidkaigi.confsched2023.model.TimetableItem.Session
import io.github.droidkaigi.confsched2023.model.fake
import io.github.droidkaigi.confsched2023.model.nameAndFloor
import io.github.droidkaigi.confsched2023.sessions.SessionsStrings

@Composable
Expand All @@ -28,6 +32,7 @@ fun TimetableItemDetailSummaryCardRow(
content: String,
modifier: Modifier = Modifier,
leadingIconContentDescription: String? = null,
onContentClick: (() -> Unit)? = null,
) {
Row(
verticalAlignment = Alignment.CenterVertically,
Expand All @@ -46,7 +51,16 @@ fun TimetableItemDetailSummaryCardRow(
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
Spacer(modifier = Modifier.width(12.dp))
Text(text = content, style = MaterialTheme.typography.bodyMedium)
if (onContentClick == null) {
Text(text = content, style = MaterialTheme.typography.bodyMedium)
} else {
ClickableLinkText(
style = MaterialTheme.typography.bodyMedium,
content = content,
onLinkClick = { _ -> onContentClick() },
regex = ".*".toRegex(),
)
}
}
}

Expand All @@ -64,3 +78,18 @@ fun TimetableItemDetailSummaryCardRowPreview() {
}
}
}

@MultiThemePreviews
@Composable
fun TimetableItemDetailSummaryCardRowRoomPreview() {
KaigiTheme {
Surface {
TimetableItemDetailSummaryCardRow(
leadingIcon = Icons.Outlined.Schedule,
label = SessionsStrings.Place.asString(),
content = Session.fake().room.nameAndFloor,
onContentClick = {},
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ internal fun TimetableItemDetail(
contentPadding: PaddingValues,
selectedLanguage: Lang?,
onLinkClick: (String) -> Unit,
onRoomClick: () -> Unit,
modifier: Modifier = Modifier,
) {
LazyColumn(
Expand All @@ -31,6 +32,7 @@ internal fun TimetableItemDetail(
TimetableItemDetailSummaryCard(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 20.dp),
timetableItem = uiState.timetableItem,
onRoomClick = onRoomClick,
)
}

Expand Down
Loading