common/app: add Settings UI composables

Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
Aditya Wasan 2021-04-02 13:36:41 +05:30 committed by Harsh Shandilya
parent a08109d745
commit ef09b241ea
No known key found for this signature in database
GPG key ID: 366D7BBAD1031E80
6 changed files with 176 additions and 1 deletions

View file

@ -0,0 +1,58 @@
package dev.msfjarvis.lobsters.ui.settings
import android.content.Context
import androidx.activity.compose.registerForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import dev.msfjarvis.lobsters.data.backup.BackupHandler
import dev.msfjarvis.lobsters.utils.Strings
import dev.msfjarvis.lobsters.utils.get
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
private const val JSON_MINE = "application/json"
@Composable
fun BackupOption(
context: Context,
backupHandler: BackupHandler,
coroutineScope: CoroutineScope,
) {
val result =
registerForActivityResult(ActivityResultContracts.CreateDocument()) { uri ->
if (uri == null) return@registerForActivityResult
context.contentResolver.openOutputStream(uri)?.use {
coroutineScope.launch(Dispatchers.IO) {
it.write(backupHandler.exportSavedPosts().toByteArray(Charsets.UTF_8))
}
}
}
SettingsActionItem(
Strings.SettingsBackup.get(),
Strings.SettingsBackupDescription.get(),
onClick = { result.launch("Claw-export.json") }
)
}
@Composable
fun RestoreOption(
context: Context,
backupHandler: BackupHandler,
coroutineScope: CoroutineScope,
) {
val result =
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if (uri == null) return@registerForActivityResult
context.contentResolver.openInputStream(uri)?.use {
coroutineScope.launch(Dispatchers.IO) {
backupHandler.importSavedPosts(it.readBytes().toString(Charsets.UTF_8))
}
}
}
SettingsActionItem(
title = Strings.SettingsRestore.get(),
description = Strings.SettingsRestoreDescription.get(),
onClick = { result.launch(JSON_MINE) }
)
}

View file

@ -0,0 +1,95 @@
package dev.msfjarvis.lobsters.ui.settings
import android.content.Context
import androidx.activity.ComponentActivity
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Icon
import androidx.compose.material.ListItem
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import dev.msfjarvis.lobsters.data.backup.BackupHandler
import dev.msfjarvis.lobsters.utils.Strings
import dev.msfjarvis.lobsters.utils.get
import kotlinx.coroutines.CoroutineScope
@Composable
fun LobstersSettings(
backupHandler: BackupHandler,
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
Scaffold(
topBar = { SettingsTopBar(context) },
content = { SettingsBody(context, backupHandler, scope) },
)
}
@Composable
fun SettingsTopBar(
context: Context,
) {
TopAppBar(
title = { Text(Strings.Settings.get()) },
navigationIcon = {
Icon(
Icons.Default.ArrowBack,
contentDescription = Strings.Settings.get(),
modifier =
Modifier.padding(start = 16.dp).clickable { (context as ComponentActivity).finish() },
)
},
)
}
@Composable
fun SettingsBody(
context: Context,
backupHandler: BackupHandler,
scope: CoroutineScope,
) {
LazyColumn {
item {
BackupOption(
context,
backupHandler,
scope,
)
}
item {
RestoreOption(
context,
backupHandler,
scope,
)
}
}
}
@Composable
fun SettingsActionItem(
title: String,
description: String? = null,
singleLineDescription: Boolean = true,
icon: ImageVector? = null,
onClick: (() -> Unit)? = null,
) {
ListItem(
text = { Text(title) },
secondaryText = { description?.let { Text(it) } },
icon = { icon?.let { Icon(icon, null, Modifier.height(32.dp)) } },
singleLineSecondaryText = singleLineDescription,
modifier = Modifier.clickable { onClick?.invoke() },
)
}