Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
4a4e499
feat: Implement loan tracking feature with a new screen, domain entit…
mixin27 Feb 23, 2026
ea0b624
feat: Implement the loan tracking screen and add its multi-language l…
mixin27 Feb 23, 2026
b1da3db
feat: Implement synchronization for loan entities across the app and …
mixin27 Feb 23, 2026
3eee08c
feat: Enhance UI responsiveness and text scaling across various widge…
mixin27 Feb 23, 2026
e7f600c
feat: Introduce `MetadataLookupService` for centralized metadata fetc…
mixin27 Feb 23, 2026
0bad5f4
feat: Introduce metadata assistance settings and enhance authenticati…
mixin27 Feb 23, 2026
be644c1
feat: Implement native device ID generation using the `native_id` pac…
mixin27 Feb 23, 2026
29280f9
feat: Implement data export/import functionality with file picker int…
mixin27 Feb 23, 2026
02b0c21
feat: Implement a data import preview dialog and correct newline char…
mixin27 Feb 23, 2026
d81adf9
feat: Update app branding and icons, introducing a new asset generati…
mixin27 Feb 23, 2026
47c96b6
chore: Update app icons and branding assets across platforms, and ref…
mixin27 Feb 23, 2026
066aa1d
feat: Introduce dynamic app versioning, add Play Store listing and pr…
mixin27 Feb 23, 2026
8d8bfea
feat: implement app update feature with backend integration, remote c…
mixin27 Feb 23, 2026
db1bb64
feat: Update app icons and brand color palette.
mixin27 Feb 23, 2026
d18a77f
feat: Use a custom image for the adaptive launcher icon background in…
mixin27 Feb 23, 2026
a23529e
docs: Add Play Store release checklist and update README to link it.
mixin27 Feb 23, 2026
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
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,32 @@

All notable changes to this project will be documented in this file.

## [1.0.1+2] - 2026-02-23

### Added

- **Release & Store Readiness**
- Added Play Store listing documentation with app metadata, SEO-oriented copy, ASO keyword strategy, release note templates, and launch checklist.
- Added MDX-ready privacy policy document for website and Play Console reuse.
- **Product Features & Platform Integrations**
- Expanded optional backend integration flow for auth and sync readiness gating via runtime feature flags.
- Added/extended Firebase integrations for runtime config, analytics consent behavior, crash diagnostics, performance monitoring, and FCM-related flows.

### Changed

- **Versioning**
- Bumped mobile app version from `1.0.0+1` to `1.0.1+2`.
- Bumped workspace version from `1.0.0` to `1.0.1`.
- **UX & Architecture**
- Continued UI/UX refinements across core screens and settings structure.
- Continued localization coverage and language improvements across key user flows.

### Fixed

- Navigation stability issues related to route stack/hero key conflicts in shell navigation flows.
- Multiple layout overflow cases on compact/Android device sizes (bottom sheets, grids, and list end visibility with custom navigation shell).
- State/controller lifecycle issues in edit/update dialogs and related action handlers.

## [1.0.0+1] - 2026-01-28

### Added
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ If either is `false`, sync UI/actions are disabled. Full explanation: [documenta
- [documentation/APP_PROGRESS.md](documentation/APP_PROGRESS.md) - implemented vs in-progress features
- [documentation/SYNC_AND_AUTH.md](documentation/SYNC_AND_AUTH.md) - sync/auth integration details
- [documentation/LOCALIZATION.md](documentation/LOCALIZATION.md) - i18n status and workflow
- [documentation/PLAY_STORE_LISTING.md](documentation/PLAY_STORE_LISTING.md) - Play Store listing and ASO package
- [documentation/PRIVACY_POLICY.md](documentation/PRIVACY_POLICY.md) - MDX-ready privacy policy template

## CI/CD

Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Collection Tracker Mobile App
# Collectra Mobile App

This is the Flutter app module for the Collection Tracker workspace.
This is the Flutter app module for the Collectra workspace.

## Main References

Expand Down
22 changes: 21 additions & 1 deletion apps/mobile/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

<application
android:label="Collection Tracker"
android:label="Collectra"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
<activity
Expand Down Expand Up @@ -54,6 +54,26 @@

In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="http" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="sms" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="tel" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="mailto" />
</intent>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
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.
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.
Original file line number Diff line number Diff line change
@@ -1,9 +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"/>
<background android:drawable="@drawable/ic_launcher_background"/>
<foreground>
<inset
android:drawable="@drawable/ic_launcher_foreground"
android:inset="16%" />
android:inset="8%" />
</foreground>
</adaptive-icon>
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.
2 changes: 1 addition & 1 deletion apps/mobile/android/app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#667eea</color>
<color name="ic_launcher_background">#1A91E6</color>
</resources>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/mobile/assets/icons/logo_background.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 apps/mobile/assets/icons/logo_dark.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 apps/mobile/assets/icons/logo_foreground.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 apps/mobile/assets/icons/logo_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions apps/mobile/flutter_launcher_icons.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ flutter_launcher_icons:
image_path: "assets/icons/logo_light.png"

android: "launcher_icon"
# image_path_android: "assets/icon/icon.png"
# image_path_android: "assets/icons/logo_light.png"
min_sdk_android: 21 # android min sdk min:16, default 21
adaptive_icon_background: "#667eea"
adaptive_icon_background: "assets/icons/logo_background.png"
adaptive_icon_foreground: "assets/icons/logo_foreground.png"
# adaptive_icon_foreground_inset: 16
adaptive_icon_foreground_inset: 8
# adaptive_icon_monochrome: "assets/icon/monochrome.png"

ios: true
# image_path_ios: "assets/icon/icon.png"
image_path_ios: "assets/icons/logo_light.png"
remove_alpha_ios: true
# image_path_ios_dark_transparent: "assets/icon/icon_dark.png"
# image_path_ios_dark_transparent: "assets/icons/logo_dark.png"
# image_path_ios_tinted_grayscale: "assets/icon/icon_tinted.png"
# desaturate_tinted_to_grayscale_ios: true
# background_color_ios: "#ffffff"
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.
11 changes: 9 additions & 2 deletions apps/mobile/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Collection Tracker</string>
<string>Collectra</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>collection_tracker</string>
<string>Collectra</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
Expand Down Expand Up @@ -71,5 +71,12 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>sms</string>
<string>tel</string>
<string>http</string>
<string>https</string>
</array>
</dict>
</plist>
50 changes: 46 additions & 4 deletions apps/mobile/lib/core/auth/backend_auth_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,37 @@ import 'dart:io';

import 'package:auth_session/auth_session.dart';
import 'package:backend_api/backend_api.dart';
import 'package:package_info_plus/package_info_plus.dart';

class BackendAuthService {
BackendAuthService({
required BackendAuthClient client,
required AuthSessionStore sessionStore,
required Future<String> Function() resolveDeviceId,
this.appVersion = '1.0.0',
this.appVersion,
}) : _client = client,
_sessionStore = sessionStore,
_resolveDeviceId = resolveDeviceId;

final BackendAuthClient _client;
final AuthSessionStore _sessionStore;
final Future<String> Function() _resolveDeviceId;
final String appVersion;
final String? appVersion;

Future<AuthSession> signIn({
required String email,
required String password,
}) async {
final deviceId = await _resolveDeviceId();
final resolvedAppVersion = await _resolveAppVersion();
final response = await _client.login(
BackendLoginRequest(
email: email,
password: password,
deviceId: deviceId,
deviceName: _deviceName(),
deviceOs: _deviceOs(),
appVersion: appVersion,
appVersion: resolvedAppVersion,
),
);

Expand All @@ -43,6 +45,7 @@ class BackendAuthService {
String? displayName,
}) async {
final deviceId = await _resolveDeviceId();
final resolvedAppVersion = await _resolveAppVersion();
final response = await _client.register(
BackendRegisterRequest(
email: email,
Expand All @@ -51,7 +54,7 @@ class BackendAuthService {
deviceId: deviceId,
deviceName: _deviceName(),
deviceOs: _deviceOs(),
appVersion: appVersion,
appVersion: resolvedAppVersion,
),
);

Expand Down Expand Up @@ -115,6 +118,26 @@ class BackendAuthService {
return response.user;
}

Future<void> requestAccountDeletion({String? reason}) async {
final existing = await _sessionStore.readSession();
if (!existing.hasAccessToken || existing.accessToken == null) {
throw const BackendApiException(
message: 'Sign in is required to request account deletion.',
code: 'AUTH_REQUIRED',
);
}

await _client.requestAccountDeletion(
accessToken: existing.accessToken!,
request: BackendAccountDeletionRequest(
reason: reason,
source: 'mobile_app',
),
);

await _sessionStore.clearSession();
}

Future<AuthSession> _persistAuthResponse(BackendAuthResponse response) async {
final session = AuthSession(
status: AuthSessionStatus.signedIn,
Expand Down Expand Up @@ -143,4 +166,23 @@ class BackendAuthService {
final version = Platform.operatingSystemVersion.trim();
return '$os $version'.trim();
}

Future<String?> _resolveAppVersion() async {
final configured = appVersion?.trim();
if (configured != null && configured.isNotEmpty) {
return configured;
}

try {
final packageInfo = await PackageInfo.fromPlatform();
final detected = packageInfo.version.trim();
if (detected.isNotEmpty) {
return detected;
}
} catch (_) {
// Keep auth non-blocking if package info is unavailable.
}

return null;
}
}
1 change: 1 addition & 0 deletions apps/mobile/lib/core/bootstrap/app_bootstrap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ abstract final class AppBootstrap {
performanceEnabled: firebaseRuntimeConfig.performanceCollectionEnabled,
appCheckEnabled: firebaseRuntimeConfig.appCheckEnabled,
fcmEnabled: firebaseRuntimeConfig.fcmEnabled,
metadataEnabled: firebaseRuntimeConfig.metadataFeatureEnabled,
backendEnabled: firebaseRuntimeConfig.backendIntegrationEnabled,
authEnabled: firebaseRuntimeConfig.authFeatureEnabled,
syncEnabled: firebaseRuntimeConfig.syncFeatureEnabled,
Expand Down
37 changes: 37 additions & 0 deletions apps/mobile/lib/core/bootstrap/firebase_services_bootstrap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,26 @@ abstract final class FirebaseServicesBootstrap {
'app_performance_collection_enabled';
static const _appCheckEnabledKey = 'app_app_check_enabled';
static const _fcmEnabledKey = 'app_fcm_enabled';
static const _metadataFeatureEnabledKey = 'app_metadata_feature_enabled';
static const _backendIntegrationEnabledKey =
'app_backend_integration_enabled';
static const _authFeatureEnabledKey = 'app_auth_feature_enabled';
static const _syncFeatureEnabledKey = 'app_sync_feature_enabled';
static const _appUpdateFeatureEnabledKey = 'app_update_feature_enabled';
static const _appUpdateUseBackendKey = 'app_update_use_backend';
static const _appUpdateCheckIntervalHoursKey =
'app_update_check_interval_hours';
static const _appUpdateSnoozeHoursKey = 'app_update_snooze_hours';
static const _appUpdateForceModeKey = 'app_update_force_mode';
static const _appUpdateMinSupportedAndroidKey =
'app_update_min_supported_android';
static const _appUpdateMinSupportedIosKey = 'app_update_min_supported_ios';
static const _appUpdateLatestAndroidKey = 'app_update_latest_android';
static const _appUpdateLatestIosKey = 'app_update_latest_ios';
static const _appUpdateStoreUrlAndroidKey = 'app_update_store_url_android';
static const _appUpdateStoreUrlIosKey = 'app_update_store_url_ios';
static const _appUpdateTitleKey = 'app_update_title';
static const _appUpdateMessageKey = 'app_update_message';

static Future<FirebaseRuntimeConfig> initialize() async {
final remoteConfigService = FirebaseRemoteConfigService.instance;
Expand All @@ -42,9 +58,23 @@ abstract final class FirebaseServicesBootstrap {
_performanceCollectionEnabledKey: true,
_appCheckEnabledKey: false,
_fcmEnabledKey: false,
_metadataFeatureEnabledKey: true,
_backendIntegrationEnabledKey: false,
_authFeatureEnabledKey: true,
_syncFeatureEnabledKey: false,
_appUpdateFeatureEnabledKey: true,
_appUpdateUseBackendKey: true,
_appUpdateCheckIntervalHoursKey: 12,
_appUpdateSnoozeHoursKey: 24,
_appUpdateForceModeKey: false,
_appUpdateMinSupportedAndroidKey: '',
_appUpdateMinSupportedIosKey: '',
_appUpdateLatestAndroidKey: '',
_appUpdateLatestIosKey: '',
_appUpdateStoreUrlAndroidKey: '',
_appUpdateStoreUrlIosKey: '',
_appUpdateTitleKey: '',
_appUpdateMessageKey: '',
},
minimumFetchInterval: kDebugMode
? const Duration(minutes: 5)
Expand All @@ -69,6 +99,7 @@ abstract final class FirebaseServicesBootstrap {
'performance: ${runtimeConfig.performanceCollectionEnabled}, '
'appCheck: ${runtimeConfig.appCheckEnabled}, '
'fcm: ${runtimeConfig.fcmEnabled}, '
'metadata: ${runtimeConfig.metadataFeatureEnabled}, '
'backend: ${runtimeConfig.backendIntegrationEnabled}, '
'auth: ${runtimeConfig.authFeatureEnabled}, '
'sync: ${runtimeConfig.syncFeatureEnabled}).',
Expand Down Expand Up @@ -115,6 +146,7 @@ abstract final class FirebaseServicesBootstrap {
'performance: ${runtimeConfig.performanceCollectionEnabled}, '
'appCheck: ${runtimeConfig.appCheckEnabled}, '
'fcm: ${runtimeConfig.fcmEnabled}, '
'metadata: ${runtimeConfig.metadataFeatureEnabled}, '
'backend: ${runtimeConfig.backendIntegrationEnabled}, '
'auth: ${runtimeConfig.authFeatureEnabled}, '
'sync: ${runtimeConfig.syncFeatureEnabled}).',
Expand All @@ -126,6 +158,7 @@ abstract final class FirebaseServicesBootstrap {
performanceEnabled: runtimeConfig.performanceCollectionEnabled,
appCheckEnabled: runtimeConfig.appCheckEnabled,
fcmEnabled: runtimeConfig.fcmEnabled,
metadataEnabled: runtimeConfig.metadataFeatureEnabled,
backendEnabled: runtimeConfig.backendIntegrationEnabled,
authEnabled: runtimeConfig.authFeatureEnabled,
syncEnabled: runtimeConfig.syncFeatureEnabled,
Expand Down Expand Up @@ -160,6 +193,10 @@ abstract final class FirebaseServicesBootstrap {
fallback: false,
),
fcmEnabled: remoteConfigService.getBool(_fcmEnabledKey, fallback: false),
metadataFeatureEnabled: remoteConfigService.getBool(
_metadataFeatureEnabledKey,
fallback: true,
),
backendIntegrationEnabled: remoteConfigService.getBool(
_backendIntegrationEnabledKey,
fallback: false,
Expand Down
3 changes: 3 additions & 0 deletions apps/mobile/lib/core/firebase/firebase_runtime_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class FirebaseRuntimeConfig {
required this.performanceCollectionEnabled,
required this.appCheckEnabled,
required this.fcmEnabled,
required this.metadataFeatureEnabled,
required this.backendIntegrationEnabled,
required this.authFeatureEnabled,
required this.syncFeatureEnabled,
Expand All @@ -16,6 +17,7 @@ class FirebaseRuntimeConfig {
performanceCollectionEnabled: true,
appCheckEnabled: false,
fcmEnabled: false,
metadataFeatureEnabled: true,
backendIntegrationEnabled: false,
authFeatureEnabled: true,
syncFeatureEnabled: false,
Expand All @@ -26,6 +28,7 @@ class FirebaseRuntimeConfig {
final bool performanceCollectionEnabled;
final bool appCheckEnabled;
final bool fcmEnabled;
final bool metadataFeatureEnabled;
final bool backendIntegrationEnabled;
final bool authFeatureEnabled;
final bool syncFeatureEnabled;
Expand Down
Loading