diff --git a/.metadata b/.metadata
index e8f7bf9..5722f85 100644
--- a/.metadata
+++ b/.metadata
@@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
- revision: "ea121f8859e4b13e47a8f845e4586164519588bc"
+ revision: "9f455d2486bcb28cad87b062475f42edc959f636"
channel: "stable"
project_type: app
@@ -13,26 +13,11 @@ project_type: app
migration:
platforms:
- platform: root
- create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- - platform: android
- create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- - platform: ios
- create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- - platform: linux
- create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- - platform: macos
- create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
+ create_revision: 9f455d2486bcb28cad87b062475f42edc959f636
+ base_revision: 9f455d2486bcb28cad87b062475f42edc959f636
- platform: web
- create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- - platform: windows
- create_revision: ea121f8859e4b13e47a8f845e4586164519588bc
- base_revision: ea121f8859e4b13e47a8f845e4586164519588bc
+ create_revision: 9f455d2486bcb28cad87b062475f42edc959f636
+ base_revision: 9f455d2486bcb28cad87b062475f42edc959f636
# User provided section
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..c17ed31
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,71 @@
+# syntax=docker/dockerfile:1.6
+
+###############################################
+# Build stage: compile Flutter web artifacts. #
+###############################################
+FROM ubuntu:22.04 AS build
+
+ENV DEBIAN_FRONTEND=noninteractive \
+ FLUTTER_CHANNEL=stable \
+ FLUTTER_VERSION=3.24.3 \
+ FLUTTER_HOME=/opt/flutter
+
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ ca-certificates \
+ curl \
+ git \
+ unzip \
+ xz-utils \
+ zip \
+ libglu1-mesa && \
+ rm -rf /var/lib/apt/lists/*
+
+RUN curl -fsSL "https://storage.googleapis.com/flutter_infra_release/releases/${FLUTTER_CHANNEL}/linux/flutter_linux_${FLUTTER_VERSION}-${FLUTTER_CHANNEL}.tar.xz" \
+ | tar -xJ -C /opt && \
+ ln -s ${FLUTTER_HOME} /usr/local/flutter
+
+ENV PATH="${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-sdk/bin:${PATH}"
+
+RUN flutter config --enable-web && \
+ flutter doctor -v
+
+WORKDIR /app
+
+COPY pubspec.yaml pubspec.lock ./
+RUN flutter pub get
+
+COPY . .
+RUN flutter build web --release
+
+##########################################
+# Runtime stage: serve assets via nginx. #
+##########################################
+FROM ubuntu:22.04 AS runner
+
+ENV DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends nginx && \
+ rm -rf /var/lib/apt/lists/*
+
+# Remove default site definition to avoid duplicate configs.
+RUN rm -f /etc/nginx/sites-enabled/default
+
+# Provide a minimal nginx site config for the Flutter web assets.
+RUN printf 'server {\n\
+ listen 80 default_server;\n\
+ listen [::]:80 default_server;\n\
+ root /var/www/html;\n\
+ index index.html;\n\
+ location / {\n\
+ try_files $uri $uri/ /index.html;\n\
+ }\n\
+}\n' > /etc/nginx/conf.d/flutter.conf
+
+COPY --from=build /app/build/web /var/www/html
+
+EXPOSE 80
+
+CMD ["nginx", "-g", "daemon off;"]
+
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 5a558c1..50096c7 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -3,7 +3,7 @@
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 8e478ad..b4cbe58 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -1,4 +1,4 @@
- Peak
+ Velocity
\ No newline at end of file
diff --git a/assets/.env b/assets/.env
index 6f89a20..7645daa 100644
--- a/assets/.env
+++ b/assets/.env
@@ -1,10 +1,11 @@
BASE_URL=https://peakapi.qantra.co.zw/api
; BASE_URL=http://192.168.100.26:6950/api
-; BASE_URL=http://10.69.5.204:6950/api
+; BASE_URL=http://173.212.247.232:6950/api
; BASE_URL=http://192.168.1.164:6950/api
; BASE_URL=http://192.168.120.160:6950/api
; BASE_URL=http://10.10.2.92:6950/api
; BASE_URL=http://172.20.5.105:6950/api
; BASE_URL=http://10.10.3.92:6950/api
CLIENTID=77433712483-ng7pntvcpf6tnjccriuqm8dbna8vvp3b.apps.googleusercontent.com
-SIMULATE_PAYMENT_SUCCESS=false
\ No newline at end of file
+SIMULATE_PAYMENT_SUCCESS=false
+; SIMULATE_PAYMENT_SUCCESS=true
diff --git a/assets/favicon.png b/assets/favicon.png
new file mode 100644
index 0000000..721aa6e
Binary files /dev/null and b/assets/favicon.png differ
diff --git a/assets/velocity-animation.gif b/assets/velocity-animation.gif
new file mode 100644
index 0000000..ca82573
Binary files /dev/null and b/assets/velocity-animation.gif differ
diff --git a/assets/velocity.png b/assets/velocity.png
new file mode 100644
index 0000000..8a3a7ca
Binary files /dev/null and b/assets/velocity.png differ
diff --git a/devtools_options.yaml b/devtools_options.yaml
new file mode 100644
index 0000000..b042345
--- /dev/null
+++ b/devtools_options.yaml
@@ -0,0 +1,5 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:
+ - provider: true
+ - shared_preferences: true
\ No newline at end of file
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index c73d391..717c9ba 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -5,7 +5,7 @@
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleDisplayName
- Peak
+ Velocity
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
@@ -13,7 +13,7 @@
CFBundleInfoDictionaryVersion
6.0
CFBundleName
- Peak
+ Velocity
CFBundlePackageType
APPL
CFBundleShortVersionString
diff --git a/lib/interop.dart b/lib/interop.dart
new file mode 100644
index 0000000..7dd7770
--- /dev/null
+++ b/lib/interop.dart
@@ -0,0 +1,7 @@
+import 'dart:js_interop';
+
+@JS('configure')
+external void configure(String sessionID);
+
+@JS('showEmbeddedPage')
+external void showEmbeddedPage();
diff --git a/lib/main.dart b/lib/main.dart
index d37a350..e089fb2 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:go_router/go_router.dart';
+import 'package:qpay/navbar.dart';
import 'package:qpay/screens/confirm/confirm_screen.dart';
import 'package:qpay/screens/gateway/gateway_screen.dart';
import 'package:qpay/screens/integration/integration_screen.dart';
@@ -13,9 +14,11 @@ import 'package:qpay/screens/onboarding/phone/phone_screen.dart';
import 'package:qpay/screens/onboarding/register/register_screen.dart';
import 'package:qpay/screens/onboarding/verify/verify_screen.dart';
import 'package:qpay/screens/pay/pay_screen.dart';
+import 'package:qpay/screens/poll/poll_screen.dart';
import 'package:qpay/screens/receipt/receipt_screen.dart';
import 'package:qpay/screens/recipient/recipients_screen.dart';
import 'package:qpay/screens/transaction_controller.dart';
+import 'screens/gateway/gateway_web_screen.dart';
import 'screens/home/home_screen.dart';
import 'screens/history/history_screen.dart';
import 'screens/profile_screen.dart';
@@ -66,7 +69,7 @@ class _MyAppState extends State {
Widget build(BuildContext context) {
if (_showSplash) {
return MaterialApp(
- title: 'Peak',
+ title: 'Velocity',
theme: AppTheme.lightTheme,
themeMode: ThemeMode.light,
home: SplashScreen(onSplashComplete: _onSplashComplete),
@@ -75,7 +78,7 @@ class _MyAppState extends State {
}
return MaterialApp.router(
- title: 'Peak',
+ title: 'Velocity',
theme: AppTheme.lightTheme,
themeMode: ThemeMode.light, // Force light mode regardless of OS setting
debugShowCheckedModeBanner: false,
@@ -112,6 +115,14 @@ class _MyAppState extends State {
path: '/gateway',
builder: (context, state) => const GatewayScreen(),
),
+ GoRoute(
+ path: '/gateway-web',
+ builder: (context, state) => const GatewayWebScreen(),
+ ),
+ GoRoute(
+ path: '/poll',
+ builder: (context, state) => const PollScreen(),
+ ),
GoRoute(
path: '/receipt',
builder: (context, state) => const ReceiptScreen(),
@@ -167,65 +178,3 @@ class _MyAppState extends State {
);
}
}
-
-class ScaffoldWithNavBar extends StatelessWidget {
- const ScaffoldWithNavBar({super.key, required this.child});
-
- final Widget child;
-
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- body: child,
- bottomNavigationBar: NavigationBar(
- onDestinationSelected: (index) {
- switch (index) {
- case 0:
- context.go('/home');
- break;
- // case 1:
- // context.go('/recipients');
- // break;
- case 1:
- context.go('/history');
- break;
- // case 2:
- // context.go('/profile');
- // break;
- }
- },
- selectedIndex: _calculateSelectedIndex(context),
- destinations: const [
- NavigationDestination(
- icon: Icon(Icons.home_outlined),
- selectedIcon: Icon(Icons.home),
- label: 'Home',
- ),
- // NavigationDestination(
- // icon: Icon(Icons.contacts_outlined),
- // selectedIcon: Icon(Icons.contacts),
- // label: 'Recipients',
- // ),
- NavigationDestination(
- icon: Icon(Icons.history_outlined),
- selectedIcon: Icon(Icons.history),
- label: 'History',
- ),
- // NavigationDestination(
- // icon: Icon(Icons.person_outline),
- // selectedIcon: Icon(Icons.person),
- // label: 'Profile',
- // ),
- ],
- ),
- );
- }
-
- int _calculateSelectedIndex(BuildContext context) {
- final String location = GoRouterState.of(context).uri.path;
- // if (location.startsWith('/recipients')) return 1;
- if (location.startsWith('/history')) return 1;
- // if (location.startsWith('/profile')) return 2;
- return 0;
- }
-}
diff --git a/lib/models/responsive_policy.dart b/lib/models/responsive_policy.dart
new file mode 100644
index 0000000..5ea284d
--- /dev/null
+++ b/lib/models/responsive_policy.dart
@@ -0,0 +1,5 @@
+class ResponsivePolicy {
+ static const int sm = 400;
+ static const int md = 600;
+ static const int lg = 950;
+}
\ No newline at end of file
diff --git a/lib/navbar.dart b/lib/navbar.dart
new file mode 100644
index 0000000..2f13235
--- /dev/null
+++ b/lib/navbar.dart
@@ -0,0 +1,209 @@
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+import 'models/responsive_policy.dart';
+
+class ScaffoldWithNavBar extends StatefulWidget {
+ const ScaffoldWithNavBar({super.key, required this.child});
+
+ final Widget child;
+
+ @override
+ State createState() => _ScaffoldWithNavBarState();
+}
+
+class _ScaffoldWithNavBarState extends State {
+ bool _isLoggedIn = false;
+ late String initials;
+
+ @override
+ void initState() {
+ super.initState();
+ init();
+ }
+
+ Future init() async {
+ var prefs = await SharedPreferences.getInstance();
+
+ if (prefs.getString("token") != null) {
+ setState(() {
+ _isLoggedIn = true;
+ initials = prefs.getString("initials")!;
+ });
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return LayoutBuilder(
+ builder: (context, constraints) {
+ if (constraints.maxWidth > ResponsivePolicy.md) {
+ return Scaffold(
+ body: SafeArea(
+ child: Row(
+ children: [
+ NavigationRail(
+ extended: true,
+ leading: Padding(
+ padding: const EdgeInsets.only(top: 20.0, bottom: 10),
+ child: Image(
+ image: AssetImage('assets/velocity.png'),
+ width: 150
+ ),
+ ),
+ trailing: _buildLogin(context),
+ labelType: NavigationRailLabelType.none,
+ indicatorColor: Theme.of(
+ context,
+ ).colorScheme.primary.withAlpha(30),
+ onDestinationSelected: (index) {
+ _handleTap(index, context);
+ },
+ selectedIndex: _calculateSelectedIndex(context),
+ destinations: _buildNavigationRailDestinations(),
+ ),
+ VerticalDivider(
+ thickness: 1,
+ width: 1,
+ color: Theme.of(context).colorScheme.primary.withAlpha(30),
+ ),
+ Expanded(child: widget.child),
+ ],
+ ),
+ ),
+ );
+ }
+ return Scaffold(
+ body: widget.child,
+ bottomNavigationBar: NavigationBar(
+ indicatorColor: Theme.of(context).colorScheme.primary.withAlpha(30),
+ onDestinationSelected: (index) {
+ _handleTap(index, context);
+ },
+ selectedIndex: _calculateSelectedIndex(context),
+ destinations: _buildNavigationDestinations(),
+ ),
+ );
+ },
+ );
+ }
+
+ List _buildNavigationRailDestinations() {
+ List destinations = [];
+ for (var destination in _buildDestinationData()) {
+ destinations.add(
+ NavigationRailDestination(
+ icon: destination["icon"] as Widget,
+ selectedIcon: destination["selectedIcon"] as Widget,
+ label: Text(destination["label"], style: TextStyle(fontSize: 16)),
+ ),
+ );
+ }
+ return destinations;
+ }
+
+ List _buildNavigationDestinations() {
+ List destinations = [];
+ for (var destination in _buildDestinationData()) {
+ destinations.add(
+ NavigationDestination(
+ icon: destination["icon"] as Widget,
+ selectedIcon: destination["selectedIcon"] as Widget,
+ label: destination["label"] as String,
+ ),
+ );
+ }
+ return destinations;
+ }
+
+ List