import 'package:flutter/material.dart'; import '../theme.dart'; /// Portrait media grid — mirrors the ui_kit/fly "Album" mockup. Media is /// placeholder content (the app has no on-device gallery source yet); the /// layout, filters and badges match the design. class AlbumPage extends StatefulWidget { const AlbumPage({super.key}); @override State createState() => _AlbumPageState(); } class _AlbumPageState extends State { static const List _filters = ['All', 'Photos', 'Videos', 'Pano']; int _active = 0; // (isVideo, duration) — placeholder set from the mockup. static const List<(bool, String?)> _media = <(bool, String?)>[ (true, '0:24'), (false, null), (false, null), (true, '1:12'), (false, null), (false, null), (false, null), (true, '0:08'), (false, null), (false, null), (true, '0:31'), (false, null), ]; @override Widget build(BuildContext context) { final PVScheme s = PVScheme.of(context); return Scaffold( backgroundColor: s.bgApp, body: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _header(s), _filterBar(s), const SizedBox(height: 14), Expanded(child: _grid(s)), ], ), ), ); } Widget _header(PVScheme s) { return Padding( padding: const EdgeInsets.fromLTRB(12, 6, 20, 12), child: Row( children: [ IconButton( onPressed: () => Navigator.of(context).maybePop(), icon: Icon(Icons.chevron_left, size: 26, color: s.textSecondary), ), Text( 'Album', style: TextStyle(fontFamily: PV.fontSans, fontSize: 20, fontWeight: FontWeight.w700, letterSpacing: -0.4, color: s.textPrimary), ), const Spacer(), Text('${_media.length} items', style: TextStyle(fontFamily: PV.fontMono, fontSize: 12, color: s.textTertiary)), ], ), ); } Widget _filterBar(PVScheme s) { return SizedBox( height: 28, child: ListView.separated( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 20), itemCount: _filters.length, separatorBuilder: (_, __) => const SizedBox(width: 8), itemBuilder: (BuildContext context, int i) { final bool active = i == _active; return GestureDetector( onTap: () => setState(() => _active = i), child: Container( padding: const EdgeInsets.symmetric(horizontal: 12), alignment: Alignment.center, decoration: BoxDecoration( color: active ? s.accent : s.surfaceInset, borderRadius: BorderRadius.circular(999), ), child: Text( _filters[i], style: TextStyle( fontFamily: PV.fontSans, fontSize: 12.5, fontWeight: FontWeight.w600, color: active ? Colors.white : s.textSecondary, ), ), ), ); }, ), ); } Widget _grid(PVScheme s) { return GridView.builder( padding: const EdgeInsets.fromLTRB(20, 0, 20, 20), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, crossAxisSpacing: 6, mainAxisSpacing: 6, ), itemCount: _media.length, itemBuilder: (BuildContext context, int i) { final (bool isVideo, String? dur) = _media[i]; return ClipRRect( borderRadius: BorderRadius.circular(10), child: Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [s.surface2, s.surfaceInset], transform: GradientRotation((140 + i * 14) * 3.1415926 / 180), ), border: Border.all(color: s.border), borderRadius: BorderRadius.circular(10), ), child: Stack( children: [ Center(child: Icon(isVideo ? Icons.videocam_outlined : Icons.image_outlined, size: 20, color: s.textTertiary)), if (dur != null) Positioned( right: 6, bottom: 5, child: Container( padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 1), decoration: BoxDecoration(color: const Color(0xB30B1730), borderRadius: BorderRadius.circular(5)), child: Text(dur, style: const TextStyle(fontFamily: PV.fontMono, fontSize: 9.5, color: Colors.white)), ), ), ], ), ), ); }, ); } }