Skip to content
Open
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
Expand Up @@ -8,34 +8,44 @@ import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.testTagsAsResourceId
import androidx.core.content.edit
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.navArgument
import androidx.preference.PreferenceManager
import com.google.gson.GsonBuilder
import kotlinx.coroutines.flow.MutableStateFlow
import org.maplibre.android.maps.MapLibreMap.OnMapLongClickListener
import org.scottishtecharmy.soundscape.MainActivity
import org.scottishtecharmy.soundscape.R
import org.scottishtecharmy.soundscape.audio.AudioTour
import org.scottishtecharmy.soundscape.audio.TourButton
import org.scottishtecharmy.soundscape.geojsonparser.geojson.LngLatAlt
import org.scottishtecharmy.soundscape.screens.home.data.LocationDescription
import org.scottishtecharmy.soundscape.screens.home.home.AdvancedMarkersAndRoutesSettingsScreenVM
import org.scottishtecharmy.soundscape.screens.home.home.AudioTourInstructionDialog
import org.scottishtecharmy.soundscape.screens.home.home.HelpScreen
import org.scottishtecharmy.soundscape.screens.home.home.Home
import org.scottishtecharmy.soundscape.screens.home.home.OfflineMapsScreenVM
import org.scottishtecharmy.soundscape.screens.home.home.SleepScreenVM
import org.scottishtecharmy.soundscape.screens.home.home.AdvancedMarkersAndRoutesSettingsScreenVM
import org.scottishtecharmy.soundscape.screens.home.home.OpenSourceLicensesVM
import org.scottishtecharmy.soundscape.screens.home.home.SleepScreenVM
import org.scottishtecharmy.soundscape.screens.home.locationDetails.LocationDetailsScreen
import org.scottishtecharmy.soundscape.screens.home.locationDetails.generateLocationDetailsRoute
import org.scottishtecharmy.soundscape.screens.home.placesnearby.PlacesNearbyScreenVM
Expand All @@ -49,9 +59,10 @@ import org.scottishtecharmy.soundscape.screens.onboarding.language.LanguageScree
import org.scottishtecharmy.soundscape.screens.onboarding.language.LanguageViewModel
import org.scottishtecharmy.soundscape.utils.Analytics
import org.scottishtecharmy.soundscape.viewmodels.SettingsViewModel
import org.scottishtecharmy.soundscape.audio.AudioTour
import org.scottishtecharmy.soundscape.viewmodels.home.HomeState
import org.scottishtecharmy.soundscape.viewmodels.home.HomeViewModel
import org.scottishtecharmy.soundscape.viewmodels.home.InitialTutorialState
import org.scottishtecharmy.soundscape.viewmodels.home.shouldShowInitialTutorialDialog
import java.net.URLDecoder
import java.nio.charset.StandardCharsets

Expand Down Expand Up @@ -117,6 +128,16 @@ fun getCurrentLocationDescription(viewModel: HomeViewModel, state: HomeState): L
}
}

fun SharedPreferences.getInitialTutorialState(): InitialTutorialState {
return getInt("INITIAL_TUTORIAL_STATE", InitialTutorialState.INCOMPLETE.ordinal).let {
InitialTutorialState.entries[it]
}
}

fun SharedPreferences.setInitialTutorialState(state: InitialTutorialState) {
this.edit(commit = true) { putInt("INITIAL_TUTORIAL_STATE", state.ordinal) }
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun HomeScreen(
Expand Down Expand Up @@ -145,6 +166,13 @@ fun HomeScreen(
}
}

val context = LocalContext.current
LaunchedEffect(viewModel) {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
val initialTutorialState = sharedPreferences.getInitialTutorialState()
viewModel.setInitialTutorialState(initialTutorialState)
}
val shouldShowInitialTutorialDialog = state.value.shouldShowInitialTutorialDialog()

Box(modifier = Modifier.fillMaxSize()) {
NavHost(
Expand Down Expand Up @@ -400,15 +428,31 @@ fun HomeScreen(
gson.fromJson(json, LocationDescription::class.java)
}

OfflineMapsScreenVM(
navController = navController,
locationDescription = locationDescription,
modifier = Modifier
.windowInsetsPadding(WindowInsets.safeDrawing)
.semantics { testTagsAsResourceId = true }
OfflineMapsScreenVM(
navController = navController,
locationDescription = locationDescription,
modifier = Modifier
.windowInsetsPadding(WindowInsets.safeDrawing)
.semantics { testTagsAsResourceId = true }
)
}
}

if (shouldShowInitialTutorialDialog) {
InitialTutorialDialog(
onDismiss = {
PreferenceManager.getDefaultSharedPreferences(context)
.setInitialTutorialState(InitialTutorialState.DISMISSED)
viewModel.setInitialTutorialState(InitialTutorialState.DISMISSED)
},
onConfirmation = {
audioTour.start()
PreferenceManager.getDefaultSharedPreferences(context)
.setInitialTutorialState(InitialTutorialState.COMPLETED)
viewModel.setInitialTutorialState(InitialTutorialState.COMPLETED)
}
)
}
}

// Show tutorial dialog on top of all screens
audioTourInstruction?.let { instruction ->
Expand All @@ -420,3 +464,33 @@ fun HomeScreen(
}
}

@Composable
fun InitialTutorialDialog(
onDismiss: () -> Unit,
onConfirmation: () -> Unit,
modifier: Modifier = Modifier,
) {
AlertDialog(
onDismissRequest = onDismiss,
confirmButton = {
TextButton(
onClick = onConfirmation
) {
Text(stringResource(R.string.initial_tutorial_dialog_yes))
}
},
dismissButton = {
TextButton(
onClick = onDismiss
) {
Text(stringResource(R.string.initial_tutorial_dialog_no))
}
},
title = {
Text(stringResource(R.string.intial_tutorial_dialog_title))
},
text = { Text(stringResource(R.string.initial_tutorial_dialog_content)) },
modifier = modifier,
)
}

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ data class HomeState(
var searchItems: List<LocationDescription>? = null,
var routesTabSelected: Boolean = true,
var currentRouteData: RoutePlayerState = RoutePlayerState(),
var permissionsRequired: Boolean = false,
var voiceCommandListening: Boolean = false,
val initialTutorialState: InitialTutorialState = InitialTutorialState.INCOMPLETE,
)

fun HomeState.shouldShowInitialTutorialDialog() =
initialTutorialState == InitialTutorialState.INCOMPLETE

enum class InitialTutorialState {
INCOMPLETE,
DISMISSED,
COMPLETED,
}
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ class HomeViewModel
context.startActivity(intent)
}

fun setInitialTutorialState(initialTutorialState: InitialTutorialState) {
_state.update { it.copy(initialTutorialState = initialTutorialState) }
}

companion object {
private const val TAG = "HomeViewModel"
}
Expand Down
7 changes: 6 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2709,5 +2709,10 @@ We\'re still working hard on improving the app, so please report any problems th
<string name="relative_left_right_direction_behind_left">"Behind left"</string>
<string name="relative_left_right_direction_behind_right">"Behind right"</string>
<string name="relative_left_right_direction_behind">"Behind"</string>
<string name="loading_indicator_content_description">Loading</string>
<string name="loading_indicator_content_description">Loading</string>
<!-- Initial Tutorial Dialog -->
<string name="initial_tutorial_dialog_yes">Yes</string>
<string name="initial_tutorial_dialog_no">No</string>
<string name="intial_tutorial_dialog_title">Guided Tutorial?</string>
<string name="initial_tutorial_dialog_content">It looks like this is your first time using Soundscape, would you like a guided tutorial to guide you through the features?</string>
</resources>