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

♻️ Add a translate button to the session details screen. #981

Merged
Merged
Show file tree
Hide file tree
Changes from 6 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
4 changes: 2 additions & 2 deletions app-ios/Modules/Sources/Session/SessionView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ public struct SessionView: View {

if let session = viewModel.timetableItem as? TimetableItem.Session {
VStack(alignment: .leading, spacing: 16) {
Text(session.description_)
Text(session.description_.currentLangTitle)
.textSelection(.enabled)
.lineLimit(isDescriptionExpanded ? nil : 5)
.background {
ViewThatFits(in: .vertical) {
Text(session.description_)
Text(session.description_.currentLangTitle)
.hidden()
// Just for receiving onAppear event if the description exceeds its line limit
Color.clear
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,17 @@ internal fun SessionsAllResponse.toTimetable(): Timetable {
isInterpretationTarget = apiSession.interpretationTarget,
),
asset = apiSession.asset.toTimetableAsset(),
description = apiSession.description ?: "",
description = if (
apiSession.i18nDesc?.ja == null &&
apiSession.i18nDesc?.en == null
) {
MultiLangText(
jaTitle = apiSession.description ?: "",
enTitle = apiSession.description ?: "",
)
} else {
apiSession.i18nDesc.toMultiLangText()
},
speakers = apiSession.speakers
.map { speakerIdToSpeaker[it]!! }
.toPersistentList(),
Expand Down Expand Up @@ -145,10 +155,12 @@ internal fun SessionsAllResponse.toTimetable(): Timetable {
)
}

private fun LocaledResponse.toMultiLangText() = MultiLangText(jaTitle = ja, enTitle = en)
private fun LocaledResponse.toMultiLangText() =
MultiLangText(jaTitle = ja ?: "", enTitle = en ?: "")

private fun SessionMessageResponse.toMultiLangText() = MultiLangText(jaTitle = ja, enTitle = en)
private fun SessionAssetResponse.toTimetableAsset() = TimetableAsset(videoUrl, slideUrl)
private fun LocaledResponse.toRoomType() = when (en.lowercase()) {
private fun LocaledResponse.toRoomType() = when (en?.lowercase()) {
"arctic fox" -> RoomA
"bumblebee" -> RoomB
"chipmunk" -> RoomC
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,14 @@ fun SessionsAllResponse.Companion.fake(): SessionsAllResponse {
en = "DroidKaigi App Architecture day$day room${room.name.en} index$index",
),
speakers = listOf("1", "2"),
description = "これはディスクリプションです。\nこれはディスクリプションです。\nこれはディスクリプションです。\n" +
"これはディスクリプションです。\nこれはディスクリプションです。\nこれはディスクリプションです。\n",
description = "\"これはディスクリプションです。\\nこれはディスクリプションです。\\nこれはディスクリプションです。\\n\" +\n" +
Copy link
Member

Choose a reason for hiding this comment

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

image There may be a little mistake 😄

"\"これはディスクリプションです。\\nこれはディスクリプションです。\\nこれはディスクリプションです。\\n\",",
i18nDesc = LocaledResponse(
ja = "\"これはディスクリプションです。\\nこれはディスクリプションです。\\nこれはディスクリプションです。\\n\" +\n" +
Copy link
Member

@takahirom takahirom Aug 29, 2023

Choose a reason for hiding this comment

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

I think \\n should be \n 👀
You can work on this another PR!

"\"これはディスクリプションです。\\nこれはディスクリプションです。\\nこれはディスクリプションです。\\n\",",
en = "\"This is a description\\nThis is a description\\nThis is a description\\n\" +\n" +
"\"This is a description\\nThis is a description\\nThis is a description\\n\",",
),
startsAt = start.toString(),
endsAt = end.toString(),
language = "JAPANESE",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ import kotlinx.serialization.Serializable

@Serializable
data class LocaledResponse(
val ja: String,
val en: String,
val ja: String?,
val en: String?,
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ data class SessionResponse(
val isServiceSession: Boolean,
val title: LocaledResponse,
val speakers: List<String>,
val description: String?,
val description: String? = null,
val i18nDesc: LocaledResponse? = null,
val startsAt: String,
val endsAt: String,
val language: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public sealed class TimetableItem {
override val asset: TimetableAsset,
override val levels: PersistentList<String>,
override val speakers: PersistentList<TimetableSpeaker>,
val description: String,
val description: MultiLangText,
val message: MultiLangText?,
) : TimetableItem() {
public companion object
Expand Down Expand Up @@ -154,7 +154,10 @@ public fun Session.Companion.fake(): Session {
tagLine = "iOS Engineer",
),
).toPersistentList(),
description = "これはディスクリプションです。\nこれはディスクリプションです。\nhttps://github.com/DroidKaigi/conference-app-2023 これはURLです。\nこれはディスクリプションです。",
description = MultiLangText(
jaTitle = "これはディスクリプションです。\nこれはディスクリプションです。\nhttps://github.com/DroidKaigi/conference-app-2023 これはURLです。\nこれはディスクリプションです。",
enTitle = "This is a description.\nThis is a description.\nhttps://github.com/DroidKaigi/conference-app-2023 This is a URL.\nThis is a description.",
),
message = MultiLangText(
jaTitle = "このセッションは事情により中止となりました",
enTitle = "This session has been cancelled due to circumstances.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import io.github.droidkaigi.confsched2023.designsystem.component.LoadingText
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.Lang
import io.github.droidkaigi.confsched2023.model.TimetableItem
import io.github.droidkaigi.confsched2023.model.TimetableItem.Session
import io.github.droidkaigi.confsched2023.model.fake
Expand Down Expand Up @@ -105,6 +106,7 @@ fun TimetableItemDetailScreen(
onBookmarkClick = viewModel::onBookmarkClick,
onLinkClick = onLinkClick,
onCalendarRegistrationClick = onCalendarRegistrationClick,
onSelectedLanguage = viewModel::onSelectDescriptionLanguage,
snackbarHostState = snackbarHostState,
)
}
Expand All @@ -116,6 +118,7 @@ sealed class TimetableItemDetailScreenUiState {
val timetableItemDetailSectionUiState: TimetableItemDetailSectionUiState,
val isBookmarked: Boolean,
val viewBookmarkListRequestState: ViewBookmarkListRequestState,
val currentLang: Lang,
) : TimetableItemDetailScreenUiState()

val shouldNavigateToBookmarkList: Boolean
Expand All @@ -135,6 +138,7 @@ private fun TimetableItemDetailScreen(
onBookmarkClick: (TimetableItem) -> Unit,
onLinkClick: (url: String) -> Unit,
onCalendarRegistrationClick: (TimetableItem) -> Unit,
onSelectedLanguage: (Lang) -> Unit,
snackbarHostState: SnackbarHostState,
) {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Expand All @@ -145,6 +149,7 @@ private fun TimetableItemDetailScreen(
TimetableItemDetailScreenTopAppBar(
title = uiState.timetableItem.title,
onNavigationIconClick = onNavigationIconClick,
onSelectedLanguage = onSelectedLanguage,
scrollBehavior = scrollBehavior,
)
}
Expand Down Expand Up @@ -177,6 +182,7 @@ private fun TimetableItemDetailScreen(
TimetableItemDetail(
modifier = Modifier.fillMaxSize(),
uiState = it.timetableItemDetailSectionUiState,
selectedLanguage = it.currentLang,
onLinkClick = onLinkClick,
contentPadding = innerPadding,
)
Expand All @@ -201,13 +207,15 @@ fun TimetableItemDetailScreenPreview() {
timetableItemDetailSectionUiState = TimetableItemDetailSectionUiState(fakeSession),
isBookmarked = isBookMarked,
viewBookmarkListRequestState = ViewBookmarkListRequestState.NotRequested,
currentLang = Lang.JAPANESE,
),
onNavigationIconClick = {},
onBookmarkClick = {
isBookMarked = !isBookMarked
},
onLinkClick = {},
onCalendarRegistrationClick = {},
onSelectedLanguage = {},
snackbarHostState = SnackbarHostState(),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import androidx.lifecycle.ViewModel
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.SessionsRepository
import io.github.droidkaigi.confsched2023.model.TimetableItem
import io.github.droidkaigi.confsched2023.model.TimetableItemId
import io.github.droidkaigi.confsched2023.model.defaultLang
import io.github.droidkaigi.confsched2023.sessions.section.TimetableItemDetailSectionUiState
import io.github.droidkaigi.confsched2023.sessions.strings.TimetableItemDetailStrings
import io.github.droidkaigi.confsched2023.ui.UserMessageResult
Expand Down Expand Up @@ -52,9 +54,14 @@ class TimetableItemDetailViewModel @Inject constructor(
)
private val viewBookmarkListRequestStateFlow =
MutableStateFlow<ViewBookmarkListRequestState>(ViewBookmarkListRequestState.NotRequested)
private val currentDescriptionLanguage = MutableStateFlow(defaultLang())
Copy link
Member

Choose a reason for hiding this comment

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

Initially, I was hoping that the session would be displayed in its original default language. The reason is that it would reflect what the speaker actually wrote. 👀
Maybe you can have userSelectedDescriptionLanguage = MutableStateFlow(null)


val uiState: StateFlow<TimetableItemDetailScreenUiState> =
buildUiState(timetableItemStateFlow, viewBookmarkListRequestStateFlow) { timetableItemAndBookmark, viewBookmarkListRequestState ->
buildUiState(
timetableItemStateFlow,
viewBookmarkListRequestStateFlow,
currentDescriptionLanguage,
) { timetableItemAndBookmark, viewBookmarkListRequestState, currentLang ->
if (timetableItemAndBookmark == null) {
return@buildUiState TimetableItemDetailScreenUiState.Loading
}
Expand All @@ -64,6 +71,7 @@ class TimetableItemDetailViewModel @Inject constructor(
timetableItemDetailSectionUiState = TimetableItemDetailSectionUiState(timetableItem),
isBookmarked = bookmarked,
viewBookmarkListRequestState = viewBookmarkListRequestState,
currentLang = currentLang,
)
}

Expand All @@ -89,4 +97,10 @@ class TimetableItemDetailViewModel @Inject constructor(
viewBookmarkListRequestStateFlow.update { ViewBookmarkListRequestState.NotRequested }
}
}

fun onSelectDescriptionLanguage(
language: Lang,
) {
currentDescriptionLanguage.value = language
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import io.github.droidkaigi.confsched2023.designsystem.preview.MultiLanguagePrev
import io.github.droidkaigi.confsched2023.designsystem.preview.MultiThemePreviews
import io.github.droidkaigi.confsched2023.designsystem.theme.KaigiTheme
import io.github.droidkaigi.confsched2023.designsystem.theme.md_theme_light_outline
import io.github.droidkaigi.confsched2023.model.Lang
import io.github.droidkaigi.confsched2023.model.TimetableItem
import io.github.droidkaigi.confsched2023.model.TimetableItem.Session
import io.github.droidkaigi.confsched2023.model.TimetableItem.Special
Expand All @@ -61,14 +62,20 @@ const val TimetableItemDetailReadMoreButtonTestTag = "TimetableItemDetailReadMor
@Composable
fun TimetableItemDetailContent(
uiState: TimetableItem,
selectedLanguage: Lang,
modifier: Modifier = Modifier,
onLinkClick: (url: String) -> Unit,
) {
Column(modifier = modifier) {
when (uiState) {
is Session -> {
val description = when (selectedLanguage) {
Lang.MIXED -> ""
Lang.JAPANESE -> uiState.description.jaTitle
Lang.ENGLISH -> uiState.description.enTitle
}
DescriptionSection(
description = uiState.description,
description = description,
onLinkClick = onLinkClick,
)
TargetAudienceSection(targetAudienceString = uiState.targetAudience)
Expand Down Expand Up @@ -336,7 +343,7 @@ fun DescriptionSectionPreview() {
KaigiTheme {
Surface {
DescriptionSection(
description = Session.fake().description,
description = Session.fake().description.currentLangTitle,
onLinkClick = {},
)
}
Expand All @@ -351,6 +358,7 @@ fun TimetableItemDetailContentPreview() {
Surface {
TimetableItemDetailContent(
uiState = Session.fake(),
selectedLanguage = Lang.JAPANESE,
onLinkClick = {},
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package io.github.droidkaigi.confsched2023.sessions.component
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.outlined.GTranslate
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
Expand All @@ -19,11 +22,14 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import io.github.droidkaigi.confsched2023.designsystem.preview.MultiLanguagePreviews
import io.github.droidkaigi.confsched2023.designsystem.preview.MultiThemePreviews
import io.github.droidkaigi.confsched2023.model.Lang
import io.github.droidkaigi.confsched2023.model.Lang.MIXED
import io.github.droidkaigi.confsched2023.model.MultiLangText
import io.github.droidkaigi.confsched2023.ui.handleOnClickIfNotNavigating
import kotlinx.collections.immutable.ImmutableList
Expand All @@ -34,6 +40,7 @@ import kotlinx.collections.immutable.persistentListOf
fun TimetableItemDetailScreenTopAppBar(
title: MultiLangText,
onNavigationIconClick: () -> Unit,
onSelectedLanguage: (Lang) -> Unit,
scrollBehavior: TopAppBarScrollBehavior,
modifier: Modifier = Modifier,
) {
Expand Down Expand Up @@ -77,6 +84,42 @@ fun TimetableItemDetailScreenTopAppBar(
)
}
},
actions = {
var expanded by remember { mutableStateOf(false) }

val expandMenu = { expanded = true }
val shrinkMenu = { expanded = false }

IconButton(onClick = expandMenu) {
Icon(
imageVector = Icons.Outlined.GTranslate,
contentDescription = null,
)
}
DropdownMenu(
expanded = expanded,
onDismissRequest = shrinkMenu,
) {
Lang.entries.forEach { lang ->
if (lang != MIXED) {
DropdownMenuItem(
text = {
Text(
text = lang.tagName,
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
},
onClick = {
onSelectedLanguage(lang)
shrinkMenu()
},
modifier = Modifier.testTag(DropdownFilterChipItemTestTag),
)
}
}
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant,
),
Expand Down Expand Up @@ -117,6 +160,7 @@ fun TimetableItemDetailScreenTopAppBarPreview() {
TimetableItemDetailScreenTopAppBar(
title = MultiLangText(jaTitle = "タイトル", enTitle = "title"),
onNavigationIconClick = {},
onSelectedLanguage = {},
scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import io.github.droidkaigi.confsched2023.model.Lang
import io.github.droidkaigi.confsched2023.model.TimetableItem
import io.github.droidkaigi.confsched2023.sessions.component.TimetableItemDetailContent
import io.github.droidkaigi.confsched2023.sessions.component.TimetableItemDetailSummaryCard
Expand All @@ -18,6 +19,7 @@ data class TimetableItemDetailSectionUiState(
internal fun TimetableItemDetail(
uiState: TimetableItemDetailSectionUiState,
contentPadding: PaddingValues,
selectedLanguage: Lang,
onLinkClick: (String) -> Unit,
modifier: Modifier = Modifier,
) {
Expand All @@ -35,6 +37,7 @@ internal fun TimetableItemDetail(
item {
TimetableItemDetailContent(
uiState = uiState.timetableItem,
selectedLanguage = selectedLanguage,
onLinkClick = onLinkClick,
)
}
Expand Down
Loading