pos changes
This commit is contained in:
@@ -35,7 +35,6 @@ class SyncConfig {
|
||||
this.password,
|
||||
this.httpBaseUrl = '',
|
||||
this.apiKey,
|
||||
this.sessionToken,
|
||||
this.ackTimeout = const Duration(seconds: 20),
|
||||
this.batchSize = 50,
|
||||
});
|
||||
@@ -53,38 +52,8 @@ class SyncConfig {
|
||||
final String? password;
|
||||
|
||||
final String httpBaseUrl;
|
||||
|
||||
/// A static key shared by every terminal at a deployment, if one is set.
|
||||
///
|
||||
/// Predates sign-in and says nothing about *who* is at the till, so it cannot
|
||||
/// scope a request to an outlet. Kept for deployments that put one in front
|
||||
/// of the endpoint.
|
||||
final String? apiKey;
|
||||
|
||||
/// The signed session from `POST /login`, held for the trading day.
|
||||
///
|
||||
/// Distinct from [apiKey] because the two answer different questions. The key
|
||||
/// says "this request came from our fleet"; the session says "this request
|
||||
/// came from Selvapuram, signed in as Ragul, and may touch that outlet and no
|
||||
/// other". Only the second can stop a till reaching another tenant's books,
|
||||
/// which is why it takes precedence when both are present.
|
||||
final String? sessionToken;
|
||||
|
||||
/// What goes in the Authorization header.
|
||||
///
|
||||
/// One accessor rather than the same `??` repeated at each call site, because
|
||||
/// the request that forgot it would be the one silently sending no
|
||||
/// credentials at all.
|
||||
String? get bearerToken {
|
||||
final session = sessionToken?.trim();
|
||||
if (session != null && session.isNotEmpty) return session;
|
||||
|
||||
final key = apiKey?.trim();
|
||||
if (key != null && key.isNotEmpty) return key;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// How long to wait for the back office to confirm a batch before treating
|
||||
/// the outcome as unknown and leaving every row pending.
|
||||
///
|
||||
@@ -179,7 +148,6 @@ class SyncConfig {
|
||||
String? password,
|
||||
String? httpBaseUrl,
|
||||
String? apiKey,
|
||||
String? sessionToken,
|
||||
Duration? ackTimeout,
|
||||
int? batchSize,
|
||||
}) =>
|
||||
@@ -194,7 +162,6 @@ class SyncConfig {
|
||||
password: password ?? this.password,
|
||||
httpBaseUrl: httpBaseUrl ?? this.httpBaseUrl,
|
||||
apiKey: apiKey ?? this.apiKey,
|
||||
sessionToken: sessionToken ?? this.sessionToken,
|
||||
ackTimeout: ackTimeout ?? this.ackTimeout,
|
||||
batchSize: batchSize ?? this.batchSize,
|
||||
);
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
/// Typed references to bundled assets.
|
||||
///
|
||||
/// Only sounds are bundled: product imagery uses emoji glyphs and the welcome
|
||||
/// artwork is painted in code, so there are no raster or SVG assets to ship.
|
||||
/// Product imagery uses emoji glyphs and the welcome artwork is painted in
|
||||
/// code, so the only raster asset shipped is the mark itself.
|
||||
class AssetPaths {
|
||||
const AssetPaths._();
|
||||
|
||||
static const String _snd = 'assets/sounds';
|
||||
static const String _img = 'assets/images';
|
||||
|
||||
/// The Nearle mark. Every place that used to draw a letter "N" in a
|
||||
/// gradient box now renders this instead, so the brand cannot drift between
|
||||
/// the login screen, the sidebar and the cashier header.
|
||||
static const String logo = '$_img/logo.png';
|
||||
|
||||
static const String beepSuccess = '$_snd/beep_success.wav';
|
||||
static const String beepError = '$_snd/beep_error.wav';
|
||||
|
||||
@@ -8,6 +8,7 @@ import '../../presentation/auth/screens/login_screen.dart';
|
||||
import '../../presentation/payment/screens/payment_screen.dart';
|
||||
import '../../presentation/pos/screens/pos_dashboard_screen.dart';
|
||||
import '../../presentation/receipt/screens/receipt_screen.dart';
|
||||
import '../../presentation/shift/screens/end_shift_screen.dart';
|
||||
|
||||
class AppRoutes {
|
||||
const AppRoutes._();
|
||||
@@ -19,6 +20,10 @@ class AppRoutes {
|
||||
static const String pos = '/';
|
||||
static const String payment = '/payment';
|
||||
static const String receipt = '/receipt';
|
||||
|
||||
/// Drawer count and hand-over. Reached from the session-end chooser, never
|
||||
/// linked to directly, and guarded like every other signed-in route.
|
||||
static const String endShift = '/end-shift';
|
||||
}
|
||||
|
||||
/// Router with an authentication guard.
|
||||
@@ -60,6 +65,11 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
pageBuilder: (context, state) =>
|
||||
_fade(state, const PosDashboardScreen()),
|
||||
),
|
||||
GoRoute(
|
||||
path: AppRoutes.endShift,
|
||||
name: 'endShift',
|
||||
pageBuilder: (context, state) => _slide(state, const EndShiftScreen()),
|
||||
),
|
||||
GoRoute(
|
||||
path: AppRoutes.payment,
|
||||
name: 'payment',
|
||||
|
||||
66
lib/core/widgets/brand_mark.dart
Normal file
66
lib/core/widgets/brand_mark.dart
Normal file
@@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../constants/asset_paths.dart';
|
||||
import '../theme/app_colors.dart';
|
||||
|
||||
/// The Nearle mark on its tile.
|
||||
///
|
||||
/// Every surface that shows the brand — login, sidebar, cashier header —
|
||||
/// renders this, so the mark cannot drift between them. It replaces the
|
||||
/// hand-drawn letter "N" in a gradient box that each of those screens used to
|
||||
/// build for itself.
|
||||
class BrandMark extends StatelessWidget {
|
||||
const BrandMark({
|
||||
super.key,
|
||||
this.size = 36,
|
||||
this.radius,
|
||||
this.onDark = false,
|
||||
});
|
||||
|
||||
final double size;
|
||||
final double? radius;
|
||||
|
||||
/// Set on a coloured background, where the tile needs no border to separate
|
||||
/// it from what is behind.
|
||||
final bool onDark;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final corner = BorderRadius.circular(radius ?? size * 0.28);
|
||||
|
||||
return Container(
|
||||
width: size,
|
||||
height: size,
|
||||
// Clipped, not padded: the mark fills the tile edge to edge and the
|
||||
// rounded corner does the trimming, so nothing can spill past the box
|
||||
// whatever aspect ratio the file happens to have.
|
||||
clipBehavior: Clip.antiAlias,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: corner,
|
||||
border: onDark ? null : Border.all(color: AppColors.border),
|
||||
),
|
||||
child: Image.asset(
|
||||
AssetPaths.logo,
|
||||
fit: BoxFit.fill,
|
||||
width: size,
|
||||
height: size,
|
||||
filterQuality: FilterQuality.medium,
|
||||
// A missing or undeclared asset would otherwise blank the brand out
|
||||
// of the sidebar entirely; the letterform is a poor substitute but a
|
||||
// better failure than nothing.
|
||||
errorBuilder: (context, _, __) => FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Text(
|
||||
'N',
|
||||
style: TextStyle(
|
||||
color: AppColors.primary,
|
||||
fontWeight: FontWeight.w800,
|
||||
fontSize: size,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user