mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3375 New Settings | Fix | Basics, part 1 (#2140)
This commit is contained in:
parent
0f03390ae4
commit
d19f5a0ba4
8 changed files with 453 additions and 306 deletions
|
@ -316,7 +316,10 @@ fun SpaceSettingsScreenPreview() {
|
|||
shareLimitReached = SpaceSettingsViewModel.ShareLimitsState(
|
||||
shareLimitReached = false,
|
||||
sharedSpacesLimit = 0
|
||||
)
|
||||
),
|
||||
isUserOwner = false,
|
||||
isEditEnabled = false,
|
||||
description = ""
|
||||
)
|
||||
),
|
||||
onNameSet = {},
|
||||
|
|
|
@ -27,6 +27,8 @@ import com.anytypeio.anytype.core_ui.features.SpaceIconView
|
|||
import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
||||
import com.anytypeio.anytype.core_ui.views.BodyRegular
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Medium
|
||||
import com.anytypeio.anytype.core_utils.ext.parseImagePath
|
||||
import com.anytypeio.anytype.core_utils.ext.toast
|
||||
import com.anytypeio.anytype.presentation.spaces.SpaceIconView
|
||||
import com.anytypeio.anytype.presentation.spaces.UiEvent
|
||||
import com.anytypeio.anytype.ui_settings.R
|
||||
|
@ -40,16 +42,23 @@ fun NewSpaceIcon(
|
|||
isEditEnabled: Boolean
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val singlePhotoPickerLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.PickVisualMedia(),
|
||||
onResult = { uri ->
|
||||
if (uri != null) {
|
||||
uiEvent(UiEvent.OnSpaceImagePicked(uri.toString()))
|
||||
runCatching {
|
||||
val path = uri.parseImagePath(context)
|
||||
uiEvent(UiEvent.OnSpaceImagePicked(path))
|
||||
}.onFailure {
|
||||
context.toast(context.getString(R.string.error_while_loading_picture))
|
||||
}
|
||||
} else {
|
||||
Timber.w("Uri was null after picking image")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
val isSpaceIconMenuExpanded = remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ import kotlinx.coroutines.flow.debounce
|
|||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.dropWhile
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import timber.log.Timber
|
||||
|
||||
@Composable
|
||||
fun MembersItem(
|
||||
|
@ -249,18 +250,24 @@ fun BaseButton(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
@Composable
|
||||
fun NewSpaceNameBlock(
|
||||
fun NewSpaceNameInputField(
|
||||
modifier: Modifier = Modifier,
|
||||
name: String,
|
||||
onNameSet: (String) -> Unit,
|
||||
isEditEnabled: Boolean
|
||||
isEditEnabled: Boolean,
|
||||
onNameSet: (String) -> Unit = {}
|
||||
) {
|
||||
|
||||
val nameValue = remember { mutableStateOf(name) }
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
LaunchedEffect(name) {
|
||||
nameValue.value = name
|
||||
}
|
||||
|
||||
LaunchedEffect(nameValue.value) {
|
||||
snapshotFlow { nameValue.value }
|
||||
.debounce(300L)
|
||||
|
@ -300,13 +307,17 @@ fun NewSpaceNameBlock(
|
|||
fun NewSpaceDescriptionBlock(
|
||||
modifier: Modifier = Modifier,
|
||||
description: String,
|
||||
onDescriptionSet: (String) -> Unit,
|
||||
isEditEnabled: Boolean
|
||||
isEditEnabled: Boolean,
|
||||
onDescriptionSet: (String) -> Unit = {},
|
||||
) {
|
||||
|
||||
val descriptionValue = remember { mutableStateOf(description) }
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
LaunchedEffect(description) {
|
||||
descriptionValue.value = description
|
||||
}
|
||||
|
||||
LaunchedEffect(descriptionValue.value) {
|
||||
snapshotFlow { descriptionValue.value }
|
||||
.debounce(300L)
|
||||
|
|
|
@ -3,11 +3,9 @@ package com.anytypeio.anytype.ui_settings.space.new_settings
|
|||
import android.os.Build
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
|
@ -16,11 +14,11 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.layout.wrapContentWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -33,8 +31,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_ui.foundation.Dragger
|
||||
import com.anytypeio.anytype.core_ui.foundation.noRippleClickable
|
||||
import com.anytypeio.anytype.core_ui.views.PreviewTitle1Medium
|
||||
import com.anytypeio.anytype.core_utils.insets.EDGE_TO_EDGE_MIN_SDK
|
||||
|
@ -42,6 +40,7 @@ import com.anytypeio.anytype.presentation.spaces.UiEvent
|
|||
import com.anytypeio.anytype.presentation.spaces.UiSpaceSettingsItem
|
||||
import com.anytypeio.anytype.presentation.spaces.UiSpaceSettingsState
|
||||
import com.anytypeio.anytype.ui_settings.R
|
||||
import timber.log.Timber
|
||||
|
||||
@Composable
|
||||
fun SpaceSettingsContainer(
|
||||
|
@ -56,24 +55,17 @@ fun SpaceSettingsContainer(
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun NewSpaceSettingsScreen(
|
||||
uiState: UiSpaceSettingsState.SpaceSettings,
|
||||
uiEvent: (UiEvent) -> Unit
|
||||
) {
|
||||
val initialName = uiState.name
|
||||
val initialDescription = uiState.description
|
||||
|
||||
// Get the initial values from your uiState items.
|
||||
val initialName = uiState.items.filterIsInstance<UiSpaceSettingsItem.Name>()
|
||||
.firstOrNull()?.name ?: ""
|
||||
val initialDescription = uiState.items.filterIsInstance<UiSpaceSettingsItem.Description>()
|
||||
.firstOrNull()?.description ?: ""
|
||||
|
||||
// Keep state of the current (edited) values.
|
||||
var nameInput by remember { mutableStateOf(initialName) }
|
||||
var descriptionInput by remember { mutableStateOf(initialDescription) }
|
||||
|
||||
// Compare against the initial values to know if something has changed.
|
||||
val isDirty = nameInput != initialName || descriptionInput != initialDescription
|
||||
var showEditDescription by remember { mutableStateOf(false) }
|
||||
var showEditTitle by remember { mutableStateOf(false) }
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
|
@ -102,29 +94,6 @@ fun NewSpaceSettingsScreen(
|
|||
uiEvent(UiEvent.OnBackPressed)
|
||||
}
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.wrapContentWidth()
|
||||
.fillMaxHeight()
|
||||
.align(Alignment.CenterEnd)
|
||||
.clickable(enabled = isDirty) {
|
||||
uiEvent(UiEvent.OnSavedClicked(nameInput, descriptionInput))
|
||||
},
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.padding(horizontal = 16.dp),
|
||||
text = stringResource(R.string.space_settings_save_button),
|
||||
style = PreviewTitle1Medium,
|
||||
color = if (isDirty) {
|
||||
colorResource(id = R.color.text_primary)
|
||||
} else {
|
||||
colorResource(id = R.color.text_tertiary)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
content = { paddingValues ->
|
||||
|
@ -160,10 +129,9 @@ fun NewSpaceSettingsScreen(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
is UiSpaceSettingsItem.Name -> {
|
||||
item {
|
||||
NewSpaceNameBlock(
|
||||
NewSpaceNameInputField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.border(
|
||||
|
@ -172,12 +140,13 @@ fun NewSpaceSettingsScreen(
|
|||
color = colorResource(id = R.color.shape_primary)
|
||||
)
|
||||
.padding(vertical = 12.dp, horizontal = 16.dp)
|
||||
.animateItem(),
|
||||
name = nameInput,
|
||||
onNameSet = { newName ->
|
||||
nameInput = newName
|
||||
},
|
||||
isEditEnabled = uiState.isEditEnabled
|
||||
.animateItem()
|
||||
.noRippleClickable {
|
||||
showEditTitle = true
|
||||
}
|
||||
,
|
||||
name = item.name,
|
||||
isEditEnabled = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -193,12 +162,13 @@ fun NewSpaceSettingsScreen(
|
|||
color = colorResource(id = R.color.shape_primary)
|
||||
)
|
||||
.padding(vertical = 12.dp, horizontal = 16.dp)
|
||||
.animateItem(),
|
||||
isEditEnabled = uiState.isEditEnabled,
|
||||
description = descriptionInput,
|
||||
onDescriptionSet = { newDescription ->
|
||||
descriptionInput = newDescription
|
||||
}
|
||||
.animateItem()
|
||||
.noRippleClickable {
|
||||
showEditDescription = true
|
||||
}
|
||||
,
|
||||
isEditEnabled = false,
|
||||
description = initialDescription
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -213,7 +183,9 @@ fun NewSpaceSettingsScreen(
|
|||
}
|
||||
}
|
||||
|
||||
is UiSpaceSettingsItem.Chat -> TODO()
|
||||
is UiSpaceSettingsItem.Chat -> {
|
||||
// TODO
|
||||
}
|
||||
is UiSpaceSettingsItem.DefaultObjectType -> {
|
||||
item {
|
||||
DefaultTypeItem(
|
||||
|
@ -257,7 +229,9 @@ fun NewSpaceSettingsScreen(
|
|||
}
|
||||
}
|
||||
|
||||
is UiSpaceSettingsItem.RemoteStorage -> TODO()
|
||||
is UiSpaceSettingsItem.RemoteStorage -> {
|
||||
// TODO
|
||||
}
|
||||
is UiSpaceSettingsItem.Section -> {
|
||||
item {
|
||||
SpaceSettingsSection(
|
||||
|
@ -302,4 +276,184 @@ fun NewSpaceSettingsScreen(
|
|||
}
|
||||
)
|
||||
|
||||
if (showEditDescription) {
|
||||
ModalBottomSheet(
|
||||
containerColor = colorResource(R.color.background_secondary),
|
||||
onDismissRequest = {
|
||||
showEditDescription = false
|
||||
},
|
||||
dragHandle = {
|
||||
Dragger(
|
||||
modifier = Modifier.padding(vertical = 6.dp)
|
||||
)
|
||||
},
|
||||
) {
|
||||
EditDescriptionField(
|
||||
initialInput = initialDescription,
|
||||
onSaveFieldValueClicked = {
|
||||
uiEvent(UiEvent.OnSaveDescriptionClicked(it)).also {
|
||||
showEditDescription = false
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
if (showEditTitle) {
|
||||
ModalBottomSheet(
|
||||
containerColor = colorResource(R.color.background_secondary),
|
||||
onDismissRequest = {
|
||||
showEditTitle = false
|
||||
},
|
||||
dragHandle = {
|
||||
Dragger(
|
||||
modifier = Modifier.padding(vertical = 6.dp)
|
||||
)
|
||||
}
|
||||
) {
|
||||
EditNameField(
|
||||
initialInput = initialName,
|
||||
onSaveFieldValueClicked = {
|
||||
uiEvent(UiEvent.OnSaveTitleClicked(it)).also {
|
||||
showEditTitle = false
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EditNameField(
|
||||
initialInput: String,
|
||||
onSaveFieldValueClicked: (String) -> Unit
|
||||
) {
|
||||
|
||||
var fieldInput by remember { mutableStateOf(initialInput) }
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
containerColor = colorResource(id = R.color.background_secondary),
|
||||
topBar = {
|
||||
Box(modifier = Modifier.fillMaxWidth().height(48.dp)) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.padding(horizontal = 16.dp)
|
||||
.noRippleClickable {
|
||||
onSaveFieldValueClicked(fieldInput)
|
||||
},
|
||||
text = "Done",
|
||||
style = PreviewTitle1Medium,
|
||||
color = if (fieldInput != initialInput) {
|
||||
colorResource(id = R.color.text_primary)
|
||||
} else {
|
||||
colorResource(id = R.color.text_tertiary)
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
content = { paddingValues ->
|
||||
val contentModifier =
|
||||
if (Build.VERSION.SDK_INT >= EDGE_TO_EDGE_MIN_SDK)
|
||||
Modifier
|
||||
.padding(top = paddingValues.calculateTopPadding())
|
||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||
.fillMaxSize()
|
||||
else
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
|
||||
Box(
|
||||
modifier = contentModifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
NewSpaceNameInputField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.border(
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
width = 2.dp,
|
||||
color = colorResource(id = R.color.palette_system_amber_50)
|
||||
)
|
||||
.padding(vertical = 12.dp, horizontal = 16.dp)
|
||||
,
|
||||
name = fieldInput,
|
||||
onNameSet = { newName ->
|
||||
fieldInput = newName
|
||||
},
|
||||
isEditEnabled = true
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun EditDescriptionField(
|
||||
initialInput: String,
|
||||
onSaveFieldValueClicked: (String) -> Unit
|
||||
) {
|
||||
|
||||
var fieldInput by remember { mutableStateOf(initialInput) }
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
containerColor = colorResource(id = R.color.background_secondary),
|
||||
topBar = {
|
||||
Box(modifier = Modifier.fillMaxWidth().height(48.dp)) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterEnd)
|
||||
.padding(horizontal = 16.dp)
|
||||
.noRippleClickable {
|
||||
onSaveFieldValueClicked(fieldInput)
|
||||
},
|
||||
text = "Done",
|
||||
style = PreviewTitle1Medium,
|
||||
color = if (fieldInput != initialInput) {
|
||||
colorResource(id = R.color.text_primary)
|
||||
} else {
|
||||
colorResource(id = R.color.text_tertiary)
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
content = { paddingValues ->
|
||||
val contentModifier =
|
||||
if (Build.VERSION.SDK_INT >= EDGE_TO_EDGE_MIN_SDK)
|
||||
Modifier
|
||||
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||
.fillMaxSize()
|
||||
.padding(top = paddingValues.calculateTopPadding())
|
||||
else
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
|
||||
Box(
|
||||
modifier = contentModifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
NewSpaceDescriptionBlock(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.border(
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
width = 2.dp,
|
||||
color = colorResource(id = R.color.palette_system_amber_50)
|
||||
)
|
||||
.padding(vertical = 12.dp, horizontal = 16.dp)
|
||||
,
|
||||
description = fieldInput,
|
||||
isEditEnabled = true,
|
||||
onDescriptionSet = {
|
||||
fieldInput = it
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue