menu: лончер приложений → bottom-sheet на пол-экрана (v0.5.116/124)

F7AppMenuSheet был fillMaxSize с непрозрачным фоном (закрывал весь экран).
Теперь выезжает снизу и занимает ~пол-экрана: якорь BottomCenter,
fillMaxHeight(0.6f), скруглённый верх 20dp + тень, ручка-хендл, лёгкий
скрим над листом (тап закрывает), зазор под нижнюю панель, сетка иконок
скроллится. Экран под меню виден сверху. Бамп версии 0.5.115→0.5.116.
This commit is contained in:
b-dev-mobile
2026-07-08 12:14:36 +00:00
parent 8cee4d61bf
commit 530663754a
3 changed files with 78 additions and 33 deletions
+2
View File
@@ -2,6 +2,8 @@
Формат: `ГГГГ-ММ-ДД | версия | изменение | контракты | риск` Формат: `ГГГГ-ММ-ДД | версия | изменение | контракты | риск`
- 2026-07-08 | v0.5.116 (124) | Меню-лончер (сетка приложений) → bottom-sheet на пол-экрана (требование владельца «выходить снизу вверх только на пол экрана»). `F7AppMenuSheet` был `fillMaxSize` с непрозрачным фоном → закрывал весь экран. Теперь: якорь снизу (`Alignment.BottomCenter`), высота `fillMaxHeight(0.6f)`, скруглённый верх (20dp) + тень, ручка-хендл, лёгкий скрим (0.18) над листом с тапом-для-закрытия, зазор `BottomBarReserve` под нижнюю панель, сетка иконок скроллится (`weight(1f)`). Экран под меню теперь виден сверху. Компилируется | контракты не менялись | низкий: только оверлей меню
- 2026-07-08 | v0.5.115 (123) | Бамп версии под дизайн-веху (0.5.114→0.5.115, code 122→123, стиль проекта: патч +1 / code +1). До этого Этапы 0/1 + весь дизайн ошибочно шли одной WIP-линией 0.5.114 (122) — теперь ревью-сборки дизайна помечены отдельной версией. Дальше — бампить на каждую заметную веху/ревью-сборку | версионирование | нет: только versionCode/Name - 2026-07-08 | v0.5.115 (123) | Бамп версии под дизайн-веху (0.5.114→0.5.115, code 122→123, стиль проекта: патч +1 / code +1). До этого Этапы 0/1 + весь дизайн ошибочно шли одной WIP-линией 0.5.114 (122) — теперь ревью-сборки дизайна помечены отдельной версией. Дальше — бампить на каждую заметную веху/ревью-сборку | версионирование | нет: только versionCode/Name
- 2026-07-08 | v0.5.114 (122) | Дизайн Календаря (месячная сетка): по «Календарь · Месяц» — дни недели вынесены в серые пилюли; сетка стала безрамочной с тонкими гридлайнами (0.5dp Grey3) вместо скруглённых боксов; номер дня сверху-слева; сегодня — белое число в зелёном круге; событие — зелёная пилюля PrimaryLight (до 2 шт + «+N») вместо одного превью/точки. Компактная мобильная модель (месяц сверху + список событий выбранного дня снизу) сохранена — не десктопная таблица. `CalendarMonthGrid`/`CalendarDayCell`, убран неиспользуемый параметр daysWithEvents. Проверено сборкой | контракты не менялись | низкий: только вид месяца - 2026-07-08 | v0.5.114 (122) | Дизайн Календаря (месячная сетка): по «Календарь · Месяц» — дни недели вынесены в серые пилюли; сетка стала безрамочной с тонкими гридлайнами (0.5dp Grey3) вместо скруглённых боксов; номер дня сверху-слева; сегодня — белое число в зелёном круге; событие — зелёная пилюля PrimaryLight (до 2 шт + «+N») вместо одного превью/точки. Компактная мобильная модель (месяц сверху + список событий выбранного дня снизу) сохранена — не десктопная таблица. `CalendarMonthGrid`/`CalendarDayCell`, убран неиспользуемый параметр daysWithEvents. Проверено сборкой | контракты не менялись | низкий: только вид месяца
+2 -2
View File
@@ -39,8 +39,8 @@ android {
applicationId 'ru.forbion.f7cloud.mobile' applicationId 'ru.forbion.f7cloud.mobile'
minSdk 26 minSdk 26
targetSdk 36 targetSdk 36
versionCode 123 versionCode 124
versionName '0.5.115' versionName '0.5.116'
missingDimensionStrategy 'default', 'f7' missingDimensionStrategy 'default', 'f7'
multiDexEnabled true multiDexEnabled true
@@ -9,10 +9,12 @@ import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
@@ -35,6 +37,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
@@ -51,6 +54,10 @@ private val BottomBarReserve: Dp = 90.dp
private val MenuIconSize = 62.dp private val MenuIconSize = 62.dp
private val MenuGridGap = 20.dp private val MenuGridGap = 20.dp
// Меню-лист выезжает снизу и занимает ~пол-экрана (не весь), по требованию владельца
private const val MenuSheetHeightFraction = 0.6f
private val MenuSheetShape = RoundedCornerShape(topStart = 20.dp, topEnd = 20.dp)
data class F7AppMenuItem( data class F7AppMenuItem(
val label: String, val label: String,
val iconUrl: String, val iconUrl: String,
@@ -78,6 +85,26 @@ fun F7AppMenuSheet(
} }
val base = serverUrl.trimEnd('/') val base = serverUrl.trimEnd('/')
Box(modifier = modifier.fillMaxSize()) {
// Затемнение над листом — тап закрывает меню (лист занимает только низ экрана)
AnimatedVisibility(
visible = visible,
enter = fadeIn(tween(200)),
exit = fadeOut(tween(200)),
modifier = Modifier.fillMaxSize(),
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Black.copy(alpha = 0.18f))
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = onDismiss,
),
)
}
// Сам лист — выезжает снизу вверх на ~пол-экрана, скруглённый верх + тень
AnimatedVisibility( AnimatedVisibility(
visible = visible, visible = visible,
enter = fadeIn(tween(250)) + slideInVertically( enter = fadeIn(tween(250)) + slideInVertically(
@@ -88,30 +115,45 @@ fun F7AppMenuSheet(
animationSpec = tween(300), animationSpec = tween(300),
targetOffsetY = { it }, targetOffsetY = { it },
), ),
modifier = modifier, modifier = Modifier.align(Alignment.BottomCenter),
) { ) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxWidth()
.fillMaxHeight(MenuSheetHeightFraction)
.padding(bottom = BottomBarReserve) .padding(bottom = BottomBarReserve)
.navigationBarsPadding() .navigationBarsPadding()
.shadow(16.dp, MenuSheetShape, clip = false)
.clip(MenuSheetShape)
.background(F7Colors.Background) .background(F7Colors.Background)
.padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 8.dp), .padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 8.dp),
) { ) {
// Ручка-хендл
Box(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(top = 2.dp, bottom = 10.dp)
.width(40.dp)
.height(4.dp)
.clip(RoundedCornerShape(2.dp))
.background(F7Colors.Border),
)
F7AppMenuSearchField( F7AppMenuSearchField(
serverUrl = base, serverUrl = base,
value = searchQuery, value = searchQuery,
onValueChange = { searchQuery = it }, onValueChange = { searchQuery = it },
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(bottom = 24.dp), .padding(bottom = 20.dp),
) )
LazyVerticalGrid( LazyVerticalGrid(
columns = GridCells.Fixed(4), columns = GridCells.Fixed(4),
horizontalArrangement = Arrangement.spacedBy(MenuGridGap), horizontalArrangement = Arrangement.spacedBy(MenuGridGap),
verticalArrangement = Arrangement.spacedBy(MenuGridGap), verticalArrangement = Arrangement.spacedBy(MenuGridGap),
contentPadding = PaddingValues(horizontal = 2.dp), contentPadding = PaddingValues(horizontal = 2.dp),
modifier = Modifier.fillMaxSize(), modifier = Modifier
.fillMaxWidth()
.weight(1f),
) { ) {
itemsIndexed( itemsIndexed(
items = filteredItems, items = filteredItems,
@@ -136,6 +178,7 @@ fun F7AppMenuSheet(
} }
} }
} }
}
@Composable @Composable
private fun F7AppMenuSearchField( private fun F7AppMenuSearchField(