Skip to content

Commit e0d1d5b

Browse files
committed
自动提交
1 parent 49818e6 commit e0d1d5b

File tree

1 file changed

+146
-77
lines changed

1 file changed

+146
-77
lines changed

Monica for Android/app/src/main/java/takagi/ru/monica/ui/SimpleMainScreen.kt

Lines changed: 146 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ import androidx.compose.animation.slideOutVertically
2323
import androidx.compose.ui.graphics.graphicsLayer
2424
import androidx.compose.foundation.ExperimentalFoundationApi
2525
import androidx.compose.foundation.background
26+
import androidx.compose.foundation.border
2627
import androidx.compose.foundation.clickable
2728
import androidx.compose.foundation.combinedClickable
29+
import androidx.compose.foundation.interaction.MutableInteractionSource
2830
import androidx.compose.foundation.gestures.detectVerticalDragGestures
2931
import androidx.compose.ui.input.nestedscroll.nestedScroll
3032
import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress
@@ -2770,6 +2772,8 @@ private fun PasswordListContent(
27702772

27712773
// 堆叠展开状态 - 记录哪些分组已展开
27722774
var expandedGroups by remember { mutableStateOf(setOf<String>()) }
2775+
val outsideTapInteractionSource = remember { MutableInteractionSource() }
2776+
val canCollapseExpandedGroups = effectiveStackCardMode == StackCardMode.AUTO && expandedGroups.isNotEmpty()
27732777

27742778
// 当分组模式改变时,重置展开状态
27752779
LaunchedEffect(effectiveGroupMode, effectiveStackCardMode) {
@@ -3421,7 +3425,17 @@ private fun PasswordListContent(
34213425
}
34223426

34233427
// 密码列表 - 使用堆叠分组视图
3424-
Box(modifier = Modifier.fillMaxSize()) {
3428+
Box(
3429+
modifier = Modifier
3430+
.fillMaxSize()
3431+
.clickable(
3432+
enabled = canCollapseExpandedGroups,
3433+
interactionSource = outsideTapInteractionSource,
3434+
indication = null
3435+
) {
3436+
expandedGroups = emptySet()
3437+
}
3438+
) {
34253439
if (passwordEntries.isEmpty() && searchQuery.isEmpty()) {
34263440
// Empty state with pull-to-search
34273441
Box(
@@ -5876,6 +5890,16 @@ private fun StackedPasswordGroup(
58765890
}
58775891
} else {
58785892
// --- 展开状态的内容 ---
5893+
val edgeInteractionSource = remember { MutableInteractionSource() }
5894+
val edgeContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.52f)
5895+
val edgeBorderColor = MaterialTheme.colorScheme.outline.copy(alpha = 0.45f)
5896+
val edgeHitWidth = 14.dp
5897+
val edgeHitHeight = 12.dp
5898+
val edgeTapModifier = Modifier.clickable(
5899+
interactionSource = edgeInteractionSource,
5900+
indication = null,
5901+
onClick = onToggleExpand
5902+
)
58795903
Column(
58805904
modifier = Modifier.fillMaxWidth()
58815905
) {
@@ -5926,89 +5950,134 @@ private fun StackedPasswordGroup(
59265950
)
59275951

59285952
// 📦 2. 密码列表内容
5929-
Column(
5930-
modifier = Modifier.padding(16.dp),
5931-
verticalArrangement = Arrangement.spacedBy(12.dp)
5953+
Box(
5954+
modifier = Modifier
5955+
.fillMaxWidth()
5956+
.padding(horizontal = 12.dp, vertical = 10.dp)
5957+
.clip(RoundedCornerShape(16.dp))
5958+
.background(edgeContainerColor)
5959+
.border(
5960+
width = 1.dp,
5961+
color = edgeBorderColor,
5962+
shape = RoundedCornerShape(16.dp)
5963+
)
59325964
) {
5933-
val groupedByInfo = passwords.groupBy { getPasswordInfoKey(it) }
5934-
5935-
groupedByInfo.values.forEachIndexed { groupIndex, passwordGroup ->
5936-
// 列表项动画
5937-
val itemEnterDelay = groupIndex * 30
5938-
var isVisible by remember { mutableStateOf(false) }
5939-
LaunchedEffect(Unit) {
5940-
isVisible = true
5941-
}
5965+
Column(
5966+
modifier = Modifier
5967+
.fillMaxWidth()
5968+
.padding(horizontal = edgeHitWidth, vertical = edgeHitHeight),
5969+
verticalArrangement = Arrangement.spacedBy(12.dp)
5970+
) {
5971+
val groupedByInfo = passwords.groupBy { getPasswordInfoKey(it) }
59425972

5943-
AnimatedVisibility(
5944-
visible = isVisible,
5945-
enter = fadeIn(tween(300, delayMillis = itemEnterDelay)) +
5946-
androidx.compose.animation.slideInVertically(
5947-
animationSpec = spring(stiffness = Spring.StiffnessMediumLow),
5948-
initialOffsetY = { 50 }
5949-
),
5950-
modifier = Modifier.fillMaxWidth()
5951-
) {
5952-
takagi.ru.monica.ui.gestures.SwipeActions(
5953-
onSwipeLeft = { onSwipeLeft(passwordGroup.first()) },
5954-
onSwipeRight = { onSwipeRight(passwordGroup.first()) },
5955-
enabled = true
5973+
groupedByInfo.values.forEachIndexed { groupIndex, passwordGroup ->
5974+
// 列表项动画
5975+
val itemEnterDelay = groupIndex * 30
5976+
var isVisible by remember { mutableStateOf(false) }
5977+
LaunchedEffect(Unit) {
5978+
isVisible = true
5979+
}
5980+
5981+
AnimatedVisibility(
5982+
visible = isVisible,
5983+
enter = fadeIn(tween(300, delayMillis = itemEnterDelay)) +
5984+
androidx.compose.animation.slideInVertically(
5985+
animationSpec = spring(stiffness = Spring.StiffnessMediumLow),
5986+
initialOffsetY = { 50 }
5987+
),
5988+
modifier = Modifier.fillMaxWidth()
59565989
) {
5957-
if (passwordGroup.size == 1) {
5958-
val password = passwordGroup.first()
5959-
PasswordEntryCard(
5960-
entry = password,
5961-
onClick = {
5962-
if (isSelectionMode) {
5963-
onToggleSelection(password.id)
5964-
} else {
5965-
onPasswordClick(password)
5966-
}
5967-
},
5968-
onLongClick = { onLongClick(password) },
5969-
onToggleFavorite = { onToggleFavorite(password) },
5970-
onToggleGroupCover = if (passwords.size > 1) {
5971-
{ onToggleGroupCover(password) }
5972-
} else null,
5973-
isSelectionMode = isSelectionMode,
5974-
isSelected = selectedPasswords.contains(password.id),
5975-
canSetGroupCover = passwords.size > 1,
5976-
isInExpandedGroup = true, // We are inside the expanded container
5977-
isSingleCard = false,
5978-
iconCardsEnabled = iconCardsEnabled,
5979-
passwordCardDisplayMode = passwordCardDisplayMode,
5980-
enableSharedBounds = enableSharedBounds
5981-
)
5982-
} else {
5983-
MultiPasswordEntryCard(
5984-
passwords = passwordGroup,
5985-
onClick = { password ->
5986-
if (isSelectionMode) {
5987-
onToggleSelection(password.id)
5988-
} else {
5989-
onPasswordClick(password)
5990-
}
5991-
},
5992-
onCardClick = if (!isSelectionMode) {
5993-
{ onOpenMultiPasswordDialog(passwordGroup) }
5994-
} else null,
5995-
onLongClick = { onLongClick(passwordGroup.first()) },
5996-
onToggleFavorite = { password -> onToggleFavorite(password) },
5997-
onToggleGroupCover = if (passwords.size > 1) {
5998-
{ password -> onToggleGroupCover(password) }
5999-
} else null,
6000-
isSelectionMode = isSelectionMode,
6001-
selectedPasswords = selectedPasswords,
6002-
canSetGroupCover = passwords.size > 1,
6003-
hasGroupCover = hasGroupCover,
6004-
isInExpandedGroup = true, // We are inside the expanded container
6005-
iconCardsEnabled = iconCardsEnabled,
6006-
passwordCardDisplayMode = passwordCardDisplayMode
6007-
)
5990+
takagi.ru.monica.ui.gestures.SwipeActions(
5991+
onSwipeLeft = { onSwipeLeft(passwordGroup.first()) },
5992+
onSwipeRight = { onSwipeRight(passwordGroup.first()) },
5993+
enabled = true
5994+
) {
5995+
if (passwordGroup.size == 1) {
5996+
val password = passwordGroup.first()
5997+
PasswordEntryCard(
5998+
entry = password,
5999+
onClick = {
6000+
if (isSelectionMode) {
6001+
onToggleSelection(password.id)
6002+
} else {
6003+
onPasswordClick(password)
6004+
}
6005+
},
6006+
onLongClick = { onLongClick(password) },
6007+
onToggleFavorite = { onToggleFavorite(password) },
6008+
onToggleGroupCover = if (passwords.size > 1) {
6009+
{ onToggleGroupCover(password) }
6010+
} else null,
6011+
isSelectionMode = isSelectionMode,
6012+
isSelected = selectedPasswords.contains(password.id),
6013+
canSetGroupCover = passwords.size > 1,
6014+
isInExpandedGroup = true, // We are inside the expanded container
6015+
isSingleCard = false,
6016+
iconCardsEnabled = iconCardsEnabled,
6017+
passwordCardDisplayMode = passwordCardDisplayMode,
6018+
enableSharedBounds = enableSharedBounds
6019+
)
6020+
} else {
6021+
MultiPasswordEntryCard(
6022+
passwords = passwordGroup,
6023+
onClick = { password ->
6024+
if (isSelectionMode) {
6025+
onToggleSelection(password.id)
6026+
} else {
6027+
onPasswordClick(password)
6028+
}
6029+
},
6030+
onCardClick = if (!isSelectionMode) {
6031+
{ onOpenMultiPasswordDialog(passwordGroup) }
6032+
} else null,
6033+
onLongClick = { onLongClick(passwordGroup.first()) },
6034+
onToggleFavorite = { password -> onToggleFavorite(password) },
6035+
onToggleGroupCover = if (passwords.size > 1) {
6036+
{ password -> onToggleGroupCover(password) }
6037+
} else null,
6038+
isSelectionMode = isSelectionMode,
6039+
selectedPasswords = selectedPasswords,
6040+
canSetGroupCover = passwords.size > 1,
6041+
hasGroupCover = hasGroupCover,
6042+
isInExpandedGroup = true, // We are inside the expanded container
6043+
iconCardsEnabled = iconCardsEnabled,
6044+
passwordCardDisplayMode = passwordCardDisplayMode
6045+
)
6046+
}
60086047
}
60096048
}
60106049
}
60116050
}
6051+
6052+
// Expanded state edge zones: only these non-card areas collapse the stack.
6053+
Box(
6054+
modifier = Modifier
6055+
.align(Alignment.TopCenter)
6056+
.fillMaxWidth()
6057+
.height(edgeHitHeight)
6058+
.then(edgeTapModifier)
6059+
)
6060+
Box(
6061+
modifier = Modifier
6062+
.align(Alignment.BottomCenter)
6063+
.fillMaxWidth()
6064+
.height(edgeHitHeight)
6065+
.then(edgeTapModifier)
6066+
)
6067+
Box(
6068+
modifier = Modifier
6069+
.align(Alignment.CenterStart)
6070+
.width(edgeHitWidth)
6071+
.fillMaxHeight()
6072+
.then(edgeTapModifier)
6073+
)
6074+
Box(
6075+
modifier = Modifier
6076+
.align(Alignment.CenterEnd)
6077+
.width(edgeHitWidth)
6078+
.fillMaxHeight()
6079+
.then(edgeTapModifier)
6080+
)
60126081
}
60136082
}
60146083
}

0 commit comments

Comments
 (0)