Rebuild UI on the Noo design system
Replaces the Material 3 screens with the Noo design system: warm neutrals, one violet accent, pill controls, Schibsted Grotesk/ Instrument Sans, Lucide icons, no gradients/shadows. - New lib/widgets/noo/ component kit (core, lists, files, media, nav, overlays) plus lib/theme/design_tokens.dart for the color/type/space/ radius/motion tokens. - Rebuilt the app shell (top/bottom bars, drawer, desktop sidebar and toolbar), every tab (Files/Offline, Photos, Favorites, Recent, Activity, Trash, Shares), Settings, the lock and login screens, the media viewer, search, the details/share sheets, and the share-upload and move/copy destination pickers. - Added a design canvas (linked from DESIGN_SYSTEM.md) covering the screens the spec didn't already describe, with matching Android and iOS chrome; wrote up the approved recipes into DESIGN_SYSTEM.md §4. - Removed now-dead legacy widgets (media_grid_tile, swipeable_item, sync_status_badge, selectable_thumbnail) and updated architecture.md/styling.md/standards.md to describe the new structure and component/testing conventions. - Added widget tests for the noo/ component kit. This is a UI-only rework: no provider/model/service behavior changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../providers/files_controller.dart';
|
||||
import '../../theme/design_tokens.dart';
|
||||
import '../noo/lists/noo_settings_row.dart';
|
||||
import 'settings_section.dart';
|
||||
|
||||
String _cachePolicyLabel(CachePolicy policy) {
|
||||
switch (policy) {
|
||||
case CachePolicy.never:
|
||||
return 'Never cache';
|
||||
case CachePolicy.interval:
|
||||
return 'Refresh periodically';
|
||||
case CachePolicy.manual:
|
||||
return 'Refresh manually only';
|
||||
}
|
||||
}
|
||||
|
||||
String _cachePolicyDescription(CachePolicy policy) {
|
||||
switch (policy) {
|
||||
case CachePolicy.never:
|
||||
return 'Every visit to a folder fetches it fresh; synced files are '
|
||||
'checked each time you open the app';
|
||||
case CachePolicy.interval:
|
||||
return "Reuse a folder's listing until it's a few minutes old; synced "
|
||||
'files update in the background on the same schedule';
|
||||
case CachePolicy.manual:
|
||||
return "Reuse a folder's listing until you pull to refresh; synced "
|
||||
'files only update when you pull down or tap Sync now';
|
||||
}
|
||||
}
|
||||
|
||||
/// Settings section 5: how often folder listings and synced files refresh
|
||||
/// from the server.
|
||||
class SettingsFilesCacheSection extends StatelessWidget {
|
||||
const SettingsFilesCacheSection({super.key});
|
||||
|
||||
void _openPolicyPicker(BuildContext context, FilesController files) {
|
||||
showSettingsPicker(
|
||||
context,
|
||||
title: 'Cache policy',
|
||||
options: [
|
||||
for (final policy in CachePolicy.values)
|
||||
NooSettingsRow(
|
||||
label: Text(_cachePolicyLabel(policy)),
|
||||
subtitle: Text(_cachePolicyDescription(policy)),
|
||||
trailing: policy == files.cachePolicy
|
||||
? Icon(LucideIcons.check, size: 18, color: context.nooColors.accentText)
|
||||
: null,
|
||||
onTap: () {
|
||||
files.setCachePolicy(policy);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final files = context.watch<FilesController>();
|
||||
|
||||
return SettingsSection(
|
||||
title: 'Files cache',
|
||||
subtitle: 'How often folder listings and synced files refresh from the server',
|
||||
children: [
|
||||
NooSettingsRow(
|
||||
icon: LucideIcons.database,
|
||||
label: const Text('Cache policy'),
|
||||
value: _cachePolicyLabel(files.cachePolicy),
|
||||
onTap: () => _openPolicyPicker(context, files),
|
||||
),
|
||||
if (files.cachePolicy == CachePolicy.interval)
|
||||
_CacheIntervalRow(
|
||||
minutes: files.cacheIntervalMinutes,
|
||||
onChanged: files.setCacheIntervalMinutes,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// The refresh-interval slider shown under "Cache policy" while
|
||||
/// [CachePolicy.interval] is selected - not a plain [NooSettingsRow] since
|
||||
/// it needs a full-width [Slider], but paints its own `surface` background
|
||||
/// the same way so it sits correctly inside the group's line dividers (see
|
||||
/// `NooGroupedList`'s doc comment).
|
||||
class _CacheIntervalRow extends StatelessWidget {
|
||||
final int minutes;
|
||||
final ValueChanged<int> onChanged;
|
||||
|
||||
const _CacheIntervalRow({required this.minutes, required this.onChanged});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colors = context.nooColors;
|
||||
return Material(
|
||||
color: colors.surface,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: NooSpace.md, vertical: 8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Refresh interval', style: NooText.bodyL.copyWith(color: colors.fg1)),
|
||||
Text('$minutes min', style: NooText.meta.copyWith(color: colors.fg3)),
|
||||
],
|
||||
),
|
||||
SliderTheme(
|
||||
data: SliderTheme.of(context).copyWith(
|
||||
activeTrackColor: colors.accent,
|
||||
inactiveTrackColor: colors.surface3,
|
||||
thumbColor: colors.accent,
|
||||
overlayColor: colors.accent.withValues(alpha: 0.12),
|
||||
),
|
||||
child: Slider(
|
||||
value: minutes.toDouble(),
|
||||
min: 1,
|
||||
max: 60,
|
||||
divisions: 59,
|
||||
label: '$minutes min',
|
||||
onChanged: (value) => onChanged(value.round()),
|
||||
),
|
||||
),
|
||||
if (minutes < 15)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: Text(
|
||||
'While the app is closed, synced files refresh at most every '
|
||||
'15 min (an Android limit).',
|
||||
style: NooText.meta.copyWith(color: colors.fg3),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user