Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
217 changes: 105 additions & 112 deletions app/src/main/java/dev/dimension/flare/ui/screen/home/GroupConfigScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,8 @@ import dev.dimension.flare.R
import dev.dimension.flare.data.model.IconType
import dev.dimension.flare.data.model.MixedTimelineTabItem
import dev.dimension.flare.data.model.TabItem
import dev.dimension.flare.data.model.TabMetaData
import dev.dimension.flare.data.model.TimelineTabItem
import dev.dimension.flare.data.model.TitleType
import dev.dimension.flare.data.repository.SettingsRepository
import dev.dimension.flare.model.AccountType
import dev.dimension.flare.ui.component.BackButton
import dev.dimension.flare.ui.component.FAIcon
Expand All @@ -63,16 +61,15 @@ import dev.dimension.flare.ui.component.FlareScaffold
import dev.dimension.flare.ui.component.TabIcon
import dev.dimension.flare.ui.presenter.invoke
import dev.dimension.flare.ui.screen.settings.AllTabsPresenter
import dev.dimension.flare.ui.screen.settings.EditTabDialog
import dev.dimension.flare.ui.screen.settings.TabAddBottomSheet
import dev.dimension.flare.ui.screen.settings.TabCustomItem
import dev.dimension.flare.ui.theme.screenHorizontalPadding
import dev.dimension.flare.ui.theme.segmentedShapes2
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import moe.tlaster.precompose.molecule.producePresenter
import org.koin.compose.koinInject
import sh.calvin.reorderable.rememberReorderableLazyListState
import dev.dimension.flare.ui.presenter.home.GroupConfigPresenter as SharedGroupConfigPresenter

@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
Expand All @@ -90,6 +87,20 @@ internal fun GroupConfigScreen(
state.commit()
}
}
state.selectedEditTab?.let {
EditTabDialog(
tabItem = it,
onDismissRequest = {
state.setEditTab(null)
},
onConfirm = { updatedTab ->
state.setEditTab(null)
if (updatedTab is TimelineTabItem) {
state.updateTab(updatedTab)
}
},
)
}

FlareScaffold(
topBar = {
Expand Down Expand Up @@ -167,14 +178,14 @@ internal fun GroupConfigScreen(
elevation = CardDefaults.elevatedCardElevation(defaultElevation = 3.dp),
) {
LazyVerticalGrid(columns = GridCells.FixedSize(48.dp)) {
items(state.availableIcons) { icon ->
items(state.availableIcons) { selectedIcon ->
TabIcon(
accountType = AccountType.Guest,
icon = icon,
icon = selectedIcon,
title = TitleType.Text(state.name.text.toString()),
modifier =
Modifier.padding(4.dp).clickable {
state.setIcon(icon)
state.setIcon(selectedIcon)
state.setShowIconPicker(false)
},
size = 48.dp,
Expand Down Expand Up @@ -225,12 +236,14 @@ internal fun GroupConfigScreen(
item = item,
shapes = ListItemDefaults.segmentedShapes2(index, state.tabs.size),
deleteTab = { state.deleteTab(item) },
// Child tabs in a group are intentionally not editable from this screen;
// only group-level configuration is supported.
editTab = { },
editTab = {
if (it is TimelineTabItem) {
state.setEditTab(it)
}
},
reorderableLazyColumnState = reorderableLazyColumnState,
canSwipeToDelete = true,
isEditing = false,
isEditing = state.selectedEditTab == item,
)
}
}
Expand All @@ -246,128 +259,108 @@ internal fun GroupConfigScreen(
state.addTab(tabItem)
}
},
onDeleteTab = { key -> state.deleteTab(key) },
onDeleteTab = state::deleteTab,
toAddRssSource = toAddRssSource,
)
}
}

@Composable
private fun GroupConfigPresenter(
initialItem: MixedTimelineTabItem?,
repository: SettingsRepository = koinInject(),
appScope: CoroutineScope = koinInject(),
) = run {
val name =
rememberTextFieldState(
initialItem?.metaData?.title?.let {
when (it) {
is TitleType.Text -> it.content
is TitleType.Localized -> "" // Or resolve string resource if possible
private fun GroupConfigPresenter(initialItem: MixedTimelineTabItem?) =
run {
val sharedState = remember { SharedGroupConfigPresenter() }.invoke()
val name =
rememberTextFieldState(
initialItem?.metaData?.title?.let {
when (it) {
is TitleType.Text -> it.content
is TitleType.Localized -> ""
}
} ?: "",
)
var icon by remember(initialItem) {
mutableStateOf<IconType>(initialItem?.metaData?.icon ?: IconType.Material(dev.dimension.flare.ui.model.UiIcon.Rss))
}
val tabs =
remember(initialItem) {
mutableStateListOf<TimelineTabItem>().apply {
initialItem
?.subTimelineTabItem
?.distinctBy { it.key }
?.let(::addAll)
}
} ?: "",
)

var icon by remember {
mutableStateOf<IconType>(initialItem?.metaData?.icon ?: IconType.Material(dev.dimension.flare.ui.model.UiIcon.Rss))
}

val tabs =
remember {
mutableStateListOf<TimelineTabItem>().apply {
initialItem?.subTimelineTabItem?.let { addAll(it) }
}
}

var showAddTab by remember { mutableStateOf(false) }
var showIconPicker by remember { mutableStateOf(false) }
val allTabs = remember { AllTabsPresenter(filterIsTimeline = true) }.invoke()
var showAddTab by remember { mutableStateOf(false) }
var showIconPicker by remember { mutableStateOf(false) }
var selectedEditTab by remember { mutableStateOf<TimelineTabItem?>(null) }
val allTabs = remember { AllTabsPresenter(filterIsTimeline = true) }.invoke()

object {
val name = name
val icon = icon
val tabs = tabs
val showAddTab = showAddTab
val showIconPicker = showIconPicker
val allTabs = allTabs
val availableIcons =
dev.dimension.flare.ui.model.UiIcon.entries
.map { IconType.Material(it) }
object {
val name = name
val icon = icon
val tabs = tabs
val showAddTab = showAddTab
val showIconPicker = showIconPicker
val selectedEditTab = selectedEditTab
val allTabs = allTabs
val availableIcons = sharedState.availableIcons

fun setIcon(newIcon: IconType) {
icon = newIcon
}
fun setIcon(value: IconType) {
icon = value
}

fun setShowIconPicker(show: Boolean) {
showIconPicker = show
}
fun setAddTab(show: Boolean) {
showAddTab = show
}

fun setAddTab(show: Boolean) {
showAddTab = show
}
fun setShowIconPicker(show: Boolean) {
showIconPicker = show
}

fun addTab(tab: TimelineTabItem) {
if (tabs.none { it.key == tab.key }) {
tabs.add(tab)
fun setEditTab(tab: TimelineTabItem?) {
selectedEditTab = tab
}
}

fun deleteTab(tab: TabItem) {
tabs.removeIf { it.key == tab.key }
}
fun addTab(tab: TimelineTabItem) {
if (tabs.none { it.key == tab.key }) {
tabs.add(tab)
}
}

fun deleteTab(key: String) {
tabs.removeIf { it.key == key }
}
fun deleteTab(tab: TabItem) {
tabs.removeIf { it.key == tab.key }
}

fun moveTab(
from: Any,
to: Any,
) {
val fromIndex = tabs.indexOfFirst { it.key == from }
val toIndex = tabs.indexOfFirst { it.key == to }
if (fromIndex != -1 && toIndex != -1) {
tabs.add(toIndex, tabs.removeAt(fromIndex))
fun deleteTab(key: String) {
tabs.removeIf { it.key == key }
}
}

fun commit() {
appScope.launch {
if (tabs.isEmpty()) {
if (initialItem != null) {
repository.updateTabSettings {
val currentTabs = mainTabs.toMutableList()
currentTabs.removeIf { it.key == initialItem.key }
copy(mainTabs = currentTabs)
}
}
return@launch
fun updateTab(tab: TimelineTabItem) {
val index = tabs.indexOfFirst { it.key == tab.key }
if (index != -1) {
tabs[index] = tab
}
val newGroup =
MixedTimelineTabItem(
subTimelineTabItem = tabs.toList(),
metaData =
TabMetaData(
title = TitleType.Text(name.text.toString().ifEmpty { "Group" }),
icon = icon,
),
)
}

repository.updateTabSettings {
val currentTabs = mainTabs.toMutableList()
if (initialItem != null) {
// Edit existing
val index = currentTabs.indexOfFirst { it.key == initialItem.key }
if (index != -1) {
currentTabs[index] = newGroup
}
} else {
// Create new
currentTabs.add(newGroup)
}
copy(mainTabs = currentTabs)
fun moveTab(
from: Any,
to: Any,
) {
val fromIndex = tabs.indexOfFirst { it.key == from }
val toIndex = tabs.indexOfFirst { it.key == to }
if (fromIndex != -1 && toIndex != -1) {
tabs.add(toIndex, tabs.removeAt(fromIndex))
}
}

fun commit() {
sharedState.commit(
initialItem = initialItem,
name = name.text.toString(),
icon = icon,
tabs = tabs.toList(),
defaultGroupName = "Group",
)
}
}
}
}
Loading
Loading