diff --git a/android/app/src/main/res/ic_launcher-web.png b/android/app/src/main/res/ic_launcher-web.png index 12f6cd5..3a93ad2 100644 Binary files a/android/app/src/main/res/ic_launcher-web.png and b/android/app/src/main/res/ic_launcher-web.png differ diff --git a/android/app/src/main/res/playstore-icon.png b/android/app/src/main/res/playstore-icon.png index 5f24ff8..3a93ad2 100644 Binary files a/android/app/src/main/res/playstore-icon.png and b/android/app/src/main/res/playstore-icon.png differ diff --git a/android/gradle.properties b/android/gradle.properties index f018a61..475a628 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,7 @@ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true +# This builtInKotlin flag was added automatically by Flutter migrator +android.builtInKotlin=false +# This newDsl flag was added automatically by Flutter migrator +android.newDsl=false diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index afa1e8e..efdcc4a 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 9e2d35c..384dd1f 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -18,7 +18,7 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.7.0" apply false + id("com.android.application") version "8.9.1" apply false // START: FlutterFire Configuration id("com.google.gms.google-services") version("4.3.15") apply false // END: FlutterFire Configuration diff --git a/assets/peak-animation.gif b/assets/peak-animation.gif deleted file mode 100644 index f180a90..0000000 Binary files a/assets/peak-animation.gif and /dev/null differ diff --git a/assets/peak-gif.mp4 b/assets/peak-gif.mp4 deleted file mode 100644 index be3a440..0000000 Binary files a/assets/peak-gif.mp4 and /dev/null differ diff --git a/assets/peak.png b/assets/peak.png deleted file mode 100644 index 814e0aa..0000000 Binary files a/assets/peak.png and /dev/null differ diff --git a/lib/browser.dart b/lib/browser.dart new file mode 100644 index 0000000..1704147 --- /dev/null +++ b/lib/browser.dart @@ -0,0 +1,14 @@ +/// Platform-aware browser API abstraction. +/// +/// On web, provides real browser localStorage and location APIs. +/// On non-web platforms (Android, iOS, desktop), returns no-op stubs. +/// +/// Usage: +/// ```dart +/// import 'package:qpay/browser.dart'; +/// Browser.localStorage.setItem('key', 'value'); +/// Browser.localStorage.getItem('key'); +/// Browser.location.href = 'https://example.com'; +/// ``` +export 'platform/browser_stub.dart' + if (dart.library.html) 'platform/browser_web.dart'; \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 16a82ef..cc09c4f 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,8 +1,9 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:provider/provider.dart'; import 'package:qpay/auth_state.dart'; import 'package:qpay/routes.dart'; +import 'package:qpay/url_strategy.dart'; import 'package:qpay/screens/transaction_controller.dart'; import 'package:qpay/screens/onboarding/onboarding_controller.dart'; import 'package:qpay/theme/app_theme.dart'; @@ -26,7 +27,9 @@ String resolveEnvFile(String env) { void main() async { WidgetsFlutterBinding.ensureInitialized(); - usePathUrlStrategy(); + if (kIsWeb) { + usePathUrlStrategy(); + } await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); await dotenv.load(fileName: resolveEnvFile(appEnv)); @@ -70,4 +73,4 @@ class _MyAppState extends State { routerConfig: buildRouter(), ); } -} +} \ No newline at end of file diff --git a/lib/platform/browser_stub.dart b/lib/platform/browser_stub.dart new file mode 100644 index 0000000..92c56ee --- /dev/null +++ b/lib/platform/browser_stub.dart @@ -0,0 +1,18 @@ +/// Stub implementation of browser APIs for non-web platforms. +class BrowserStorage { + String? getItem(String key) => null; + void setItem(String key, String value) {} + void removeItem(String key) {} +} + +/// Stub for window.location +class BrowserLocation { + String get href => ''; + set href(String value) {} +} + +/// Browser utility class for non-web platforms. +class Browser { + static final BrowserStorage localStorage = BrowserStorage(); + static final BrowserLocation location = BrowserLocation(); +} \ No newline at end of file diff --git a/lib/platform/browser_web.dart b/lib/platform/browser_web.dart new file mode 100644 index 0000000..7d01e26 --- /dev/null +++ b/lib/platform/browser_web.dart @@ -0,0 +1,22 @@ +import 'package:web/web.dart' as web; + +/// Web implementation of browser APIs using package:web. +class BrowserStorage { + String? getItem(String key) => web.window.localStorage.getItem(key); + void setItem(String key, String value) => + web.window.localStorage.setItem(key, value); + void removeItem(String key) => + web.window.localStorage.removeItem(key); +} + +/// Web implementation for window.location +class BrowserLocation { + String get href => web.window.location.href; + set href(String value) => web.window.location.href = value; +} + +/// Browser utility class using package:web. +class Browser { + static final BrowserStorage localStorage = BrowserStorage(); + static final BrowserLocation location = BrowserLocation(); +} \ No newline at end of file diff --git a/lib/platform/url_strategy_stub.dart b/lib/platform/url_strategy_stub.dart new file mode 100644 index 0000000..569ab6d --- /dev/null +++ b/lib/platform/url_strategy_stub.dart @@ -0,0 +1,3 @@ +/// Stub for path URL strategy on non-web platforms. +/// Does nothing since URL strategies are web-only. +void usePathUrlStrategy() {} \ No newline at end of file diff --git a/lib/platform/url_strategy_web.dart b/lib/platform/url_strategy_web.dart new file mode 100644 index 0000000..919bcee --- /dev/null +++ b/lib/platform/url_strategy_web.dart @@ -0,0 +1,6 @@ +import 'package:flutter_web_plugins/flutter_web_plugins.dart'; + +/// Web implementation that sets the path URL strategy. +void usePathUrlStrategy() { + flutter_web_plugins.usePathUrlStrategy(); +} \ No newline at end of file diff --git a/lib/screens/gateway/gateway_web_screen.dart b/lib/screens/gateway/gateway_web_screen.dart index da68cb6..4f9f343 100644 --- a/lib/screens/gateway/gateway_web_screen.dart +++ b/lib/screens/gateway/gateway_web_screen.dart @@ -3,7 +3,7 @@ import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:go_router/go_router.dart'; import 'package:qpay/models/responsive_policy.dart'; import 'package:qpay/screens/gateway/gateway_controller.dart'; -import 'package:web/web.dart' as web; +import 'package:qpay/browser.dart'; class GatewayWebScreen extends StatefulWidget { const GatewayWebScreen({super.key}); @@ -50,7 +50,7 @@ class _GatewayWebScreenState extends State { final transactionId = controller.transactionController.model.confirmationData['id']; if (transactionId != null) { - web.window.localStorage.setItem( + Browser.localStorage.setItem( 'pendingTransactionId', transactionId.toString(), ); @@ -60,7 +60,7 @@ class _GatewayWebScreenState extends State { // After payment, the gateway will redirect back to this app's host. // index.html then reads the saved transaction ID and navigates to // /poll/:id so the app can immediately start polling for the result. - web.window.location.href = url; + Browser.location.href = url; } @override diff --git a/lib/screens/poll/poll_screen.dart b/lib/screens/poll/poll_screen.dart index 3ec6d14..0a84319 100644 --- a/lib/screens/poll/poll_screen.dart +++ b/lib/screens/poll/poll_screen.dart @@ -5,7 +5,7 @@ import 'package:provider/provider.dart'; import 'package:qpay/screens/gateway/gateway_controller.dart'; import 'package:qpay/screens/transaction_controller.dart'; import 'package:qpay/widgets/step_loading_widget.dart'; -import 'package:web/web.dart' as web; +import 'package:qpay/browser.dart'; class PollScreen extends StatefulWidget { final String? transactionId; @@ -39,8 +39,8 @@ class _PollScreenState extends State { // Priority 2: localStorage (for when gateway redirect causes page reload // and the route param path is not available due to hub redirect override) if (transactionId == null && kIsWeb) { - transactionId = web.window.localStorage.getItem('pendingTransactionId'); - web.window.localStorage.removeItem('pendingTransactionId'); + transactionId = Browser.localStorage.getItem('pendingTransactionId'); + Browser.localStorage.removeItem('pendingTransactionId'); } // Priority 3: in-memory confirmation data (normal SPA navigation) diff --git a/lib/url_strategy.dart b/lib/url_strategy.dart new file mode 100644 index 0000000..c6a98b1 --- /dev/null +++ b/lib/url_strategy.dart @@ -0,0 +1,6 @@ +/// Platform-aware path URL strategy. +/// +/// On web, sets the path URL strategy via [usePathUrlStrategy]. +/// On non-web platforms, this is a no-op. +export 'platform/url_strategy_stub.dart' + if (dart.library.html) 'platform/url_strategy_web.dart'; \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index bb16ffd..478f532 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -120,6 +120,10 @@ flutter: icons_launcher: image_path: "assets/velocity-icon-black.png" + adaptive_background_color: "#ffffff" + adaptive_foreground_image: "assets/velocity-icon-black.png" + adaptive_round_image: "assets/velocity-icon-black.png" + notification_image: "assets/velocity-icon-black.png" platforms: android: enable: true