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
44 changes: 34 additions & 10 deletions .github/workflows/release-apk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,26 +197,50 @@ jobs:
| **ARM32 (armeabi-v7a)** | `${{ steps.apk_files.outputs.apk_armv7 }}` |
| **x86_64** | `${{ steps.apk_files.outputs.apk_x86_64 }}` |

### Changes
## ✨ What's New
EOF

# Try to get commits since last tag, or last 10 commits if no previous tag
# Determine range
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")

if [ -n "$LAST_TAG" ]; then
echo "Changes since $LAST_TAG:" >> RELEASE_NOTES.md
echo "" >> RELEASE_NOTES.md
git log ${LAST_TAG}..HEAD --pretty=format:"- %s (%h)" --no-merges >> RELEASE_NOTES.md
RANGE="${LAST_TAG}..HEAD"
echo "Generating notes for range: $RANGE"
else
RANGE="HEAD~10..HEAD"
echo "No previous tag found, using last 10 commits"
fi

# Features
echo "🚀 **New Features:**" >> RELEASE_NOTES.md
FEATURES=$(git log ${RANGE} --grep="✨\|feat" --pretty=format:"- %s" --no-merges || echo "")
if [ -n "$FEATURES" ]; then
echo "$FEATURES" >> RELEASE_NOTES.md
else
echo "Recent commits:" >> RELEASE_NOTES.md
echo "" >> RELEASE_NOTES.md
git log -10 --pretty=format:"- %s (%h)" --no-merges >> RELEASE_NOTES.md
echo "- General improvements and updates" >> RELEASE_NOTES.md
fi
echo "" >> RELEASE_NOTES.md

# Bug Fixes
echo "🐛 **Bug Fixes:**" >> RELEASE_NOTES.md
FIXES=$(git log ${RANGE} --grep="🐛\|fix" --pretty=format:"- %s" --no-merges || echo "")
if [ -n "$FIXES" ]; then
echo "$FIXES" >> RELEASE_NOTES.md
else
echo "- Stability improvements" >> RELEASE_NOTES.md
fi
echo "" >> RELEASE_NOTES.md

# Improvements
echo "🎨 **Improvements:**" >> RELEASE_NOTES.md
IMPROVEMENTS=$(git log ${RANGE} --grep="🎨\|♻️\|🏗\|💄\|refactor\|perf" --pretty=format:"- %s" --no-merges || echo "")
if [ -n "$IMPROVEMENTS" ]; then
echo "$IMPROVEMENTS" >> RELEASE_NOTES.md
else
echo "- UI refinements and performance tweaks" >> RELEASE_NOTES.md
fi

echo "" >> RELEASE_NOTES.md
echo "---" >> RELEASE_NOTES.md
echo "" >> RELEASE_NOTES.md
echo "_Built with Flutter on GitHub Actions_" >> RELEASE_NOTES.md

# Output for debugging
Expand Down
65 changes: 28 additions & 37 deletions lib/src/core/di/injection.config.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 13 additions & 2 deletions lib/src/models/map_region.dart
Original file line number Diff line number Diff line change
Expand Up @@ -502,10 +502,21 @@ class StorageInfo {
/// Available storage in GB.
double get availableGB => availableBytes / (1024 * 1024 * 1024);

/// Total used percentage.
double get usedPercentage =>
/// Total device storage used percentage (for informational purposes).
double get deviceUsedPercentage =>
totalBytes > 0 ? (totalBytes - availableBytes) / totalBytes : 0.0;

/// Map cache usage as a percentage of total usable space (cache + available).
/// This is what the storage bar should display:
/// - When cache is 0 and available is 10GB, bar shows nearly empty (0%)
/// - When cache is 5GB and available is 5GB, bar shows 50%
/// - When cache is 10GB and available is 0, bar shows 100%
double get usedPercentage {
final totalUsableSpace = mapCacheBytes + availableBytes;
if (totalUsableSpace <= 0) return 0.0;
return mapCacheBytes / totalUsableSpace;
}

/// Formatted string for map cache size.
String get mapCacheFormatted {
if (mapCacheBytes < 1024 * 1024) {
Expand Down
38 changes: 38 additions & 0 deletions lib/src/models/transport_mode.dart
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,42 @@ enum TransportMode {
orElse: () => TransportMode.jeepney, // Default fallback
);
}

/// Parses a transport mode string into its base mode name and optional subtype.
///
/// Examples:
/// - "Jeepney (Traditional)" -> ("Jeepney", "Traditional")
/// - "Bus (Aircon)" -> ("Bus", "Aircon")
/// - "Jeepney (Modern (PUJ))" -> ("Jeepney", "Modern (PUJ)")
/// - "Taxi" -> ("Taxi", null)
///
/// Returns a record with baseName and subtype (nullable).
static ({String baseName, String? subtype}) parseTransportMode(String mode) {
final trimmed = mode.trim();

// Find the first opening parenthesis
final firstParenIndex = trimmed.indexOf('(');

if (firstParenIndex == -1) {
// No subtype
return (baseName: trimmed, subtype: null);
}

// Extract base name (everything before the first '(')
final baseName = trimmed.substring(0, firstParenIndex).trim();

// Extract subtype (everything between first '(' and last ')')
final lastParenIndex = trimmed.lastIndexOf(')');
if (lastParenIndex <= firstParenIndex) {
// Malformed string, treat as no subtype
return (baseName: baseName, subtype: null);
}

final subtype = trimmed.substring(firstParenIndex + 1, lastParenIndex).trim();

return (
baseName: baseName,
subtype: subtype.isNotEmpty ? subtype : null,
);
}
}
39 changes: 34 additions & 5 deletions lib/src/presentation/controllers/main_screen_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:latlong2/latlong.dart';
import '../../core/di/injection.dart';
import '../../core/errors/failures.dart';
import '../../core/hybrid_engine.dart';
import '../../models/discount_type.dart';
import '../../models/fare_formula.dart';
import '../../models/fare_result.dart';
import '../../models/location.dart';
Expand Down Expand Up @@ -140,9 +141,22 @@ class MainScreenController extends ChangeNotifier {
return _settingsService.hasSetDiscountType();
}

/// Set user discount type preference
Future<void> setUserDiscountType(dynamic discountType) async {
/// Set user discount type preference and update local passenger state.
Future<void> setUserDiscountType(DiscountType discountType) async {
await _settingsService.setUserDiscountType(discountType);

// Update local passenger counts based on the selected discount type
// Assuming a total of 1 passenger when first setting the preference
if (discountType == DiscountType.discounted) {
_regularPassengers = 0;
_discountedPassengers = 1;
} else {
_regularPassengers = 1;
_discountedPassengers = 0;
}
_passengerCount = _regularPassengers + _discountedPassengers;

notifyListeners();
}

/// Search locations with debounce for autocomplete
Expand Down Expand Up @@ -204,7 +218,9 @@ class MainScreenController extends ChangeNotifier {
}
}

/// Swap origin and destination
/// Swap origin and destination.
/// Note: Fare results are preserved on swap since the route distance
/// remains the same (just reversed direction).
void swapLocations() {
if (_originLocation == null && _destinationLocation == null) return;

Expand All @@ -217,7 +233,12 @@ class MainScreenController extends ChangeNotifier {
_destinationLocation = tempLocation;
_destinationLatLng = tempLatLng;

_resetResult();
// Note: We do NOT reset fare results on swap.
// The fare is based on distance which is the same regardless of direction.
// Only clear route points so they can be recalculated.
_routePoints = [];
_routeResult = null;

notifyListeners();

if (_originLocation != null && _destinationLocation != null) {
Expand Down Expand Up @@ -297,10 +318,18 @@ class MainScreenController extends ChangeNotifier {

final List<FareResult> results = [];
final trafficFactor = await _settingsService.getTrafficFactor();
final hasSetPrefs = await _settingsService.hasSetTransportModePreferences();
final hiddenModes = await _settingsService.getHiddenTransportModes();

final visibleFormulas = _availableFormulas.where((formula) {
final modeSubTypeKey = '${formula.mode}::${formula.subType}';

if (!hasSetPrefs) {
// New user - use default enabled modes
final defaultModes = SettingsService.getDefaultEnabledModes();
return defaultModes.contains(modeSubTypeKey);
}
// Existing user - check hidden modes
return !hiddenModes.contains(modeSubTypeKey);
}).toList();

Expand Down Expand Up @@ -338,7 +367,7 @@ class MainScreenController extends ChangeNotifier {
results.add(
FareResult(
transportMode: '${formula.mode} (${formula.subType})',
fare: fare,
fare: _passengerCount > 0 ? fare / _passengerCount : fare,
indicatorLevel: indicator,
isRecommended: false,
passengerCount: _passengerCount,
Expand Down
Loading
Loading