From adaf0f655e49c032b4f8d1de252009dca588a94d Mon Sep 17 00:00:00 2001 From: itsgnex <100925921+itsgnex@users.noreply.github.com> Date: Sun, 18 Jan 2026 03:37:55 -0800 Subject: [PATCH] Collapsing header UI (#173) * Add collapsing / expanding header behavior * Improve header behavior with scroll-direction based expansion --- .gitignore | 5 ++ lib/main.dart | 132 +++++++++++++++++++++++--------------------------- 2 files changed, 65 insertions(+), 72 deletions(-) diff --git a/.gitignore b/.gitignore index 24476c5..2b65f53 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,11 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ migrate_working_dir/ # IntelliJ related @@ -42,3 +44,6 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release +*.jdk/ +openJdk-25.jdk/ +oracleJdk-25.jdk/ diff --git a/lib/main.dart b/lib/main.dart index fd9491c..e875a97 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,6 +4,7 @@ import 'dart:io' show Platform; // Flutter imports: import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter/rendering.dart'; // <-- REQUIRED // Package imports: import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -40,25 +41,21 @@ void main() async { MyLibraryDb dataBase = MyLibraryDb.instance; bool isDarkMode = await dataBase.getPreference('darkMode') == 0 ? false : true; - bool openPdfwithExternalapp = await dataBase - .getPreference('openPdfwithExternalApp') - .catchError((e) => print(e)) == - 0 - ? false - : true; - bool openEpubwithExternalapp = await dataBase - .getPreference('openEpubwithExternalApp') - .catchError((e) => print(e)) == - 0 - ? false - : true; + bool openPdfwithExternalapp = + await dataBase.getPreference('openPdfwithExternalApp') == 0 + ? false + : true; + + bool openEpubwithExternalapp = + await dataBase.getPreference('openEpubwithExternalApp') == 0 + ? false + : true; String browserUserAgent = await dataBase.getBrowserOptions('userAgent'); String browserCookie = await dataBase.getBrowserOptions('cookie'); if (Platform.isAndroid) { - //[SystemChrome] Also change colors in settings page Theme colors if any change SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( systemNavigationBarColor: isDarkMode ? Colors.black : Colors.grey.shade200)); @@ -84,14 +81,14 @@ void main() async { class MyApp extends ConsumerWidget { const MyApp({super.key}); + @override Widget build(BuildContext context, WidgetRef ref) { return MaterialApp( - builder: (BuildContext context, Widget? child) { + builder: (context, child) { return MediaQuery( - data: MediaQuery.of(context).copyWith( - textScaler: const TextScaler.linear(1.0), - ), + data: MediaQuery.of(context) + .copyWith(textScaler: const TextScaler.linear(1.0)), child: child!, ); }, @@ -117,25 +114,50 @@ class _MainScreenState extends ConsumerState { HomePage(), SearchPage(), MyLibraryPage(), - SettingsPage() + SettingsPage(), ]; + bool _showExpandedHeader = true; // <-- ONLY new state + @override Widget build(BuildContext context) { final isDarkMode = Theme.of(context).brightness == Brightness.dark; - final selectedIndex = ref.watch(selectedIndexProvider); return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.surface, - title: const Text("Openlib"), - titleTextStyle: Theme.of(context).textTheme.displayLarge, + body: NotificationListener( + onNotification: (notification) { + if (notification.direction == ScrollDirection.reverse && + _showExpandedHeader) { + setState(() => _showExpandedHeader = false); + } else if (notification.direction == ScrollDirection.forward && + !_showExpandedHeader) { + setState(() => _showExpandedHeader = true); + } + return false; + }, + child: Column( + children: [ + AnimatedContainer( + duration: const Duration(milliseconds: 200), + height: _showExpandedHeader ? kToolbarHeight : 0, + child: AppBar( + backgroundColor: Theme.of(context).colorScheme.surface, + title: const Text("Openlib"), + titleTextStyle: + Theme.of(context).textTheme.displayLarge, + ), + ), + Expanded( + child: _widgetOptions.elementAt(selectedIndex), + ), + ], + ), ), - body: _widgetOptions.elementAt(selectedIndex), bottomNavigationBar: SafeArea( child: GNav( - backgroundColor: isDarkMode ? Colors.black : Colors.grey.shade200, + backgroundColor: + isDarkMode ? Colors.black : Colors.grey.shade200, haptic: true, tabBorderRadius: 50, tabActiveBorder: Border.all( @@ -145,55 +167,21 @@ class _MainScreenState extends ConsumerState { curve: Curves.fastLinearToSlowEaseIn, duration: const Duration(milliseconds: 25), gap: 5, - color: const Color.fromARGB(255, 255, 255, 255), - activeColor: const Color.fromARGB(255, 255, 255, 255), - iconSize: 19, // tab button icon size - tabBackgroundColor: Theme.of(context).colorScheme.secondary, - padding: const EdgeInsets.symmetric(horizontal: 13, vertical: 6.5), - tabs: [ - GButton( - icon: Icons.trending_up, - text: 'Home', - iconColor: isDarkMode ? Colors.white : Colors.black, - textStyle: const TextStyle( - fontWeight: FontWeight.w900, - color: Colors.white, - fontSize: 11, - ), - ), - GButton( - icon: Icons.search, - text: 'Search', - iconColor: isDarkMode ? Colors.white : Colors.black, - textStyle: const TextStyle( - fontWeight: FontWeight.w900, - color: Colors.white, - fontSize: 11, - ), - ), - GButton( - icon: Icons.collections_bookmark, - text: 'My Library', - iconColor: isDarkMode ? Colors.white : Colors.black, - textStyle: const TextStyle( - fontWeight: FontWeight.w900, - color: Colors.white, - fontSize: 11, - ), - ), - GButton( - icon: Icons.build, - text: 'Settings', - iconColor: isDarkMode ? Colors.white : Colors.black, - textStyle: const TextStyle( - fontWeight: FontWeight.w900, - color: Colors.white, - fontSize: 11, - ), - ), + color: Colors.white, + activeColor: Colors.white, + iconSize: 19, + tabBackgroundColor: + Theme.of(context).colorScheme.secondary, + padding: + const EdgeInsets.symmetric(horizontal: 13, vertical: 6.5), + tabs: const [ + GButton(icon: Icons.trending_up, text: 'Home'), + GButton(icon: Icons.search, text: 'Search'), + GButton(icon: Icons.collections_bookmark, text: 'My Library'), + GButton(icon: Icons.build, text: 'Settings'), ], selectedIndex: selectedIndex, - onTabChange: (index) async { + onTabChange: (index) { ref.read(selectedIndexProvider.notifier).state = index; }, ),