fix: settings vertical text wrapping and pinned quick navigation v2.0.15
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/Version-2.0.14-blueviolet?style=for-the-badge" alt="Version 2.0.14" />
|
||||
<img src="https://img.shields.io/badge/Version-2.0.15-blueviolet?style=for-the-badge" alt="Version 2.0.15" />
|
||||
<img src="https://img.shields.io/badge/Flutter-3.47+-02569B?style=for-the-badge&logo=flutter&logoColor=white" alt="Flutter" />
|
||||
<img src="https://img.shields.io/badge/Platform-Android%20%7C%20Linux%20%7C%20Windows-brightgreen?style=for-the-badge" alt="Platforms" />
|
||||
<img src="https://img.shields.io/badge/Gitea-RarDog%2FLunaris-orange?style=for-the-badge&logo=gitea&logoColor=white" alt="Gitea" />
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
const appDisplayVersion = '2.0.14';
|
||||
const appBuildNumber = 36;
|
||||
const appDisplayVersion = '2.0.15';
|
||||
const appBuildNumber = 37;
|
||||
const appReleaseChannel = 'Stable';
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
const lunarisChangelog = [
|
||||
LunarisChange(
|
||||
version: '2.0.15',
|
||||
title: 'Settings 2.0 Layout Fixes & Pinned Quick Navigation',
|
||||
bullets: [
|
||||
'Fixed vertical text wrapping on mobile: separated title and full-width SegmentedButtons for Theme, Language, and Media Quality so text never collapses.',
|
||||
'Pinned Category Quick Navigation: bar now stays at the top of the screen and reliably scrolls to all 7 sections.',
|
||||
'SingleChildScrollView Migration: ensures all section keys remain mounted and scrollable on demand.',
|
||||
'Full-width Folder Structure Tile: added clean monospace path card with dedicated change button.',
|
||||
'Header text overflow protections: wrapped title texts in Expanded across all settings cards.',
|
||||
],
|
||||
),
|
||||
LunarisChange(
|
||||
version: '2.0.14',
|
||||
title: 'Settings 2.0: Modern Grouped Design & Quick Ergonomics',
|
||||
|
||||
@@ -69,8 +69,8 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
Scrollable.ensureVisible(
|
||||
ctx,
|
||||
duration: const Duration(milliseconds: 380),
|
||||
curve: Curves.easeOutCubic,
|
||||
alignment: 0.04,
|
||||
curve: Curves.easeInOutCubic,
|
||||
alignment: 0.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -79,6 +79,7 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final isAndroid = Platform.isAndroid;
|
||||
final strings = AppStrings(settings.languageCode);
|
||||
final isRu = strings.ru;
|
||||
@@ -139,21 +140,43 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
),
|
||||
];
|
||||
|
||||
return Align(
|
||||
alignment: Alignment.topCenter,
|
||||
return Column(
|
||||
children: [
|
||||
// Pinned Top Category Quick Navigation
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.scaffoldBackgroundColor,
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: theme.colorScheme.outlineVariant.withValues(alpha: 0.25),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Align(
|
||||
alignment: Alignment.center,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 860),
|
||||
child: ListView(
|
||||
controller: _scrollController,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
children: [
|
||||
// Top Quick-Nav Bar
|
||||
_CategoryQuickNav(
|
||||
child: _CategoryQuickNav(
|
||||
categories: navCategories,
|
||||
onSelect: _scrollTo,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Scrollable Settings Cards
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
child: Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 860),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// 1. General Section
|
||||
_SettingsCardGroup(
|
||||
sectionKey: _generalKey,
|
||||
@@ -161,19 +184,13 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
icon: Icons.tune_rounded,
|
||||
accentColor: const Color(0xFF6366F1),
|
||||
children: [
|
||||
_SettingsTile(
|
||||
_SettingsSegmentedTile<String>(
|
||||
icon: Icons.brightness_6_rounded,
|
||||
iconColor: const Color(0xFF6366F1),
|
||||
title: strings.theme,
|
||||
subtitle: isRu
|
||||
? 'Оформление цветовой схемы приложения'
|
||||
: 'App theme brightness mode',
|
||||
trailing: SegmentedButton<String>(
|
||||
showSelectedIcon: false,
|
||||
style: const ButtonStyle(
|
||||
visualDensity: VisualDensity.compact,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
segments: [
|
||||
ButtonSegment(
|
||||
value: 'dark',
|
||||
@@ -197,7 +214,6 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
settings.copyWith(themeMode: set.first),
|
||||
),
|
||||
),
|
||||
),
|
||||
const _SettingsDivider(),
|
||||
_SettingsSwitchTile(
|
||||
icon: Icons.explicit_rounded,
|
||||
@@ -281,27 +297,21 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
icon: Icons.palette_rounded,
|
||||
accentColor: const Color(0xFF8B5CF6),
|
||||
children: [
|
||||
_SettingsTile(
|
||||
_SettingsSegmentedTile<String>(
|
||||
icon: Icons.translate_rounded,
|
||||
iconColor: const Color(0xFF8B5CF6),
|
||||
title: strings.language,
|
||||
subtitle: isRu
|
||||
? 'Язык интерфейса приложения'
|
||||
: 'App user interface language',
|
||||
trailing: SegmentedButton<String>(
|
||||
showSelectedIcon: false,
|
||||
style: const ButtonStyle(
|
||||
visualDensity: VisualDensity.compact,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
segments: const [
|
||||
ButtonSegment(
|
||||
value: 'ru',
|
||||
label: Text('🇷🇺 RU'),
|
||||
label: Text('🇷🇺 Русский'),
|
||||
),
|
||||
ButtonSegment(
|
||||
value: 'en',
|
||||
label: Text('🇬🇧 EN'),
|
||||
label: Text('🇬🇧 English'),
|
||||
),
|
||||
],
|
||||
selected: {settings.languageCode},
|
||||
@@ -310,7 +320,6 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
settings.copyWith(languageCode: set.first),
|
||||
),
|
||||
),
|
||||
),
|
||||
const _SettingsDivider(),
|
||||
_SettingsSwitchTile(
|
||||
icon: Icons.contrast_rounded,
|
||||
@@ -389,19 +398,13 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
icon: Icons.dashboard_customize_rounded,
|
||||
accentColor: const Color(0xFF10B981),
|
||||
children: [
|
||||
_SettingsTile(
|
||||
_SettingsSegmentedTile<String>(
|
||||
icon: Icons.high_quality_rounded,
|
||||
iconColor: const Color(0xFF10B981),
|
||||
title: strings.mediaQuality,
|
||||
subtitle: isRu
|
||||
? 'Разрешение загружаемых картинок в сетке'
|
||||
: 'Resolution profile for feed thumbnails',
|
||||
trailing: SegmentedButton<String>(
|
||||
showSelectedIcon: false,
|
||||
style: const ButtonStyle(
|
||||
visualDensity: VisualDensity.compact,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
segments: [
|
||||
for (final mode in MediaQualityMode.values)
|
||||
ButtonSegment(
|
||||
@@ -410,7 +413,7 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
isRu
|
||||
? switch (mode) {
|
||||
MediaQualityMode.auto => 'Авто',
|
||||
MediaQualityMode.dataSaver => 'Трафик',
|
||||
MediaQualityMode.dataSaver => 'Экономия',
|
||||
MediaQualityMode.highQuality => 'HQ',
|
||||
}
|
||||
: mode.label,
|
||||
@@ -423,7 +426,6 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
settings.copyWith(mediaQualityMode: set.first),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isAndroid) ...[
|
||||
const _SettingsDivider(),
|
||||
Padding(
|
||||
@@ -459,21 +461,16 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
isRu
|
||||
? 'Частота обновления экрана'
|
||||
: 'Animation refresh profile',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyLarge
|
||||
style: theme.textTheme.bodyLarge
|
||||
?.copyWith(fontWeight: FontWeight.w600),
|
||||
),
|
||||
Text(
|
||||
isRu
|
||||
? 'Оптимизация плавности скролла ленты'
|
||||
: 'Fluid 120-165 Hz scrolling optimization',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium
|
||||
style: theme.textTheme.bodyMedium
|
||||
?.copyWith(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
color: theme.colorScheme
|
||||
.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
@@ -482,7 +479,7 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
const SizedBox(height: 12),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
@@ -534,8 +531,8 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
iconColor: const Color(0xFF3B82F6),
|
||||
title: strings.desktopColumns,
|
||||
subtitle: isRu
|
||||
? 'Количество столбцов постов на ПК и широких экранах'
|
||||
: 'Number of columns on desktop layout',
|
||||
? 'Количество столбцов постов на ПК'
|
||||
: 'Columns on desktop layout',
|
||||
value: settings.desktopColumns,
|
||||
min: 3,
|
||||
max: 8,
|
||||
@@ -548,8 +545,8 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
iconColor: const Color(0xFF6366F1),
|
||||
title: strings.mobileColumns,
|
||||
subtitle: isRu
|
||||
? 'Количество столбцов постов на телефонах'
|
||||
: 'Number of columns on phone layout',
|
||||
? 'Количество столбцов постов на телефоне'
|
||||
: 'Columns on phone layout',
|
||||
value: settings.mobileColumns,
|
||||
min: 1,
|
||||
max: 3,
|
||||
@@ -816,6 +813,10 @@ class _SettingsContentState extends ConsumerState<_SettingsContent> {
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1058,8 +1059,9 @@ class _CategoryQuickNav extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return SizedBox(
|
||||
height: 44,
|
||||
height: 40,
|
||||
child: ListView.separated(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: categories.length,
|
||||
separatorBuilder: (_, __) => const SizedBox(width: 8),
|
||||
@@ -1067,14 +1069,14 @@ class _CategoryQuickNav extends StatelessWidget {
|
||||
final cat = categories[index];
|
||||
return Material(
|
||||
color: theme.colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(22),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(22),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
onTap: () => onSelect(cat.key),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(22),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(
|
||||
color: theme.colorScheme.outlineVariant.withValues(alpha: 0.35),
|
||||
),
|
||||
@@ -1148,13 +1150,15 @@ class _SettingsCardGroup extends StatelessWidget {
|
||||
child: Icon(icon, size: 18, color: accentColor),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Text(
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
letterSpacing: -0.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -1250,6 +1254,90 @@ class _SettingsTile extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Full-width segmented tile so titles never get squeezed vertically on narrow screens.
|
||||
class _SettingsSegmentedTile<T> extends StatelessWidget {
|
||||
const _SettingsSegmentedTile({
|
||||
required this.icon,
|
||||
required this.iconColor,
|
||||
required this.title,
|
||||
required this.segments,
|
||||
required this.selected,
|
||||
required this.onSelectionChanged,
|
||||
this.subtitle,
|
||||
});
|
||||
|
||||
final IconData icon;
|
||||
final Color iconColor;
|
||||
final String title;
|
||||
final String? subtitle;
|
||||
final List<ButtonSegment<T>> segments;
|
||||
final Set<T> selected;
|
||||
final ValueChanged<Set<T>> onSelectionChanged;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 38,
|
||||
height: 38,
|
||||
decoration: BoxDecoration(
|
||||
color: iconColor.withValues(alpha: 0.12),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Icon(icon, size: 20, color: iconColor),
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: theme.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
if (subtitle != null) ...[
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
subtitle!,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: SegmentedButton<T>(
|
||||
showSelectedIcon: false,
|
||||
style: const ButtonStyle(
|
||||
visualDensity: VisualDensity.compact,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
segments: segments,
|
||||
selected: selected,
|
||||
onSelectionChanged: onSelectionChanged,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SettingsSwitchTile extends StatelessWidget {
|
||||
const _SettingsSwitchTile({
|
||||
required this.icon,
|
||||
@@ -1404,44 +1492,96 @@ class _SettingsFolderStructureTile extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return _SettingsTile(
|
||||
icon: Icons.folder_copy_rounded,
|
||||
iconColor: const Color(0xFF0EA5E9),
|
||||
title: isRu ? 'Папки скачивания' : 'Download folder structure',
|
||||
subtitle: isRu
|
||||
? 'Шаблон организации сохраняемых файлов'
|
||||
: 'Path template for organized downloads',
|
||||
trailing: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
return InkWell(
|
||||
onTap: () => _showPicker(context),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 38,
|
||||
height: 38,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHighest,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: theme.colorScheme.outlineVariant.withValues(alpha: 0.4),
|
||||
color: const Color(0xFF0EA5E9).withValues(alpha: 0.12),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.folder_copy_rounded,
|
||||
size: 20,
|
||||
color: Color(0xFF0EA5E9),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
currentTemplate,
|
||||
style: TextStyle(
|
||||
fontFamily: 'monospace',
|
||||
fontSize: 12,
|
||||
isRu ? 'Папки скачивания' : 'Download folder structure',
|
||||
style: theme.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Icon(
|
||||
Icons.unfold_more_rounded,
|
||||
size: 16,
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
isRu
|
||||
? 'Шаблон организации сохраняемых файлов'
|
||||
: 'Path template for organized downloads',
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Icon(
|
||||
Icons.chevron_right_rounded,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.surfaceContainerHighest.withValues(alpha: 0.5),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: theme.colorScheme.outlineVariant.withValues(alpha: 0.35),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.folder_open_rounded, size: 16),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
currentTemplate,
|
||||
style: TextStyle(
|
||||
fontFamily: 'monospace',
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
isRu ? 'Выбрать' : 'Select',
|
||||
style: theme.textTheme.labelMedium?.copyWith(
|
||||
color: theme.colorScheme.primary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () => _showPicker(context),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1627,12 +1767,14 @@ class _TagListEditorState extends State<_TagListEditor> {
|
||||
children: [
|
||||
Icon(widget.icon, size: 20, color: widget.accentColor),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.title,
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
@@ -1743,12 +1885,14 @@ class _ColorSwatches extends StatelessWidget {
|
||||
children: [
|
||||
const Icon(Icons.palette_outlined, size: 20, color: Color(0xFF8B5CF6)),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Акцентный цвет интерфейса',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
@@ -1830,12 +1974,14 @@ class _TabVisibilityEditor extends StatelessWidget {
|
||||
children: [
|
||||
const Icon(Icons.tab_rounded, size: 20, color: Color(0xFF8B5CF6)),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Отображение вкладок навигации',
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
name: gel_rule_app
|
||||
description: Local backend/core layer for a Flutter booru browser app.
|
||||
publish_to: "none"
|
||||
version: 2.0.14+36
|
||||
version: 2.0.15+37
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.0 <4.0.0"
|
||||
|
||||
@@ -6,8 +6,9 @@ import 'package:gel_rule_app/features/settings/presentation/settings_controller.
|
||||
import 'package:gel_rule_app/features/settings/presentation/settings_screen.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('SettingsScreen renders category quick nav and sections', (tester) async {
|
||||
tester.view.physicalSize = const Size(1200, 2400);
|
||||
testWidgets('SettingsScreen renders category quick nav and sections without overflow', (tester) async {
|
||||
// Test on typical mobile viewport: 390x844
|
||||
tester.view.physicalSize = const Size(390, 844);
|
||||
tester.view.devicePixelRatio = 1.0;
|
||||
addTearDown(() {
|
||||
tester.view.resetPhysicalSize();
|
||||
@@ -34,22 +35,25 @@ void main() {
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Verify Category Quick Nav renders
|
||||
// Verify pinned Category Quick Nav renders
|
||||
expect(find.text('Основное'), findsWidgets);
|
||||
expect(find.text('Внешний вид'), findsWidgets);
|
||||
expect(find.text('Лента и раскладка'), findsWidgets);
|
||||
expect(find.text('Фильтры'), findsWidgets);
|
||||
expect(find.text('Хранилище'), findsWidgets);
|
||||
|
||||
// Verify Theme mode segment buttons
|
||||
expect(find.text('Темная'), findsOneWidget);
|
||||
expect(find.text('Светлая'), findsOneWidget);
|
||||
// Both ThemeMode and MediaQualityMode have 'Авто'
|
||||
expect(find.text('Авто'), findsNWidgets(2));
|
||||
|
||||
// Verify Language segmented buttons
|
||||
expect(find.text('🇷🇺 RU'), findsOneWidget);
|
||||
expect(find.text('🇬🇧 EN'), findsOneWidget);
|
||||
// Tap a quick nav chip to test scrolling
|
||||
await tester.tap(find.text('Внешний вид').first);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Verify language segment is visible and tappable
|
||||
expect(find.text('🇷🇺 Русский'), findsOneWidget);
|
||||
expect(find.text('🇬🇧 English'), findsOneWidget);
|
||||
|
||||
// Tap English to test selection
|
||||
await tester.tap(find.text('🇬🇧 English'));
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user