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

feat(Android): add basic onboarding UX #592

Merged
merged 10 commits into from
Dec 17, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import com.mbta.tid.mbta_app.android.location.rememberLocationDataManager
import com.mbta.tid.mbta_app.android.pages.MorePage
import com.mbta.tid.mbta_app.android.pages.NearbyTransit
import com.mbta.tid.mbta_app.android.pages.NearbyTransitPage
import com.mbta.tid.mbta_app.android.pages.OnboardingPage
import com.mbta.tid.mbta_app.android.phoenix.PhoenixSocketWrapper
import com.mbta.tid.mbta_app.android.state.getGlobalData
import com.mbta.tid.mbta_app.android.state.getPendingOnboarding
import com.mbta.tid.mbta_app.android.state.subscribeToAlerts
import com.mbta.tid.mbta_app.model.response.AlertsStreamDataResponse
import com.mbta.tid.mbta_app.network.PhoenixSocket
Expand All @@ -40,6 +42,8 @@ fun ContentView(
val navController = rememberNavController()
var alertData: AlertsStreamDataResponse? = subscribeToAlerts()
val globalResponse = getGlobalData()
val pendingOnboarding = getPendingOnboarding()
var onboardingJustCompleted by remember { mutableStateOf(false) }
val locationDataManager = rememberLocationDataManager()
val mapViewportState = rememberMapViewportState {
setCameraOptions {
Expand All @@ -62,6 +66,16 @@ fun ContentView(
(socket as? PhoenixSocketWrapper)?.attachLogging()
onDispose { socket.detach() }
}

if (!pendingOnboarding.isNullOrEmpty() && !onboardingJustCompleted) {
OnboardingPage(
pendingOnboarding,
onFinish = { onboardingJustCompleted = true },
boringcactus marked this conversation as resolved.
Show resolved Hide resolved
locationDataManager = locationDataManager
)
return
}

val sheetModifier = Modifier.fillMaxSize().background(colorResource(id = R.color.fill1))
NavHost(navController = navController, startDestination = Routes.NearbyTransit) {
composable<Routes.NearbyTransit> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,13 @@ open class LocationDataManager {

@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun rememberPermissions() =
fun rememberPermissions(onPermissionsResult: (Map<String, Boolean>) -> Unit = {}) =
rememberMultiplePermissionsState(
listOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
),
onPermissionsResult
)

open val currentLocation = _currentLocation.asStateFlow()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.mbta.tid.mbta_app.android.onboarding

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.mbta.tid.mbta_app.android.R
import com.mbta.tid.mbta_app.android.location.LocationDataManager
import com.mbta.tid.mbta_app.model.OnboardingScreen
import com.mbta.tid.mbta_app.repositories.ISettingsRepository
import com.mbta.tid.mbta_app.repositories.Settings
import kotlinx.coroutines.launch
import org.koin.compose.koinInject

@OptIn(ExperimentalPermissionsApi::class)
@Composable
fun OnboardingScreenView(
screen: OnboardingScreen,
advance: () -> Unit,
locationDataManager: LocationDataManager,
skipLocationDialogue: Boolean = false,
settingsRepository: ISettingsRepository = koinInject()
) {
val coroutineScope = rememberCoroutineScope()
var sharingLocation by remember { mutableStateOf(false) }
Copy link
Collaborator

Choose a reason for hiding this comment

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

question: Is it safe to use remember instead of rememberSaveable here?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's not! If the orientation changes, the permission response is ignored, because this will have been forgotten. Good catch.

val permissions =
locationDataManager.rememberPermissions(
onPermissionsResult = {
// This only fires after the permissions state has changed
if (sharingLocation) {
advance()
}
}
)

fun hideMaps(hide: Boolean) {
coroutineScope.launch {
settingsRepository.setSettings(mapOf(Settings.HideMaps to hide))
advance()
}
}

fun shareLocation() {
if (skipLocationDialogue || permissions.permissions.any { it.status.isGranted }) {
advance()
} else {
sharingLocation = true
permissions.launchMultiplePermissionRequest()
}
}

Column {
when (screen) {
OnboardingScreen.Feedback -> {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.Start
) {
Text(stringResource(R.string.onboarding_feedback_header))
Text(stringResource(R.string.onboarding_feedback_body))
Button(onClick = advance) {
Text(stringResource(R.string.onboarding_feedback_advance))
}
}
}
OnboardingScreen.HideMaps -> {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.Start
) {
Text(stringResource(R.string.onboarding_hide_maps_header))
Text(stringResource(R.string.onboarding_hide_maps_body))
Button(onClick = { hideMaps(true) }) {
Text(stringResource(R.string.onboarding_hide_maps_hide))
}
Button(onClick = { hideMaps(false) }) {
Text(stringResource(R.string.onboarding_hide_maps_show))
}
}
}
OnboardingScreen.Location -> {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.Start
) {
Text(stringResource(R.string.onboarding_location_header))
Text(stringResource(R.string.onboarding_location_body))
Button(onClick = ::shareLocation) {
Text(stringResource(R.string.onboarding_location_advance))
}
Text(stringResource(R.string.onboarding_location_footer))
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.mbta.tid.mbta_app.android.pages

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import com.mbta.tid.mbta_app.android.location.LocationDataManager
import com.mbta.tid.mbta_app.android.onboarding.OnboardingScreenView
import com.mbta.tid.mbta_app.model.OnboardingScreen
import com.mbta.tid.mbta_app.repositories.IOnboardingRepository
import kotlinx.coroutines.launch
import org.koin.compose.koinInject

@Composable
fun OnboardingPage(
screens: List<OnboardingScreen>,
locationDataManager: LocationDataManager,
onFinish: () -> Unit,
onAdvance: () -> Unit = {},
onboardingRepository: IOnboardingRepository = koinInject(),
skipLocationDialogue: Boolean = false
) {
var selectedIndex by remember { mutableIntStateOf(0) }
val coroutineScope = rememberCoroutineScope()

val screen = screens[selectedIndex]
OnboardingScreenView(
screen,
{
coroutineScope.launch {
onboardingRepository.markOnboardingCompleted(screen)
if (selectedIndex < screens.size - 1) {
selectedIndex += 1
onAdvance()
} else {
onFinish()
}
}
},
locationDataManager,
skipLocationDialogue
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.mbta.tid.mbta_app.android.state

import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.remember
import androidx.lifecycle.ViewModel
import com.mbta.tid.mbta_app.model.OnboardingScreen
import com.mbta.tid.mbta_app.repositories.IOnboardingRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.koin.compose.koinInject

class PendingOnboardingViewModel(private val onboardingRepository: IOnboardingRepository) :
ViewModel() {
private val _pendingOnboarding: MutableStateFlow<List<OnboardingScreen>?> =
MutableStateFlow(null)
val pendingOnboarding: StateFlow<List<OnboardingScreen>?> = _pendingOnboarding

init {
CoroutineScope(Dispatchers.IO).launch {
pendingOnboarding.collect { getPendingOnboarding() }
}
}

suspend fun getPendingOnboarding() {
val data = onboardingRepository.getPendingOnboarding()
_pendingOnboarding.value = data
}
}

@Composable
fun getPendingOnboarding(
onboardingRepository: IOnboardingRepository = koinInject()
): List<OnboardingScreen>? {
val viewModel = remember { PendingOnboardingViewModel(onboardingRepository) }
return viewModel.pendingOnboarding.collectAsState(initial = null).value
}
11 changes: 11 additions & 0 deletions androidApp/src/main/res/values-b+es/strings_ios_converted.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@
<string name="no_stops_nearby_title">No hay paradas cercanas</string>
<string name="northbound">En dirección norte</string>
<string name="now">Ahora</string>
<string name="onboarding_feedback_advance">Empezar</string>
<string name="onboarding_feedback_body">MBTA Go está en su etapa inicial. Queremos recibir sus comentarios mientras seguimos realizando mejoras y agregando nuevas características.</string>
<string name="onboarding_feedback_header">Ayúdenos a mejorar</string>
<string name="onboarding_hide_maps_body">Al usar TalkBack, podemos omitir la lectura de mapas para que usted se concentre en la información de tránsito.</string>
<string name="onboarding_hide_maps_header">Establecer preferencia de mapa</string>
<string name="onboarding_hide_maps_hide">Ocultar mapas</string>
<string name="onboarding_hide_maps_show">Mostrar mapas</string>
<string name="onboarding_location_advance">Continuar</string>
<string name="onboarding_location_body">Usamos su ubicación para mostrarle opciones de tráfico cercanas.</string>
<string name="onboarding_location_footer">Puede cambiar la configuración de ubicación en la aplicación de Configuración.</string>
<string name="onboarding_location_header">Ver tráfico cerca de usted</string>
<string name="other_link_privacy_policy">Política de privacidad</string>
<string name="other_link_source_code">Ver código fuente en GitHub</string>
<string name="other_link_tos">Términos de uso</string>
Expand Down
11 changes: 11 additions & 0 deletions androidApp/src/main/res/values-b+ht/strings_ios_converted.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@
<string name="no_stops_nearby_title">Pa gen arè ki tou pre</string>
<string name="northbound">Nan direksyon nò</string>
<string name="now">Kounye a</string>
<string name="onboarding_feedback_advance">Kòmanse</string>
<string name="onboarding_feedback_body">MBTA Go nan etap kòmansman yo! Nou vle kòmantè w pandan n ap kontinye fè amelyorasyon epi ajoute nouvo opsyon.</string>
<string name="onboarding_feedback_header">Ede nou amelyore</string>
<string name="onboarding_hide_maps_body">Lè w ap itilize TalkBack, nou ka sote lekti kat yo pou kenbe w konsantre sou enfòmasyon transpò.</string>
<string name="onboarding_hide_maps_header">Defini preferans kat la</string>
<string name="onboarding_hide_maps_hide">Kache kat yo</string>
<string name="onboarding_hide_maps_show">Montre kat yo</string>
<string name="onboarding_location_advance">Kontinye</string>
<string name="onboarding_location_body">Nou itilize pozisyon w pou montre w opsyon transpò piblik ki toupre yo.</string>
<string name="onboarding_location_footer">Ou ka toujou chanje paramèt pozisyon yo apre nan paramèt aplikasyon an.</string>
<string name="onboarding_location_header">Gade transpò piblik toupre w</string>
<string name="other_link_privacy_policy">Règleman sou Vi Prive</string>
<string name="other_link_source_code">Gade sous sou GitHub</string>
<string name="other_link_tos">Kondisyon itilizasyon</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@
<string name="no_stops_nearby_title">Nenhuma parada próxima</string>
<string name="northbound">Sentido norte</string>
<string name="now">Agora</string>
<string name="onboarding_feedback_advance">Comece aqui</string>
<string name="onboarding_feedback_body">O MBTA Go está no estágio inicial! Queremos seus comentários enquanto continuamos a fazer melhorias e adicionar novos recursos.</string>
<string name="onboarding_feedback_header">Ajude-nos a melhorar</string>
<string name="onboarding_hide_maps_body">Ao usar o TalkBack, podemos pular a leitura de mapas para manter você focado nas informações de trânsito.</string>
<string name="onboarding_hide_maps_header">Definir preferência de mapas</string>
<string name="onboarding_hide_maps_hide">Ocultar mapas</string>
<string name="onboarding_hide_maps_show">Exibir mapas</string>
<string name="onboarding_location_advance">Continuar</string>
<string name="onboarding_location_body">Usamos sua localização para lhe mostrar suas opções de transporte próximas.</string>
<string name="onboarding_location_footer">Você sempre poderá mudar as configurações de localização mais tarde no aplicativo Configurações.</string>
<string name="onboarding_location_header">Ver transporte perto de você</string>
<string name="other_link_privacy_policy">Política de Privacidade</string>
<string name="other_link_source_code">Exibir origem no GitHub</string>
<string name="other_link_tos">Termos de Uso</string>
Expand Down
11 changes: 11 additions & 0 deletions androidApp/src/main/res/values-b+vi/strings_ios_converted.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@
<string name="no_stops_nearby_title">Không có điểm dừng gần đó</string>
<string name="northbound">Về hướng bắc</string>
<string name="now">Hiện nay</string>
<string name="onboarding_feedback_advance">Bắt đầu</string>
<string name="onboarding_feedback_body">MBTA Go đang trong giai đoạn đầu! Chúng tôi muốn nghe ý kiến đóng góp của bạn để tiếp tục cải thiện và bổ sung các tính năng mới.</string>
<string name="onboarding_feedback_header">Giúp chúng tôi cải thiện</string>
<string name="onboarding_hide_maps_body">Khi sử dụng TalkBack, chúng ta có thể bỏ qua việc đọc bản đồ để bạn tập trung vào thông tin giao thông.</string>
<string name="onboarding_hide_maps_header">Đặt tùy chọn bản đồ</string>
<string name="onboarding_hide_maps_hide">Ẩn bản đồ</string>
<string name="onboarding_hide_maps_show">Hiển thị bản đồ</string>
<string name="onboarding_location_advance">Tiếp tục</string>
<string name="onboarding_location_body">Chúng tôi sử dụng vị trí của bạn để hiển thị cho bạn các lựa chọn phương tiện công cộng ở gần.</string>
<string name="onboarding_location_footer">Bạn luôn có thể thay đổi cài đặt vị trí sau trong ứng dụng Cài đặt.</string>
<string name="onboarding_location_header">Xem phương tiện công cộng gần bạn</string>
<string name="other_link_privacy_policy">Chính sách bảo mật</string>
<string name="other_link_source_code">Xem nguồn trên GitHub</string>
<string name="other_link_tos">Điều khoản sử dụng</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@
<string name="no_stops_nearby_title">附近无站点</string>
<string name="northbound">北行</string>
<string name="now">现在</string>
<string name="onboarding_feedback_advance">开始</string>
<string name="onboarding_feedback_body">MBTA Go尚处于试运行阶段!我们希望收到您的反馈,以便我们继续改进和新增功能。</string>
<string name="onboarding_feedback_header">帮助我们改进</string>
<string name="onboarding_hide_maps_body">使用 TalkBack 时,我们可以跳过读地图的步骤,让您专注于交通信息。</string>
<string name="onboarding_hide_maps_header">设置地图偏好</string>
<string name="onboarding_hide_maps_hide">隐藏地图</string>
<string name="onboarding_hide_maps_show">显示地图</string>
<string name="onboarding_location_advance">继续</string>
<string name="onboarding_location_body">我们使用您的位置向您显示附近的交通选择。</string>
<string name="onboarding_location_footer">您可以随时在“设置”应用程序中更改位置设置。</string>
<string name="onboarding_location_header">查看您附近的交通</string>
<string name="other_link_privacy_policy">隐私政策</string>
<string name="other_link_source_code">在GitHub上查看源代码</string>
<string name="other_link_tos">使用条款</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@
<string name="no_stops_nearby_title">附近沒有停靠站</string>
<string name="northbound">北行</string>
<string name="now">現在</string>
<string name="onboarding_feedback_advance">開始</string>
<string name="onboarding_feedback_body">MBTA Go尚處於試運行階段!我們希望收到您的回饋,以便我們繼續改進和新增功能。</string>
<string name="onboarding_feedback_header">幫助我們改進</string>
<string name="onboarding_hide_maps_body">使用 TalkBack 時,我們可以跳過讀取地圖,讓您專注於交通資訊。</string>
<string name="onboarding_hide_maps_header">設定地圖偏好</string>
<string name="onboarding_hide_maps_hide">隱藏地圖</string>
<string name="onboarding_hide_maps_show">顯示地圖</string>
<string name="onboarding_location_advance">繼續</string>
<string name="onboarding_location_body">我們使用您的位置向您顯示附近的交通選擇。</string>
<string name="onboarding_location_footer">您可以隨時在「設定」應用程式中變更位置設定。</string>
<string name="onboarding_location_header">查看您附近的交通</string>
<string name="other_link_privacy_policy">隱私政策</string>
<string name="other_link_source_code">在GitHub上查看原始程式碼</string>
<string name="other_link_tos">使用條款</string>
Expand Down
11 changes: 11 additions & 0 deletions androidApp/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@
<string name="no_stops_nearby_title">No nearby stops</string>
<string name="northbound">Northbound</string>
<string name="now">Now</string>
<string name="onboarding_feedback_advance">Get started</string>
<string name="onboarding_feedback_body">MBTA Go is in the early stages! We want your feedback as we continue making improvements and adding new features.</string>
<string name="onboarding_feedback_header">Help us improve</string>
<string name="onboarding_hide_maps_body">When using TalkBack, we can skip reading out maps to keep you focused on transit information.</string>
<string name="onboarding_hide_maps_header">Set map preference</string>
<string name="onboarding_hide_maps_hide">Hide maps</string>
<string name="onboarding_hide_maps_show">Show maps</string>
<string name="onboarding_location_advance">Continue</string>
<string name="onboarding_location_body">We use your location to show you nearby transit options.</string>
<string name="onboarding_location_footer">You can always change location settings later in the Settings app.</string>
<string name="onboarding_location_header">See transit near you</string>
<string name="other_link_privacy_policy">Privacy Policy</string>
<string name="other_link_source_code">View source on GitHub</string>
<string name="other_link_tos">Terms of Use</string>
Expand Down
Loading
Loading