feat: add total count at order page
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
name: Build Android APK (split per ABI)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-apk:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: "temurin"
|
||||
java-version: "17"
|
||||
cache: "gradle"
|
||||
|
||||
- name: Setup Flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
# Samain dengan versi di ios.yml biar konsisten.
|
||||
flutter-version: "3.47.0"
|
||||
cache: true
|
||||
|
||||
- name: Install Dependencies
|
||||
run: flutter pub get
|
||||
|
||||
# ── Build ───────────────────────────────────────────────────────────────
|
||||
|
||||
- name: Build APK (split per ABI)
|
||||
run: flutter build apk --release --split-per-abi
|
||||
|
||||
# ── Artifact ────────────────────────────────────────────────────────────
|
||||
|
||||
- name: Upload APKs as Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: android-apk
|
||||
path: build/app/outputs/flutter-apk/app-*-release.apk
|
||||
retention-days: 7
|
||||
@@ -46,6 +46,31 @@ class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
|
||||
|
||||
emit(newState);
|
||||
},
|
||||
summaryFetched: (e) async {
|
||||
emit(state.copyWith(isFetchingSummary: true));
|
||||
|
||||
final results = await Future.wait([
|
||||
_repository.getTotalCount(
|
||||
outletId: state.outletId,
|
||||
dateFrom: state.dateFrom,
|
||||
dateTo: state.dateTo,
|
||||
),
|
||||
_repository.getTotalCount(
|
||||
status: 'pending',
|
||||
outletId: state.outletId,
|
||||
dateFrom: state.dateFrom,
|
||||
dateTo: state.dateTo,
|
||||
),
|
||||
]);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isFetchingSummary: false,
|
||||
totalOrder: results[0].getOrElse(() => 0),
|
||||
totalPendingOrder: results[1].getOrElse(() => 0),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ mixin _$OrderLoaderEvent {
|
||||
required TResult Function(String search) searchChanged,
|
||||
required TResult Function(String? outletId) outletChanged,
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
required TResult Function() summaryFetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
@@ -33,6 +34,7 @@ mixin _$OrderLoaderEvent {
|
||||
TResult? Function(String search)? searchChanged,
|
||||
TResult? Function(String? outletId)? outletChanged,
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
TResult? Function()? summaryFetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
@@ -41,6 +43,7 @@ mixin _$OrderLoaderEvent {
|
||||
TResult Function(String search)? searchChanged,
|
||||
TResult Function(String? outletId)? outletChanged,
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
TResult Function()? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
@@ -50,6 +53,7 @@ mixin _$OrderLoaderEvent {
|
||||
required TResult Function(_SearchChanged value) searchChanged,
|
||||
required TResult Function(_OutletChanged value) outletChanged,
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
required TResult Function(_SummaryFetched value) summaryFetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
@@ -58,6 +62,7 @@ mixin _$OrderLoaderEvent {
|
||||
TResult? Function(_SearchChanged value)? searchChanged,
|
||||
TResult? Function(_OutletChanged value)? outletChanged,
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
TResult? Function(_SummaryFetched value)? summaryFetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
@@ -66,6 +71,7 @@ mixin _$OrderLoaderEvent {
|
||||
TResult Function(_SearchChanged value)? searchChanged,
|
||||
TResult Function(_OutletChanged value)? outletChanged,
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
TResult Function(_SummaryFetched value)? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -179,6 +185,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
|
||||
required TResult Function(String search) searchChanged,
|
||||
required TResult Function(String? outletId) outletChanged,
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
required TResult Function() summaryFetched,
|
||||
}) {
|
||||
return rangeDateChanged(dateFrom, dateTo);
|
||||
}
|
||||
@@ -191,6 +198,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
|
||||
TResult? Function(String search)? searchChanged,
|
||||
TResult? Function(String? outletId)? outletChanged,
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
TResult? Function()? summaryFetched,
|
||||
}) {
|
||||
return rangeDateChanged?.call(dateFrom, dateTo);
|
||||
}
|
||||
@@ -203,6 +211,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
|
||||
TResult Function(String search)? searchChanged,
|
||||
TResult Function(String? outletId)? outletChanged,
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
TResult Function()? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (rangeDateChanged != null) {
|
||||
@@ -219,6 +228,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
|
||||
required TResult Function(_SearchChanged value) searchChanged,
|
||||
required TResult Function(_OutletChanged value) outletChanged,
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
required TResult Function(_SummaryFetched value) summaryFetched,
|
||||
}) {
|
||||
return rangeDateChanged(this);
|
||||
}
|
||||
@@ -231,6 +241,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
|
||||
TResult? Function(_SearchChanged value)? searchChanged,
|
||||
TResult? Function(_OutletChanged value)? outletChanged,
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
TResult? Function(_SummaryFetched value)? summaryFetched,
|
||||
}) {
|
||||
return rangeDateChanged?.call(this);
|
||||
}
|
||||
@@ -243,6 +254,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
|
||||
TResult Function(_SearchChanged value)? searchChanged,
|
||||
TResult Function(_OutletChanged value)? outletChanged,
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
TResult Function(_SummaryFetched value)? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (rangeDateChanged != null) {
|
||||
@@ -344,6 +356,7 @@ class _$StatusChangedImpl implements _StatusChanged {
|
||||
required TResult Function(String search) searchChanged,
|
||||
required TResult Function(String? outletId) outletChanged,
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
required TResult Function() summaryFetched,
|
||||
}) {
|
||||
return statusChanged(status);
|
||||
}
|
||||
@@ -356,6 +369,7 @@ class _$StatusChangedImpl implements _StatusChanged {
|
||||
TResult? Function(String search)? searchChanged,
|
||||
TResult? Function(String? outletId)? outletChanged,
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
TResult? Function()? summaryFetched,
|
||||
}) {
|
||||
return statusChanged?.call(status);
|
||||
}
|
||||
@@ -368,6 +382,7 @@ class _$StatusChangedImpl implements _StatusChanged {
|
||||
TResult Function(String search)? searchChanged,
|
||||
TResult Function(String? outletId)? outletChanged,
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
TResult Function()? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (statusChanged != null) {
|
||||
@@ -384,6 +399,7 @@ class _$StatusChangedImpl implements _StatusChanged {
|
||||
required TResult Function(_SearchChanged value) searchChanged,
|
||||
required TResult Function(_OutletChanged value) outletChanged,
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
required TResult Function(_SummaryFetched value) summaryFetched,
|
||||
}) {
|
||||
return statusChanged(this);
|
||||
}
|
||||
@@ -396,6 +412,7 @@ class _$StatusChangedImpl implements _StatusChanged {
|
||||
TResult? Function(_SearchChanged value)? searchChanged,
|
||||
TResult? Function(_OutletChanged value)? outletChanged,
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
TResult? Function(_SummaryFetched value)? summaryFetched,
|
||||
}) {
|
||||
return statusChanged?.call(this);
|
||||
}
|
||||
@@ -408,6 +425,7 @@ class _$StatusChangedImpl implements _StatusChanged {
|
||||
TResult Function(_SearchChanged value)? searchChanged,
|
||||
TResult Function(_OutletChanged value)? outletChanged,
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
TResult Function(_SummaryFetched value)? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (statusChanged != null) {
|
||||
@@ -505,6 +523,7 @@ class _$SearchChangedImpl implements _SearchChanged {
|
||||
required TResult Function(String search) searchChanged,
|
||||
required TResult Function(String? outletId) outletChanged,
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
required TResult Function() summaryFetched,
|
||||
}) {
|
||||
return searchChanged(search);
|
||||
}
|
||||
@@ -517,6 +536,7 @@ class _$SearchChangedImpl implements _SearchChanged {
|
||||
TResult? Function(String search)? searchChanged,
|
||||
TResult? Function(String? outletId)? outletChanged,
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
TResult? Function()? summaryFetched,
|
||||
}) {
|
||||
return searchChanged?.call(search);
|
||||
}
|
||||
@@ -529,6 +549,7 @@ class _$SearchChangedImpl implements _SearchChanged {
|
||||
TResult Function(String search)? searchChanged,
|
||||
TResult Function(String? outletId)? outletChanged,
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
TResult Function()? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (searchChanged != null) {
|
||||
@@ -545,6 +566,7 @@ class _$SearchChangedImpl implements _SearchChanged {
|
||||
required TResult Function(_SearchChanged value) searchChanged,
|
||||
required TResult Function(_OutletChanged value) outletChanged,
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
required TResult Function(_SummaryFetched value) summaryFetched,
|
||||
}) {
|
||||
return searchChanged(this);
|
||||
}
|
||||
@@ -557,6 +579,7 @@ class _$SearchChangedImpl implements _SearchChanged {
|
||||
TResult? Function(_SearchChanged value)? searchChanged,
|
||||
TResult? Function(_OutletChanged value)? outletChanged,
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
TResult? Function(_SummaryFetched value)? summaryFetched,
|
||||
}) {
|
||||
return searchChanged?.call(this);
|
||||
}
|
||||
@@ -569,6 +592,7 @@ class _$SearchChangedImpl implements _SearchChanged {
|
||||
TResult Function(_SearchChanged value)? searchChanged,
|
||||
TResult Function(_OutletChanged value)? outletChanged,
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
TResult Function(_SummaryFetched value)? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (searchChanged != null) {
|
||||
@@ -667,6 +691,7 @@ class _$OutletChangedImpl implements _OutletChanged {
|
||||
required TResult Function(String search) searchChanged,
|
||||
required TResult Function(String? outletId) outletChanged,
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
required TResult Function() summaryFetched,
|
||||
}) {
|
||||
return outletChanged(outletId);
|
||||
}
|
||||
@@ -679,6 +704,7 @@ class _$OutletChangedImpl implements _OutletChanged {
|
||||
TResult? Function(String search)? searchChanged,
|
||||
TResult? Function(String? outletId)? outletChanged,
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
TResult? Function()? summaryFetched,
|
||||
}) {
|
||||
return outletChanged?.call(outletId);
|
||||
}
|
||||
@@ -691,6 +717,7 @@ class _$OutletChangedImpl implements _OutletChanged {
|
||||
TResult Function(String search)? searchChanged,
|
||||
TResult Function(String? outletId)? outletChanged,
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
TResult Function()? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (outletChanged != null) {
|
||||
@@ -707,6 +734,7 @@ class _$OutletChangedImpl implements _OutletChanged {
|
||||
required TResult Function(_SearchChanged value) searchChanged,
|
||||
required TResult Function(_OutletChanged value) outletChanged,
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
required TResult Function(_SummaryFetched value) summaryFetched,
|
||||
}) {
|
||||
return outletChanged(this);
|
||||
}
|
||||
@@ -719,6 +747,7 @@ class _$OutletChangedImpl implements _OutletChanged {
|
||||
TResult? Function(_SearchChanged value)? searchChanged,
|
||||
TResult? Function(_OutletChanged value)? outletChanged,
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
TResult? Function(_SummaryFetched value)? summaryFetched,
|
||||
}) {
|
||||
return outletChanged?.call(this);
|
||||
}
|
||||
@@ -731,6 +760,7 @@ class _$OutletChangedImpl implements _OutletChanged {
|
||||
TResult Function(_SearchChanged value)? searchChanged,
|
||||
TResult Function(_OutletChanged value)? outletChanged,
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
TResult Function(_SummaryFetched value)? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (outletChanged != null) {
|
||||
@@ -830,6 +860,7 @@ class _$FetchedImpl implements _Fetched {
|
||||
required TResult Function(String search) searchChanged,
|
||||
required TResult Function(String? outletId) outletChanged,
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
required TResult Function() summaryFetched,
|
||||
}) {
|
||||
return fetched(isRefresh);
|
||||
}
|
||||
@@ -842,6 +873,7 @@ class _$FetchedImpl implements _Fetched {
|
||||
TResult? Function(String search)? searchChanged,
|
||||
TResult? Function(String? outletId)? outletChanged,
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
TResult? Function()? summaryFetched,
|
||||
}) {
|
||||
return fetched?.call(isRefresh);
|
||||
}
|
||||
@@ -854,6 +886,7 @@ class _$FetchedImpl implements _Fetched {
|
||||
TResult Function(String search)? searchChanged,
|
||||
TResult Function(String? outletId)? outletChanged,
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
TResult Function()? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (fetched != null) {
|
||||
@@ -870,6 +903,7 @@ class _$FetchedImpl implements _Fetched {
|
||||
required TResult Function(_SearchChanged value) searchChanged,
|
||||
required TResult Function(_OutletChanged value) outletChanged,
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
required TResult Function(_SummaryFetched value) summaryFetched,
|
||||
}) {
|
||||
return fetched(this);
|
||||
}
|
||||
@@ -882,6 +916,7 @@ class _$FetchedImpl implements _Fetched {
|
||||
TResult? Function(_SearchChanged value)? searchChanged,
|
||||
TResult? Function(_OutletChanged value)? outletChanged,
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
TResult? Function(_SummaryFetched value)? summaryFetched,
|
||||
}) {
|
||||
return fetched?.call(this);
|
||||
}
|
||||
@@ -894,6 +929,7 @@ class _$FetchedImpl implements _Fetched {
|
||||
TResult Function(_SearchChanged value)? searchChanged,
|
||||
TResult Function(_OutletChanged value)? outletChanged,
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
TResult Function(_SummaryFetched value)? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (fetched != null) {
|
||||
@@ -915,6 +951,138 @@ abstract class _Fetched implements OrderLoaderEvent {
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SummaryFetchedImplCopyWith<$Res> {
|
||||
factory _$$SummaryFetchedImplCopyWith(
|
||||
_$SummaryFetchedImpl value,
|
||||
$Res Function(_$SummaryFetchedImpl) then,
|
||||
) = __$$SummaryFetchedImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SummaryFetchedImplCopyWithImpl<$Res>
|
||||
extends _$OrderLoaderEventCopyWithImpl<$Res, _$SummaryFetchedImpl>
|
||||
implements _$$SummaryFetchedImplCopyWith<$Res> {
|
||||
__$$SummaryFetchedImplCopyWithImpl(
|
||||
_$SummaryFetchedImpl _value,
|
||||
$Res Function(_$SummaryFetchedImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of OrderLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SummaryFetchedImpl implements _SummaryFetched {
|
||||
const _$SummaryFetchedImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'OrderLoaderEvent.summaryFetched()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$SummaryFetchedImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(DateTime dateFrom, DateTime dateTo)
|
||||
rangeDateChanged,
|
||||
required TResult Function(String status) statusChanged,
|
||||
required TResult Function(String search) searchChanged,
|
||||
required TResult Function(String? outletId) outletChanged,
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
required TResult Function() summaryFetched,
|
||||
}) {
|
||||
return summaryFetched();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
|
||||
TResult? Function(String status)? statusChanged,
|
||||
TResult? Function(String search)? searchChanged,
|
||||
TResult? Function(String? outletId)? outletChanged,
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
TResult? Function()? summaryFetched,
|
||||
}) {
|
||||
return summaryFetched?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
|
||||
TResult Function(String status)? statusChanged,
|
||||
TResult Function(String search)? searchChanged,
|
||||
TResult Function(String? outletId)? outletChanged,
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
TResult Function()? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (summaryFetched != null) {
|
||||
return summaryFetched();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_RangeDateChanged value) rangeDateChanged,
|
||||
required TResult Function(_StatusChanged value) statusChanged,
|
||||
required TResult Function(_SearchChanged value) searchChanged,
|
||||
required TResult Function(_OutletChanged value) outletChanged,
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
required TResult Function(_SummaryFetched value) summaryFetched,
|
||||
}) {
|
||||
return summaryFetched(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_RangeDateChanged value)? rangeDateChanged,
|
||||
TResult? Function(_StatusChanged value)? statusChanged,
|
||||
TResult? Function(_SearchChanged value)? searchChanged,
|
||||
TResult? Function(_OutletChanged value)? outletChanged,
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
TResult? Function(_SummaryFetched value)? summaryFetched,
|
||||
}) {
|
||||
return summaryFetched?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_RangeDateChanged value)? rangeDateChanged,
|
||||
TResult Function(_StatusChanged value)? statusChanged,
|
||||
TResult Function(_SearchChanged value)? searchChanged,
|
||||
TResult Function(_OutletChanged value)? outletChanged,
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
TResult Function(_SummaryFetched value)? summaryFetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (summaryFetched != null) {
|
||||
return summaryFetched(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _SummaryFetched implements OrderLoaderEvent {
|
||||
const factory _SummaryFetched() = _$SummaryFetchedImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$OrderLoaderState {
|
||||
List<Order> get orders => throw _privateConstructorUsedError;
|
||||
@@ -926,6 +1094,9 @@ mixin _$OrderLoaderState {
|
||||
bool get isFetching => throw _privateConstructorUsedError;
|
||||
bool get hasReachedMax => throw _privateConstructorUsedError;
|
||||
int get page => throw _privateConstructorUsedError;
|
||||
int get totalOrder => throw _privateConstructorUsedError;
|
||||
int get totalPendingOrder => throw _privateConstructorUsedError;
|
||||
bool get isFetchingSummary => throw _privateConstructorUsedError;
|
||||
DateTime get dateFrom => throw _privateConstructorUsedError;
|
||||
DateTime get dateTo => throw _privateConstructorUsedError;
|
||||
|
||||
@@ -952,6 +1123,9 @@ abstract class $OrderLoaderStateCopyWith<$Res> {
|
||||
bool isFetching,
|
||||
bool hasReachedMax,
|
||||
int page,
|
||||
int totalOrder,
|
||||
int totalPendingOrder,
|
||||
bool isFetchingSummary,
|
||||
DateTime dateFrom,
|
||||
DateTime dateTo,
|
||||
});
|
||||
@@ -980,6 +1154,9 @@ class _$OrderLoaderStateCopyWithImpl<$Res, $Val extends OrderLoaderState>
|
||||
Object? isFetching = null,
|
||||
Object? hasReachedMax = null,
|
||||
Object? page = null,
|
||||
Object? totalOrder = null,
|
||||
Object? totalPendingOrder = null,
|
||||
Object? isFetchingSummary = null,
|
||||
Object? dateFrom = null,
|
||||
Object? dateTo = null,
|
||||
}) {
|
||||
@@ -1017,6 +1194,18 @@ class _$OrderLoaderStateCopyWithImpl<$Res, $Val extends OrderLoaderState>
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
totalOrder: null == totalOrder
|
||||
? _value.totalOrder
|
||||
: totalOrder // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
totalPendingOrder: null == totalPendingOrder
|
||||
? _value.totalPendingOrder
|
||||
: totalPendingOrder // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
isFetchingSummary: null == isFetchingSummary
|
||||
? _value.isFetchingSummary
|
||||
: isFetchingSummary // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
dateFrom: null == dateFrom
|
||||
? _value.dateFrom
|
||||
: dateFrom // ignore: cast_nullable_to_non_nullable
|
||||
@@ -1049,6 +1238,9 @@ abstract class _$$OrderLoaderStateImplCopyWith<$Res>
|
||||
bool isFetching,
|
||||
bool hasReachedMax,
|
||||
int page,
|
||||
int totalOrder,
|
||||
int totalPendingOrder,
|
||||
bool isFetchingSummary,
|
||||
DateTime dateFrom,
|
||||
DateTime dateTo,
|
||||
});
|
||||
@@ -1076,6 +1268,9 @@ class __$$OrderLoaderStateImplCopyWithImpl<$Res>
|
||||
Object? isFetching = null,
|
||||
Object? hasReachedMax = null,
|
||||
Object? page = null,
|
||||
Object? totalOrder = null,
|
||||
Object? totalPendingOrder = null,
|
||||
Object? isFetchingSummary = null,
|
||||
Object? dateFrom = null,
|
||||
Object? dateTo = null,
|
||||
}) {
|
||||
@@ -1113,6 +1308,18 @@ class __$$OrderLoaderStateImplCopyWithImpl<$Res>
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
totalOrder: null == totalOrder
|
||||
? _value.totalOrder
|
||||
: totalOrder // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
totalPendingOrder: null == totalPendingOrder
|
||||
? _value.totalPendingOrder
|
||||
: totalPendingOrder // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
isFetchingSummary: null == isFetchingSummary
|
||||
? _value.isFetchingSummary
|
||||
: isFetchingSummary // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
dateFrom: null == dateFrom
|
||||
? _value.dateFrom
|
||||
: dateFrom // ignore: cast_nullable_to_non_nullable
|
||||
@@ -1138,6 +1345,9 @@ class _$OrderLoaderStateImpl implements _OrderLoaderState {
|
||||
this.isFetching = false,
|
||||
this.hasReachedMax = false,
|
||||
this.page = 1,
|
||||
this.totalOrder = 0,
|
||||
this.totalPendingOrder = 0,
|
||||
this.isFetchingSummary = false,
|
||||
required this.dateFrom,
|
||||
required this.dateTo,
|
||||
}) : _orders = orders;
|
||||
@@ -1168,13 +1378,22 @@ class _$OrderLoaderStateImpl implements _OrderLoaderState {
|
||||
@JsonKey()
|
||||
final int page;
|
||||
@override
|
||||
@JsonKey()
|
||||
final int totalOrder;
|
||||
@override
|
||||
@JsonKey()
|
||||
final int totalPendingOrder;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isFetchingSummary;
|
||||
@override
|
||||
final DateTime dateFrom;
|
||||
@override
|
||||
final DateTime dateTo;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'OrderLoaderState(orders: $orders, failureOptionOrder: $failureOptionOrder, status: $status, search: $search, outletId: $outletId, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page, dateFrom: $dateFrom, dateTo: $dateTo)';
|
||||
return 'OrderLoaderState(orders: $orders, failureOptionOrder: $failureOptionOrder, status: $status, search: $search, outletId: $outletId, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page, totalOrder: $totalOrder, totalPendingOrder: $totalPendingOrder, isFetchingSummary: $isFetchingSummary, dateFrom: $dateFrom, dateTo: $dateTo)';
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -1194,6 +1413,12 @@ class _$OrderLoaderStateImpl implements _OrderLoaderState {
|
||||
(identical(other.hasReachedMax, hasReachedMax) ||
|
||||
other.hasReachedMax == hasReachedMax) &&
|
||||
(identical(other.page, page) || other.page == page) &&
|
||||
(identical(other.totalOrder, totalOrder) ||
|
||||
other.totalOrder == totalOrder) &&
|
||||
(identical(other.totalPendingOrder, totalPendingOrder) ||
|
||||
other.totalPendingOrder == totalPendingOrder) &&
|
||||
(identical(other.isFetchingSummary, isFetchingSummary) ||
|
||||
other.isFetchingSummary == isFetchingSummary) &&
|
||||
(identical(other.dateFrom, dateFrom) ||
|
||||
other.dateFrom == dateFrom) &&
|
||||
(identical(other.dateTo, dateTo) || other.dateTo == dateTo));
|
||||
@@ -1210,6 +1435,9 @@ class _$OrderLoaderStateImpl implements _OrderLoaderState {
|
||||
isFetching,
|
||||
hasReachedMax,
|
||||
page,
|
||||
totalOrder,
|
||||
totalPendingOrder,
|
||||
isFetchingSummary,
|
||||
dateFrom,
|
||||
dateTo,
|
||||
);
|
||||
@@ -1236,6 +1464,9 @@ abstract class _OrderLoaderState implements OrderLoaderState {
|
||||
final bool isFetching,
|
||||
final bool hasReachedMax,
|
||||
final int page,
|
||||
final int totalOrder,
|
||||
final int totalPendingOrder,
|
||||
final bool isFetchingSummary,
|
||||
required final DateTime dateFrom,
|
||||
required final DateTime dateTo,
|
||||
}) = _$OrderLoaderStateImpl;
|
||||
@@ -1257,6 +1488,12 @@ abstract class _OrderLoaderState implements OrderLoaderState {
|
||||
@override
|
||||
int get page;
|
||||
@override
|
||||
int get totalOrder;
|
||||
@override
|
||||
int get totalPendingOrder;
|
||||
@override
|
||||
bool get isFetchingSummary;
|
||||
@override
|
||||
DateTime get dateFrom;
|
||||
@override
|
||||
DateTime get dateTo;
|
||||
|
||||
@@ -12,4 +12,5 @@ class OrderLoaderEvent with _$OrderLoaderEvent {
|
||||
_OutletChanged;
|
||||
const factory OrderLoaderEvent.fetched({@Default(false) bool isRefresh}) =
|
||||
_Fetched;
|
||||
const factory OrderLoaderEvent.summaryFetched() = _SummaryFetched;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ class OrderLoaderState with _$OrderLoaderState {
|
||||
@Default(false) bool isFetching,
|
||||
@Default(false) bool hasReachedMax,
|
||||
@Default(1) int page,
|
||||
@Default(0) int totalOrder,
|
||||
@Default(0) int totalPendingOrder,
|
||||
@Default(false) bool isFetchingSummary,
|
||||
required DateTime dateFrom,
|
||||
required DateTime dateTo,
|
||||
}) = _OrderLoaderState;
|
||||
|
||||
@@ -10,4 +10,11 @@ abstract class IOrderRepository {
|
||||
required DateTime dateFrom,
|
||||
required DateTime dateTo,
|
||||
});
|
||||
|
||||
Future<Either<OrderFailure, int>> getTotalCount({
|
||||
String? status,
|
||||
String? outletId,
|
||||
required DateTime dateFrom,
|
||||
required DateTime dateTo,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,9 +43,9 @@ class OrderRemoteDataProvider {
|
||||
params['search'] = search;
|
||||
}
|
||||
|
||||
// if (outletId != null) {
|
||||
// params['outlet_id'] = outletId;
|
||||
// }
|
||||
if (outletId != null) {
|
||||
params['outlet_id'] = outletId;
|
||||
}
|
||||
|
||||
final response = await _apiClient.get(
|
||||
ApiPath.order,
|
||||
@@ -67,4 +67,47 @@ class OrderRemoteDataProvider {
|
||||
return DC.error(OrderFailure.serverError(e));
|
||||
}
|
||||
}
|
||||
|
||||
/// Backend belum punya endpoint ringkasan order, jadi jumlahnya diambil
|
||||
/// dari `total_count` list order (limit 1 supaya payload kecil).
|
||||
Future<DC<OrderFailure, int>> fetchTotalCount({
|
||||
String? status,
|
||||
String? outletId,
|
||||
required DateTime dateFrom,
|
||||
required DateTime dateTo,
|
||||
}) async {
|
||||
try {
|
||||
Map<String, dynamic> params = {
|
||||
'page': 1,
|
||||
'limit': 1,
|
||||
'date_from': dateFrom.toServerDate,
|
||||
'date_to': dateTo.toServerDate,
|
||||
};
|
||||
|
||||
if (status != null && status.isNotEmpty) {
|
||||
params['status'] = status;
|
||||
}
|
||||
|
||||
if (outletId != null) {
|
||||
params['outlet_id'] = outletId;
|
||||
}
|
||||
|
||||
final response = await _apiClient.get(
|
||||
ApiPath.order,
|
||||
params: params,
|
||||
headers: getAuthorizationHeader(),
|
||||
);
|
||||
|
||||
if (response.data['data'] == null) {
|
||||
return DC.error(OrderFailure.empty());
|
||||
}
|
||||
|
||||
final total = response.data['data']['total_count'] as num? ?? 0;
|
||||
|
||||
return DC.data(total.toInt());
|
||||
} on ApiFailure catch (e, s) {
|
||||
log('fetchOrderTotalCountError', name: _logName, error: e, stackTrace: s);
|
||||
return DC.error(OrderFailure.serverError(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,15 @@ import 'package:dartz/dartz.dart' hide Order;
|
||||
import 'package:injectable/injectable.dart' hide Order;
|
||||
|
||||
import '../../../domain/order/order.dart';
|
||||
import '../../outlet/datasource/local_data_provider.dart';
|
||||
import '../datasource/remote_data_provider.dart';
|
||||
|
||||
/// `outletId` null = semua outlet (sesuai pilihan "Semua Outlet" di filter).
|
||||
@Injectable(as: IOrderRepository)
|
||||
class OrderRepository implements IOrderRepository {
|
||||
final OrderRemoteDataProvider _dataProvider;
|
||||
final OutletLocalDataProvider _outletLocalDataProvider;
|
||||
final String _logName = 'OrderRepository';
|
||||
|
||||
OrderRepository(this._dataProvider, this._outletLocalDataProvider);
|
||||
OrderRepository(this._dataProvider);
|
||||
|
||||
@override
|
||||
Future<Either<OrderFailure, List<Order>>> get({
|
||||
@@ -26,15 +25,12 @@ class OrderRepository implements IOrderRepository {
|
||||
required DateTime dateTo,
|
||||
}) async {
|
||||
try {
|
||||
final resolvedOutletId =
|
||||
outletId ?? _outletLocalDataProvider.getSelectedOutletId();
|
||||
|
||||
final result = await _dataProvider.fetch(
|
||||
page: page,
|
||||
limit: limit,
|
||||
status: status,
|
||||
search: search,
|
||||
outletId: resolvedOutletId,
|
||||
outletId: outletId,
|
||||
dateFrom: dateFrom,
|
||||
dateTo: dateTo,
|
||||
);
|
||||
@@ -51,4 +47,30 @@ class OrderRepository implements IOrderRepository {
|
||||
return left(const OrderFailure.unexpectedError());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Either<OrderFailure, int>> getTotalCount({
|
||||
String? status,
|
||||
String? outletId,
|
||||
required DateTime dateFrom,
|
||||
required DateTime dateTo,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _dataProvider.fetchTotalCount(
|
||||
status: status,
|
||||
outletId: outletId,
|
||||
dateFrom: dateFrom,
|
||||
dateTo: dateTo,
|
||||
);
|
||||
|
||||
if (result.hasError) {
|
||||
return left(result.error!);
|
||||
}
|
||||
|
||||
return right(result.data!);
|
||||
} catch (e, s) {
|
||||
log('getOrderTotalCountError', name: _logName, error: e, stackTrace: s);
|
||||
return left(const OrderFailure.unexpectedError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,6 +207,9 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh.factory<_i48.ICustomerRepository>(
|
||||
() => _i550.CustomerRepository(gh<_i1006.CustomerRemoteDataProvider>()),
|
||||
);
|
||||
gh.factory<_i219.IOrderRepository>(
|
||||
() => _i641.OrderRepository(gh<_i130.OrderRemoteDataProvider>()),
|
||||
);
|
||||
gh.factory<_i49.IAuthRepository>(
|
||||
() => _i1035.AuthRepository(
|
||||
gh<_i991.AuthLocalDataProvider>(),
|
||||
@@ -225,12 +228,6 @@ extension GetItInjectableX on _i174.GetIt {
|
||||
gh.factory<_i419.IProductRepository>(
|
||||
() => _i121.ProductRepository(gh<_i823.ProductRemoteDataProvider>()),
|
||||
);
|
||||
gh.factory<_i219.IOrderRepository>(
|
||||
() => _i641.OrderRepository(
|
||||
gh<_i130.OrderRemoteDataProvider>(),
|
||||
gh<_i850.OutletLocalDataProvider>(),
|
||||
),
|
||||
);
|
||||
gh.factory<_i972.CustomerLoaderBloc>(
|
||||
() => _i972.CustomerLoaderBloc(gh<_i48.ICustomerRepository>()),
|
||||
);
|
||||
|
||||
+10
-1
@@ -621,5 +621,14 @@
|
||||
"status_critical": "Unhealthy",
|
||||
"@status_critical": {},
|
||||
"tap_row_for_detail": "Tap a card to see sub category and product details",
|
||||
"@tap_row_for_detail": {}
|
||||
"@tap_row_for_detail": {},
|
||||
"order_unpaid_ratio": "{percent}% of orders still awaiting payment",
|
||||
"@order_unpaid_ratio": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "String",
|
||||
"example": "25"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -621,5 +621,14 @@
|
||||
"status_critical": "Tidak Sehat",
|
||||
"@status_critical": {},
|
||||
"tap_row_for_detail": "Ketuk kartu untuk melihat rincian sub kategori dan produk",
|
||||
"@tap_row_for_detail": {}
|
||||
"@tap_row_for_detail": {},
|
||||
"order_unpaid_ratio": "{percent}% pesanan masih menunggu pembayaran",
|
||||
"@order_unpaid_ratio": {
|
||||
"placeholders": {
|
||||
"percent": {
|
||||
"type": "String",
|
||||
"example": "25"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1750,6 +1750,12 @@ abstract class AppLocalizations {
|
||||
/// In en, this message translates to:
|
||||
/// **'Tap a card to see sub category and product details'**
|
||||
String get tap_row_for_detail;
|
||||
|
||||
/// No description provided for @order_unpaid_ratio.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'{percent}% of orders still awaiting payment'**
|
||||
String order_unpaid_ratio(String percent);
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||||
|
||||
@@ -855,4 +855,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get tap_row_for_detail => 'Tap a card to see sub category and product details';
|
||||
|
||||
@override
|
||||
String order_unpaid_ratio(String percent) {
|
||||
return '$percent% of orders still awaiting payment';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -855,4 +855,9 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get tap_row_for_detail => 'Ketuk kartu untuk melihat rincian sub kategori dan produk';
|
||||
|
||||
@override
|
||||
String order_unpaid_ratio(String percent) {
|
||||
return '$percent% pesanan masih menunggu pembayaran';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import '../../../components/appbar/appbar.dart';
|
||||
import '../../../components/widgets/empty_widget.dart';
|
||||
import '../../../router/app_router.gr.dart';
|
||||
import 'widgets/filter_header_delegate.dart';
|
||||
import 'widgets/order_summary.dart';
|
||||
import 'widgets/order_tile.dart';
|
||||
|
||||
@RoutePage()
|
||||
@@ -29,7 +30,8 @@ class OrderPage extends StatefulWidget implements AutoRouteWrapper {
|
||||
BlocProvider(
|
||||
create: (_) =>
|
||||
getIt<OrderLoaderBloc>()
|
||||
..add(OrderLoaderEvent.fetched(isRefresh: true)),
|
||||
..add(OrderLoaderEvent.fetched(isRefresh: true))
|
||||
..add(const OrderLoaderEvent.summaryFetched()),
|
||||
),
|
||||
BlocProvider(
|
||||
create: (_) =>
|
||||
@@ -192,9 +194,9 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
|
||||
BlocListener<OrderLoaderBloc, OrderLoaderState>(
|
||||
listenWhen: (p, c) => p.outletId != c.outletId,
|
||||
listener: (context, state) {
|
||||
context.read<OrderLoaderBloc>().add(
|
||||
OrderLoaderEvent.fetched(isRefresh: true),
|
||||
);
|
||||
context.read<OrderLoaderBloc>()
|
||||
..add(OrderLoaderEvent.fetched(isRefresh: true))
|
||||
..add(const OrderLoaderEvent.summaryFetched());
|
||||
},
|
||||
),
|
||||
BlocListener<OrderLoaderBloc, OrderLoaderState>(
|
||||
@@ -210,9 +212,9 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
|
||||
previous.dateFrom != current.dateFrom ||
|
||||
previous.dateTo != current.dateTo,
|
||||
listener: (context, state) {
|
||||
context.read<OrderLoaderBloc>().add(
|
||||
OrderLoaderEvent.fetched(isRefresh: true),
|
||||
);
|
||||
context.read<OrderLoaderBloc>()
|
||||
..add(OrderLoaderEvent.fetched(isRefresh: true))
|
||||
..add(const OrderLoaderEvent.summaryFetched());
|
||||
},
|
||||
),
|
||||
],
|
||||
@@ -301,6 +303,14 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
|
||||
position: _slideAnimation,
|
||||
child: Column(
|
||||
children: [
|
||||
OrderSummary(
|
||||
totalOrder: state.totalOrder,
|
||||
totalPendingOrder:
|
||||
state.totalPendingOrder,
|
||||
isLoading: state.isFetchingSummary,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Show filtered transaction count
|
||||
if (state.status != 'all' &&
|
||||
!state.isFetching)
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
import '../../../../../common/extension/extension.dart';
|
||||
import '../../../../../common/theme/theme.dart';
|
||||
import '../../../../components/spacer/spacer.dart';
|
||||
import '../../../../components/widgets/particle_card.dart';
|
||||
|
||||
/// Aksen pesanan pending — amber supaya kontras di atas gradient merah.
|
||||
const Color _pendingColor = Color(0xFFFFB300);
|
||||
|
||||
class OrderSummary extends StatelessWidget {
|
||||
final int totalOrder;
|
||||
final int totalPendingOrder;
|
||||
final bool isLoading;
|
||||
|
||||
const OrderSummary({
|
||||
super.key,
|
||||
required this.totalOrder,
|
||||
required this.totalPendingOrder,
|
||||
this.isLoading = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pendingRatio = totalOrder > 0
|
||||
? (totalPendingOrder / totalOrder).clamp(0.0, 1.0)
|
||||
: 0.0;
|
||||
|
||||
return ParticleCard(
|
||||
borderRadius: 18,
|
||||
decorationOpacity: 0.8,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
IntrinsicHeight(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _SummaryStat(
|
||||
title: context.lang.total_orders,
|
||||
value: totalOrder,
|
||||
icon: Icons.receipt_long_rounded,
|
||||
iconBackground: AppColor.white.withOpacity(0.2),
|
||||
isLoading: isLoading,
|
||||
),
|
||||
),
|
||||
VerticalDivider(
|
||||
width: 28,
|
||||
thickness: 1,
|
||||
color: AppColor.white.withOpacity(0.25),
|
||||
),
|
||||
Expanded(
|
||||
child: _SummaryStat(
|
||||
title: context.lang.pending_order,
|
||||
value: totalPendingOrder,
|
||||
icon: Icons.hourglass_top_rounded,
|
||||
iconBackground: _pendingColor,
|
||||
isLoading: isLoading,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SpaceHeight(16),
|
||||
_PendingRatioBar(ratio: pendingRatio),
|
||||
const SpaceHeight(8),
|
||||
Text(
|
||||
context.lang.order_unpaid_ratio(
|
||||
(pendingRatio * 100).round().toString(),
|
||||
),
|
||||
style: AppStyle.xs.copyWith(
|
||||
color: AppColor.white.withOpacity(0.8),
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _SummaryStat extends StatelessWidget {
|
||||
final String title;
|
||||
final int value;
|
||||
final IconData icon;
|
||||
final Color iconBackground;
|
||||
final bool isLoading;
|
||||
|
||||
const _SummaryStat({
|
||||
required this.title,
|
||||
required this.value,
|
||||
required this.icon,
|
||||
required this.iconBackground,
|
||||
required this.isLoading,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(7),
|
||||
decoration: BoxDecoration(
|
||||
color: iconBackground,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Icon(icon, color: AppColor.white, size: 16),
|
||||
),
|
||||
const SpaceWidth(8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
title,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: AppStyle.sm.copyWith(
|
||||
color: AppColor.white.withOpacity(0.9),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SpaceHeight(12),
|
||||
if (isLoading)
|
||||
Shimmer.fromColors(
|
||||
baseColor: AppColor.white.withOpacity(0.2),
|
||||
highlightColor: AppColor.white.withOpacity(0.45),
|
||||
child: Container(
|
||||
width: 56,
|
||||
height: 30,
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.white,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
TweenAnimationBuilder<int>(
|
||||
tween: IntTween(begin: 0, end: value),
|
||||
duration: const Duration(milliseconds: 900),
|
||||
curve: Curves.easeOutCubic,
|
||||
builder: (context, animatedValue, _) => Text(
|
||||
animatedValue.thousandFormat,
|
||||
style: AppStyle.h1.copyWith(
|
||||
color: AppColor.white,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 28,
|
||||
height: 1.1,
|
||||
shadows: [
|
||||
Shadow(
|
||||
color: Colors.black.withOpacity(0.25),
|
||||
blurRadius: 6,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PendingRatioBar extends StatelessWidget {
|
||||
final double ratio;
|
||||
|
||||
const _PendingRatioBar({required this.ratio});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Container(
|
||||
height: 6,
|
||||
color: AppColor.white.withOpacity(0.2),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(begin: 0, end: ratio),
|
||||
duration: const Duration(milliseconds: 900),
|
||||
curve: Curves.easeOutCubic,
|
||||
builder: (context, value, _) => FractionallySizedBox(
|
||||
widthFactor: value,
|
||||
heightFactor: 1,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: _pendingColor,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ description: "A new Flutter project."
|
||||
|
||||
publish_to: "none"
|
||||
|
||||
version: 1.0.4+14
|
||||
version: 1.0.4+15
|
||||
|
||||
environment:
|
||||
sdk: ^3.8.1
|
||||
|
||||
Reference in New Issue
Block a user