Conversation
…integrate real Firebase data
BREAKING CHANGE: ProfileScreen now requires real Firestore and Firebase Storage integration
Features:
- Real profile photo upload/management with Firebase Storage integration
- Real notification settings saved to Firestore (cycleReminders, periodAlerts, cartUpdates)
- Real cart data loaded from Firestore sub-collection with empty state
- Real cycle predictions calculated from CycleDataService
- Device system date formatting instead of hardcoded dates
- New CycleHistoryScreen showing real historical cycle data from Firestore
- New DeleteAccountScreen with secure account deletion and data cleanup
- Comprehensive error handling with user-friendly messages
- Graceful fallbacks for missing data
UI/UX Improvements:
- Profile photo with camera icon and loading spinner
- Photo options modal (change/remove)
- Empty states with helpful icons and messages
- Error display in safe, non-intrusive containers
- Real-time notification toggle persistence
- Proper confirmation dialogs for destructive actions
New Dependencies:
- firebase_storage: ^13.0.5 (Cloud Storage for photos)
- image_picker: ^1.0.0 (Gallery photo selection)
- intl: ^0.20.0 (Date localization and formatting)
Data Architecture:
- Firestore: users/{uid}/{name,profilePhotoUrl,cycleLength,periodDuration}
- Firestore: users/{uid}/settings/notifications/{cycleReminders,periodAlerts,cartUpdates}
- Firestore: users/{uid}/cart/{itemId}/{name,price,image,quantity}
- Firestore: users/{uid}/cycleHistory/{recordId}/{startDate,endDate,cycleLength,notes}
- Firebase Storage: profile_photos/{uid}.jpg
All code compiles with zero errors. All features tested. Production ready.
…eens - ProfileScreen: Convert from .get() to real-time StreamBuilder listeners - Implement Instagram-style tappable profile avatar with photo upload/remove - Real-time user data, notifications, cart, and cycle predictions - CycleHistoryScreen: Switch to snapshots() for live cycle history updates - CycleDataService: Add getUserCycleDataStream() for real-time listeners - All date displays use DateTime.now() with intl formatting - Removed all hardcoded/static data - everything is live from Firestore - All settings menu items functional with proper navigation - Zero compilation errors, production-ready
- Deleted profile_screen_old.dart (legacy backup) - Consolidated 17 redundant markdown files into single CHANGELOG.md - Removed all update-specific documentation files - Kept only essential docs: README, CHANGELOG, ARCHITECTURE, CONTRIBUTORS, ISSUES - Verified zero compilation errors after cleanup - Enforced single active implementation for all screens - Repository now follows minimalism principle (every file purposeful)
- Created comprehensive design system with Material You colors, soft corners, and calm motion curves - Implemented reusable minimal component library (SoftContainer, MinimalButton, MinimalTextField, ExpandableSection) - Redesigned all authentication screens (Splash, Login, Signup) with smooth animations and calm typography - Redesigned home dashboard with cycle status tracking, quick actions, and daily insights - Redesigned shop screen with product grid, search, and modal bottom sheet details - Redesigned profile screen with user info, settings, and logout functionality - Updated minimal bottom navigation with smooth active state transitions - All functionality preserved while upgrading to minimalist, premium-feeling design - Implements quiet UI philosophy: UI that disappears, content first, chrome second - Soft surfaces via blur-based elevation instead of harsh shadows - System-blended colors with low contrast and muted tones - Smooth motion with calm easing curves (no bouncy animations) - Emotional, adaptable design suitable for Android 16+ devices
- Added 'Create Account' heading to Signup screen - Added 'Login' heading to Login screen - Added 'Update Password' heading to Change Password screen - Implemented password visibility toggle (eye icon) for all password fields - Users can now click to show/hide passwords while typing - Improved UX with better visual hierarchy and form labels
- Create LocalCycleStorage class for device-only menstrual history
* Store period start/end events locally with no Firebase sync
* Automatic data wipe on logout for privacy
* JSON serialization for events and notification settings
- Add iOS-style period input bottom sheet (PeriodInputSheet)
* Two-branch logic: Period Start (if not marked) or Period End (if marked)
* Date picker with Today/Yesterday/2-3 days ago options
* Smooth animations and modern UI
- Update Calendar screen with local period tracking
* Floating action button ('+') to trigger period input
* Color-coded calendar cells: Red (period), Green (fertile), Purple (ovulation)
* Snackbar confirmation when period events are saved
- Add notification controls to Profile screen
* Keep only Cycle Reminder and Period Alert toggles
* Remove Cart & Order Updates notifications
* Settings persist locally via LocalCycleStorage
* Notifications cleared on logout for privacy
- Update cycle algorithm integration
* Calendar rendering now uses algorithm predictions
* Manual period marks take precedence over predictions
MAJOR IMPROVEMENTS: - Algorithm now uses ACTUAL period data from LocalCycleStorage * recentPeriodStart/recentPeriodEnd properties added * getType() checks marked periods FIRST, then falls back to predictions * Calendar shows red from marked startend (or start + periodLength if no end marked) - Smart period flow detection * '+' button now detects if TODAY is in a marked period * Shows 'Did your period start?' ONLY if not currently in period * Shows 'Did your period stop?' when already in marked period - Real-time calendar updates on save * After marking period start/end, _loadRecentPeriodData() reloads actual events * Calendar immediately refreshes with new predictions * Old period dates stay on calendar while new predictions update - Home screen integration * initState loads period data on app startup * Algorithm gets recentPeriodStart/End on load * All screens see same updated algorithm instance WORKFLOW EXAMPLE: 1. Today is Jan 21 Tap '+' 'Did period start?' Yes Today Save 2. Calendar shows red: 21, 22, 23, 24, 25, 26 (based on periodLength ~5-6) 3. Tomorrow (Jan 22, still red) Tap '+' Now asks 'Did period stop?' Yes Today Save 4. Calendar updates: marked period is Jan 21-22 only 5. Algorithm recalculates next cycle based on actual data No Firebase sync - all local only!
- Remove debug print() calls from calendar_screen.dart - Remove debug print() calls from home_screen.dart - Replace with silent error handling for production All compilation issues resolved. Code is production-ready.
MAJOR ARCHITECTURAL CHANGE - Event-Driven State Machine NEW CLASSES: - CycleHistoryEntry: Immutable cycle record (start, end, lengths) - CycleState: Single source of truth with: * bleedingState (ACTIVE_BLEEDING | NO_ACTIVE_BLEEDING) * bleedingStartDate/EndDate * averageCycleLength/BleedingLength * cycleHistory[] (all confirmed cycles) - PredictionEngine: Pure functions for: * getDayType() - returns DayType from state * getNextPeriodStart/End() - future predictions * getOvulationDate() - mid-cycle calculation * getFertileWindow() - 5 days before ovulation REFACTORED STORAGE: - LocalCycleStorage now saves entire CycleState (not events) - saveCycleState() / loadCycleState() - atomic operations - No predictions stored, only state REFACTORED CALENDAR: - _dayCell now uses PredictionEngine.getDayType() - Pure rendering from state (no side effects) - Calendar re-renders fully on state change REFACTORED HOME/CALENDAR: - Removed CycleAlgorithm, CycleSession dependencies - Uses CycleState + PredictionEngine - Immediate calendar updates after SAVE STATE MUTATIONS: - markPeriodStart(): Sets state.ACTIVE_BLEEDING - markPeriodStop(): Calculates lengths, finalizes cycle, WEIGHTED averages FLOW: INPUT STATE MUTATION PREDICTION RENDER No prediction caching. Pure functions. State is truth.
…ization and loading
- Enhanced CycleState with isActiveBleeding getter, confirmedCycles getter, and getHistoricalBleedingRanges() method - Fixed weighted average calculation bug in _updateAveragesFromHistory() - Enhanced PredictionEngine to detect ALL historical confirmed cycles - Added activePeriod DayType for ongoing bleeding with animation support - Fixed _todayCell() in calendar to show day type colors while keeping today indicator - Added comprehensive tests for edge cases (short/long cycles, early periods, two periods per month) - Added new prediction_engine_test.dart test file This implements the event-driven cycle state machine as specified: User Action -> State Mutation -> Prediction Recalculation -> Calendar Redraw
alwin-m
left a comment
There was a problem hiding this comment.
image_picker (direct main)
You explicitly added this package.
It lets your app pick images or videos from the camera or gallery.
Platform-specific packages (transitive)
Automatically added by Flutter to support each platform:
- Android, iOS, Web, Windows, macOS, Linux
You don’t import these directly.
image_picker_platform_interface
Defines the common API that all platforms must follow.
Think of it as an interface or abstract class.
sha256 & url
Used by Dart to verify package security and source.
intl (direct main)
You explicitly added this.
Used for date, time, number, and locale-based formatting.
Summary
You use one Dart API, Flutter handles platform differences automatically.
| image_picker: | ||
| dependency: "direct main" | ||
| description: | ||
| name: image_picker | ||
| sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320" | ||
| url: "https://pub.dev" | ||
| source: hosted | ||
| version: "1.2.1" | ||
| image_picker_android: | ||
| dependency: transitive | ||
| description: | ||
| name: image_picker_android | ||
| sha256: "5e9bf126c37c117cf8094215373c6d561117a3cfb50ebc5add1a61dc6e224677" | ||
| url: "https://pub.dev" | ||
| source: hosted | ||
| version: "0.8.13+10" | ||
| image_picker_for_web: | ||
| dependency: transitive | ||
| description: | ||
| name: image_picker_for_web | ||
| sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214" | ||
| url: "https://pub.dev" | ||
| source: hosted | ||
| version: "3.1.1" | ||
| image_picker_ios: | ||
| dependency: transitive | ||
| description: | ||
| name: image_picker_ios | ||
| sha256: "956c16a42c0c708f914021666ffcd8265dde36e673c9fa68c81f7d085d9774ad" | ||
| url: "https://pub.dev" | ||
| source: hosted | ||
| version: "0.8.13+3" | ||
| image_picker_linux: | ||
| dependency: transitive | ||
| description: | ||
| name: image_picker_linux | ||
| sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" | ||
| url: "https://pub.dev" | ||
| source: hosted | ||
| version: "0.2.2" | ||
| image_picker_macos: | ||
| dependency: transitive | ||
| description: | ||
| name: image_picker_macos | ||
| sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" | ||
| url: "https://pub.dev" | ||
| source: hosted | ||
| version: "0.2.2+1" | ||
| image_picker_platform_interface: | ||
| dependency: transitive | ||
| description: | ||
| name: image_picker_platform_interface | ||
| sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" | ||
| url: "https://pub.dev" | ||
| source: hosted | ||
| version: "2.11.1" | ||
| image_picker_windows: | ||
| dependency: transitive | ||
| description: | ||
| name: image_picker_windows | ||
| sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae | ||
| url: "https://pub.dev" | ||
| source: hosted | ||
| version: "0.2.2" | ||
| intl: | ||
| dependency: "direct main" |
There was a problem hiding this comment.
image_picker (direct main)
This is the package you explicitly added in pubspec.yaml.
What it does:
image_picker provides a simple Dart API to pick images or videos from the device gallery or camera.
Why it’s “direct main”:
- You directly depend on it
- You import and use it in your Flutter code
Platform-specific implementations (transitive)
These are automatically pulled in by Flutter. You do not import them directly.
image_picker_android
Handles Android-specific camera and gallery access using native Android APIs.
image_picker_ios
Implements image picking for iOS using Apple’s photo picker and permission system.
image_picker_for_web
Uses browser file input when your Flutter app runs on the web.
image_picker_macos
Provides image picking support for macOS desktop apps.
image_picker_linux
Implements file selection for Linux desktop environments.
image_picker_windows
Implements file picker functionality for Windows apps.
Why they’re “transitive”:
You didn’t add them directly. image_picker depends on them to work on each platform.
image_picker_platform_interface
This is the shared contract between Flutter and all platform implementations.
Purpose:
- Defines the methods every platform must implement
- Ensures Android, iOS, Web, and Desktop behave consistently
Think of it like an abstract class or interface in object-oriented programming.
sha256 and url fields
These are used by Dart’s package manager to:
- Verify package integrity
- Ensure secure downloads from pub.dev
You never need to modify these manually.
intl (direct main)
This is another package you explicitly added.
What it does:
intl is used for internationalization and localization, including:
- Date and time formatting
- Number and currency formatting
- Locale-aware text handling
Why it’s “direct main”:
- You added it yourself
- It’s likely used for formatting dates, times, or localized strings
Big picture
This structure allows you to write one Dart API while Flutter handles platform-specific details behind the scenes. The result is clean, maintainable, and platform-independent code.
alwin-m
left a comment
There was a problem hiding this comment.
Small Explanation
This code is used to show and hide passwords in the Change Password screen.
Each bool variable controls one password field:
- Old password
- New password
- Confirm password
Passwords are hidden by default for security.
When the eye icon is tapped:
setState()is called- The password visibility toggles (hidden ↔ visible)
- The UI updates instantly
This improves security, usability, and user experience.
| @@ -1,5 +1,6 @@ | |||
| import 'package:flutter/material.dart'; | |||
| import 'package:firebase_auth/firebase_auth.dart'; | |||
| import 'package:google_fonts/google_fonts.dart'; | |||
There was a problem hiding this comment.
import 'package:google_fonts/google_fonts.dart';
| bool _obscureOldPassword = true; | ||
| bool _obscureNewPassword = true; | ||
| bool _obscureConfirmPassword = true; |
There was a problem hiding this comment.
These booleans
bool _obscureOldPassword = true;
bool _obscureNewPassword = true;
bool _obscureConfirmPassword = true;
Control whether each password field is hidden or visible
true → password is hidden (••••)
false → password text is shown
Each field has its own variable, so toggling one does not affect the others.
| obscureText: _obscureOldPassword, | ||
| decoration: InputDecoration( | ||
| labelText: "Old password", | ||
| suffixIcon: IconButton( | ||
| icon: Icon( | ||
| _obscureOldPassword | ||
| ? Icons.visibility_off | ||
| : Icons.visibility, | ||
| ), | ||
| onPressed: () { | ||
| setState(() { | ||
| _obscureOldPassword = !_obscureOldPassword; | ||
| }); | ||
| }, | ||
| ), | ||
| ), | ||
| ), | ||
| const SizedBox(height: 16), | ||
|
|
||
| TextField( | ||
| controller: newPasswordController, | ||
| obscureText: true, | ||
| decoration: const InputDecoration(labelText: "New password"), | ||
| obscureText: _obscureNewPassword, | ||
| decoration: InputDecoration( | ||
| labelText: "New password", | ||
| suffixIcon: IconButton( | ||
| icon: Icon( | ||
| _obscureNewPassword | ||
| ? Icons.visibility_off | ||
| : Icons.visibility, | ||
| ), | ||
| onPressed: () { | ||
| setState(() { | ||
| _obscureNewPassword = !_obscureNewPassword; | ||
| }); | ||
| }, | ||
| ), | ||
| ), | ||
| ), | ||
| const SizedBox(height: 16), | ||
|
|
||
| TextField( | ||
| controller: confirmPasswordController, | ||
| obscureText: true, | ||
| decoration: | ||
| const InputDecoration(labelText: "Confirm new password"), | ||
| obscureText: _obscureConfirmPassword, | ||
| decoration: InputDecoration( | ||
| labelText: "Confirm new password", | ||
| suffixIcon: IconButton( | ||
| icon: Icon( | ||
| _obscureConfirmPassword | ||
| ? Icons.visibility_off | ||
| : Icons.visibility, | ||
| ), | ||
| onPressed: () { | ||
| setState(() { | ||
| _obscureConfirmPassword = !_obscureConfirmPassword; | ||
| }); | ||
| }, | ||
| ), | ||
| ), | ||
| ), | ||
| const SizedBox(height: 32), | ||
|
|
There was a problem hiding this comment.
Explanation of the Change Password UI Logic
This section explains how the password visibility and input fields work in your Change Password screen.
1. Password Visibility State Variables
bool _obscureOldPassword = true;
bool _obscureNewPassword = true;
bool _obscureConfirmPassword = true;Each boolean controls whether a password field hides (true) or shows (false) the text:
_obscureOldPassword→ Old password field_obscureNewPassword→ New password field_obscureConfirmPassword→ Confirm password field
Using separate variables allows each field to toggle visibility independently.
2. TextField with Visibility Toggle (Old Password)
TextField(
controller: oldPasswordController,
obscureText: _obscureOldPassword,
decoration: InputDecoration(
labelText: "Old password",
suffixIcon: IconButton(
icon: Icon(
_obscureOldPassword
? Icons.visibility_off
: Icons.visibility,
),
onPressed: () {
setState(() {
_obscureOldPassword = !_obscureOldPassword;
});
},
),
),
)How it works:
obscureTexthides the password whentrue- The eye icon changes depending on visibility state
- Pressing the icon calls
setState()and toggles the boolean - Flutter rebuilds the widget and updates the UI instantly
3. New Password & Confirm Password Fields
These fields work exactly the same way as the old password field but use their own state variables:
_obscureNewPassword_obscureConfirmPassword
This ensures toggling one field does not affect the others.
4. Layout Spacing
const SizedBox(height: 16);
const SizedBox(height: 32);SizedBox(height: 16)adds spacing between fieldsSizedBox(height: 32)adds spacing before the action button (e.g., Update Password)
This improves readability and touch comfort.
5. UX & Security Benefits
- Passwords are hidden by default for security
- Users can temporarily reveal passwords to avoid typing mistakes
- Independent toggles improve usability
- Clean, minimal UI consistent with modern Android & iOS standards
✅ Result: A secure, user-friendly password update screen that follows best UX practices.
No description provided.