Skip to content

Commit a3ab0de

Browse files
authored
chore(merge): merge pull request #7 from MasuRii/feature/location-suggestions-and-transport-mode-ux
feat: implement location suggestions and comprehensive transport mode UX improvements
2 parents 651b458 + bd89a98 commit a3ab0de

21 files changed

Lines changed: 1766 additions & 269 deletions

.github/workflows/release-apk.yml

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,26 +197,50 @@ jobs:
197197
| **ARM32 (armeabi-v7a)** | `${{ steps.apk_files.outputs.apk_armv7 }}` |
198198
| **x86_64** | `${{ steps.apk_files.outputs.apk_x86_64 }}` |
199199
200-
### Changes
200+
## ✨ What's New
201201
EOF
202202
203-
# Try to get commits since last tag, or last 10 commits if no previous tag
203+
# Determine range
204204
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
205-
206205
if [ -n "$LAST_TAG" ]; then
207-
echo "Changes since $LAST_TAG:" >> RELEASE_NOTES.md
208-
echo "" >> RELEASE_NOTES.md
209-
git log ${LAST_TAG}..HEAD --pretty=format:"- %s (%h)" --no-merges >> RELEASE_NOTES.md
206+
RANGE="${LAST_TAG}..HEAD"
207+
echo "Generating notes for range: $RANGE"
208+
else
209+
RANGE="HEAD~10..HEAD"
210+
echo "No previous tag found, using last 10 commits"
211+
fi
212+
213+
# Features
214+
echo "🚀 **New Features:**" >> RELEASE_NOTES.md
215+
FEATURES=$(git log ${RANGE} --grep="✨\|feat" --pretty=format:"- %s" --no-merges || echo "")
216+
if [ -n "$FEATURES" ]; then
217+
echo "$FEATURES" >> RELEASE_NOTES.md
210218
else
211-
echo "Recent commits:" >> RELEASE_NOTES.md
212-
echo "" >> RELEASE_NOTES.md
213-
git log -10 --pretty=format:"- %s (%h)" --no-merges >> RELEASE_NOTES.md
219+
echo "- General improvements and updates" >> RELEASE_NOTES.md
214220
fi
221+
echo "" >> RELEASE_NOTES.md
215222
223+
# Bug Fixes
224+
echo "🐛 **Bug Fixes:**" >> RELEASE_NOTES.md
225+
FIXES=$(git log ${RANGE} --grep="🐛\|fix" --pretty=format:"- %s" --no-merges || echo "")
226+
if [ -n "$FIXES" ]; then
227+
echo "$FIXES" >> RELEASE_NOTES.md
228+
else
229+
echo "- Stability improvements" >> RELEASE_NOTES.md
230+
fi
216231
echo "" >> RELEASE_NOTES.md
232+
233+
# Improvements
234+
echo "🎨 **Improvements:**" >> RELEASE_NOTES.md
235+
IMPROVEMENTS=$(git log ${RANGE} --grep="🎨\|♻️\|🏗\|💄\|refactor\|perf" --pretty=format:"- %s" --no-merges || echo "")
236+
if [ -n "$IMPROVEMENTS" ]; then
237+
echo "$IMPROVEMENTS" >> RELEASE_NOTES.md
238+
else
239+
echo "- UI refinements and performance tweaks" >> RELEASE_NOTES.md
240+
fi
241+
217242
echo "" >> RELEASE_NOTES.md
218243
echo "---" >> RELEASE_NOTES.md
219-
echo "" >> RELEASE_NOTES.md
220244
echo "_Built with Flutter on GitHub Actions_" >> RELEASE_NOTES.md
221245
222246
# Output for debugging

lib/src/core/di/injection.config.dart

Lines changed: 28 additions & 37 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/src/models/map_region.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,10 +502,21 @@ class StorageInfo {
502502
/// Available storage in GB.
503503
double get availableGB => availableBytes / (1024 * 1024 * 1024);
504504

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

509+
/// Map cache usage as a percentage of total usable space (cache + available).
510+
/// This is what the storage bar should display:
511+
/// - When cache is 0 and available is 10GB, bar shows nearly empty (0%)
512+
/// - When cache is 5GB and available is 5GB, bar shows 50%
513+
/// - When cache is 10GB and available is 0, bar shows 100%
514+
double get usedPercentage {
515+
final totalUsableSpace = mapCacheBytes + availableBytes;
516+
if (totalUsableSpace <= 0) return 0.0;
517+
return mapCacheBytes / totalUsableSpace;
518+
}
519+
509520
/// Formatted string for map cache size.
510521
String get mapCacheFormatted {
511522
if (mapCacheBytes < 1024 * 1024) {

lib/src/models/transport_mode.dart

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,42 @@ enum TransportMode {
107107
orElse: () => TransportMode.jeepney, // Default fallback
108108
);
109109
}
110+
111+
/// Parses a transport mode string into its base mode name and optional subtype.
112+
///
113+
/// Examples:
114+
/// - "Jeepney (Traditional)" -> ("Jeepney", "Traditional")
115+
/// - "Bus (Aircon)" -> ("Bus", "Aircon")
116+
/// - "Jeepney (Modern (PUJ))" -> ("Jeepney", "Modern (PUJ)")
117+
/// - "Taxi" -> ("Taxi", null)
118+
///
119+
/// Returns a record with baseName and subtype (nullable).
120+
static ({String baseName, String? subtype}) parseTransportMode(String mode) {
121+
final trimmed = mode.trim();
122+
123+
// Find the first opening parenthesis
124+
final firstParenIndex = trimmed.indexOf('(');
125+
126+
if (firstParenIndex == -1) {
127+
// No subtype
128+
return (baseName: trimmed, subtype: null);
129+
}
130+
131+
// Extract base name (everything before the first '(')
132+
final baseName = trimmed.substring(0, firstParenIndex).trim();
133+
134+
// Extract subtype (everything between first '(' and last ')')
135+
final lastParenIndex = trimmed.lastIndexOf(')');
136+
if (lastParenIndex <= firstParenIndex) {
137+
// Malformed string, treat as no subtype
138+
return (baseName: baseName, subtype: null);
139+
}
140+
141+
final subtype = trimmed.substring(firstParenIndex + 1, lastParenIndex).trim();
142+
143+
return (
144+
baseName: baseName,
145+
subtype: subtype.isNotEmpty ? subtype : null,
146+
);
147+
}
110148
}

lib/src/presentation/controllers/main_screen_controller.dart

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:latlong2/latlong.dart';
66
import '../../core/di/injection.dart';
77
import '../../core/errors/failures.dart';
88
import '../../core/hybrid_engine.dart';
9+
import '../../models/discount_type.dart';
910
import '../../models/fare_formula.dart';
1011
import '../../models/fare_result.dart';
1112
import '../../models/location.dart';
@@ -140,9 +141,22 @@ class MainScreenController extends ChangeNotifier {
140141
return _settingsService.hasSetDiscountType();
141142
}
142143

143-
/// Set user discount type preference
144-
Future<void> setUserDiscountType(dynamic discountType) async {
144+
/// Set user discount type preference and update local passenger state.
145+
Future<void> setUserDiscountType(DiscountType discountType) async {
145146
await _settingsService.setUserDiscountType(discountType);
147+
148+
// Update local passenger counts based on the selected discount type
149+
// Assuming a total of 1 passenger when first setting the preference
150+
if (discountType == DiscountType.discounted) {
151+
_regularPassengers = 0;
152+
_discountedPassengers = 1;
153+
} else {
154+
_regularPassengers = 1;
155+
_discountedPassengers = 0;
156+
}
157+
_passengerCount = _regularPassengers + _discountedPassengers;
158+
159+
notifyListeners();
146160
}
147161

148162
/// Search locations with debounce for autocomplete
@@ -204,7 +218,9 @@ class MainScreenController extends ChangeNotifier {
204218
}
205219
}
206220

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

@@ -217,7 +233,12 @@ class MainScreenController extends ChangeNotifier {
217233
_destinationLocation = tempLocation;
218234
_destinationLatLng = tempLatLng;
219235

220-
_resetResult();
236+
// Note: We do NOT reset fare results on swap.
237+
// The fare is based on distance which is the same regardless of direction.
238+
// Only clear route points so they can be recalculated.
239+
_routePoints = [];
240+
_routeResult = null;
241+
221242
notifyListeners();
222243

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

298319
final List<FareResult> results = [];
299320
final trafficFactor = await _settingsService.getTrafficFactor();
321+
final hasSetPrefs = await _settingsService.hasSetTransportModePreferences();
300322
final hiddenModes = await _settingsService.getHiddenTransportModes();
301323

302324
final visibleFormulas = _availableFormulas.where((formula) {
303325
final modeSubTypeKey = '${formula.mode}::${formula.subType}';
326+
327+
if (!hasSetPrefs) {
328+
// New user - use default enabled modes
329+
final defaultModes = SettingsService.getDefaultEnabledModes();
330+
return defaultModes.contains(modeSubTypeKey);
331+
}
332+
// Existing user - check hidden modes
304333
return !hiddenModes.contains(modeSubTypeKey);
305334
}).toList();
306335

@@ -338,7 +367,7 @@ class MainScreenController extends ChangeNotifier {
338367
results.add(
339368
FareResult(
340369
transportMode: '${formula.mode} (${formula.subType})',
341-
fare: fare,
370+
fare: _passengerCount > 0 ? fare / _passengerCount : fare,
342371
indicatorLevel: indicator,
343372
isRecommended: false,
344373
passengerCount: _passengerCount,

0 commit comments

Comments
 (0)