mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3527 Primitives | Edit Type title screen (#2240)
This commit is contained in:
parent
33796425b4
commit
4727bebae9
9 changed files with 227 additions and 201 deletions
|
@ -13,7 +13,6 @@ import androidx.core.os.bundleOf
|
|||
import androidx.fragment.app.viewModels
|
||||
import androidx.fragment.compose.content
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.navOptions
|
||||
import com.anytypeio.anytype.R
|
||||
|
@ -28,7 +27,6 @@ import com.anytypeio.anytype.feature_object_type.viewmodel.CreateObjectTypeVMFac
|
|||
import com.anytypeio.anytype.feature_object_type.viewmodel.CreateObjectTypeViewModel
|
||||
import com.anytypeio.anytype.feature_object_type.viewmodel.CreateTypeCommand
|
||||
import com.anytypeio.anytype.feature_object_type.viewmodel.CreateTypeVmParams
|
||||
import com.anytypeio.anytype.ui.base.navigation
|
||||
import javax.inject.Inject
|
||||
import kotlin.getValue
|
||||
import timber.log.Timber
|
||||
|
@ -50,8 +48,6 @@ class CreateTypeFragment: BaseBottomSheetComposeFragment() {
|
|||
SetTypeTitlesAndIconScreen(
|
||||
uiState = vm.uiState.collectAsStateWithLifecycle().value,
|
||||
onDismiss = vm::onDismiss,
|
||||
onTitleChanged = vm::onTypeTitleChanged,
|
||||
onPluralChanged = vm::onTypePluralChanged,
|
||||
onIconClicked = vm::onIconClicked,
|
||||
onButtonClicked = vm::onButtonClicked
|
||||
)
|
||||
|
|
|
@ -33,6 +33,7 @@ import com.anytypeio.anytype.feature_object_type.ui.ObjectTypeVmParams
|
|||
import com.anytypeio.anytype.feature_object_type.ui.TypeEvent
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiErrorState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiIconsPickerState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.create.SetTypeTitlesAndIconScreen
|
||||
import com.anytypeio.anytype.feature_object_type.ui.icons.ChangeIconScreen
|
||||
import com.anytypeio.anytype.feature_object_type.viewmodel.ObjectTypeVMFactory
|
||||
import com.anytypeio.anytype.feature_object_type.viewmodel.ObjectTypeViewModel
|
||||
|
@ -60,6 +61,7 @@ class ObjectTypeFragment : BaseComposeFragment() {
|
|||
) = content {
|
||||
MaterialTheme {
|
||||
ObjectTypeScreen()
|
||||
IconAndTitleUpdateScreen()
|
||||
IconsPickerScreen()
|
||||
ErrorScreen()
|
||||
}
|
||||
|
@ -216,6 +218,16 @@ class ObjectTypeFragment : BaseComposeFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun IconAndTitleUpdateScreen() {
|
||||
SetTypeTitlesAndIconScreen(
|
||||
uiState = vm.uiTitleAndIconUpdateState.collectAsStateWithLifecycle().value,
|
||||
onDismiss = vm::onDismissTitleAndIconScreen,
|
||||
onIconClicked = vm::onIconClickedTitleAndIconScreen,
|
||||
onButtonClicked = vm::onButtonClickedTitleAndIconScreen
|
||||
)
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
val params = ObjectTypeVmParams(
|
||||
spaceId = SpaceId(space),
|
||||
|
|
|
@ -20,6 +20,7 @@ sealed class TypeEvent {
|
|||
//region Object Type Header
|
||||
data object OnObjectTypeIconClick : TypeEvent()
|
||||
data class OnObjectTypeTitleUpdate(val title: String) : TypeEvent()
|
||||
data object OnObjectTypeTitleClick : TypeEvent()
|
||||
//endregion
|
||||
|
||||
//region Templates
|
||||
|
|
|
@ -43,9 +43,9 @@ data class UiTitleState(val title: String, val isEditable: Boolean) {
|
|||
}
|
||||
}
|
||||
|
||||
data class UiIconState(val icon: ObjectIcon, val isEditable: Boolean) {
|
||||
data class UiIconState(val icon: ObjectIcon.TypeIcon, val isEditable: Boolean) {
|
||||
companion object {
|
||||
val EMPTY = UiIconState(icon = ObjectIcon.None, isEditable = false)
|
||||
val EMPTY = UiIconState(icon = ObjectIcon.TypeIcon.Default.DEFAULT, isEditable = false)
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
|
|
@ -21,6 +21,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
|||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
@ -59,13 +60,13 @@ import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
|
|||
fun SetTypeTitlesAndIconScreen(
|
||||
uiState: UiTypeSetupTitleAndIconState,
|
||||
modifier: Modifier = Modifier,
|
||||
onTitleChanged: (String) -> Unit,
|
||||
onPluralChanged: (String) -> Unit,
|
||||
onIconClicked: () -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
onButtonClicked: () -> Unit
|
||||
onButtonClicked: (String, String) -> Unit
|
||||
) {
|
||||
|
||||
if (uiState !is UiTypeSetupTitleAndIconState.Visible) return
|
||||
|
||||
val bottomSheetState = rememberModalBottomSheetState(
|
||||
skipPartiallyExpanded = true
|
||||
)
|
||||
|
@ -89,8 +90,6 @@ fun SetTypeTitlesAndIconScreen(
|
|||
) {
|
||||
CreateNewTypeScreenContent(
|
||||
uiState = uiState,
|
||||
onTitleChanged = onTitleChanged,
|
||||
onPluralChanged = onPluralChanged,
|
||||
onIconClicked = onIconClicked,
|
||||
onButtonClicked = onButtonClicked
|
||||
)
|
||||
|
@ -99,15 +98,22 @@ fun SetTypeTitlesAndIconScreen(
|
|||
|
||||
@Composable
|
||||
private fun ColumnScope.CreateNewTypeScreenContent(
|
||||
uiState: UiTypeSetupTitleAndIconState,
|
||||
onTitleChanged: (String) -> Unit,
|
||||
onPluralChanged: (String) -> Unit,
|
||||
uiState: UiTypeSetupTitleAndIconState.Visible,
|
||||
onIconClicked: () -> Unit,
|
||||
onButtonClicked: () -> Unit
|
||||
onButtonClicked: (String, String) -> Unit
|
||||
) {
|
||||
|
||||
var isButtonEnabled by remember {
|
||||
mutableStateOf(false)
|
||||
// Maintain individual state for each field's "not empty" condition.
|
||||
var isTitleNotEmpty by remember { mutableStateOf(false) }
|
||||
var isPluralNotEmpty by remember { mutableStateOf(false) }
|
||||
var titleText by remember { mutableStateOf(uiState.getInitialTitleValue()) }
|
||||
var pluralText by remember { mutableStateOf(uiState.getInitialPluralValue()) }
|
||||
// Compute the button enabled state.
|
||||
val isButtonEnabled = isTitleNotEmpty && isPluralNotEmpty
|
||||
|
||||
val icon = when(uiState) {
|
||||
is UiTypeSetupTitleAndIconState.Visible.CreateNewType -> uiState.icon
|
||||
is UiTypeSetupTitleAndIconState.Visible.EditType -> uiState.icon
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
@ -139,7 +145,7 @@ private fun ColumnScope.CreateNewTypeScreenContent(
|
|||
onIconClicked()
|
||||
},
|
||||
iconSize = 48.dp,
|
||||
icon = uiState.icon,
|
||||
icon = icon,
|
||||
backgroundColor = R.color.amp_transparent
|
||||
)
|
||||
Spacer(modifier = Modifier.width(0.dp))
|
||||
|
@ -149,9 +155,12 @@ private fun ColumnScope.CreateNewTypeScreenContent(
|
|||
.padding(top = 11.5.dp)
|
||||
.wrapContentHeight(),
|
||||
hint = uiState.getTitleHint(),
|
||||
initialValue = uiState.getInitialTitleValue(),
|
||||
onTextChanged = {
|
||||
onTitleChanged(it)
|
||||
isButtonEnabled = it.isNotEmpty()
|
||||
titleText = it
|
||||
},
|
||||
onButtonEnabled = { enable ->
|
||||
isTitleNotEmpty = enable
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -183,8 +192,14 @@ private fun ColumnScope.CreateNewTypeScreenContent(
|
|||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
hint = uiState.getPluralHint(),
|
||||
initialValue = uiState.getInitialPluralValue(),
|
||||
textStyle = BodyRegular,
|
||||
onTextChanged = onPluralChanged
|
||||
onTextChanged = {
|
||||
pluralText = it
|
||||
},
|
||||
onButtonEnabled = { enable ->
|
||||
isPluralNotEmpty = enable
|
||||
}
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(22.dp))
|
||||
|
@ -194,7 +209,7 @@ private fun ColumnScope.CreateNewTypeScreenContent(
|
|||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp),
|
||||
onClick = {
|
||||
onButtonClicked()
|
||||
onButtonClicked(titleText, pluralText)
|
||||
},
|
||||
enabled = isButtonEnabled,
|
||||
text = uiState.getButtonTitle(),
|
||||
|
@ -206,17 +221,23 @@ private fun ColumnScope.CreateNewTypeScreenContent(
|
|||
@Composable
|
||||
private fun CreateTypeField(
|
||||
modifier: Modifier,
|
||||
initialValue: String = "",
|
||||
textStyle: androidx.compose.ui.text.TextStyle = HeadlineHeading,
|
||||
hint: String,
|
||||
onButtonEnabled: (Boolean) -> Unit = {},
|
||||
onTextChanged: (String) -> Unit
|
||||
) {
|
||||
|
||||
var textFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
|
||||
mutableStateOf(
|
||||
TextFieldValue("")
|
||||
TextFieldValue(initialValue)
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(textFieldValue) {
|
||||
onButtonEnabled(textFieldValue.text.isNotEmpty())
|
||||
}
|
||||
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
@ -261,35 +282,49 @@ private fun CreateTypeField(
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UiTypeSetupTitleAndIconState.getTitleHint(): String {
|
||||
fun UiTypeSetupTitleAndIconState.Visible.getInitialTitleValue(): String {
|
||||
return when (this) {
|
||||
is UiTypeSetupTitleAndIconState.CreateNewType -> stringResource(id = R.string.object_type_create_title_hint)
|
||||
is UiTypeSetupTitleAndIconState.EditType -> stringResource(id = R.string.untitled)
|
||||
is UiTypeSetupTitleAndIconState.Visible.CreateNewType -> ""
|
||||
is UiTypeSetupTitleAndIconState.Visible.EditType -> this.initialTitle ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
fun UiTypeSetupTitleAndIconState.Visible.getInitialPluralValue(): String {
|
||||
return when (this) {
|
||||
is UiTypeSetupTitleAndIconState.Visible.CreateNewType -> ""
|
||||
is UiTypeSetupTitleAndIconState.Visible.EditType -> this.initialPlural ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UiTypeSetupTitleAndIconState.getPluralHint(): String {
|
||||
fun UiTypeSetupTitleAndIconState.Visible.getTitleHint(): String {
|
||||
return when (this) {
|
||||
is UiTypeSetupTitleAndIconState.CreateNewType -> stringResource(id = R.string.object_type_create_plural_title_hint)
|
||||
is UiTypeSetupTitleAndIconState.EditType -> stringResource(id = R.string.untitled)
|
||||
is UiTypeSetupTitleAndIconState.Visible.CreateNewType -> stringResource(id = R.string.object_type_create_title_hint)
|
||||
is UiTypeSetupTitleAndIconState.Visible.EditType -> stringResource(id = R.string.untitled)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UiTypeSetupTitleAndIconState.getTitle(): String {
|
||||
fun UiTypeSetupTitleAndIconState.Visible.getPluralHint(): String {
|
||||
return when (this) {
|
||||
is UiTypeSetupTitleAndIconState.CreateNewType -> stringResource(id = R.string.object_type_create_new_title)
|
||||
is UiTypeSetupTitleAndIconState.EditType -> stringResource(id = R.string.object_type_rename_title)
|
||||
is UiTypeSetupTitleAndIconState.Visible.CreateNewType -> stringResource(id = R.string.object_type_create_plural_title_hint)
|
||||
is UiTypeSetupTitleAndIconState.Visible.EditType -> stringResource(id = R.string.untitled)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UiTypeSetupTitleAndIconState.getButtonTitle(): String {
|
||||
fun UiTypeSetupTitleAndIconState.Visible.getTitle(): String {
|
||||
return when (this) {
|
||||
is UiTypeSetupTitleAndIconState.CreateNewType -> stringResource(id = R.string.create)
|
||||
is UiTypeSetupTitleAndIconState.EditType -> stringResource(id = R.string.done)
|
||||
is UiTypeSetupTitleAndIconState.Visible.CreateNewType -> stringResource(id = R.string.object_type_create_new_title)
|
||||
is UiTypeSetupTitleAndIconState.Visible.EditType -> stringResource(id = R.string.object_type_rename_title)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UiTypeSetupTitleAndIconState.Visible.getButtonTitle(): String {
|
||||
return when (this) {
|
||||
is UiTypeSetupTitleAndIconState.Visible.CreateNewType -> stringResource(id = R.string.create)
|
||||
is UiTypeSetupTitleAndIconState.Visible.EditType -> stringResource(id = R.string.done)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -298,16 +333,14 @@ fun UiTypeSetupTitleAndIconState.getButtonTitle(): String {
|
|||
fun CreateNewTypeScreenPreview() {
|
||||
Column {
|
||||
CreateNewTypeScreenContent(
|
||||
uiState = UiTypeSetupTitleAndIconState.CreateNewType(
|
||||
uiState = UiTypeSetupTitleAndIconState.Visible.CreateNewType(
|
||||
icon = ObjectIcon.TypeIcon.Default(
|
||||
rawValue = "american-football",
|
||||
color = CustomIconColor.Red
|
||||
)
|
||||
),
|
||||
onTitleChanged = {},
|
||||
onPluralChanged = {},
|
||||
onIconClicked = { /* no-op */ },
|
||||
onButtonClicked = { /* no-op */ }
|
||||
onButtonClicked = { _, _ -> }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -317,16 +350,16 @@ fun CreateNewTypeScreenPreview() {
|
|||
fun EditTypeScreenPreview() {
|
||||
Column {
|
||||
CreateNewTypeScreenContent(
|
||||
uiState = UiTypeSetupTitleAndIconState.EditType(
|
||||
uiState = UiTypeSetupTitleAndIconState.Visible.EditType(
|
||||
icon = ObjectIcon.TypeIcon.Default(
|
||||
rawValue = "american-football",
|
||||
color = CustomIconColor.Red
|
||||
)
|
||||
),
|
||||
initialTitle = "Page",
|
||||
initialPlural = "Pages"
|
||||
),
|
||||
onTitleChanged = {},
|
||||
onPluralChanged = {},
|
||||
onIconClicked = { /* no-op */ },
|
||||
onButtonClicked = { /* no-op */ }
|
||||
onButtonClicked = { _, _ -> }
|
||||
)
|
||||
}
|
||||
}
|
|
@ -4,17 +4,20 @@ import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
|||
|
||||
sealed class UiTypeSetupTitleAndIconState {
|
||||
|
||||
abstract val icon: ObjectIcon.TypeIcon.Default
|
||||
data object Hidden : UiTypeSetupTitleAndIconState()
|
||||
|
||||
data class CreateNewType(
|
||||
override val icon: ObjectIcon.TypeIcon.Default,
|
||||
val initialTitle: String = "",
|
||||
val initialPlural: String = ""
|
||||
) : UiTypeSetupTitleAndIconState()
|
||||
sealed class Visible : UiTypeSetupTitleAndIconState() {
|
||||
|
||||
data class EditType(
|
||||
override val icon: ObjectIcon.TypeIcon.Default,
|
||||
val initialTitle: String = "",
|
||||
val initialPlural: String = ""
|
||||
) : UiTypeSetupTitleAndIconState()
|
||||
data class CreateNewType(
|
||||
val icon: ObjectIcon.TypeIcon.Default,
|
||||
val initialTitle: String = "",
|
||||
val initialPlural: String = ""
|
||||
) : Visible()
|
||||
|
||||
data class EditType(
|
||||
val icon: ObjectIcon.TypeIcon,
|
||||
val initialTitle: String?,
|
||||
val initialPlural: String?
|
||||
) : Visible()
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.anytypeio.anytype.feature_object_type.ui.header
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
@ -65,7 +66,6 @@ fun IconAndTitleWidget(
|
|||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
initialName = uiTitleState.title,
|
||||
enabled = uiTitleState.isEditable,
|
||||
onTypeEvent = onTypeEvent,
|
||||
)
|
||||
}
|
||||
|
@ -75,68 +75,21 @@ fun IconAndTitleWidget(
|
|||
fun NameField(
|
||||
modifier: Modifier,
|
||||
initialName: String,
|
||||
enabled: Boolean,
|
||||
onTypeEvent: (TypeEvent) -> Unit
|
||||
) {
|
||||
|
||||
var textFieldValue by rememberSaveable(stateSaver = TextFieldValue.Saver) {
|
||||
mutableStateOf(
|
||||
TextFieldValue(initialName)
|
||||
)
|
||||
val (text, color) = if (initialName.isEmpty()) {
|
||||
stringResource(R.string.untitled) to colorResource(id = R.color.text_tertiary)
|
||||
} else {
|
||||
initialName to colorResource(id = R.color.text_primary)
|
||||
}
|
||||
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val keyboardController = LocalSoftwareKeyboardController.current
|
||||
|
||||
BasicTextField(
|
||||
value = textFieldValue,
|
||||
onValueChange = { newValue ->
|
||||
textFieldValue = newValue
|
||||
onTypeEvent.invoke(
|
||||
TypeEvent.OnObjectTypeTitleUpdate(
|
||||
title = textFieldValue.text
|
||||
)
|
||||
)
|
||||
},
|
||||
textStyle = HeadlineTitle.copy(color = colorResource(id = R.color.text_primary)),
|
||||
singleLine = false,
|
||||
enabled = enabled,
|
||||
cursorBrush = SolidColor(colorResource(id = R.color.text_primary)),
|
||||
Text(
|
||||
text = text,
|
||||
style = HeadlineTitle.copy(color = color),
|
||||
modifier = modifier
|
||||
.padding(start = 12.dp, end = 20.dp)
|
||||
.focusRequester(focusRequester),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = KeyboardActions {
|
||||
keyboardController?.hide()
|
||||
focusManager.clearFocus()
|
||||
onTypeEvent.invoke(
|
||||
TypeEvent.OnObjectTypeTitleUpdate(
|
||||
title = textFieldValue.text
|
||||
)
|
||||
)
|
||||
},
|
||||
decorationBox = { innerTextField ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(32.dp),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
if (textFieldValue.text.isEmpty()) {
|
||||
Text(
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
text = stringResource(id = R.string.untitled),
|
||||
style = HeadlineTitle,
|
||||
color = colorResource(id = R.color.text_tertiary),
|
||||
)
|
||||
}
|
||||
.noRippleThrottledClickable {
|
||||
onTypeEvent(TypeEvent.OnObjectTypeTitleClick)
|
||||
}
|
||||
innerTextField()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -148,7 +101,7 @@ fun IconAndTitleWidgetPreview() {
|
|||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
onTypeEvent = {},
|
||||
uiIconState = UiIconState(icon = ObjectIcon.Task(isChecked = false), isEditable = true),
|
||||
uiIconState = UiIconState(icon = ObjectIcon.TypeIcon.Default.DEFAULT, isEditable = true),
|
||||
uiTitleState = UiTitleState(
|
||||
title = "I understand that contributing to this repository will require me to agree with the",
|
||||
isEditable = true
|
||||
|
@ -164,7 +117,7 @@ fun IconAndTitleEmptyWidgetPreview() {
|
|||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
onTypeEvent = {},
|
||||
uiIconState = UiIconState(icon = ObjectIcon.Task(isChecked = false), isEditable = true),
|
||||
uiIconState = UiIconState(icon = ObjectIcon.TypeIcon.Default.DEFAULT, isEditable = true),
|
||||
uiTitleState = UiTitleState(
|
||||
title = "",
|
||||
isEditable = true
|
||||
|
|
|
@ -31,18 +31,11 @@ class CreateObjectTypeViewModel(
|
|||
private val analyticSpaceHelperDelegate: AnalyticSpaceHelperDelegate
|
||||
) : ViewModel(), AnalyticSpaceHelperDelegate by analyticSpaceHelperDelegate {
|
||||
|
||||
private val INIT =
|
||||
when (vmParams.mode) {
|
||||
MODE.CREATE -> UiTypeSetupTitleAndIconState.CreateNewType(
|
||||
icon = ObjectIcon.TypeIcon.Default.DEFAULT
|
||||
)
|
||||
|
||||
MODE.EDIT -> UiTypeSetupTitleAndIconState.EditType(
|
||||
icon = ObjectIcon.TypeIcon.Default.DEFAULT
|
||||
)
|
||||
}
|
||||
|
||||
private val _uiState = MutableStateFlow<UiTypeSetupTitleAndIconState>(INIT)
|
||||
private val _uiState = MutableStateFlow<UiTypeSetupTitleAndIconState>(
|
||||
UiTypeSetupTitleAndIconState.Visible.CreateNewType(
|
||||
icon = ObjectIcon.TypeIcon.Default.DEFAULT
|
||||
)
|
||||
)
|
||||
val uiState = _uiState.asStateFlow()
|
||||
|
||||
//icons picker screen
|
||||
|
@ -50,21 +43,10 @@ class CreateObjectTypeViewModel(
|
|||
|
||||
val commands = MutableSharedFlow<CreateTypeCommand>(replay = 0)
|
||||
|
||||
private val typeTitle = MutableStateFlow("")
|
||||
private val typePlural = MutableStateFlow("")
|
||||
|
||||
init {
|
||||
Timber.d("CreateObjectTypeViewModel initialized")
|
||||
}
|
||||
|
||||
fun onTypeTitleChanged(title: String) {
|
||||
typeTitle.value = title
|
||||
}
|
||||
|
||||
fun onTypePluralChanged(plural: String) {
|
||||
typePlural.value = plural
|
||||
}
|
||||
|
||||
fun onDismiss() {
|
||||
viewModelScope.launch {
|
||||
commands.emit(CreateTypeCommand.Dismiss)
|
||||
|
@ -72,23 +54,20 @@ class CreateObjectTypeViewModel(
|
|||
}
|
||||
|
||||
fun onRemoveIcon() {
|
||||
val defaultIcon = ObjectIcon.TypeIcon.Default.DEFAULT
|
||||
_uiState.value = when (val currentState = _uiState.value) {
|
||||
is UiTypeSetupTitleAndIconState.CreateNewType -> currentState.copy(icon = defaultIcon)
|
||||
is UiTypeSetupTitleAndIconState.EditType -> currentState.copy(icon = defaultIcon)
|
||||
}
|
||||
val currentState =
|
||||
_uiState.value as? UiTypeSetupTitleAndIconState.Visible.CreateNewType ?: return
|
||||
_uiState.value = currentState.copy(icon = ObjectIcon.TypeIcon.Default.DEFAULT)
|
||||
uiIconsPickerScreen.value = UiIconsPickerState.Hidden
|
||||
}
|
||||
|
||||
fun onNewIconPicked(iconName: String, color: CustomIconColor?) {
|
||||
val currentState =
|
||||
_uiState.value as? UiTypeSetupTitleAndIconState.Visible.CreateNewType ?: return
|
||||
val newIcon = ObjectIcon.TypeIcon.Default(
|
||||
rawValue = iconName,
|
||||
color = color ?: CustomIconColor.DEFAULT
|
||||
)
|
||||
_uiState.value = when (val currentState = _uiState.value) {
|
||||
is UiTypeSetupTitleAndIconState.CreateNewType -> currentState.copy(icon = newIcon)
|
||||
is UiTypeSetupTitleAndIconState.EditType -> currentState.copy(icon = newIcon)
|
||||
}
|
||||
_uiState.value = currentState.copy(icon = newIcon)
|
||||
uiIconsPickerScreen.value = UiIconsPickerState.Hidden
|
||||
}
|
||||
|
||||
|
@ -100,24 +79,20 @@ class CreateObjectTypeViewModel(
|
|||
uiIconsPickerScreen.value = UiIconsPickerState.Hidden
|
||||
}
|
||||
|
||||
fun onButtonClicked() {
|
||||
when (vmParams.mode) {
|
||||
MODE.CREATE -> createNewType()
|
||||
MODE.EDIT -> updateType()
|
||||
}
|
||||
fun onButtonClicked(title: String, plurals: String) {
|
||||
createNewType(title = title, plurals = plurals)
|
||||
}
|
||||
|
||||
private fun createNewType() {
|
||||
val icon = _uiState.value.icon
|
||||
val name = typeTitle.value
|
||||
val plural = typePlural.value
|
||||
Timber.d("Creating new type with name: $name, plural: $plural, icon: $icon")
|
||||
private fun createNewType(title: String, plurals: String) {
|
||||
val state = _uiState.value as? UiTypeSetupTitleAndIconState.Visible.CreateNewType ?: return
|
||||
val icon = state.icon
|
||||
Timber.d("Creating new type with title: $title, plurals: $plurals, icon: $icon")
|
||||
viewModelScope.launch {
|
||||
createObjectType.execute(
|
||||
CreateObjectType.Params(
|
||||
space = vmParams.spaceId,
|
||||
name = name,
|
||||
pluralName = plural,
|
||||
name = title,
|
||||
pluralName = plurals,
|
||||
iconName = icon.rawValue,
|
||||
iconColor = icon.color.iconOption.toDouble()
|
||||
)
|
||||
|
@ -149,26 +124,12 @@ class CreateObjectTypeViewModel(
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
private fun updateType() {
|
||||
val icon = _uiState.value.icon
|
||||
val name = typeTitle.value
|
||||
val plural = typePlural.value
|
||||
viewModelScope.launch {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class CreateTypeVmParams(
|
||||
val spaceId: Id,
|
||||
val mode: MODE = MODE.CREATE
|
||||
val spaceId: Id
|
||||
)
|
||||
|
||||
enum class MODE {
|
||||
CREATE,
|
||||
EDIT
|
||||
}
|
||||
|
||||
sealed class CreateTypeCommand {
|
||||
data object Dismiss : CreateTypeCommand()
|
||||
data class NavigateToObjectType(val id: Id, val space: Id) : CreateTypeCommand()
|
||||
|
|
|
@ -51,6 +51,7 @@ import com.anytypeio.anytype.feature_object_type.ui.UiTemplatesButtonState
|
|||
import com.anytypeio.anytype.feature_object_type.ui.UiTemplatesModalListState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.UiTitleState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.buildUiPropertiesList
|
||||
import com.anytypeio.anytype.feature_object_type.ui.create.UiTypeSetupTitleAndIconState
|
||||
import com.anytypeio.anytype.feature_object_type.ui.toTemplateView
|
||||
import com.anytypeio.anytype.feature_properties.edit.UiEditPropertyState
|
||||
import com.anytypeio.anytype.feature_properties.edit.UiEditPropertyState.Visible.View
|
||||
|
@ -59,6 +60,7 @@ import com.anytypeio.anytype.presentation.analytics.AnalyticSpaceHelperDelegate
|
|||
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
|
||||
import com.anytypeio.anytype.presentation.extension.sendAnalyticsScreenObjectType
|
||||
import com.anytypeio.anytype.presentation.mapper.objectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.ObjectIcon
|
||||
import com.anytypeio.anytype.presentation.objects.custom_icon.CustomIconColor
|
||||
import com.anytypeio.anytype.presentation.search.ObjectSearchConstants.defaultKeys
|
||||
import com.anytypeio.anytype.presentation.sync.SyncStatusWidgetState
|
||||
|
@ -143,6 +145,10 @@ class ObjectTypeViewModel(
|
|||
//icons picker screen
|
||||
val uiIconsPickerScreen = MutableStateFlow<UiIconsPickerState>(UiIconsPickerState.Hidden)
|
||||
|
||||
//title and icon update screen
|
||||
val uiTitleAndIconUpdateState =
|
||||
MutableStateFlow<UiTypeSetupTitleAndIconState>(UiTypeSetupTitleAndIconState.Hidden)
|
||||
|
||||
//error
|
||||
val errorState = MutableStateFlow<UiErrorState>(UiErrorState.Hidden)
|
||||
//endregion
|
||||
|
@ -315,13 +321,17 @@ class ObjectTypeViewModel(
|
|||
_objectTypePermissionsState.value = objectPermissions
|
||||
|
||||
uiTitleState.value = UiTitleState(
|
||||
title = fieldParser.getObjectPluralName(objectWrapper = objType),
|
||||
title = objType.pluralName.orEmpty(),
|
||||
isEditable = objectPermissions.canEditDetails
|
||||
)
|
||||
val newIcon = objType.objectIcon()
|
||||
uiIconState.value = UiIconState(
|
||||
icon = objType.objectIcon(),
|
||||
icon = newIcon,
|
||||
isEditable = objectPermissions.canEditDetails
|
||||
)
|
||||
(uiTitleAndIconUpdateState.value as? UiTypeSetupTitleAndIconState.Visible.EditType)?.let {
|
||||
uiTitleAndIconUpdateState.value = it.copy(icon = newIcon)
|
||||
}
|
||||
if (objectPermissions.canDelete) {
|
||||
uiEditButtonState.value = UiEditButton.Visible
|
||||
}
|
||||
|
@ -395,31 +405,32 @@ class ObjectTypeViewModel(
|
|||
val formatName = stringResourceProvider.getPropertiesFormatPrettyString(item.format)
|
||||
val formatIcon = item.format.simpleIcon()
|
||||
|
||||
uiEditPropertyScreen.value = if (permissions?.participantCanEdit == true && item.isEditableField) {
|
||||
UiEditPropertyState.Visible.Edit(
|
||||
id = item.id,
|
||||
key = item.fieldKey,
|
||||
name = item.fieldTitle,
|
||||
formatName = formatName,
|
||||
formatIcon = formatIcon,
|
||||
format = item.format,
|
||||
limitObjectTypes = computedLimitTypes,
|
||||
isPossibleToUnlinkFromType = item.isPossibleToUnlinkFromType,
|
||||
showLimitTypes = false
|
||||
)
|
||||
} else {
|
||||
UiEditPropertyState.Visible.View(
|
||||
id = item.id,
|
||||
key = item.fieldKey,
|
||||
name = item.fieldTitle,
|
||||
formatName = formatName,
|
||||
formatIcon = formatIcon,
|
||||
format = item.format,
|
||||
limitObjectTypes = computedLimitTypes,
|
||||
isPossibleToUnlinkFromType = item.isPossibleToUnlinkFromType,
|
||||
showLimitTypes = false
|
||||
)
|
||||
}
|
||||
uiEditPropertyScreen.value =
|
||||
if (permissions?.participantCanEdit == true && item.isEditableField) {
|
||||
UiEditPropertyState.Visible.Edit(
|
||||
id = item.id,
|
||||
key = item.fieldKey,
|
||||
name = item.fieldTitle,
|
||||
formatName = formatName,
|
||||
formatIcon = formatIcon,
|
||||
format = item.format,
|
||||
limitObjectTypes = computedLimitTypes,
|
||||
isPossibleToUnlinkFromType = item.isPossibleToUnlinkFromType,
|
||||
showLimitTypes = false
|
||||
)
|
||||
} else {
|
||||
UiEditPropertyState.Visible.View(
|
||||
id = item.id,
|
||||
key = item.fieldKey,
|
||||
name = item.fieldTitle,
|
||||
formatName = formatName,
|
||||
formatIcon = formatIcon,
|
||||
format = item.format,
|
||||
limitObjectTypes = computedLimitTypes,
|
||||
isPossibleToUnlinkFromType = item.isPossibleToUnlinkFromType,
|
||||
showLimitTypes = false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
@ -472,6 +483,10 @@ class ObjectTypeViewModel(
|
|||
updateTitle(event.title)
|
||||
}
|
||||
|
||||
is TypeEvent.OnObjectTypeTitleClick -> {
|
||||
showTitleAndIconUpdateScreen()
|
||||
}
|
||||
|
||||
TypeEvent.OnMenuItemDeleteClick -> {
|
||||
uiAlertState.value = UiDeleteAlertState.Show
|
||||
}
|
||||
|
@ -865,6 +880,7 @@ class ObjectTypeViewModel(
|
|||
else -> state
|
||||
}
|
||||
}
|
||||
|
||||
FieldEvent.EditProperty.OnLimitTypesDismiss -> {
|
||||
uiEditPropertyScreen.value = when (val state = uiEditPropertyScreen.value) {
|
||||
is UiEditPropertyState.Visible.Edit -> state.copy(showLimitTypes = false)
|
||||
|
@ -1034,6 +1050,57 @@ class ObjectTypeViewModel(
|
|||
}
|
||||
//endregion
|
||||
|
||||
//region Title and Icon Update Screen
|
||||
|
||||
private fun showTitleAndIconUpdateScreen() {
|
||||
val objType = _objTypeState.value ?: return
|
||||
val initialIcon = uiIconState.value.icon
|
||||
val initialTitle = objType.name
|
||||
val initialPlural = objType.pluralName
|
||||
Timber.d(
|
||||
"showTitleAndIconUpdateScreen, initialIcon: $initialIcon, " +
|
||||
"initialTitle: $initialTitle, initialPlural: $initialPlural"
|
||||
)
|
||||
uiTitleAndIconUpdateState.value = UiTypeSetupTitleAndIconState.Visible.EditType(
|
||||
icon = initialIcon,
|
||||
initialTitle = initialTitle,
|
||||
initialPlural = initialPlural
|
||||
)
|
||||
}
|
||||
|
||||
fun onDismissTitleAndIconScreen() {
|
||||
uiTitleAndIconUpdateState.value = UiTypeSetupTitleAndIconState.Hidden
|
||||
}
|
||||
|
||||
fun onIconClickedTitleAndIconScreen() {
|
||||
uiIconsPickerScreen.value = UiIconsPickerState.Visible
|
||||
}
|
||||
|
||||
fun onButtonClickedTitleAndIconScreen(title: String, plurals: String) {
|
||||
val objType = _objTypeState.value ?: return
|
||||
Timber.d("onButtonClickedTitleAndIconScreen, title: $title, plural: $plurals")
|
||||
val params = SetObjectDetails.Params(
|
||||
ctx = objType.id,
|
||||
details = mapOf(
|
||||
Relations.NAME to title,
|
||||
Relations.PLURAL_NAME to plurals
|
||||
)
|
||||
)
|
||||
viewModelScope.launch {
|
||||
setObjectDetails.async(params).fold(
|
||||
onSuccess = {
|
||||
Timber.d("Object type title updated")
|
||||
uiTitleAndIconUpdateState.value = UiTypeSetupTitleAndIconState.Hidden
|
||||
},
|
||||
onFailure = {
|
||||
Timber.e(it, "Error while updating object type title")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//endregion
|
||||
|
||||
companion object {
|
||||
const val TEMPLATE_MAX_COUNT = 100
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue