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() },
)
}

View file

@ -11,13 +11,18 @@ private fun stringEnumMapper(stringEnum: Strings): Int {
Strings.AvatarContentDescription -> R.string.avatar_content_description
Strings.ChangeSortingOrder -> R.string.change_sorting_order
Strings.HottestPosts -> R.string.hottest_posts
Strings.NewestPosts -> R.string.newest_posts
Strings.NoSavedPost -> R.string.no_saved_posts
Strings.OpenComments -> R.string.open_comments
Strings.RefreshPostsContentDescription -> R.string.refresh_posts_content_description
Strings.RemoveFromSavedPosts -> R.string.remove_from_saved_posts
Strings.SavedPosts -> R.string.saved_posts
Strings.SubmittedBy -> R.string.submitted_by
Strings.NewestPosts -> R.string.newest_posts
Strings.Settings -> R.string.settings
Strings.SettingsBackup -> R.string.settings_backup
Strings.SettingsBackupDescription -> R.string.settings_backup_desc
Strings.SettingsRestore -> R.string.settings_restore
Strings.SettingsRestoreDescription -> R.string.settings_restore_desc
}
}

View file

@ -11,4 +11,9 @@
<string name="open_comments">Open comments</string>
<string name="change_sorting_order">Change sort order</string>
<string name="newest_posts">Newest</string>
<string name="settings">Settings</string>
<string name="settings_backup">Backup saved posts</string>
<string name="settings_backup_desc">Export saved posts in a JSON file that can be restored later</string>
<string name="settings_restore">Restore saved posts</string>
<string name="settings_restore_desc">Import a previously exported copy of saved posts. Existing saved posts are not cleared</string>
</resources>

View file

@ -13,4 +13,9 @@ enum class Strings {
SavedPosts,
SubmittedBy,
NewestPosts,
Settings,
SettingsBackup,
SettingsBackupDescription,
SettingsRestore,
SettingsRestoreDescription,
}

View file

@ -16,6 +16,13 @@ private fun stringEnumMapper(stringEnum: Strings): String {
Strings.SavedPosts -> "Saved"
Strings.SubmittedBy -> "submitted by %1s"
Strings.NewestPosts -> "Newest"
Strings.Settings -> "Settings"
Strings.SettingsBackup -> "Backup saved posts"
Strings.SettingsBackupDescription ->
"Export saved posts in a JSON file that can be restored later"
Strings.SettingsRestore -> "Restore saved posts"
Strings.SettingsRestoreDescription ->
"Import a previously exported copy of saved posts. Existing saved posts are not cleared"
}
}