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

Wear app: Add session detail screen #232

Merged
merged 1 commit into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package fr.paug.androidmakers.wear.di

import fr.paug.androidmakers.wear.ui.main.MainViewModel
import fr.paug.androidmakers.wear.ui.session.details.SessionDetailViewModel
import fr.paug.androidmakers.wear.ui.settings.SettingsViewModel
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module

val androidViewModelModule = module {
viewModel { MainViewModel(get(), get(), get(), get(), get(), get()) }
viewModel { SettingsViewModel(get(), get()) }
viewModel { SessionDetailViewModel(get(), get(), get(), get(), get(), get()) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package fr.paug.androidmakers.wear.ui.common

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.wear.compose.material.CircularProgressIndicator

@Composable
fun Loading() {
Box(
modifier = Modifier
.fillMaxSize(),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,47 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.core.app.ActivityCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.navigation.NavType
import androidx.navigation.navArgument
import androidx.wear.compose.foundation.SwipeToDismissBoxState
import androidx.wear.compose.foundation.SwipeToDismissValue
import androidx.wear.compose.foundation.edgeSwipeToDismiss
import androidx.wear.compose.foundation.rememberSwipeToDismissBoxState
import androidx.wear.compose.navigation.SwipeDismissableNavHost
import androidx.wear.compose.navigation.composable
import androidx.wear.compose.navigation.currentBackStackEntryAsState
import androidx.wear.compose.navigation.rememberSwipeDismissableNavController
import androidx.wear.compose.navigation.rememberSwipeDismissableNavHostState
import com.google.android.horologist.compose.layout.AppScaffold
import com.google.android.horologist.compose.pager.PagerScreen
import fr.androidmakers.domain.model.User
import fr.paug.androidmakers.wear.R
import fr.paug.androidmakers.wear.ui.session.UISession
import fr.paug.androidmakers.wear.ui.session.details.SessionDetailScreen
import fr.paug.androidmakers.wear.ui.session.details.SessionDetailViewModel
import fr.paug.androidmakers.wear.ui.session.list.SessionListScreen
import fr.paug.androidmakers.wear.ui.settings.SettingsScreen
import fr.paug.androidmakers.wear.ui.signin.SignInScreen
import fr.paug.androidmakers.wear.ui.theme.AndroidMakersWearTheme
import org.koin.androidx.compose.koinViewModel
import org.koin.core.parameter.parametersOf

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
installSplashScreen()
WearApp()
WearApp(onSwipeToDismissRootLevel = { ActivityCompat.finishAffinity(this) })
setTheme(android.R.style.Theme_DeviceDefault)
}
}
Expand All @@ -43,39 +56,69 @@ class MainActivity : ComponentActivity() {
@Composable
fun WearApp(
viewModel: MainViewModel = koinViewModel(),
onSwipeToDismissRootLevel: () -> Unit,
) {
val navController = rememberSwipeDismissableNavController()
val swipeToDismissBoxState = rememberSwipeToDismissBoxState()
val swipeDismissableNavHostState = rememberSwipeDismissableNavHostState(swipeToDismissBoxState)

// Workaround so swipe to dismiss works on the root level
// See https://slack-chats.kotlinlang.org/t/16230979/problem-changing-basicswipetodismiss-background-color-gt
var currentRoute by remember { mutableStateOf("") }
LaunchedEffect(swipeToDismissBoxState.currentValue) {
if (swipeToDismissBoxState.currentValue == SwipeToDismissValue.Dismissed) {
if (currentRoute == Navigation.main) {
onSwipeToDismissRootLevel()
}
}
}

val onSignInClick: () -> Unit = {
navController.navigate(Navigation.SIGN_IN)
navController.navigate(Navigation.signIn)
}
val onSignInDismissOrTimeout: () -> Unit = {
navController.popBackStack()
}

navController.currentBackStackEntryAsState().value?.let { backStackEntry ->
currentRoute = backStackEntry.destination.route ?: ""
}

val onSignInSuccess = viewModel::onSignInSuccess
AndroidMakersWearTheme {
AppScaffold {
val swipeToDismissBoxState = rememberSwipeToDismissBoxState()
val swipeDismissableNavHostState =
rememberSwipeDismissableNavHostState(swipeToDismissBoxState)
SwipeDismissableNavHost(
navController = navController,
startDestination = Navigation.MAIN,
startDestination = Navigation.main,
state = swipeDismissableNavHostState,
) {
composable(Navigation.MAIN) {
composable(Navigation.main) {
MainScreen(
viewModel = viewModel,
swipeToDismissBoxState = swipeToDismissBoxState,
onSignInClick = onSignInClick,
onSignOutClick = { viewModel.signOut() },
swipeToDismissBoxState = swipeToDismissBoxState,
viewModel = viewModel,
onSessionClick = { sessionId ->
navController.navigate(Navigation.sessionDetail(sessionId))
}
)
}
composable(Navigation.SIGN_IN) {
composable(Navigation.signIn) {
SignInScreen(
onSignInSuccess = onSignInSuccess,
onDismissOrTimeout = onSignInDismissOrTimeout
)
}
composable(
Navigation.sessionDetail,
arguments = listOf(navArgument(Navigation.id) { type = NavType.StringType })
) {
val sessionId = it.arguments!!.getString(Navigation.id)!!
val sessionDetailViewModel: SessionDetailViewModel =
koinViewModel { parametersOf(sessionId) }

SessionDetailScreen(sessionDetailViewModel)
}
}
}
}
Expand All @@ -87,6 +130,7 @@ fun MainScreen(
swipeToDismissBoxState: SwipeToDismissBoxState,
onSignInClick: () -> Unit,
onSignOutClick: () -> Unit,
onSessionClick: (String) -> Unit,
) {
val pagerState: PagerState =
rememberPagerState(initialPage = viewModel.getConferenceDay() + 1, pageCount = { 3 })
Expand All @@ -110,11 +154,19 @@ fun MainScreen(
}

1 -> {
SessionListScreen(sessions = sessionsDay1, title = stringResource(id = R.string.main_day1))
SessionListScreen(
sessions = sessionsDay1,
title = stringResource(id = R.string.main_day1),
onSessionClick = onSessionClick
)
}

2 -> {
SessionListScreen(sessions = sessionsDay2, title = stringResource(id = R.string.main_day2))
SessionListScreen(
sessions = sessionsDay2,
title = stringResource(id = R.string.main_day2),
onSessionClick = onSessionClick
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import fr.androidmakers.domain.repo.UserRepository
import fr.paug.androidmakers.wear.R
import fr.paug.androidmakers.wear.applicationContext
import fr.paug.androidmakers.wear.data.LocalPreferencesRepository
import fr.paug.androidmakers.wear.ui.session.UISession
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package fr.paug.androidmakers.wear.ui.main

object Navigation {
const val MAIN = "MAIN"
const val SIGN_IN = "SIGN_IN"
const val main = "main"

const val signIn = "signIn"

const val id = "id"
const val sessionDetail = "sessionDetail/{$id}"
fun sessionDetail(id: String): String {
return "sessionDetail/$id"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package fr.paug.androidmakers.wear.ui.session

import fr.androidmakers.domain.model.Room
import fr.androidmakers.domain.model.Session
import fr.androidmakers.domain.model.Speaker
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.Month

val uiSession1 = UISession(
session = Session(
id = "1",
title = "Android Graphics: the Path to [UI] Riches",
description = "Android's graphics APIs are extensive and powerful... but maybe a little complicated. This session will show ways to use the graphics APIs to achieve cool effects and improve the visual quality and richness of your applications.",
roomId = "",
speakers = emptyList(),
startsAt = LocalDateTime(2023, Month.APRIL, 27, 9, 15),
endsAt = LocalDateTime(2023, Month.APRIL, 27, 10, 0),
isServiceSession = false,
),
speakers = listOf(
Speaker(
id = "1",
name = "Speaker 1",
bio = "Bio 1",
),
Speaker(
id = "2",
name = "Speaker 2",
bio = "Bio 2",
)
),
room = Room(
id = "1",
name = "Room 1"
),
isBookmarked = true,
)

val uiSession2 = UISession(
session = Session(
id = "2",
title = "Using Compose Runtime to create a client library",
description = "Jetpack Compose (UI) is a powerful UI toolkit for Android. Have you ever wondered where this power comes from? The answer is Compose Runtime. \r\n\r\nIn this talk, we will see how we can use Compose Runtime to create client libraries. Firstly, we will talk about Compose nodes, Composition, Recomposer, and how they are orchestrated to create a slot table. Then, we will see how the changes in the slot table are applied with an Applier. Moreover, we will touch upon the Snapshot system and how the changes in the state objects trigger a recomposition. Finally, we will create a basic UI toolkit for PowerPoint using Compose Runtime.",
roomId = "",
speakers = emptyList(),
startsAt = LocalDateTime(2023, Month.APRIL, 27, 10, 15),
endsAt = LocalDateTime(2023, Month.APRIL, 27, 11, 0),
isServiceSession = false,
),
speakers = listOf(
Speaker(
id = "3",
name = "Speaker 3",
bio = "Bio 3",
),
),
room = Room(
id = "2",
name = "Room 2"
),
isBookmarked = false,
)

val uiSessions = listOf(
uiSession1,
uiSession2,
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package fr.paug.androidmakers.wear.ui.main
package fr.paug.androidmakers.wear.ui.session

import fr.androidmakers.domain.model.Room
import fr.androidmakers.domain.model.Session
Expand Down
Loading
Loading