Skip to content

Feature/authentication#6

Open
alwin-m wants to merge 22 commits intomainfrom
feature/authentication
Open

Feature/authentication#6
alwin-m wants to merge 22 commits intomainfrom
feature/authentication

Conversation

@alwin-m
Copy link
Owner

@alwin-m alwin-m commented Jan 21, 2026

No description provided.

…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.
- 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
Copy link
Owner Author

@alwin-m alwin-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines 307 to 372
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"
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Owner Author

@alwin-m alwin-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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';
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import 'package:google_fonts/google_fonts.dart';

Comment on lines 18 to 20
bool _obscureOldPassword = true;
bool _obscureNewPassword = true;
bool _obscureConfirmPassword = true;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines 76 to 136
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),

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  • obscureText hides the password when true
  • 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 fields
  • SizedBox(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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant