Rebuild Noo as a full Nextcloud client: auth, media, and Material You UI

Replaces the starter template with Login Flow v2 auth, WebDAV-backed
Files/Photos/Activity tabs, a swipeable media viewer with PDF/text/video
preview, Material You dynamic theming, a frosted-glass floating nav bar,
and a rebranded app icon/identity (com.example -> family.nasa).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 16:07:02 -04:00
co-authored by Claude Sonnet 5
parent 54f80a65e7
commit f62d912ef7
47 changed files with 5083 additions and 1571 deletions
+65
View File
@@ -0,0 +1,65 @@
import 'package:flutter/material.dart';
/// A single icon button that fills with a solid circle when active —
/// the building block for Drive-style toggle controls.
class ToggleIconButton extends StatelessWidget {
final IconData icon;
final bool isSelected;
final VoidCallback onTap;
final String? tooltip;
const ToggleIconButton({
super.key,
required this.icon,
required this.isSelected,
required this.onTap,
this.tooltip,
});
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
final button = Material(
color: isSelected ? colorScheme.primaryContainer : Colors.transparent,
shape: const CircleBorder(),
child: InkWell(
onTap: onTap,
customBorder: const CircleBorder(),
child: Padding(
padding: const EdgeInsets.all(8),
child: Icon(
icon,
size: 20,
color: isSelected
? colorScheme.onPrimaryContainer
: colorScheme.onSurfaceVariant,
),
),
),
);
return tooltip != null ? Tooltip(message: tooltip!, child: button) : button;
}
}
/// A pill-shaped row of [ToggleIconButton]s sharing one background, matching
/// the list/grid view switch seen in Google Drive's toolbar.
class SegmentedIconGroup extends StatelessWidget {
final List<Widget> children;
const SegmentedIconGroup({super.key, required this.children});
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
color: colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(20),
),
child: Row(mainAxisSize: MainAxisSize.min, children: children),
);
}
}