refactor: уменьшил отступы от краев + сделал кастомизацию разворачиваемой
This commit is contained in:
@@ -3897,7 +3897,7 @@ class _ChatScreenState extends State<ChatScreen>
|
||||
final cs = Theme.of(context).colorScheme;
|
||||
final accent = cs.primary;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(12, 8, 12, 6),
|
||||
padding: const EdgeInsets.fromLTRB(8, 8, 8, 6),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
import '../../widgets/connection_status.dart';
|
||||
|
||||
import '../../../core/utils/haptics.dart';
|
||||
import '../../widgets/glossy_pill.dart';
|
||||
import 'app_icon_screen.dart';
|
||||
import 'appearance_screen.dart';
|
||||
import 'chat_background_screen.dart';
|
||||
import 'font_settings_screen.dart';
|
||||
import 'message_actions_screen.dart';
|
||||
import 'theme_settings_screen.dart';
|
||||
|
||||
class _CustomizationCategory {
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final String subtitle;
|
||||
final WidgetBuilder builder;
|
||||
|
||||
const _CustomizationCategory({
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
required this.builder,
|
||||
});
|
||||
}
|
||||
|
||||
class CustomizationScreen extends StatelessWidget {
|
||||
const CustomizationScreen({super.key});
|
||||
|
||||
static const List<_CustomizationCategory> _categories = [
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.dark_mode,
|
||||
title: 'Тема',
|
||||
subtitle: 'Светлая, тёмная, AMOLED, расписание',
|
||||
builder: _buildThemeSettings,
|
||||
),
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.palette,
|
||||
title: 'Внешний вид',
|
||||
subtitle: 'Акцентный цвет интерфейса',
|
||||
builder: _buildAppearance,
|
||||
),
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.wallpaper,
|
||||
title: 'Фон чатов',
|
||||
subtitle: 'Общие обои и темы для всех чатов',
|
||||
builder: _buildChatBackground,
|
||||
),
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.text_fields,
|
||||
title: 'Шрифты',
|
||||
subtitle: 'Шрифт приложения, свои шрифты, размер текста',
|
||||
builder: _buildFontSettings,
|
||||
),
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.touch_app,
|
||||
title: 'Меню действий',
|
||||
subtitle: 'Радиальное или список — для долгого нажатия на сообщение',
|
||||
builder: _buildMessageActions,
|
||||
),
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.apps,
|
||||
title: 'Иконка приложения',
|
||||
subtitle: 'Default или Minimal — иконка на главном экране',
|
||||
builder: _buildAppIcon,
|
||||
),
|
||||
];
|
||||
|
||||
static Widget _buildAppearance(BuildContext context) =>
|
||||
const AppearanceScreen();
|
||||
|
||||
static Widget _buildChatBackground(BuildContext context) =>
|
||||
const ChatBackgroundScreen();
|
||||
|
||||
static Widget _buildFontSettings(BuildContext context) =>
|
||||
const FontSettingsScreen();
|
||||
|
||||
static Widget _buildThemeSettings(BuildContext context) =>
|
||||
const ThemeSettingsScreen();
|
||||
|
||||
static Widget _buildMessageActions(BuildContext context) =>
|
||||
const MessageActionsScreen();
|
||||
|
||||
static Widget _buildAppIcon(BuildContext context) => const AppIconScreen();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final cs = Theme.of(context).colorScheme;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: cs.surface,
|
||||
appBar: ConnectionTitleBar(
|
||||
titleText: 'Кастомизация',
|
||||
backgroundColor: cs.surface,
|
||||
),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
child: ListView(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 120),
|
||||
children: [
|
||||
for (final category in _categories) ...[
|
||||
_CategoryCard(
|
||||
category: category,
|
||||
onTap: () {
|
||||
Haptics.tap();
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: category.builder),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _CategoryCard extends StatelessWidget {
|
||||
final _CustomizationCategory category;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const _CategoryCard({required this.category, required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final cs = Theme.of(context).colorScheme;
|
||||
return GlossyPill(
|
||||
color: cs.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 18),
|
||||
depth: 6,
|
||||
onTap: onTap,
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
decoration: BoxDecoration(
|
||||
color: cs.primaryContainer,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Icon(
|
||||
category.icon,
|
||||
color: cs.onPrimaryContainer,
|
||||
size: 24,
|
||||
weight: 500,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
category.title,
|
||||
style: TextStyle(
|
||||
color: cs.onSurface,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
Text(
|
||||
category.subtitle,
|
||||
style: TextStyle(
|
||||
color: cs.onSurfaceVariant,
|
||||
fontSize: 13,
|
||||
height: 1.3,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Icon(Symbols.chevron_right, color: cs.outline, size: 22),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
|
||||
import '../../../core/utils/haptics.dart';
|
||||
import '../../widgets/glossy_pill.dart';
|
||||
import '../../widgets/settings_card.dart';
|
||||
import 'app_icon_screen.dart';
|
||||
import 'appearance_screen.dart';
|
||||
import 'chat_background_screen.dart';
|
||||
import 'font_settings_screen.dart';
|
||||
import 'message_actions_screen.dart';
|
||||
import 'theme_settings_screen.dart';
|
||||
|
||||
class _CustomizationCategory {
|
||||
final IconData icon;
|
||||
final String title;
|
||||
final WidgetBuilder builder;
|
||||
|
||||
const _CustomizationCategory({
|
||||
required this.icon,
|
||||
required this.title,
|
||||
required this.builder,
|
||||
});
|
||||
}
|
||||
|
||||
class CustomizationSection extends StatefulWidget {
|
||||
const CustomizationSection({super.key});
|
||||
|
||||
@override
|
||||
State<CustomizationSection> createState() => _CustomizationSectionState();
|
||||
}
|
||||
|
||||
class _CustomizationSectionState extends State<CustomizationSection> {
|
||||
bool _expanded = false;
|
||||
|
||||
static final List<_CustomizationCategory> _categories = [
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.dark_mode,
|
||||
title: 'Тема',
|
||||
builder: (context) => const ThemeSettingsScreen(),
|
||||
),
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.palette,
|
||||
title: 'Внешний вид',
|
||||
builder: (context) => const AppearanceScreen(),
|
||||
),
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.wallpaper,
|
||||
title: 'Фон чатов',
|
||||
builder: (context) => const ChatBackgroundScreen(),
|
||||
),
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.text_fields,
|
||||
title: 'Шрифты',
|
||||
builder: (context) => const FontSettingsScreen(),
|
||||
),
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.touch_app,
|
||||
title: 'Меню действий',
|
||||
builder: (context) => const MessageActionsScreen(),
|
||||
),
|
||||
_CustomizationCategory(
|
||||
icon: Symbols.apps,
|
||||
title: 'Иконка приложения',
|
||||
builder: (context) => const AppIconScreen(),
|
||||
),
|
||||
];
|
||||
|
||||
void _toggle() {
|
||||
Haptics.tap();
|
||||
setState(() => _expanded = !_expanded);
|
||||
}
|
||||
|
||||
void _open(_CustomizationCategory category) {
|
||||
Haptics.tap();
|
||||
Navigator.push(context, MaterialPageRoute(builder: category.builder));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final cs = Theme.of(context).colorScheme;
|
||||
return GlossyPill(
|
||||
color: cs.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
depth: 6,
|
||||
child: Column(
|
||||
children: [
|
||||
_buildHeader(cs),
|
||||
AnimatedSize(
|
||||
duration: const Duration(milliseconds: 220),
|
||||
curve: Curves.easeInOut,
|
||||
alignment: Alignment.topCenter,
|
||||
child: _expanded
|
||||
? Column(children: _buildCategoryTiles(cs))
|
||||
: const SizedBox(width: double.infinity),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildHeader(ColorScheme cs) {
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: _toggle,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 17),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Symbols.palette,
|
||||
color: cs.onSurfaceVariant,
|
||||
size: 22,
|
||||
weight: 400,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Кастомизация',
|
||||
style: TextStyle(
|
||||
color: cs.onSurface,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
AnimatedRotation(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
turns: _expanded ? 0.5 : 0,
|
||||
child: Icon(
|
||||
Symbols.expand_more,
|
||||
color: cs.outline,
|
||||
size: 22,
|
||||
weight: 400,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _buildCategoryTiles(ColorScheme cs) {
|
||||
final tiles = <Widget>[];
|
||||
for (var i = 0; i < _categories.length; i++) {
|
||||
final category = _categories[i];
|
||||
tiles.add(
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 58),
|
||||
child: Divider(
|
||||
height: 1,
|
||||
thickness: 1,
|
||||
color: cs.outlineVariant.withValues(alpha: 0.35),
|
||||
),
|
||||
),
|
||||
);
|
||||
tiles.add(
|
||||
SettingsNavTile(
|
||||
icon: category.icon,
|
||||
label: category.title,
|
||||
onTap: () => _open(category),
|
||||
isLast: i == _categories.length - 1,
|
||||
),
|
||||
);
|
||||
}
|
||||
return tiles;
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import '../digital_id/digital_id_screen.dart';
|
||||
import '../digital_id/digital_id_web_screen.dart';
|
||||
import '../webapp/web_app_screen.dart';
|
||||
import 'cloud_storage_screen.dart';
|
||||
import 'customization_screen.dart';
|
||||
import 'customization_section.dart';
|
||||
import 'debug_menu_screen.dart';
|
||||
import 'devices_screen.dart';
|
||||
import 'edit_profile_screen.dart';
|
||||
@@ -298,26 +298,10 @@ class _SettingsTabState extends State<SettingsTab> {
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
const SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 0),
|
||||
child: _buildSection(
|
||||
context,
|
||||
items: [
|
||||
_SettingsItem(
|
||||
icon: Symbols.palette,
|
||||
label: 'Кастомизация',
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const CustomizationScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.fromLTRB(16, 12, 16, 0),
|
||||
child: CustomizationSection(),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
|
||||
@@ -530,8 +530,8 @@ class MessageBubble extends StatelessWidget {
|
||||
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 12,
|
||||
right: 12,
|
||||
left: 8,
|
||||
right: 8,
|
||||
top: topMargin,
|
||||
bottom: bottomMargin,
|
||||
),
|
||||
@@ -545,9 +545,7 @@ class MessageBubble extends StatelessWidget {
|
||||
children: [
|
||||
if (showAvatar)
|
||||
_buildLeadingAvatar(cs)
|
||||
else if (showAvatarSlot && chatType != "CHAT")
|
||||
const SizedBox(width: 0)
|
||||
else if (showAvatarSlot)
|
||||
else if (showAvatarSlot && chatType == "CHAT")
|
||||
const CircleAvatar(
|
||||
radius: 15,
|
||||
backgroundColor: Color(0x00000000),
|
||||
|
||||
Reference in New Issue
Block a user