Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.4.0] - 2026-01-01

### Added
- **Transport Icon Service**: Unique icons for all 12 Philippine transport modes with `TransportIconStyle` support.
- **7-Layer Surface Container System**: Implemented Material 3 surface hierarchy for improved visual depth.
- **Security Audit Documentation**: Comprehensive security audit in `docs/security/`.

### Changed
- **Dark Mode Migration**: Updated to 2025 M3 standards with #121212 baseline.
- **Security Hardening**: Removed `.env` from assets and improved null safety in `fare_formula.dart`.

## [2.3.0+1] - 2025-01-01

### Added
Expand Down
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Flutter](https://img.shields.io/badge/Built%20with-Flutter-blue.svg)](https://flutter.dev/)
[![CI](https://github.com/MasuRii/ph-fare-calculator/actions/workflows/ci.yml/badge.svg)](https://github.com/MasuRii/ph-fare-calculator/actions/workflows/ci.yml)
[![Version](https://img.shields.io/badge/version-2.3.0-blue.svg)](https://github.com/MasuRii/ph-fare-calculator/releases)
[![Version](https://img.shields.io/badge/version-2.4.0-blue.svg)](https://github.com/MasuRii/ph-fare-calculator/releases)

**PH Fare Calculator** is a cross-platform mobile application designed to help tourists, expats, and locals estimate public transport costs across the Philippines.

Expand All @@ -26,6 +26,8 @@ Unlike city-centric navigation apps, this tool focuses on **"How much?"** rather
- **Nationwide Coverage:** Works in Metro Manila, Cebu, Davao, and rural provinces.
- **Modular Offline Maps:** Download maps by island group (Luzon, Visayas, Mindanao) to save storage space while ensuring functionality without internet.
- **Material 3 Design:** A completely redesigned UI/UX that follows modern Material Design guidelines for better accessibility and aesthetics.
- **Dark Mode (2025 M3 Standards):** Full dark mode implementation using Material Design 3 #121212 baseline with 7-layer surface container system for optimal eye comfort and accessibility.
- **Transport Icon Service:** Unique icons for all 12 Philippine transport modes (Jeepney, Bus, Taxi, Train, Ferry, Tricycle, UV Express, Van, Motorcycle, EDSA Carousel, Pedicab, Kuliglig) with TransportIconStyle enum supporting 4 variants (filled, rounded, outlined, sharp).
- **Hybrid Calculation Engine:**
- **Dynamic:** Uses **OSRM (Open Source Routing Machine)** to calculate road distance for Jeeps, Taxis, Buses, and Tricycles.
- **Static:** Uses embedded Lookup Tables for fixed-price modes like MRT/LRT (Trains) and Ferries.
Expand All @@ -38,6 +40,28 @@ Unlike city-centric navigation apps, this tool focuses on **"How much?"** rather
- **Offline Reference:** View saved routes and static fare matrices (Cheat Sheets) without an internet connection using **Hive** local storage.
- **Discount Support:** Built-in support for Student, Senior Citizen, and PWD discounts (20% off).

## πŸ“‹ Recent Changes (v2.4.0)

This release focuses on documentation improvements and security hardening to achieve A+ documentation assessment standards.

### Visual Improvements
- **Dark Mode Migration to 2025 M3 Standards:** Implemented Material Design 3 dark theme with #121212 baseline color, replacing the previous dark cyan theme for better eye comfort and accessibility compliance.
- **7-Layer Surface Container System:** Added comprehensive surface hierarchy with surfaceContainerLowest through surfaceBright roles for improved visual depth and accessibility.
- **Transport Icon Service:** Created centralized `TransportIconService` providing unique icons for all 12 Philippine transport modes:
- Jeepney, Bus (Ordinary/Aircon), Taxi, Train, Ferry, Tricycle, UV Express, Van, Motorcycle, EDSA Carousel, Pedicab, Kuliglig
- `TransportIconStyle` enum with 4 variants: filled, rounded, outlined, sharp
- Accessibility-friendly semantic labels for all icons

### Security Enhancements
- **Environment Configuration:** Removed `.env` file from assets directory to eliminate any potential exposure risk in production builds.
- **Null Safety:** Implemented comprehensive null safety patterns in fare formula parsing to prevent runtime exceptions.
- **Security Audit:** Completed comprehensive security audit documenting findings and remediation steps.

### Documentation Updates
- Created `docs/security/SECURITY_AUDIT_2026-01-01.md` with executive summary, findings, and remediation status
- Updated `docs/architecture/TRANSPORT_ICONS_DESIGN.md` with complete API design for icon service
- Added dark mode research documentation in `docs/research/mobile-dark-mode-standards-2025-01-01.md`

## πŸ›  Tech Stack

- **Framework:** Flutter & Dart
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground>
<inset
android:drawable="@drawable/ic_launcher_foreground"
android:inset="16%" />
</foreground>
</adaptive-icon>
Binary file modified android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions android/app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#0038A8</color>
</resources>
4 changes: 2 additions & 2 deletions ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
Expand Down Expand Up @@ -484,7 +484,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
Expand Down
123 changes: 1 addition & 122 deletions ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
Original file line number Diff line number Diff line change
@@ -1,122 +1 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions lib/src/core/constants/transport_icon_style.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/// Defines the available icon style variants for transport mode icons.
///
/// Each style provides a different visual appearance while maintaining
/// semantic consistency across the application.
enum TransportIconStyle {
/// Filled style - solid shapes with no negative space.
///
/// Typically used for primary actions or highly emphasized elements
/// to provide strong visual weight.
filled,

/// Rounded style - softer, friendlier appearance with rounded corners.
///
/// This is the default style used throughout the application to create
/// a modern and approachable feel.
rounded,

/// Outlined style - line-based icons with negative space.
///
/// Useful for secondary actions or in dense UIs where a lighter
/// visual weight is preferred to avoid overwhelming the user.
outlined,

/// Sharp style - angular, geometric appearance with square corners.
///
/// Can be used when a more technical, industrial, or precise
/// aesthetic is desired.
sharp;

/// Gets the suffix used in Material Icon names for this style.
///
/// Returns an empty string for [filled], and '_rounded', '_outlined',
/// or '_sharp' for the respective styles.
String get suffix {
return switch (this) {
TransportIconStyle.filled => '',
TransportIconStyle.rounded => '_rounded',
TransportIconStyle.outlined => '_outlined',
TransportIconStyle.sharp => '_sharp',
};
}

/// Gets the human-readable display name for this style.
String get displayName {
return switch (this) {
TransportIconStyle.filled => 'Filled',
TransportIconStyle.rounded => 'Rounded',
TransportIconStyle.outlined => 'Outlined',
TransportIconStyle.sharp => 'Sharp',
};
}

/// Gets the string representation of this style.
///
/// Returns the lowercase name of the style (e.g., 'rounded').
@override
String toString() => name;
}
Loading
Loading