creek

The AI Image Editor of 2030
commit 104ce305cb45402a93618fb018309a439294d0df
parent a7a2ef91001d50bf7cbca0e114b4f5ad8b907ff3
Author: maydayv7 <maydayv7@gmail.com>
Date:   Sat,  6 Dec 2025 05:30:26 +0530

Add setting for user name

Diffstat:
Mlib/ui/pages/canvas_page.dart | 2+-
Mlib/ui/pages/define_brand_page.dart | 2+-
Mlib/ui/pages/home_page.dart | 50+++++++++++++++++++++++++++++++++++---------------
Mlib/ui/pages/settings_page.dart | 165++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mlib/ui/pages/stylesheet_page.dart | 2+-
Mlib/ui/widgets/note_input_sheet.dart | 18+++++++++++++++---
Mlib/ui/widgets/top_bar.dart | 19++++++++++++-------
7 files changed, 207 insertions(+), 51 deletions(-)

diff --git a/lib/ui/pages/canvas_page.dart b/lib/ui/pages/canvas_page.dart @@ -1605,7 +1605,7 @@ class _CanvasPageState extends State<CanvasPage> { debugPrint("Generation Error: $e"); ScaffoldMessenger.of( context, - ).showSnackBar(const SnackBar(content: Text("Generation failed."))); + ).showSnackBar(const SnackBar(content: Text("Generation failed"))); } finally { setState(() { _isInpainting = false; diff --git a/lib/ui/pages/define_brand_page.dart b/lib/ui/pages/define_brand_page.dart @@ -61,7 +61,7 @@ class _DefineBrandPageState extends State<DefineBrandPage> { // 1. Basic Validation if (_projectNameController.text.trim().isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Project name is required.')), + const SnackBar(content: Text('Project name is required')), ); return; } diff --git a/lib/ui/pages/home_page.dart b/lib/ui/pages/home_page.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:image/image.dart' as img; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:creekui/data/models/project_model.dart'; import 'package:creekui/data/models/file_model.dart'; import 'package:creekui/data/repos/project_repo.dart'; @@ -14,6 +15,7 @@ import 'package:creekui/ui/widgets/file_card.dart'; import 'package:creekui/ui/widgets/project_card.dart'; import 'package:creekui/ui/widgets/empty_state.dart'; import 'package:creekui/ui/widgets/section_header.dart'; +import 'package:creekui/ui/pages/settings_page.dart'; import 'project_detail_page.dart'; import 'define_brand_page.dart'; import 'canvas_page.dart'; @@ -40,7 +42,7 @@ class _HomePageState extends State<HomePage> { final Map<int, List<String>> _projectPreviews = {}; Map<String, Map<String, String>> _fileMetadata = {}; bool _isLoading = true; - final String _userName = "Alex"; // TODO + String _userName = "Alex"; // Default @override void initState() { @@ -57,6 +59,10 @@ class _HomePageState extends State<HomePage> { Future<void> _loadData() async { setState(() => _isLoading = true); try { + // Load User Name + final prefs = await SharedPreferences.getInstance(); + final storedName = prefs.getString('user_name') ?? "Alex"; + final allProjects = await _projectRepo.getAllProjects(); final Map<int, ProjectModel> projectMap = {}; for (final project in allProjects) { @@ -114,6 +120,7 @@ class _HomePageState extends State<HomePage> { if (mounted) { setState(() { + _userName = storedName; _allProjects = allProjects; _recentFiles = recentFiles; _projectMap = projectMap; @@ -470,21 +477,34 @@ class _HomePageState extends State<HomePage> { ), ), const Spacer(), - Container( - width: 30, - height: 30, - decoration: BoxDecoration( - color: theme.colorScheme.primaryContainer, - shape: BoxShape.circle, - border: Border.all( - color: theme.scaffoldBackgroundColor, - width: 1.25, + GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => const SettingsPage(), + ), + ).then((_) { + _loadData(); // Reload to update name + }); + }, + behavior: HitTestBehavior.opaque, + child: Container( + width: 30, + height: 30, + decoration: BoxDecoration( + color: theme.colorScheme.primaryContainer, + shape: BoxShape.circle, + border: Border.all( + color: theme.scaffoldBackgroundColor, + width: 1.25, + ), + ), + child: Icon( + Icons.person, + size: 16, + color: theme.colorScheme.onPrimaryContainer, ), - ), - child: Icon( - Icons.person, - size: 16, - color: theme.colorScheme.onPrimaryContainer, ), ), ], diff --git a/lib/ui/pages/settings_page.dart b/lib/ui/pages/settings_page.dart @@ -1,12 +1,66 @@ import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:creekui/ui/styles/variables.dart'; import 'package:creekui/ui/pages/image_analysis_page.dart'; +import 'package:creekui/ui/widgets/primary_button.dart'; -class SettingsPage extends StatelessWidget { +class SettingsPage extends StatefulWidget { const SettingsPage({super.key}); @override + State<SettingsPage> createState() => _SettingsPageState(); +} + +class _SettingsPageState extends State<SettingsPage> { + final TextEditingController _nameController = TextEditingController(); + bool _isLoading = true; + String _originalName = ''; + + @override + void initState() { + super.initState(); + _loadUserData(); + } + + Future<void> _loadUserData() async { + final prefs = await SharedPreferences.getInstance(); + String name = prefs.getString('user_name') ?? 'Alex'; + if (name.trim().isEmpty) { + name = 'Alex'; + } + + setState(() { + _nameController.text = name; + _originalName = name; + _isLoading = false; + }); + } + + Future<void> _saveUserName() async { + final newName = _nameController.text.trim(); + if (newName.isEmpty) return; + + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('user_name', newName); + + setState(() { + _originalName = newName; + }); + + if (mounted) { + FocusScope.of(context).unfocus(); + } + } + + @override + void dispose() { + _nameController.dispose(); + super.dispose(); + } + + @override Widget build(BuildContext context) { + final bool hasChanges = _nameController.text.trim() != _originalName; return Scaffold( backgroundColor: Colors.white, appBar: AppBar( @@ -21,29 +75,94 @@ class SettingsPage extends StatelessWidget { elevation: 0, iconTheme: const IconThemeData(color: Variables.textPrimary), ), - body: ListView( - children: [ - ListTile( - title: const Text( - "Test Image Analysis", - style: TextStyle( - fontFamily: 'GeneralSans', - color: Variables.textPrimary, + body: + _isLoading + ? const Center(child: CircularProgressIndicator()) + : Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + "Profile Settings", + style: TextStyle( + fontFamily: 'GeneralSans', + fontSize: 18, + fontWeight: FontWeight.w600, + color: Variables.textPrimary, + ), + ), + const SizedBox(height: 16), + + // User Name Field + const Text( + "Your Name", + style: TextStyle( + fontFamily: 'GeneralSans', + fontSize: 14, + color: Variables.textSecondary, + ), + ), + const SizedBox(height: 8), + TextField( + controller: _nameController, + onChanged: (val) { + setState( + () {}, + ); // Trigger rebuild to show/hide checkmark + }, + decoration: InputDecoration( + hintText: "Enter your name", + hintStyle: TextStyle( + color: Variables.textSecondary.withValues(alpha: 0.5), + ), + filled: true, + fillColor: Variables.surfaceSubtle, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide.none, + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), + suffixIcon: + hasChanges + ? IconButton( + icon: const Icon( + Icons.check, + color: Variables.textPrimary, + ), + onPressed: _saveUserName, + tooltip: 'Save Name', + ) + : null, + ), + style: const TextStyle( + fontFamily: 'GeneralSans', + fontSize: 16, + color: Variables.textPrimary, + ), + ), + + const Spacer(), + + // Test Analysis + PrimaryButton( + text: "Test Image Analysis", + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => const ImageAnalysisPage(), + ), + ); + }, + ), + const SizedBox(height: 20), + ], + ), ), - ), - trailing: const Icon( - Icons.chevron_right, - color: Variables.textSecondary, - ), - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (_) => const ImageAnalysisPage()), - ); - }, - ), - ], - ), ); } } diff --git a/lib/ui/pages/stylesheet_page.dart b/lib/ui/pages/stylesheet_page.dart @@ -178,7 +178,7 @@ class _StylesheetPageState extends State<StylesheetPage> { if (analysisData.isEmpty) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text("No analyzed images or notes found.")), + const SnackBar(content: Text("No analyzed images or notes found")), ); } return; diff --git a/lib/ui/widgets/note_input_sheet.dart b/lib/ui/widgets/note_input_sheet.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:creekui/ui/styles/variables.dart'; class NoteInputSheet extends StatefulWidget { @@ -20,11 +21,22 @@ class NoteInputSheet extends StatefulWidget { class _NoteInputSheetState extends State<NoteInputSheet> { late String _selectedCategory; final TextEditingController _controller = TextEditingController(); + String _userName = "Alex"; // Default @override void initState() { super.initState(); _selectedCategory = widget.initialCategory; + _loadUserName(); + } + + Future<void> _loadUserName() async { + final prefs = await SharedPreferences.getInstance(); + if (mounted) { + setState(() { + _userName = prefs.getString('user_name') ?? "Alex"; + }); + } } @override @@ -60,9 +72,9 @@ class _NoteInputSheetState extends State<NoteInputSheet> { ), ), const SizedBox(width: 10), - const Text( - "Alex", // TODO - style: TextStyle( + Text( + _userName, + style: const TextStyle( fontFamily: 'GeneralSans', fontSize: 12, fontWeight: FontWeight.w500, diff --git a/lib/ui/widgets/top_bar.dart b/lib/ui/widgets/top_bar.dart @@ -150,6 +150,7 @@ class _TopBarState extends State<TopBar> { // Back Button GestureDetector( onTap: _handleSafeBack, + behavior: HitTestBehavior.opaque, child: Container( width: 24, height: 24, @@ -198,13 +199,17 @@ class _TopBarState extends State<TopBar> { if (!widget.hideSecondRow) GestureDetector( onTap: _openSettings, - child: SvgPicture.asset( - 'assets/icons/settings-line.svg', - width: 24, - height: 24, - colorFilter: const ColorFilter.mode( - Variables.textPrimary, - BlendMode.srcIn, + behavior: HitTestBehavior.opaque, + child: Container( + padding: const EdgeInsets.all(4), + child: SvgPicture.asset( + 'assets/icons/settings-line.svg', + width: 24, + height: 24, + colorFilter: const ColorFilter.mode( + Variables.textPrimary, + BlendMode.srcIn, + ), ), ), ),