Prepare Lunaris 1.1.2 experimental

This commit is contained in:
2026-05-26 11:43:25 +03:00
parent 369dee02be
commit 9cff9e5307
42 changed files with 2041 additions and 303 deletions
+4 -2
View File
@@ -6,12 +6,14 @@ class AdaptiveScaffold extends StatelessWidget {
const AdaptiveScaffold({
required this.title,
required this.body,
this.titleWidget,
this.actions = const [],
this.floatingActionButton,
super.key,
});
final String title;
final Widget? titleWidget;
final Widget body;
final List<Widget> actions;
final Widget? floatingActionButton;
@@ -21,7 +23,7 @@ class AdaptiveScaffold extends StatelessWidget {
if (Responsive.isMobile(context)) {
return Scaffold(
appBar: AppBar(
title: Text(title),
title: titleWidget ?? Text(title),
actions: actions,
toolbarHeight: 52,
titleTextStyle: Theme.of(context).textTheme.titleLarge?.copyWith(
@@ -33,7 +35,7 @@ class AdaptiveScaffold extends StatelessWidget {
);
}
return Scaffold(
appBar: AppBar(title: Text(title), actions: actions),
appBar: AppBar(title: titleWidget ?? Text(title), actions: actions),
body: body,
floatingActionButton: floatingActionButton,
);
-21
View File
@@ -3,7 +3,6 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../app/motion.dart';
import '../../backend/backend.dart';
class AppSearchBar extends StatefulWidget {
@@ -253,7 +252,6 @@ class _TagInputSearchBarState extends State<TagInputSearchBar> {
void _commitDraft(String value) {
final additions = _parseTags(value);
if (additions.isEmpty) return;
final keepInputVisible = _isInputNearEnd();
setState(() {
for (final tag in additions) {
if (!_tags.contains(tag)) _tags.add(tag);
@@ -261,7 +259,6 @@ class _TagInputSearchBarState extends State<TagInputSearchBar> {
_controller.clear();
});
_notifyChanged();
if (keepInputVisible) _scrollTagsToEnd();
}
void _submit() {
@@ -301,7 +298,6 @@ class _TagInputSearchBarState extends State<TagInputSearchBar> {
void _applySuggestion(String suggestion) {
final draft = _controller.text.trim();
final keepInputVisible = _isInputNearEnd();
setState(() {
if (draft.isNotEmpty) {
final draftTags = _parseTags(draft);
@@ -313,7 +309,6 @@ class _TagInputSearchBarState extends State<TagInputSearchBar> {
_notifyChanged();
widget.onSuggestionApplied?.call(_query);
_focusNode.requestFocus();
if (keepInputVisible) _scrollTagsToEnd();
}
void _notifyChangedDebounced() {
@@ -341,22 +336,6 @@ class _TagInputSearchBarState extends State<TagInputSearchBar> {
final all = [..._tags, if (draft.isNotEmpty) draft];
return all.join(' ');
}
void _scrollTagsToEnd() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted || !_tagScrollController.hasClients) return;
_tagScrollController.animateTo(
_tagScrollController.position.maxScrollExtent,
duration: AppMotion.duration(context, 120),
curve: Curves.easeOut,
);
});
}
bool _isInputNearEnd() {
if (!_tagScrollController.hasClients) return true;
return _tagScrollController.position.extentAfter < 96;
}
}
class _TagSuggestionDropdown extends StatelessWidget {
+26 -5
View File
@@ -16,7 +16,12 @@ class AppShell extends StatelessWidget {
_Destination('Favorites', Icons.favorite_rounded, '/favorites'),
_Destination('Viewed', Icons.history_rounded, '/viewed'),
_Destination(
'Collections', Icons.collections_bookmark_rounded, '/collections'),
'Collections',
Icons.collections_bookmark_rounded,
'/collections',
mobileLabel: 'Boards',
),
_Destination('Artists', Icons.person_search_rounded, '/artists'),
_Destination('Providers', Icons.hub_rounded, '/providers'),
_Destination('Settings', Icons.settings_rounded, '/settings'),
];
@@ -38,8 +43,10 @@ class AppShell extends StatelessWidget {
LogicalKeySet(LogicalKeyboardKey.digit5):
const _NavigateIntent('/collections'),
LogicalKeySet(LogicalKeyboardKey.digit6):
const _NavigateIntent('/providers'),
const _NavigateIntent('/artists'),
LogicalKeySet(LogicalKeyboardKey.digit7):
const _NavigateIntent('/providers'),
LogicalKeySet(LogicalKeyboardKey.digit8):
const _NavigateIntent('/settings'),
},
child: Actions(
@@ -216,7 +223,11 @@ class _MobileShell extends StatelessWidget {
@override
Widget build(BuildContext context) {
final items = AppShell.destinations.take(5).toList();
final items = AppShell.destinations
.where((item) =>
item.location != '/providers' && item.location != '/settings')
.take(6)
.toList();
final location = GoRouterState.of(context).uri.path;
final selected = items.indexWhere(
(item) => item.location == '/'
@@ -239,7 +250,10 @@ class _MobileShell extends StatelessWidget {
onDestinationSelected: (index) => context.go(items[index].location),
destinations: [
for (final item in items)
NavigationDestination(icon: Icon(item.icon), label: item.label),
NavigationDestination(
icon: Icon(item.icon),
label: item.mobileLabel,
),
],
),
);
@@ -247,8 +261,15 @@ class _MobileShell extends StatelessWidget {
}
class _Destination {
const _Destination(this.label, this.icon, this.location);
const _Destination(
this.label,
this.icon,
this.location, {
String? mobileLabel,
}) : mobileLabel = mobileLabel ?? label;
final String label;
final String mobileLabel;
final IconData icon;
final String location;
}