creek

The AI Image Editor of 2030
commit e7bec3073e0200306d5023d98a1b01433e41e667
parent f42c4c7a3fe0eda2e6a6a0b8cfda7253f4def07a
Author: aditya-samal <samaladitya2004@gmail.com>
Date:   Tue,  2 Dec 2025 00:03:59 +0530

Updated topbar

Diffstat:
Mios/Flutter/AppFrameworkInfo.plist | 2+-
Mios/Runner.xcodeproj/project.pbxproj | 6+++---
Mios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme | 2++
Mlib/ui/pages/project_board_page.dart | 94++++++-------------------------------------------------------------------------
Mlib/ui/pages/project_board_page_alternate.dart | 8--------
Mlib/ui/pages/project_detail_page.dart | 46+++++++++++++++++++++++-----------------------
Mlib/ui/widgets/top_bar.dart | 347+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
7 files changed, 253 insertions(+), 252 deletions(-)

diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ <key>CFBundleVersion</key> <string>1.0</string> <key>MinimumOSVersion</key> - <string>12.0</string> + <string>13.0</string> </dict> </plist> diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj @@ -346,7 +346,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -472,7 +472,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -523,7 +523,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -26,6 +26,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" shouldUseLaunchSchemeArgsEnv = "YES"> <MacroExpansion> <BuildableReference @@ -54,6 +55,7 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" + customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/lib/ui/pages/project_board_page.dart b/lib/ui/pages/project_board_page.dart @@ -161,6 +161,13 @@ class _ProjectBoardPageState extends State<ProjectBoardPage> { onBack: () => Navigator.pop(context), onProjectChanged: _onProjectChanged, onSettingsPressed: () {}, + isAlternateView: _showAlternateView, + onLayoutToggle: () { + setState(() { + _showAlternateView = !_showAlternateView; + if (!_showAlternateView) _loadImagesForSelected(); + }); + }, ), bottomNavigationBar: BottomBar( currentTab: BottomBarItem.moodboard, @@ -174,93 +181,6 @@ class _ProjectBoardPageState extends State<ProjectBoardPage> { ), body: Column( children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - vertical: 12.0, - ), - child: Row( - children: [ - InkWell( - onTap: () { - setState(() { - _showAlternateView = !_showAlternateView; - if (!_showAlternateView) _loadImagesForSelected(); - }); - }, - borderRadius: BorderRadius.circular(20), - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), - decoration: BoxDecoration( - color: Variables.surfaceSubtle, - borderRadius: BorderRadius.circular(20), - border: Border.all(color: Variables.borderSubtle), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - _showAlternateView - ? Icons.dashboard - : Icons.view_agenda_outlined, - size: 18, - color: Variables.textPrimary, - ), - const SizedBox(width: 8), - Text( - _showAlternateView ? "Categorized" : "All Images", - style: Variables.bodyStyle.copyWith( - fontWeight: FontWeight.w600, - fontSize: 13, - ), - ), - ], - ), - ), - ), - const Spacer(), - if (_showAlternateView) - InkWell( - onTap: () { - _alternatePageKey.currentState?.showFilterDialog(); - }, - borderRadius: BorderRadius.circular(20), - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8, - ), - decoration: BoxDecoration( - color: Variables.surfaceSubtle, - borderRadius: BorderRadius.circular(20), - border: Border.all(color: Variables.borderSubtle), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon( - Icons.tune_outlined, - size: 18, - color: Variables.textPrimary, - ), - const SizedBox(width: 8), - Text( - "Filter", - style: Variables.bodyStyle.copyWith( - fontWeight: FontWeight.w600, - fontSize: 13, - ), - ), - ], - ), - ), - ), - ], - ), - ), Expanded( child: _showAlternateView diff --git a/lib/ui/pages/project_board_page_alternate.dart b/lib/ui/pages/project_board_page_alternate.dart @@ -221,14 +221,6 @@ class ProjectBoardPageAlternateState extends State<ProjectBoardPageAlternate> { padding: const EdgeInsets.fromLTRB(16, 0, 16, 16), child: Row( children: [ - Text( - "ALL IMAGES (${_filteredImages.length})", - style: Variables.captionStyle.copyWith( - fontWeight: FontWeight.bold, - letterSpacing: 1.2, - color: Variables.textSecondary, - ), - ), const Spacer(), if (_selectedTags.isNotEmpty) Container( diff --git a/lib/ui/pages/project_detail_page.dart b/lib/ui/pages/project_detail_page.dart @@ -216,6 +216,8 @@ class _ProjectDetailPageState extends State<ProjectDetailPage> { ), backgroundColor: const Color(0xFFFAFAFA), elevation: 0, + leadingWidth: 40, + titleSpacing: 4, actions: [ IconButton( icon: SvgPicture.asset( @@ -509,46 +511,44 @@ class _ProjectDetailPageState extends State<ProjectDetailPage> { width: 1, ), ), + clipBehavior: Clip.antiAlias, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Three images side by side (or fewer if not available) Container( height: 115, - padding: const EdgeInsets.all(4), + padding: const EdgeInsets.only(bottom: 4), child: Row( children: [ // Show up to 3 images - for (int i = 0; i < 3; i++) + for (int i = 0; i < 3; i++) ...[ Expanded( - child: Padding( - padding: EdgeInsets.only( - right: i < 2 ? 4 : 0, - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(4), - child: i < eventImages.length - ? Image.file( - File(eventImages[i].filePath), - fit: BoxFit.cover, - errorBuilder: (context, error, stackTrace) { - return Container( - color: Colors.grey[300], - ); - }, - ) - : Container( - color: Colors.grey[200], - ), - ), + child: ClipRRect( + borderRadius: BorderRadius.circular(4), + child: i < eventImages.length + ? Image.file( + File(eventImages[i].filePath), + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + return Container( + color: Colors.grey[300], + ); + }, + ) + : Container( + color: Colors.grey[200], + ), ), ), + if (i < 2) const SizedBox(width: 4), + ], ], ), ), // Event title Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), + padding: const EdgeInsets.fromLTRB(4, 16, 16, 16), child: Text( event.title, style: const TextStyle( diff --git a/lib/ui/widgets/top_bar.dart b/lib/ui/widgets/top_bar.dart @@ -10,6 +10,11 @@ class TopBar extends StatefulWidget implements PreferredSizeWidget { final Function(ProjectModel)? onProjectChanged; final VoidCallback? onSettingsPressed; final String? titleOverride; + final VoidCallback? onLayoutPressed; + final VoidCallback? onFilterPressed; + final VoidCallback? onAIPressed; + final bool? isAlternateView; // For toggle state + final VoidCallback? onLayoutToggle; // For toggle callback const TopBar({ super.key, @@ -18,13 +23,18 @@ class TopBar extends StatefulWidget implements PreferredSizeWidget { this.onProjectChanged, this.onSettingsPressed, this.titleOverride, + this.onLayoutPressed, + this.onFilterPressed, + this.onAIPressed, + this.isAlternateView, + this.onLayoutToggle, }); @override State<TopBar> createState() => _TopBarState(); @override - Size get preferredSize => const Size.fromHeight(kToolbarHeight); + Size get preferredSize => const Size.fromHeight(88.0); // Height for two rows } class _TopBarState extends State<TopBar> { @@ -91,154 +101,231 @@ class _TopBarState extends State<TopBar> { Widget build(BuildContext context) { final textScaler = MediaQuery.of(context).textScaler; return Container( - color: Variables.background, + color: Colors.white, // White background child: SafeArea( bottom: false, - child: SizedBox( - height: kToolbarHeight, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: Row( - children: [ - // 1. Back Button - if (widget.onBack != null) ...[ - IconButton( - icon: const Icon( - Icons.arrow_back, - color: Variables.textPrimary, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // First Row: Title and Settings + Container( + height: 48.0, // py-[12px] = 24px + 24px content + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Row( + children: [ + // Back Button + if (widget.onBack != null) ...[ + GestureDetector( + onTap: widget.onBack, + child: Container( + width: 24, + height: 24, + alignment: Alignment.center, + child: const Icon( + Icons.arrow_back, + size: 20, + color: Variables.textPrimary, + ), + ), ), - onPressed: widget.onBack, - ), - const SizedBox(width: 8), - ], - - // 2. Title & Selector - Expanded( - child: - widget.titleOverride != null - ? Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text( - widget.titleOverride!, + const SizedBox(width: 8), + ], + // Title + Expanded( + child: widget.titleOverride != null + ? Text( + widget.titleOverride!, + style: const TextStyle( + fontFamily: 'GeneralSans', + fontSize: 20, + fontWeight: FontWeight.w500, + height: 24 / 20, // line-height: 24px + color: Variables.textPrimary, + ), + overflow: TextOverflow.ellipsis, + ) + : (!_isLoading && + _currentProject != null && + _rootProject != null) + ? Text( + _rootProject!.title, style: const TextStyle( fontFamily: 'GeneralSans', fontSize: 20, fontWeight: FontWeight.w500, + height: 24 / 20, color: Variables.textPrimary, ), overflow: TextOverflow.ellipsis, - ), - ) - : (!_isLoading && - _currentProject != null && - _rootProject != null) - ? Row( - children: [ - if (widget.onBack == null) - const SizedBox(width: 12), - Flexible( - child: Text( - _rootProject!.title, - style: const TextStyle( - fontFamily: 'GeneralSans', - fontSize: 20, - fontWeight: FontWeight.w500, - color: Variables.textPrimary, - ), - overflow: TextOverflow.ellipsis, - ), - ), - const SizedBox(width: 8), - ], - ) - : const SizedBox(), - ), - if (!_isLoading && - _currentProject != null && - _rootProject != null) - PopupMenuButton<ProjectModel>( - padding: EdgeInsets.zero, - onSelected: - (project) => widget.onProjectChanged?.call(project), - color: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), - ), - offset: const Offset(0, 38), - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 14, - vertical: 10, - ), - decoration: BoxDecoration( - color: Variables.surfaceSubtle, - borderRadius: BorderRadius.circular(16), + ) + : const SizedBox(), + ), + // Settings Icon + GestureDetector( + onTap: widget.onSettingsPressed, + child: SvgPicture.asset( + 'assets/icons/settings-line.svg', + width: 24, + height: 24, + colorFilter: const ColorFilter.mode( + Variables.textPrimary, + BlendMode.srcIn, ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - _currentProject!.id == _rootProject!.id - ? "Main" - : _currentProject!.title, - style: Variables.bodyStyle.copyWith( - fontFamily: 'GeneralSans', - fontSize: 15 * textScaler.scale(1.1), - fontWeight: FontWeight.w500, - color: Variables.textPrimary, + ), + ), + ], + ), + ), + // Second Row: Global Dropdown and Action Buttons + Container( + height: 40.0, // py-[8px] = 16px + 24px content + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Row( + children: [ + // Left group: Global Dropdown and Layout Button + Row( + children: [ + // Global Dropdown + if (!_isLoading && + _currentProject != null && + _rootProject != null) + PopupMenuButton<ProjectModel>( + padding: EdgeInsets.zero, + onSelected: (project) => + widget.onProjectChanged?.call(project), + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + offset: const Offset(0, 42), + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + decoration: BoxDecoration( + color: Variables.borderSubtle, // #e4e4e7 + borderRadius: BorderRadius.circular(8), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + _currentProject!.id == _rootProject!.id + ? "Global" + : _currentProject!.title, + style: const TextStyle( + fontFamily: 'GeneralSans', + fontSize: 16, + fontWeight: FontWeight.w500, + height: 24 / 16, + color: Variables.textPrimary, + ), + ), + const SizedBox(width: 8), + const Icon( + Icons.keyboard_arrow_down_rounded, + size: 20, + color: Variables.textPrimary, + ), + ], ), ), - const SizedBox(width: 6), - const Icon( - Icons.keyboard_arrow_down_rounded, - size: 18, + itemBuilder: (context) { + return _contextList.map((project) { + final isSelected = project.id == _currentProject!.id; + final isRoot = project.id == _rootProject!.id; + return PopupMenuItem<ProjectModel>( + value: project, + child: Text( + isRoot ? "Global" : project.title, + style: Variables.bodyStyle.copyWith( + fontFamily: 'GeneralSans', + fontWeight: isSelected + ? FontWeight.bold + : FontWeight.normal, + color: isSelected + ? Variables.textPrimary + : Variables.textSecondary, + ), + ), + ); + }).toList(); + }, + ), + const SizedBox(width: 8), + // Layout Icon Button (Toggle between All Images/Categorized) + GestureDetector( + onTap: widget.onLayoutToggle ?? widget.onLayoutPressed, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + decoration: BoxDecoration( + color: Variables.borderSubtle, + borderRadius: BorderRadius.circular(1000), + ), + child: Icon( + widget.isAlternateView == true + ? Icons.dashboard + : Icons.view_agenda_outlined, + size: 20, color: Variables.textPrimary, ), - ], + ), ), - ), - itemBuilder: (context) { - return _contextList.map((project) { - final isSelected = project.id == _currentProject!.id; - final isRoot = project.id == _rootProject!.id; - return PopupMenuItem<ProjectModel>( - value: project, - child: Text( - isRoot ? "Main Project" : project.title, - style: Variables.bodyStyle.copyWith( - fontFamily: 'GeneralSans', - fontWeight: - isSelected - ? FontWeight.bold - : FontWeight.normal, - color: - isSelected - ? Variables.textPrimary - : Variables.textSecondary, - ), - ), - ); - }).toList(); - }, + ], ), - const SizedBox(width: 4), - - // 3. Settings Icon - IconButton( - icon: SvgPicture.asset( - 'assets/icons/settings-line.svg', - width: 24, - height: 24, - colorFilter: const ColorFilter.mode( - Variables.textPrimary, - BlendMode.srcIn, - ), + const Spacer(), + // Right group: Filter and AI/Sparkle Buttons + Row( + children: [ + // Filter Icon Button + GestureDetector( + onTap: widget.onFilterPressed, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 10, + ), + decoration: BoxDecoration( + color: Variables.borderSubtle, + borderRadius: BorderRadius.circular(1000), + ), + child: const Icon( + Icons.tune, + size: 20, + color: Variables.textPrimary, + ), + ), + ), + const SizedBox(width: 8), + // AI/Sparkle Icon Button + GestureDetector( + onTap: widget.onAIPressed, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 10, + ), + decoration: BoxDecoration( + color: Variables.borderSubtle, + borderRadius: BorderRadius.circular(1000), + ), + child: const Icon( + Icons.auto_awesome, + size: 20, + color: Variables.textPrimary, + ), + ), + ), + ], ), - onPressed: widget.onSettingsPressed, - ), - ], + ], + ), ), - ), + ], ), ), );