minor fixes

This commit is contained in:
2026-06-24 00:59:19 +02:00
parent 5a5aab6956
commit a79cfadf51
13 changed files with 70 additions and 42 deletions

View File

@@ -0,0 +1,53 @@
/// Application configuration sourced entirely from compile-time
/// `--dart-define` flags. No `.env` file is read at runtime, so no
/// secrets can leak into the web bundle via asset files.
///
/// Every value has a sensible default so the project still builds and
/// runs locally without specifying any flags.
class AppConfig {
AppConfig._();
// -----------------------------------------------------------------
// Compile-time values (set via `--dart-define=<KEY>=<VALUE>`)
// -----------------------------------------------------------------
/// Runtime environment: `test`, `live`, etc.
static const String env = String.fromEnvironment(
'APP_ENV',
defaultValue: 'test',
);
/// Base URL of the backend API.
static const String baseUrl = String.fromEnvironment(
'BASE_URL',
defaultValue: 'http://localhost:6950/api',
);
/// Google OAuth web client ID. This is *not* a secret — it is
/// intended to be embedded in public-facing web applications.
static const String clientId = String.fromEnvironment(
'CLIENTID',
defaultValue: '',
);
/// When `true` the payment gateway screens skip the real flow and
/// return a simulated success immediately. Useful during development.
static const bool simulatePaymentSuccess = bool.fromEnvironment(
'SIMULATE_PAYMENT_SUCCESS',
defaultValue: false,
);
/// URL of the Mastercard Gateway checkout JavaScript bundle.
static const String gatewayScriptUrl = String.fromEnvironment(
'GATEWAY_SCRIPT_URL',
defaultValue:
'https://test-gateway.mastercard.com/static/checkout/checkout.min.js',
);
// -----------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------
/// `true` when [env] is `live`.
static bool get isLive => env.toLowerCase() == 'live';
}

View File

@@ -1,14 +1,14 @@
import 'package:dio/dio.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:logger/logger.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:qpay/config/app_config.dart';
var logger = Logger(printer: PrettyPrinter());
class Http {
final Dio dio = Dio();
final String baseUrl = dotenv.env['BASE_URL'] ?? '';
final String baseUrl = AppConfig.baseUrl;
Http() {
dio.options.baseUrl = baseUrl;

View File

@@ -1,12 +1,9 @@
import 'dart:async';
import 'dart:js_interop';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:qpay/config/app_config.dart';
import 'package:web/web.dart' as web;
const String _defaultGatewayScriptUrl =
'https://test-gateway.mastercard.com/static/checkout/checkout.min.js';
@JS('Checkout')
external JSAny? _checkout;
@@ -23,8 +20,7 @@ Future<void> ensureCheckoutScriptLoaded() async {
return;
}
final scriptUrl =
dotenv.env['GATEWAY_SCRIPT_URL'] ?? _defaultGatewayScriptUrl;
final scriptUrl = AppConfig.gatewayScriptUrl;
final scriptElement = web.HTMLScriptElement()
..id = 'mastercard-checkout-script'

View File

@@ -10,23 +10,9 @@ import 'package:qpay/providers/splash_provider.dart';
import 'package:qpay/screens/workspaces/workspace_provider.dart';
import 'package:qpay/providers/uptime_provider.dart';
import 'package:qpay/theme/app_theme.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
const String testEnv = 'assets/.env.test';
const String liveEnv = 'assets/.env.live';
const String appEnv = String.fromEnvironment('APP_ENV', defaultValue: 'test');
String resolveEnvFile(String env) {
switch (env.toLowerCase()) {
case 'live':
return liveEnv;
case 'test':
default:
return testEnv;
}
}
import 'config/app_config.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@@ -35,8 +21,6 @@ void main() async {
}
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await dotenv.load(fileName: resolveEnvFile(appEnv));
// Read the persisted auth token before the first frame so the router
// knows whether the user is already signed in on cold start. Without
// this we would briefly treat logged-in users as guests and bounce

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:go_router/go_router.dart';
import 'package:qpay/config/app_config.dart';
import 'package:qpay/screens/gateway/gateway_controller.dart';
import 'package:qpay/widgets/app_snack_bar.dart';
import 'package:webview_flutter/webview_flutter.dart';
@@ -56,7 +56,7 @@ class _GatewayScreenState extends State<GatewayScreen> {
)
..loadRequest(Uri.parse(url));
bool simulate = bool.parse(dotenv.env['SIMULATE_PAYMENT_SUCCESS']!);
bool simulate = AppConfig.simulatePaymentSuccess;
if (simulate) {
await Future.delayed(Duration(seconds: 10));
String targetUrl = url.replaceAll("/pay/", "/receipt/");

View File

@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:go_router/go_router.dart';
import 'package:qpay/config/app_config.dart';
import 'package:qpay/models/responsive_policy.dart';
import 'package:qpay/screens/gateway/gateway_controller.dart';
import 'package:qpay/browser.dart';
@@ -34,9 +34,7 @@ class _GatewayWebScreenState extends State<GatewayWebScreen> {
redirecting = true;
});
bool simulate = bool.parse(
dotenv.env['SIMULATE_PAYMENT_SUCCESS'] ?? 'false',
);
bool simulate = AppConfig.simulatePaymentSuccess;
if (simulate) {
// In simulation mode, just go to polling
WidgetsBinding.instance.addPostFrameCallback((_) {