diff --git a/theme-m3/speakers/speakers-feature/build.gradle.kts b/theme-m3/speakers/speakers-feature/build.gradle.kts index 42eb6c4db..905528335 100644 --- a/theme-m3/speakers/speakers-feature/build.gradle.kts +++ b/theme-m3/speakers/speakers-feature/build.gradle.kts @@ -13,6 +13,7 @@ dependencies { implementation(projects.themeM3.schedules.schedulesUi) implementation(projects.themeM3.speakers.speakersUi) implementation(projects.themeM3.navigation) + implementation(projects.themeM3.style.schedules) implementation(projects.themeM3.style.speakers) implementation(projects.themeM3.style.theme) diff --git a/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailHorizontal.kt b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailHorizontal.kt new file mode 100644 index 000000000..844e80679 --- /dev/null +++ b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailHorizontal.kt @@ -0,0 +1,93 @@ +package org.gdglille.devfest.android.theme.m3.speakers.feature + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.GridItemSpan +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.lazy.grid.items +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.gdglille.devfest.android.theme.m3.schedules.ui.talks.SmallScheduleItem +import org.gdglille.devfest.android.theme.m3.speakers.ui.SpeakerDetailSectionHorizontal +import org.gdglille.devfest.android.theme.m3.style.Conferences4HallTheme +import org.gdglille.devfest.android.theme.m3.style.R +import org.gdglille.devfest.android.theme.m3.style.appbars.TopAppBar +import org.gdglille.devfest.android.theme.m3.style.placeholder +import org.gdglille.devfest.android.theme.m3.style.previews.PHONE_LANDSCAPE +import org.gdglille.devfest.models.ui.SpeakerUi +import org.gdglille.devfest.models.ui.TalkItemUi + +@ExperimentalMaterial3Api +@Composable +fun SpeakerDetailHorizontal( + speaker: SpeakerUi, + onTalkClicked: (id: String) -> Unit, + onFavoriteClicked: (TalkItemUi) -> Unit, + onLinkClicked: (url: String) -> Unit, + onBackClicked: () -> Unit, + modifier: Modifier = Modifier, + isLoading: Boolean = false +) { + Scaffold( + modifier = modifier, + topBar = { + TopAppBar( + title = stringResource(id = R.string.screen_speaker_detail), + navigationIcon = { Back(onClick = onBackClicked) } + ) + }, + content = { + LazyVerticalGrid( + columns = GridCells.Fixed(count = 2), + modifier = Modifier.padding(it), + contentPadding = PaddingValues(vertical = 24.dp, horizontal = 16.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + item(span = { GridItemSpan(2) }) { + SpeakerDetailSectionHorizontal( + speaker = speaker, + isLoading = isLoading, + onLinkClicked = onLinkClicked + ) + } + item(span = { GridItemSpan(2) }) { + Spacer(modifier = Modifier.height(24.dp)) + } + items(speaker.talks) { + SmallScheduleItem( + talk = it, + modifier = Modifier + .placeholder(visible = isLoading), + onFavoriteClicked = onFavoriteClicked, + onTalkClicked = onTalkClicked + ) + Spacer(modifier = Modifier.height(8.dp)) + } + } + } + ) +} + +@ExperimentalMaterial3Api +@Preview(device = PHONE_LANDSCAPE) +@Composable +private fun SpeakerDetailPreview() { + Conferences4HallTheme { + SpeakerDetailHorizontal( + speaker = SpeakerUi.fake, + onTalkClicked = {}, + onFavoriteClicked = {}, + onLinkClicked = {}, + onBackClicked = {} + ) + } +} diff --git a/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailOrientable.kt b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailOrientable.kt new file mode 100644 index 000000000..a6a1d39a4 --- /dev/null +++ b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailOrientable.kt @@ -0,0 +1,44 @@ +package org.gdglille.devfest.android.theme.m3.speakers.feature + +import android.content.res.Configuration +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalConfiguration +import org.gdglille.devfest.models.ui.SpeakerUi +import org.gdglille.devfest.models.ui.TalkItemUi + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SpeakerDetailOrientable( + speaker: SpeakerUi, + onTalkClicked: (id: String) -> Unit, + onFavoriteClicked: (TalkItemUi) -> Unit, + onLinkClicked: (url: String) -> Unit, + onBackClicked: () -> Unit, + modifier: Modifier = Modifier, + isLoading: Boolean = false +) { + val orientation = LocalConfiguration.current + if (orientation.orientation == Configuration.ORIENTATION_LANDSCAPE) { + SpeakerDetailHorizontal( + speaker = speaker, + modifier = modifier, + onTalkClicked = onTalkClicked, + onFavoriteClicked = onFavoriteClicked, + onLinkClicked = onLinkClicked, + onBackClicked = onBackClicked, + isLoading = isLoading + ) + } else { + SpeakerDetailVertical( + speaker = speaker, + modifier = modifier, + onTalkClicked = onTalkClicked, + onFavoriteClicked = onFavoriteClicked, + onLinkClicked = onLinkClicked, + onBackClicked = onBackClicked, + isLoading = isLoading + ) + } +} diff --git a/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailVM.kt b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailVM.kt index 190e17919..1a414082e 100644 --- a/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailVM.kt +++ b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailVM.kt @@ -1,6 +1,5 @@ package org.gdglille.devfest.android.theme.m3.speakers.feature -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState @@ -12,7 +11,6 @@ import org.gdglille.devfest.AlarmScheduler import org.gdglille.devfest.android.theme.m3.style.R import org.gdglille.devfest.repositories.AgendaRepository -@OptIn(ExperimentalMaterial3Api::class) @Composable fun SpeakerDetailVM( speakerId: String, @@ -29,7 +27,7 @@ fun SpeakerDetailVM( val context = LocalContext.current val uiState = viewModel.uiState.collectAsState() when (uiState.value) { - is SpeakerUiState.Loading -> SpeakerDetail( + is SpeakerUiState.Loading -> SpeakerDetailOrientable( speaker = (uiState.value as SpeakerUiState.Loading).speaker, modifier = modifier, onTalkClicked = {}, @@ -39,7 +37,7 @@ fun SpeakerDetailVM( ) is SpeakerUiState.Failure -> Text(text = stringResource(id = R.string.text_error)) - is SpeakerUiState.Success -> SpeakerDetail( + is SpeakerUiState.Success -> SpeakerDetailOrientable( speaker = (uiState.value as SpeakerUiState.Success).speaker, modifier = modifier, onTalkClicked = onTalkClicked, diff --git a/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetail.kt b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailVertical.kt similarity index 85% rename from theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetail.kt rename to theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailVertical.kt index 3b91d38fb..cd959032d 100644 --- a/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetail.kt +++ b/theme-m3/speakers/speakers-feature/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/feature/SpeakerDetailVertical.kt @@ -1,6 +1,6 @@ package org.gdglille.devfest.android.theme.m3.speakers.feature -import android.annotation.SuppressLint +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -11,21 +11,20 @@ import androidx.compose.material3.Scaffold import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import org.gdglille.devfest.android.theme.m3.schedules.ui.talks.MediumScheduleItem import org.gdglille.devfest.android.theme.m3.speakers.ui.SpeakerDetailSectionVertical import org.gdglille.devfest.android.theme.m3.style.Conferences4HallTheme +import org.gdglille.devfest.android.theme.m3.style.R import org.gdglille.devfest.android.theme.m3.style.appbars.TopAppBar import org.gdglille.devfest.android.theme.m3.style.placeholder -import org.gdglille.devfest.android.theme.m3.style.R +import org.gdglille.devfest.android.theme.m3.style.previews.ThemedPreviews import org.gdglille.devfest.models.ui.SpeakerUi import org.gdglille.devfest.models.ui.TalkItemUi @ExperimentalMaterial3Api -@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @Composable -fun SpeakerDetail( +fun SpeakerDetailVertical( speaker: SpeakerUi, onTalkClicked: (id: String) -> Unit, onFavoriteClicked: (TalkItemUi) -> Unit, @@ -43,7 +42,10 @@ fun SpeakerDetail( ) }, content = { - LazyColumn(contentPadding = it) { + LazyColumn( + contentPadding = PaddingValues(vertical = 24.dp, horizontal = 16.dp), + modifier = Modifier.padding(it) + ) { item { SpeakerDetailSectionVertical( speaker = speaker, @@ -58,7 +60,6 @@ fun SpeakerDetail( MediumScheduleItem( talk = it, modifier = Modifier - .padding(horizontal = 16.dp) .placeholder(visible = isLoading), onFavoriteClicked = onFavoriteClicked, onTalkClicked = onTalkClicked @@ -70,12 +71,13 @@ fun SpeakerDetail( ) } +@Suppress("UnusedPrivateMember") @ExperimentalMaterial3Api -@Preview +@ThemedPreviews @Composable -private fun SpeakerListPreview() { +private fun SpeakerDetailPreview() { Conferences4HallTheme { - SpeakerDetail( + SpeakerDetailVertical( speaker = SpeakerUi.fake, onTalkClicked = {}, onFavoriteClicked = {}, diff --git a/theme-m3/speakers/speakers-ui/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/ui/SpeakerDetailSection.kt b/theme-m3/speakers/speakers-ui/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/ui/SpeakerDetailSection.kt index 3cbfe0735..abe33394d 100644 --- a/theme-m3/speakers/speakers-ui/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/ui/SpeakerDetailSection.kt +++ b/theme-m3/speakers/speakers-ui/src/main/kotlin/org/gdglille/devfest/android/theme/m3/speakers/ui/SpeakerDetailSection.kt @@ -31,9 +31,7 @@ fun SpeakerDetailSectionVertical( modifier = modifier .fillMaxWidth() .background(MaterialTheme.colorScheme.surface) - .padding(horizontal = 16.dp) ) { - Spacer(modifier = Modifier.height(24.dp)) MediumSpeakerAvatar( url = speaker.url, contentDescription = null, @@ -53,8 +51,10 @@ fun SpeakerDetailSectionVertical( onLinkClicked = onLinkClicked ) Spacer(modifier = Modifier.height(8.dp)) - MarkdownText(text = speaker.bio) - Spacer(modifier = Modifier.height(24.dp)) + MarkdownText( + text = speaker.bio, + modifier = Modifier.placeholder(visible = isLoading) + ) } } @@ -68,8 +68,7 @@ fun SpeakerDetailSectionHorizontal( Column( modifier = modifier .fillMaxWidth() - .background(MaterialTheme.colorScheme.surface) - .padding(vertical = 24.dp, horizontal = 16.dp), + .background(MaterialTheme.colorScheme.surface), verticalArrangement = Arrangement.spacedBy(8.dp) ) { Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) { @@ -91,10 +90,14 @@ fun SpeakerDetailSectionHorizontal( onLinkClicked = onLinkClicked ) } - MarkdownText(text = speaker.bio) + MarkdownText( + text = speaker.bio, + modifier = Modifier.placeholder(visible = isLoading) + ) } } +@Suppress("UnusedPrivateMember") @ThemedPreviews @Composable private fun SpeakerDetailSectionVerticalPreview() { @@ -106,6 +109,7 @@ private fun SpeakerDetailSectionVerticalPreview() { } } +@Suppress("UnusedPrivateMember") @ThemedPreviews @Composable private fun SpeakerDetailSectionHorizontalPreview() {