diff --git a/app/src/main/java/eu/m724/pojavbackup/core/datastore/SettingsRepository.kt b/app/src/main/java/eu/m724/pojavbackup/core/datastore/SettingsRepository.kt index 7cbb3b7..c586581 100644 --- a/app/src/main/java/eu/m724/pojavbackup/core/datastore/SettingsRepository.kt +++ b/app/src/main/java/eu/m724/pojavbackup/core/datastore/SettingsRepository.kt @@ -1,6 +1,7 @@ package eu.m724.pojavbackup.core.datastore import androidx.datastore.core.DataStore +import eu.m724.pojavbackup.proto.BackupDestination import eu.m724.pojavbackup.proto.Settings import eu.m724.pojavbackup.proto.WorldOrder import kotlinx.coroutines.flow.Flow @@ -28,4 +29,26 @@ class SettingsRepository @Inject constructor( .build() } } + + /* Destination */ + + suspend fun getDestinations(): List { + return getSettings().destinationsList + } + + suspend fun addDestination(destination: BackupDestination) { + dataStore.updateData { + it.toBuilder() + .addDestinations(destination) + .build() + } + } + + suspend fun removeDestination(index: Int) { + dataStore.updateData { + it.toBuilder() + .removeDestinations(index) + .build() + } + } } \ No newline at end of file diff --git a/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt b/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt index ad33fa6..01a7e25 100644 --- a/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt +++ b/app/src/main/java/eu/m724/pojavbackup/home/HomeActivity.kt @@ -5,15 +5,14 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.activity.result.ActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.viewModels +import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxSize @@ -29,7 +28,6 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource -import androidx.core.net.toUri import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController import androidx.navigation.NavDestination.Companion.hierarchy @@ -50,18 +48,20 @@ import eu.m724.pojavbackup.ui.theme.PojavBackupTheme class HomeActivity : ComponentActivity() { private val viewModel: HomeViewModel by viewModels() + private val setupResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == 0) { + // TODO success + } else { + // TODO failure + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewModel.load( onSetupNeeded = { - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> - if (result.resultCode == 0) { - // TODO success - } else { - // TODO failure - } - }.launch(Intent(applicationContext, SetupActivity::class.java)) + setupResult.launch(Intent(applicationContext, SetupActivity::class.java)) } ) @@ -122,10 +122,14 @@ fun HomeScaffold( startDestination = HomeScreen.Dashboard, modifier = Modifier.padding(innerPadding), enterTransition = { - fadeIn() + slideInHorizontally(initialOffsetX = { it / 10 }) + fadeIn( + animationSpec = tween(100) + ) + slideInHorizontally(initialOffsetX = { it / 10 }) }, exitTransition = { - fadeOut() + slideOutHorizontally(targetOffsetX = { -it / 10 }) + fadeOut( + animationSpec = tween(100) + ) + slideOutHorizontally(targetOffsetX = { -it / 15 }) } ) { composable { diff --git a/app/src/main/java/eu/m724/pojavbackup/home/screen/history/HistoryScreen.kt b/app/src/main/java/eu/m724/pojavbackup/home/screen/history/HistoryScreen.kt index c8fe9d3..a0e46d7 100644 --- a/app/src/main/java/eu/m724/pojavbackup/home/screen/history/HistoryScreen.kt +++ b/app/src/main/java/eu/m724/pojavbackup/home/screen/history/HistoryScreen.kt @@ -1,6 +1,5 @@ package eu.m724.pojavbackup.home.screen.history -import android.system.Os.stat import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -10,9 +9,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width -import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults -import androidx.compose.material3.CardElevation import androidx.compose.material3.ElevatedCard import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -23,7 +20,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource -import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import eu.m724.pojavbackup.R import eu.m724.pojavbackup.core.BackupStatus @@ -31,7 +27,6 @@ import eu.m724.pojavbackup.home.screen.ScreenColumn import java.time.ZonedDateTime import java.time.format.DateTimeFormatter import java.time.format.FormatStyle -import java.util.Locale @Composable fun HistoryScreen() { @@ -101,6 +96,7 @@ fun BackupCard( ) { Row( modifier = Modifier + .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp), verticalAlignment = Alignment.CenterVertically ) { diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/SettingsActivity.kt b/app/src/main/java/eu/m724/pojavbackup/settings/SettingsActivity.kt index 5c7383e..0851a07 100644 --- a/app/src/main/java/eu/m724/pojavbackup/settings/SettingsActivity.kt +++ b/app/src/main/java/eu/m724/pojavbackup/settings/SettingsActivity.kt @@ -4,6 +4,9 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.activity.result.contract.ActivityResultContracts +import androidx.activity.viewModels +import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideInHorizontally @@ -11,11 +14,14 @@ import androidx.compose.animation.slideOutHorizontally import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.Scaffold import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier @@ -30,17 +36,26 @@ import dagger.hilt.android.AndroidEntryPoint import eu.m724.pojavbackup.R import eu.m724.pojavbackup.settings.screen.SettingsScreen import eu.m724.pojavbackup.settings.screen.content.ContentScreen +import eu.m724.pojavbackup.settings.screen.destination.DestinationScreen import eu.m724.pojavbackup.settings.screen.options.OptionsScreen import eu.m724.pojavbackup.ui.theme.PojavBackupTheme @AndroidEntryPoint class SettingsActivity : ComponentActivity() { + private val viewModel: SettingsViewModel by viewModels() + + private val openDocumentTree = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { + viewModel.onOpenDocumentTree(it) + } + + @OptIn(ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val startPage = when (intent.getStringExtra("settingsPage")) { "options" -> SettingsScreen.Options "content" -> SettingsScreen.Content + "destination" -> SettingsScreen.Destination else -> SettingsScreen.Options } @@ -51,6 +66,25 @@ class SettingsActivity : ComponentActivity() { PojavBackupTheme { Scaffold( modifier = Modifier.fillMaxSize(), + topBar = { + TopAppBar( + title = { + Text("Settings") + }, + navigationIcon = { + IconButton( + onClick = { + finish() + } + ) { + Icon( + painter = painterResource(R.drawable.baseline_arrow_back_24), + contentDescription = "Exit Settings" + ) + } + } + ) + }, bottomBar = { NavigationBar { ScreenNavigationBarItem( @@ -65,6 +99,12 @@ class SettingsActivity : ComponentActivity() { route = SettingsScreen.Content, iconResourceId = R.drawable.baseline_folder_copy_24 ) + ScreenNavigationBarItem( + navController = navController, + label = "Destination", + route = SettingsScreen.Destination, + iconResourceId = R.drawable.baseline_cloud_24 + ) } } ) { innerPadding -> @@ -73,10 +113,14 @@ class SettingsActivity : ComponentActivity() { startDestination = startPage, modifier = Modifier.padding(innerPadding), enterTransition = { - fadeIn() + slideInHorizontally(initialOffsetX = { it / 10 }) + fadeIn( + animationSpec = tween(100) + ) + slideInHorizontally(initialOffsetX = { it / 10 }) }, exitTransition = { - fadeOut() + slideOutHorizontally(targetOffsetX = { -it / 10 }) + fadeOut( + animationSpec = tween(100) + ) + slideOutHorizontally(targetOffsetX = { -it / 15 }) } ) { composable { @@ -85,12 +129,19 @@ class SettingsActivity : ComponentActivity() { composable { ContentScreen(navController) } + composable { + DestinationScreen(navController, onAddDestination = { onAddDestination() }) + } // Add more destinations similarly. } } } } } + + fun onAddDestination() { + openDocumentTree.launch(null) + } } // TODO those functions are reused in Home @@ -107,6 +158,7 @@ fun RowScope.ScreenNavigationBarItem( selected = selected, onClick = { if (!selected) { + navController.popBackStack() // this makes back exit settings navController.navigate(route) } }, diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/SettingsViewModel.kt b/app/src/main/java/eu/m724/pojavbackup/settings/SettingsViewModel.kt new file mode 100644 index 0000000..b9e41eb --- /dev/null +++ b/app/src/main/java/eu/m724/pojavbackup/settings/SettingsViewModel.kt @@ -0,0 +1,42 @@ +package eu.m724.pojavbackup.settings + +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import eu.m724.pojavbackup.core.datastore.SettingsRepository +import eu.m724.pojavbackup.proto.BackupDestination +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class SettingsViewModel @Inject constructor( + @ApplicationContext private val appContext: Context, + private val settingsRepository: SettingsRepository +) : ViewModel() { + private val TAG = javaClass.name + + fun onOpenDocumentTree(uri: Uri?) { + if (uri != null) { + Log.i(TAG, "Got URI: $uri") + + appContext.contentResolver.takePersistableUriPermission( + uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + + val destination = BackupDestination.newBuilder() + .setLabel("label") + .setUri(uri.toString()) + .build() + + viewModelScope.launch { + settingsRepository.addDestination(destination) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/screen/SettingsScreen.kt b/app/src/main/java/eu/m724/pojavbackup/settings/screen/SettingsScreen.kt index 41ef73f..6d3b45f 100644 --- a/app/src/main/java/eu/m724/pojavbackup/settings/screen/SettingsScreen.kt +++ b/app/src/main/java/eu/m724/pojavbackup/settings/screen/SettingsScreen.kt @@ -13,6 +13,7 @@ import kotlinx.serialization.Serializable @Serializable sealed interface SettingsScreen { @Serializable data object Options : SettingsScreen @Serializable data object Content : SettingsScreen + @Serializable data object Destination : SettingsScreen } @Composable diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreen.kt b/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreen.kt index a1c751d..32b2453 100644 --- a/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreen.kt +++ b/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreen.kt @@ -12,13 +12,11 @@ import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults -import androidx.compose.material3.CardElevation +import androidx.compose.material3.ElevatedCard import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -55,41 +53,42 @@ fun ContentScreen( val worlds by viewModel.worlds.collectAsStateWithLifecycle() - LaunchedEffect(Unit) { - viewModel.listWorlds() - } - ScreenColumn { - val state = rememberReorderableLazyListState(onMove = { from, to -> - viewModel.moveWorld(from.index, to.index) - }) + if (worlds.size <= 1) { // separator + Text( + text = "No worlds available!" + ) + } else { + val state = rememberReorderableLazyListState(onMove = { from, to -> + viewModel.moveWorld(from.index, to.index) + }) - LazyColumn( - modifier = Modifier - .reorderable(state) - .detectReorderAfterLongPress(state), - state = state.listState, - horizontalAlignment = Alignment.CenterHorizontally - ) { - items( - items = worlds, - key = { it.id } - ) { world -> - ReorderableItem(state, key = world.id) { isDragging -> - if (!world.id.isEmpty()) { - WorldInfoCard( - bitmap = world.icon, - id = world.id, - displayName = world.displayName, - lastPlayed = world.lastPlayed, - elevation = if (isDragging) CardDefaults.elevatedCardElevation() else CardDefaults.cardElevation() - ) - } else { - Text( - text = "↑ Worlds above this line will be backed up ↑", - modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), - textAlign = TextAlign.Center - ) + LazyColumn( + modifier = Modifier + .reorderable(state) + .detectReorderAfterLongPress(state), + state = state.listState, + horizontalAlignment = Alignment.CenterHorizontally + ) { + items( + items = worlds, + key = { it.id } + ) { world -> + ReorderableItem(state, key = world.id) { isDragging -> + if (!world.id.isEmpty()) { + WorldInfoCard( + bitmap = world.icon, + id = world.id, + displayName = world.displayName, + lastPlayed = world.lastPlayed + ) + } else { + Text( + text = "↑ Worlds above this line will be backed up ↑", + modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), + textAlign = TextAlign.Center + ) + } } } } @@ -118,10 +117,7 @@ fun WorldInfoCard( iconSize: Dp = 64.dp, // Control icon size here id: String, displayName: String, - lastPlayed: ZonedDateTime, - elevation: CardElevation = CardDefaults.cardElevation(defaultElevation = 4.dp), - internalPadding: Dp = 16.dp, - spacingBetweenIconAndText: Dp = 16.dp + lastPlayed: ZonedDateTime ) { // Formatter for the timestamp - remember caches the formatter across recompositions val formatter = remember { @@ -131,15 +127,14 @@ fun WorldInfoCard( lastPlayed.format(formatter) } - Card( + ElevatedCard( modifier = modifier .padding(horizontal = 8.dp, vertical = 4.dp) - .width(300.dp), - elevation = elevation + .width(300.dp) ) { Row( modifier = Modifier - .padding(internalPadding) + .padding(horizontal = 16.dp, vertical = 8.dp) .fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { @@ -163,20 +158,17 @@ fun WorldInfoCard( contentScale = ContentScale.Crop // Crop is usually best for fixed aspect ratio ) - Spacer(modifier = Modifier.width(spacingBetweenIconAndText)) + Spacer(modifier = Modifier.width(16.dp)) // --- Text Column --- Column( - modifier = Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(4.dp) ) { Text( text = displayName, style = MaterialTheme.typography.titleLarge ) - Spacer( - modifier = Modifier.width(5.dp) - ) + Text( text = "Last played $formattedTimestamp", // Use formatted timestamp style = MaterialTheme.typography.bodySmall, diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreenViewModel.kt b/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreenViewModel.kt index f3cb096..232a1a7 100644 --- a/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreenViewModel.kt +++ b/app/src/main/java/eu/m724/pojavbackup/settings/screen/content/ContentScreenViewModel.kt @@ -10,13 +10,11 @@ import eu.m724.pojavbackup.core.World import eu.m724.pojavbackup.core.WorldRepository import eu.m724.pojavbackup.core.datastore.SettingsRepository import eu.m724.pojavbackup.proto.WorldOrder -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import java.time.Instant import java.time.ZoneOffset import javax.inject.Inject @@ -30,32 +28,16 @@ class ContentScreenViewModel @Inject constructor( private val _worlds = MutableStateFlow>(emptyList()) val worlds: StateFlow> = _worlds.asStateFlow() - fun listWorlds() { + init { viewModelScope.launch { - withContext(Dispatchers.IO) { - // TODO load order - val worldOrder = settingsRepository.getSettings().worldOrder - val worlds = worldOrder.worldIdsList.map { + settingsRepository.getSettingsFlow().collect { settings -> + val worlds = settings.worldOrder.worldIdsList.map { // TODO mark deleted worlds better worldRepository.getWorld(it) ?: World(it, "Deleted world", Instant.EPOCH.atZone(ZoneOffset.UTC), null) }.toMutableList() - worlds.add(worldOrder.separatorIndex, World.SEPARATOR) + worlds.add(settings.worldOrder.separatorIndex, World.SEPARATOR) - _worlds.update { worlds } - } - } - } - - fun listExtras() { - viewModelScope.launch { - withContext(Dispatchers.IO) { - // TODO load order - val worldOrder = settingsRepository.getSettings().worldOrder - val worlds = worldOrder.worldIdsList.map { - // TODO mark deleted worlds better - worldRepository.getWorld(it) ?: World(it, "Deleted world", Instant.EPOCH.atZone(ZoneOffset.UTC), null) - }.toMutableList() - worlds.add(worldOrder.separatorIndex, World.SEPARATOR) + // TODO same for extras _worlds.update { worlds } } diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/screen/destination/DestinationScreen.kt b/app/src/main/java/eu/m724/pojavbackup/settings/screen/destination/DestinationScreen.kt new file mode 100644 index 0000000..59747e4 --- /dev/null +++ b/app/src/main/java/eu/m724/pojavbackup/settings/screen/destination/DestinationScreen.kt @@ -0,0 +1,83 @@ +package eu.m724.pojavbackup.settings.screen.destination + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavController +import eu.m724.pojavbackup.R +import eu.m724.pojavbackup.settings.screen.ScreenColumn + +@Composable +fun DestinationScreen( + navController: NavController, + onAddDestination: () -> Unit +) { + val viewModel: DestinationScreenViewModel = hiltViewModel() + val destinations by viewModel.destinations.collectAsStateWithLifecycle() + + ScreenColumn { + Column( + modifier = Modifier.fillMaxWidth().fillMaxHeight(0.5f), // TODO make room for more destinations + horizontalAlignment = Alignment.CenterHorizontally + ) { + if (destinations.isEmpty()) { + Text("There are no destinations.") + } else { + LazyColumn( + horizontalAlignment = Alignment.CenterHorizontally + ) { + items( + items = destinations + ) { destination -> + Card { // this is TODO + Text(destination.label) + Text(destination.uri) + } + } + } + } + } + + + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Button( + onClick = onAddDestination + ) { + Icon( + painter = painterResource(R.drawable.baseline_add_24), + contentDescription = null + ) + + Spacer( + modifier = Modifier.width(10.dp) + ) + + Text( + text = "Add destination" + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/m724/pojavbackup/settings/screen/destination/DestinationScreenViewModel.kt b/app/src/main/java/eu/m724/pojavbackup/settings/screen/destination/DestinationScreenViewModel.kt new file mode 100644 index 0000000..6acd468 --- /dev/null +++ b/app/src/main/java/eu/m724/pojavbackup/settings/screen/destination/DestinationScreenViewModel.kt @@ -0,0 +1,34 @@ +package eu.m724.pojavbackup.settings.screen.destination + +import android.content.Context +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import eu.m724.pojavbackup.core.datastore.SettingsRepository +import eu.m724.pojavbackup.proto.BackupDestination +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class DestinationScreenViewModel @Inject constructor( + @ApplicationContext private val appContext: Context, + private val settingsRepository: SettingsRepository +) : ViewModel() { + private val _destinations = MutableStateFlow>(emptyList()) + val destinations: StateFlow> = _destinations.asStateFlow() + + init { + viewModelScope.launch { + settingsRepository.getSettingsFlow().collect { settings -> + _destinations.update { + settings.destinationsList + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/proto/settings.proto b/app/src/main/proto/settings.proto index 8381791..da938c5 100644 --- a/app/src/main/proto/settings.proto +++ b/app/src/main/proto/settings.proto @@ -8,7 +8,14 @@ message WorldOrder { int32 separatorIndex = 2; } +message BackupDestination { + string label = 1; + string uri = 2; // TODO +} + message Settings { WorldOrder worldOrder = 1; repeated string extraPaths = 2; + + repeated BackupDestination destinations = 3; } \ No newline at end of file diff --git a/app/src/main/res/drawable/baseline_add_24.xml b/app/src/main/res/drawable/baseline_add_24.xml new file mode 100644 index 0000000..9f83b8f --- /dev/null +++ b/app/src/main/res/drawable/baseline_add_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/baseline_arrow_back_24.xml b/app/src/main/res/drawable/baseline_arrow_back_24.xml new file mode 100644 index 0000000..075e95d --- /dev/null +++ b/app/src/main/res/drawable/baseline_arrow_back_24.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/baseline_cloud_24.xml b/app/src/main/res/drawable/baseline_cloud_24.xml new file mode 100644 index 0000000..3f6f187 --- /dev/null +++ b/app/src/main/res/drawable/baseline_cloud_24.xml @@ -0,0 +1,5 @@ + + + + +