-
Notifications
You must be signed in to change notification settings - Fork 39
Alan/generategeodatabasereplicafromfeatureservice migration #297
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
Changes from 4 commits
e690b96
9ba05f7
0b08389
ebd27dc
237df47
b3cd64a
6aff845
a5111cc
a3747c3
f430f2d
f2f9bcb
619ed28
0c7ec96
bfa10e8
7f87a0e
53d4eda
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,10 +17,6 @@ | |
package com.esri.arcgismaps.sample.generategeodatabasereplicafromfeatureservice.components | ||
|
||
import android.app.Application | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.runtime.mutableIntStateOf | ||
import androidx.compose.runtime.mutableStateOf | ||
import androidx.compose.runtime.setValue | ||
import androidx.compose.ui.unit.IntSize | ||
import androidx.lifecycle.AndroidViewModel | ||
import androidx.lifecycle.viewModelScope | ||
|
@@ -41,6 +37,8 @@ import com.arcgismaps.tasks.geodatabase.GeodatabaseSyncTask | |
import com.arcgismaps.toolkit.geoviewcompose.MapViewProxy | ||
import com.esri.arcgismaps.sample.sampleslib.components.MessageDialogViewModel | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.asStateFlow | ||
import kotlinx.coroutines.launch | ||
import java.io.File | ||
|
||
|
@@ -95,19 +93,9 @@ class GenerateGeodatabaseReplicaFromFeatureServiceViewModel( | |
// a message dialog view model for handling error messages | ||
val messageDialogVM = MessageDialogViewModel() | ||
|
||
// job progress dialog visibility state | ||
var showJobProgressDialog by mutableStateOf(false) | ||
private set | ||
|
||
// job progress percentage | ||
var jobProgress by mutableIntStateOf(0) | ||
private set | ||
|
||
// state variables indicating if the buttons are enabled | ||
var resetButtonEnabled by mutableStateOf(false) | ||
private set | ||
var generateButtonEnabled by mutableStateOf(false) | ||
private set | ||
// state flow to expose current UI state to UI | ||
private val _uiStateFlow = MutableStateFlow(UiState(status = UiStatus.STARTING)) | ||
val uiStateFlow = _uiStateFlow.asStateFlow() | ||
|
||
// create a GeodatabaseSyncTask with the URL of the feature service | ||
private var geodatabaseSyncTask = GeodatabaseSyncTask(FEATURE_SERVICE_URL) | ||
|
@@ -124,21 +112,21 @@ class GenerateGeodatabaseReplicaFromFeatureServiceViewModel( | |
|
||
viewModelScope.launch { | ||
// load the map | ||
arcGISMap.load().onFailure { error -> | ||
messageDialogVM.showMessageDialog( | ||
title = "Failed to load map", | ||
description = error.message.toString() | ||
) | ||
}.onSuccess { | ||
arcGISMap.load().onSuccess { | ||
// load the GeodatabaseSyncTask | ||
geodatabaseSyncTask.load().onFailure { error -> | ||
geodatabaseSyncTask.load().onSuccess { | ||
_uiStateFlow.value = UiState(status = UiStatus.READY_FOR_GENERATE) | ||
}.onFailure { error -> | ||
messageDialogVM.showMessageDialog( | ||
title = "Failed to load GeodatabaseSyncTask", | ||
description = error.message.toString() | ||
) | ||
}.onSuccess { | ||
generateButtonEnabled = true | ||
} | ||
}.onFailure { error -> | ||
messageDialogVM.showMessageDialog( | ||
title = "Failed to load map", | ||
description = error.message.toString() | ||
) | ||
} | ||
} | ||
} | ||
|
@@ -178,7 +166,7 @@ class GenerateGeodatabaseReplicaFromFeatureServiceViewModel( | |
* Reset the map to its original state. | ||
*/ | ||
fun resetMap() { | ||
// clear any layers and symbols already on the map | ||
// clear any layers and symbols already on the map | ||
arcGISMap.operationalLayers.clear() | ||
graphicsOverlay.graphics.clear() | ||
// add the download area boundary | ||
|
@@ -187,17 +175,14 @@ class GenerateGeodatabaseReplicaFromFeatureServiceViewModel( | |
arcGISMap.operationalLayers.add(featureLayer) | ||
// close the current geodatabase, if a replica was already generated | ||
geodatabase?.close() | ||
// show the Generate button | ||
generateButtonEnabled = true | ||
resetButtonEnabled = false | ||
_uiStateFlow.value = UiState(status = UiStatus.READY_FOR_GENERATE) | ||
} | ||
|
||
/** | ||
* Generate the geodatabase replica. | ||
*/ | ||
fun generateGeodatabaseReplica() { | ||
// disable the Generate button | ||
generateButtonEnabled = false | ||
_uiStateFlow.value = UiState(status = UiStatus.GENERATING, jobProgress = 0) | ||
|
||
val offlineGeodatabasePath = | ||
application.getExternalFilesDir(null)?.path + "/portland_trees_gdb.geodatabase" | ||
|
@@ -250,18 +235,14 @@ class GenerateGeodatabaseReplicaFromFeatureServiceViewModel( | |
// create a flow-collection for the job's progress | ||
viewModelScope.launch(Dispatchers.Main) { | ||
job.progress.collect { progress -> | ||
jobProgress = progress | ||
_uiStateFlow.value = UiState(status = UiStatus.GENERATING, jobProgress = progress) | ||
} | ||
} | ||
|
||
// show the Job Progress Dialog | ||
showJobProgressDialog = true | ||
|
||
// start the job and wait for Job result | ||
job.start() | ||
job.result().onSuccess { geodatabase -> | ||
// dismiss the progress dialog and display the data | ||
showJobProgressDialog = false | ||
// display the data | ||
loadGeodatabaseAndAddToMap(geodatabase) | ||
|
||
// unregister the geodatabase since we will not sync changes to the service | ||
|
@@ -272,12 +253,11 @@ class GenerateGeodatabaseReplicaFromFeatureServiceViewModel( | |
) | ||
} | ||
}.onFailure { error -> | ||
_uiStateFlow.value = UiState(status = UiStatus.READY_FOR_GENERATE) | ||
messageDialogVM.showMessageDialog( | ||
title = "Error generating geodatabase", | ||
description = error.message.toString() | ||
) | ||
showJobProgressDialog = false | ||
generateButtonEnabled = true | ||
} | ||
} | ||
|
||
|
@@ -297,13 +277,14 @@ class GenerateGeodatabaseReplicaFromFeatureServiceViewModel( | |
} | ||
// keep track of the geodatabase to close it before generating a new replica | ||
geodatabase = replicaGeodatabase | ||
_uiStateFlow.value = UiState(status = UiStatus.REPLICA_DISPLAYED) | ||
}.onFailure { error -> | ||
_uiStateFlow.value = UiState(status = UiStatus.READY_FOR_GENERATE) | ||
messageDialogVM.showMessageDialog( | ||
title = "Error loading geodatabase", | ||
description = error.message.toString() | ||
) | ||
} | ||
resetButtonEnabled = true | ||
} | ||
|
||
/** | ||
|
@@ -313,6 +294,27 @@ class GenerateGeodatabaseReplicaFromFeatureServiceViewModel( | |
viewModelScope.launch(Dispatchers.IO) { | ||
generateGeodatabaseJob?.cancel() | ||
} | ||
generateButtonEnabled = true | ||
_uiStateFlow.value = UiState(status = UiStatus.READY_FOR_GENERATE) | ||
} | ||
|
||
override fun onCleared() { | ||
super.onCleared() | ||
// close the current geodatabase, if any, to release internal resources and file locks | ||
geodatabase?.close() | ||
} | ||
} | ||
|
||
/** | ||
* Data class representing the UI state. | ||
*/ | ||
data class UiState( | ||
val status: UiStatus, | ||
val jobProgress: Int = 0 | ||
) | ||
|
||
enum class UiStatus { | ||
STARTING, | ||
READY_FOR_GENERATE, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reads slightly odd to me, how about |
||
GENERATING, | ||
REPLICA_DISPLAYED | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add newline |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,16 +26,19 @@ import androidx.compose.material3.Button | |
import androidx.compose.material3.Scaffold | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.layout.onSizeChanged | ||
import androidx.compose.ui.platform.LocalContext | ||
import androidx.compose.ui.unit.dp | ||
import androidx.core.content.ContextCompat.getString | ||
import androidx.lifecycle.compose.collectAsStateWithLifecycle | ||
import androidx.lifecycle.viewmodel.compose.viewModel | ||
import com.arcgismaps.LoadStatus | ||
import com.arcgismaps.toolkit.geoviewcompose.MapView | ||
import com.esri.arcgismaps.sample.generategeodatabasereplicafromfeatureservice.components.GenerateGeodatabaseReplicaFromFeatureServiceViewModel | ||
import com.esri.arcgismaps.sample.generategeodatabasereplicafromfeatureservice.R | ||
import com.esri.arcgismaps.sample.generategeodatabasereplicafromfeatureservice.components.UiStatus | ||
import com.esri.arcgismaps.sample.sampleslib.components.JobLoadingDialog | ||
import com.esri.arcgismaps.sample.sampleslib.components.MessageDialog | ||
import com.esri.arcgismaps.sample.sampleslib.components.SampleTopAppBar | ||
|
@@ -47,6 +50,7 @@ import com.esri.arcgismaps.sample.sampleslib.components.SampleTopAppBar | |
fun GenerateGeodatabaseReplicaFromFeatureServiceScreen(sampleName: String) { | ||
val application = LocalContext.current.applicationContext | ||
val mapViewModel: GenerateGeodatabaseReplicaFromFeatureServiceViewModel = viewModel() | ||
val uiState by mapViewModel.uiStateFlow.collectAsStateWithLifecycle() | ||
Scaffold( | ||
topBar = { SampleTopAppBar(title = sampleName) }, | ||
content = { | ||
|
@@ -86,32 +90,30 @@ fun GenerateGeodatabaseReplicaFromFeatureServiceScreen(sampleName: String) { | |
.padding(16.dp), | ||
horizontalArrangement = Arrangement.SpaceEvenly | ||
) { | ||
// the Reset Map button | ||
Button( | ||
onClick = { | ||
mapViewModel.resetMap() | ||
}, | ||
enabled = mapViewModel.resetButtonEnabled | ||
enabled = uiState.status == UiStatus.REPLICA_DISPLAYED | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On naming: |
||
) { | ||
Text(text = getString(application, R.string.reset_map)) | ||
} | ||
|
||
// the Generate button | ||
Button( | ||
onClick = { | ||
mapViewModel.generateGeodatabaseReplica() | ||
}, | ||
enabled = mapViewModel.generateButtonEnabled | ||
enabled = uiState.status == UiStatus.READY_FOR_GENERATE | ||
) { | ||
Text(text = getString(application, R.string.generate_button_text)) | ||
} | ||
} | ||
|
||
// display progress dialog while generating a geodatabase replica | ||
if (mapViewModel.showJobProgressDialog) { | ||
if (uiState.status == UiStatus.GENERATING) { | ||
JobLoadingDialog( | ||
title = "Generating geodatabase replica...", | ||
progress = mapViewModel.jobProgress, | ||
title = getString(application, R.string.dialog_title), | ||
progress = uiState.jobProgress, | ||
cancelJobRequest = { mapViewModel.cancelOfflineGeodatabaseJob() } | ||
) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
<resources> | ||
<string name="generate_geodatabase_replica_from_feature_service_app_name">Generate geodatabase replica from feature service</string> | ||
<string name="generate_button_text">Generate</string> | ||
<string name="dialog_title">Fetching result</string> | ||
<string name="dialog_title">Generating geodatabase replica...</string> | ||
<string name="reset_map">Reset map</string> | ||
</resources> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a lot of things called uiState/status here - wonder if some of them could be renamed for clarity.
Not 100% sure what to do: maybe
UiState
→GenerateGeodatabaseJobStatus
orUiStatus
→GeodatabaseGenerationStatus
?Think the comment could be rewritten too - surely we're exposing application state to the UI, not UI state? UI state is the product of whatever data we pass to the UI.