feat: inventory report
This commit is contained in:
parent
50934bfed9
commit
1aa65d1732
@ -1,5 +1,10 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="Apskel Owner"
|
android:label="Apskel Owner"
|
||||||
|
|||||||
@ -0,0 +1,66 @@
|
|||||||
|
import 'package:bloc/bloc.dart';
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:injectable/injectable.dart';
|
||||||
|
|
||||||
|
import '../../../domain/analytic/analytic.dart';
|
||||||
|
import '../../../domain/analytic/repositories/i_analytic_repository.dart';
|
||||||
|
import '../../../domain/outlet/outlet.dart';
|
||||||
|
|
||||||
|
part 'inventory_report_event.dart';
|
||||||
|
part 'inventory_report_state.dart';
|
||||||
|
part 'inventory_report_bloc.freezed.dart';
|
||||||
|
|
||||||
|
@injectable
|
||||||
|
class InventoryReportBloc
|
||||||
|
extends Bloc<InventoryReportEvent, InventoryReportState> {
|
||||||
|
final IAnalyticRepository _analyticRepository;
|
||||||
|
final IOutletRepository _outletRepository;
|
||||||
|
InventoryReportBloc(this._analyticRepository, this._outletRepository)
|
||||||
|
: super(InventoryReportState.initial()) {
|
||||||
|
on<InventoryReportEvent>(_onInventoryReportEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onInventoryReportEvent(
|
||||||
|
InventoryReportEvent event,
|
||||||
|
Emitter<InventoryReportState> emit,
|
||||||
|
) {
|
||||||
|
return event.map(
|
||||||
|
fetchedOutlet: (e) async {
|
||||||
|
emit(
|
||||||
|
state.copyWith(isFetchingOutlet: true, failureOptionOutlet: none()),
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await _outletRepository.currentOutlet();
|
||||||
|
|
||||||
|
var data = result.fold(
|
||||||
|
(f) => state.copyWith(failureOptionOutlet: optionOf(f)),
|
||||||
|
(currentOutlet) => state.copyWith(outlet: currentOutlet),
|
||||||
|
);
|
||||||
|
|
||||||
|
emit(data.copyWith(isFetchingOutlet: false));
|
||||||
|
},
|
||||||
|
fetchedInventory: (e) async {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
isFetching: true,
|
||||||
|
failureOptionInventoryAnalytic: none(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final result = await _analyticRepository.getInventory(
|
||||||
|
dateFrom: e.dateFrom,
|
||||||
|
dateTo: e.dateTo,
|
||||||
|
);
|
||||||
|
|
||||||
|
var data = result.fold(
|
||||||
|
(f) => state.copyWith(failureOptionInventoryAnalytic: optionOf(f)),
|
||||||
|
(inventoryAnalytic) =>
|
||||||
|
state.copyWith(inventoryAnalytic: inventoryAnalytic),
|
||||||
|
);
|
||||||
|
|
||||||
|
emit(data.copyWith(isFetching: false));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,645 @@
|
|||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'inventory_report_bloc.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$InventoryReportEvent {
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>({
|
||||||
|
required TResult Function() fetchedOutlet,
|
||||||
|
required TResult Function(DateTime dateFrom, DateTime dateTo)
|
||||||
|
fetchedInventory,
|
||||||
|
}) => throw _privateConstructorUsedError;
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function()? fetchedOutlet,
|
||||||
|
TResult? Function(DateTime dateFrom, DateTime dateTo)? fetchedInventory,
|
||||||
|
}) => throw _privateConstructorUsedError;
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
|
TResult Function()? fetchedOutlet,
|
||||||
|
TResult Function(DateTime dateFrom, DateTime dateTo)? fetchedInventory,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) => throw _privateConstructorUsedError;
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>({
|
||||||
|
required TResult Function(_FetchedOutlet value) fetchedOutlet,
|
||||||
|
required TResult Function(_FetchedInventory value) fetchedInventory,
|
||||||
|
}) => throw _privateConstructorUsedError;
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function(_FetchedOutlet value)? fetchedOutlet,
|
||||||
|
TResult? Function(_FetchedInventory value)? fetchedInventory,
|
||||||
|
}) => throw _privateConstructorUsedError;
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>({
|
||||||
|
TResult Function(_FetchedOutlet value)? fetchedOutlet,
|
||||||
|
TResult Function(_FetchedInventory value)? fetchedInventory,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) => throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $InventoryReportEventCopyWith<$Res> {
|
||||||
|
factory $InventoryReportEventCopyWith(
|
||||||
|
InventoryReportEvent value,
|
||||||
|
$Res Function(InventoryReportEvent) then,
|
||||||
|
) = _$InventoryReportEventCopyWithImpl<$Res, InventoryReportEvent>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$InventoryReportEventCopyWithImpl<
|
||||||
|
$Res,
|
||||||
|
$Val extends InventoryReportEvent
|
||||||
|
>
|
||||||
|
implements $InventoryReportEventCopyWith<$Res> {
|
||||||
|
_$InventoryReportEventCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportEvent
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$FetchedOutletImplCopyWith<$Res> {
|
||||||
|
factory _$$FetchedOutletImplCopyWith(
|
||||||
|
_$FetchedOutletImpl value,
|
||||||
|
$Res Function(_$FetchedOutletImpl) then,
|
||||||
|
) = __$$FetchedOutletImplCopyWithImpl<$Res>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$FetchedOutletImplCopyWithImpl<$Res>
|
||||||
|
extends _$InventoryReportEventCopyWithImpl<$Res, _$FetchedOutletImpl>
|
||||||
|
implements _$$FetchedOutletImplCopyWith<$Res> {
|
||||||
|
__$$FetchedOutletImplCopyWithImpl(
|
||||||
|
_$FetchedOutletImpl _value,
|
||||||
|
$Res Function(_$FetchedOutletImpl) _then,
|
||||||
|
) : super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportEvent
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
class _$FetchedOutletImpl implements _FetchedOutlet {
|
||||||
|
const _$FetchedOutletImpl();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'InventoryReportEvent.fetchedOutlet()';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType && other is _$FetchedOutletImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => runtimeType.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>({
|
||||||
|
required TResult Function() fetchedOutlet,
|
||||||
|
required TResult Function(DateTime dateFrom, DateTime dateTo)
|
||||||
|
fetchedInventory,
|
||||||
|
}) {
|
||||||
|
return fetchedOutlet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function()? fetchedOutlet,
|
||||||
|
TResult? Function(DateTime dateFrom, DateTime dateTo)? fetchedInventory,
|
||||||
|
}) {
|
||||||
|
return fetchedOutlet?.call();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
|
TResult Function()? fetchedOutlet,
|
||||||
|
TResult Function(DateTime dateFrom, DateTime dateTo)? fetchedInventory,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
if (fetchedOutlet != null) {
|
||||||
|
return fetchedOutlet();
|
||||||
|
}
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>({
|
||||||
|
required TResult Function(_FetchedOutlet value) fetchedOutlet,
|
||||||
|
required TResult Function(_FetchedInventory value) fetchedInventory,
|
||||||
|
}) {
|
||||||
|
return fetchedOutlet(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function(_FetchedOutlet value)? fetchedOutlet,
|
||||||
|
TResult? Function(_FetchedInventory value)? fetchedInventory,
|
||||||
|
}) {
|
||||||
|
return fetchedOutlet?.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>({
|
||||||
|
TResult Function(_FetchedOutlet value)? fetchedOutlet,
|
||||||
|
TResult Function(_FetchedInventory value)? fetchedInventory,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
if (fetchedOutlet != null) {
|
||||||
|
return fetchedOutlet(this);
|
||||||
|
}
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _FetchedOutlet implements InventoryReportEvent {
|
||||||
|
const factory _FetchedOutlet() = _$FetchedOutletImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$FetchedInventoryImplCopyWith<$Res> {
|
||||||
|
factory _$$FetchedInventoryImplCopyWith(
|
||||||
|
_$FetchedInventoryImpl value,
|
||||||
|
$Res Function(_$FetchedInventoryImpl) then,
|
||||||
|
) = __$$FetchedInventoryImplCopyWithImpl<$Res>;
|
||||||
|
@useResult
|
||||||
|
$Res call({DateTime dateFrom, DateTime dateTo});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$FetchedInventoryImplCopyWithImpl<$Res>
|
||||||
|
extends _$InventoryReportEventCopyWithImpl<$Res, _$FetchedInventoryImpl>
|
||||||
|
implements _$$FetchedInventoryImplCopyWith<$Res> {
|
||||||
|
__$$FetchedInventoryImplCopyWithImpl(
|
||||||
|
_$FetchedInventoryImpl _value,
|
||||||
|
$Res Function(_$FetchedInventoryImpl) _then,
|
||||||
|
) : super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportEvent
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({Object? dateFrom = null, Object? dateTo = null}) {
|
||||||
|
return _then(
|
||||||
|
_$FetchedInventoryImpl(
|
||||||
|
null == dateFrom
|
||||||
|
? _value.dateFrom
|
||||||
|
: dateFrom // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,
|
||||||
|
null == dateTo
|
||||||
|
? _value.dateTo
|
||||||
|
: dateTo // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
class _$FetchedInventoryImpl implements _FetchedInventory {
|
||||||
|
const _$FetchedInventoryImpl(this.dateFrom, this.dateTo);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final DateTime dateFrom;
|
||||||
|
@override
|
||||||
|
final DateTime dateTo;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'InventoryReportEvent.fetchedInventory(dateFrom: $dateFrom, dateTo: $dateTo)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$FetchedInventoryImpl &&
|
||||||
|
(identical(other.dateFrom, dateFrom) ||
|
||||||
|
other.dateFrom == dateFrom) &&
|
||||||
|
(identical(other.dateTo, dateTo) || other.dateTo == dateTo));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, dateFrom, dateTo);
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportEvent
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$FetchedInventoryImplCopyWith<_$FetchedInventoryImpl> get copyWith =>
|
||||||
|
__$$FetchedInventoryImplCopyWithImpl<_$FetchedInventoryImpl>(
|
||||||
|
this,
|
||||||
|
_$identity,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult when<TResult extends Object?>({
|
||||||
|
required TResult Function() fetchedOutlet,
|
||||||
|
required TResult Function(DateTime dateFrom, DateTime dateTo)
|
||||||
|
fetchedInventory,
|
||||||
|
}) {
|
||||||
|
return fetchedInventory(dateFrom, dateTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? whenOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function()? fetchedOutlet,
|
||||||
|
TResult? Function(DateTime dateFrom, DateTime dateTo)? fetchedInventory,
|
||||||
|
}) {
|
||||||
|
return fetchedInventory?.call(dateFrom, dateTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeWhen<TResult extends Object?>({
|
||||||
|
TResult Function()? fetchedOutlet,
|
||||||
|
TResult Function(DateTime dateFrom, DateTime dateTo)? fetchedInventory,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
if (fetchedInventory != null) {
|
||||||
|
return fetchedInventory(dateFrom, dateTo);
|
||||||
|
}
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult map<TResult extends Object?>({
|
||||||
|
required TResult Function(_FetchedOutlet value) fetchedOutlet,
|
||||||
|
required TResult Function(_FetchedInventory value) fetchedInventory,
|
||||||
|
}) {
|
||||||
|
return fetchedInventory(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult? mapOrNull<TResult extends Object?>({
|
||||||
|
TResult? Function(_FetchedOutlet value)? fetchedOutlet,
|
||||||
|
TResult? Function(_FetchedInventory value)? fetchedInventory,
|
||||||
|
}) {
|
||||||
|
return fetchedInventory?.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@optionalTypeArgs
|
||||||
|
TResult maybeMap<TResult extends Object?>({
|
||||||
|
TResult Function(_FetchedOutlet value)? fetchedOutlet,
|
||||||
|
TResult Function(_FetchedInventory value)? fetchedInventory,
|
||||||
|
required TResult orElse(),
|
||||||
|
}) {
|
||||||
|
if (fetchedInventory != null) {
|
||||||
|
return fetchedInventory(this);
|
||||||
|
}
|
||||||
|
return orElse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _FetchedInventory implements InventoryReportEvent {
|
||||||
|
const factory _FetchedInventory(
|
||||||
|
final DateTime dateFrom,
|
||||||
|
final DateTime dateTo,
|
||||||
|
) = _$FetchedInventoryImpl;
|
||||||
|
|
||||||
|
DateTime get dateFrom;
|
||||||
|
DateTime get dateTo;
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportEvent
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
_$$FetchedInventoryImplCopyWith<_$FetchedInventoryImpl> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$InventoryReportState {
|
||||||
|
InventoryAnalytic get inventoryAnalytic => throw _privateConstructorUsedError;
|
||||||
|
Option<AnalyticFailure> get failureOptionInventoryAnalytic =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
Outlet get outlet => throw _privateConstructorUsedError;
|
||||||
|
Option<OutletFailure> get failureOptionOutlet =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
bool get isFetching => throw _privateConstructorUsedError;
|
||||||
|
bool get isFetchingOutlet => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportState
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
$InventoryReportStateCopyWith<InventoryReportState> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $InventoryReportStateCopyWith<$Res> {
|
||||||
|
factory $InventoryReportStateCopyWith(
|
||||||
|
InventoryReportState value,
|
||||||
|
$Res Function(InventoryReportState) then,
|
||||||
|
) = _$InventoryReportStateCopyWithImpl<$Res, InventoryReportState>;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
InventoryAnalytic inventoryAnalytic,
|
||||||
|
Option<AnalyticFailure> failureOptionInventoryAnalytic,
|
||||||
|
Outlet outlet,
|
||||||
|
Option<OutletFailure> failureOptionOutlet,
|
||||||
|
bool isFetching,
|
||||||
|
bool isFetchingOutlet,
|
||||||
|
});
|
||||||
|
|
||||||
|
$InventoryAnalyticCopyWith<$Res> get inventoryAnalytic;
|
||||||
|
$OutletCopyWith<$Res> get outlet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$InventoryReportStateCopyWithImpl<
|
||||||
|
$Res,
|
||||||
|
$Val extends InventoryReportState
|
||||||
|
>
|
||||||
|
implements $InventoryReportStateCopyWith<$Res> {
|
||||||
|
_$InventoryReportStateCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportState
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? inventoryAnalytic = null,
|
||||||
|
Object? failureOptionInventoryAnalytic = null,
|
||||||
|
Object? outlet = null,
|
||||||
|
Object? failureOptionOutlet = null,
|
||||||
|
Object? isFetching = null,
|
||||||
|
Object? isFetchingOutlet = null,
|
||||||
|
}) {
|
||||||
|
return _then(
|
||||||
|
_value.copyWith(
|
||||||
|
inventoryAnalytic: null == inventoryAnalytic
|
||||||
|
? _value.inventoryAnalytic
|
||||||
|
: inventoryAnalytic // ignore: cast_nullable_to_non_nullable
|
||||||
|
as InventoryAnalytic,
|
||||||
|
failureOptionInventoryAnalytic:
|
||||||
|
null == failureOptionInventoryAnalytic
|
||||||
|
? _value.failureOptionInventoryAnalytic
|
||||||
|
: failureOptionInventoryAnalytic // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Option<AnalyticFailure>,
|
||||||
|
outlet: null == outlet
|
||||||
|
? _value.outlet
|
||||||
|
: outlet // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Outlet,
|
||||||
|
failureOptionOutlet: null == failureOptionOutlet
|
||||||
|
? _value.failureOptionOutlet
|
||||||
|
: failureOptionOutlet // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Option<OutletFailure>,
|
||||||
|
isFetching: null == isFetching
|
||||||
|
? _value.isFetching
|
||||||
|
: isFetching // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
isFetchingOutlet: null == isFetchingOutlet
|
||||||
|
? _value.isFetchingOutlet
|
||||||
|
: isFetchingOutlet // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
)
|
||||||
|
as $Val,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportState
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$InventoryAnalyticCopyWith<$Res> get inventoryAnalytic {
|
||||||
|
return $InventoryAnalyticCopyWith<$Res>(_value.inventoryAnalytic, (value) {
|
||||||
|
return _then(_value.copyWith(inventoryAnalytic: value) as $Val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportState
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$OutletCopyWith<$Res> get outlet {
|
||||||
|
return $OutletCopyWith<$Res>(_value.outlet, (value) {
|
||||||
|
return _then(_value.copyWith(outlet: value) as $Val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$InventoryReportStateImplCopyWith<$Res>
|
||||||
|
implements $InventoryReportStateCopyWith<$Res> {
|
||||||
|
factory _$$InventoryReportStateImplCopyWith(
|
||||||
|
_$InventoryReportStateImpl value,
|
||||||
|
$Res Function(_$InventoryReportStateImpl) then,
|
||||||
|
) = __$$InventoryReportStateImplCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
InventoryAnalytic inventoryAnalytic,
|
||||||
|
Option<AnalyticFailure> failureOptionInventoryAnalytic,
|
||||||
|
Outlet outlet,
|
||||||
|
Option<OutletFailure> failureOptionOutlet,
|
||||||
|
bool isFetching,
|
||||||
|
bool isFetchingOutlet,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
$InventoryAnalyticCopyWith<$Res> get inventoryAnalytic;
|
||||||
|
@override
|
||||||
|
$OutletCopyWith<$Res> get outlet;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$InventoryReportStateImplCopyWithImpl<$Res>
|
||||||
|
extends _$InventoryReportStateCopyWithImpl<$Res, _$InventoryReportStateImpl>
|
||||||
|
implements _$$InventoryReportStateImplCopyWith<$Res> {
|
||||||
|
__$$InventoryReportStateImplCopyWithImpl(
|
||||||
|
_$InventoryReportStateImpl _value,
|
||||||
|
$Res Function(_$InventoryReportStateImpl) _then,
|
||||||
|
) : super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportState
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? inventoryAnalytic = null,
|
||||||
|
Object? failureOptionInventoryAnalytic = null,
|
||||||
|
Object? outlet = null,
|
||||||
|
Object? failureOptionOutlet = null,
|
||||||
|
Object? isFetching = null,
|
||||||
|
Object? isFetchingOutlet = null,
|
||||||
|
}) {
|
||||||
|
return _then(
|
||||||
|
_$InventoryReportStateImpl(
|
||||||
|
inventoryAnalytic: null == inventoryAnalytic
|
||||||
|
? _value.inventoryAnalytic
|
||||||
|
: inventoryAnalytic // ignore: cast_nullable_to_non_nullable
|
||||||
|
as InventoryAnalytic,
|
||||||
|
failureOptionInventoryAnalytic: null == failureOptionInventoryAnalytic
|
||||||
|
? _value.failureOptionInventoryAnalytic
|
||||||
|
: failureOptionInventoryAnalytic // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Option<AnalyticFailure>,
|
||||||
|
outlet: null == outlet
|
||||||
|
? _value.outlet
|
||||||
|
: outlet // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Outlet,
|
||||||
|
failureOptionOutlet: null == failureOptionOutlet
|
||||||
|
? _value.failureOptionOutlet
|
||||||
|
: failureOptionOutlet // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Option<OutletFailure>,
|
||||||
|
isFetching: null == isFetching
|
||||||
|
? _value.isFetching
|
||||||
|
: isFetching // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
isFetchingOutlet: null == isFetchingOutlet
|
||||||
|
? _value.isFetchingOutlet
|
||||||
|
: isFetchingOutlet // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
class _$InventoryReportStateImpl implements _InventoryReportState {
|
||||||
|
const _$InventoryReportStateImpl({
|
||||||
|
required this.inventoryAnalytic,
|
||||||
|
required this.failureOptionInventoryAnalytic,
|
||||||
|
required this.outlet,
|
||||||
|
required this.failureOptionOutlet,
|
||||||
|
this.isFetching = false,
|
||||||
|
this.isFetchingOutlet = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
final InventoryAnalytic inventoryAnalytic;
|
||||||
|
@override
|
||||||
|
final Option<AnalyticFailure> failureOptionInventoryAnalytic;
|
||||||
|
@override
|
||||||
|
final Outlet outlet;
|
||||||
|
@override
|
||||||
|
final Option<OutletFailure> failureOptionOutlet;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
final bool isFetching;
|
||||||
|
@override
|
||||||
|
@JsonKey()
|
||||||
|
final bool isFetchingOutlet;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'InventoryReportState(inventoryAnalytic: $inventoryAnalytic, failureOptionInventoryAnalytic: $failureOptionInventoryAnalytic, outlet: $outlet, failureOptionOutlet: $failureOptionOutlet, isFetching: $isFetching, isFetchingOutlet: $isFetchingOutlet)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$InventoryReportStateImpl &&
|
||||||
|
(identical(other.inventoryAnalytic, inventoryAnalytic) ||
|
||||||
|
other.inventoryAnalytic == inventoryAnalytic) &&
|
||||||
|
(identical(
|
||||||
|
other.failureOptionInventoryAnalytic,
|
||||||
|
failureOptionInventoryAnalytic,
|
||||||
|
) ||
|
||||||
|
other.failureOptionInventoryAnalytic ==
|
||||||
|
failureOptionInventoryAnalytic) &&
|
||||||
|
(identical(other.outlet, outlet) || other.outlet == outlet) &&
|
||||||
|
(identical(other.failureOptionOutlet, failureOptionOutlet) ||
|
||||||
|
other.failureOptionOutlet == failureOptionOutlet) &&
|
||||||
|
(identical(other.isFetching, isFetching) ||
|
||||||
|
other.isFetching == isFetching) &&
|
||||||
|
(identical(other.isFetchingOutlet, isFetchingOutlet) ||
|
||||||
|
other.isFetchingOutlet == isFetchingOutlet));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType,
|
||||||
|
inventoryAnalytic,
|
||||||
|
failureOptionInventoryAnalytic,
|
||||||
|
outlet,
|
||||||
|
failureOptionOutlet,
|
||||||
|
isFetching,
|
||||||
|
isFetchingOutlet,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportState
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$InventoryReportStateImplCopyWith<_$InventoryReportStateImpl>
|
||||||
|
get copyWith =>
|
||||||
|
__$$InventoryReportStateImplCopyWithImpl<_$InventoryReportStateImpl>(
|
||||||
|
this,
|
||||||
|
_$identity,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _InventoryReportState implements InventoryReportState {
|
||||||
|
const factory _InventoryReportState({
|
||||||
|
required final InventoryAnalytic inventoryAnalytic,
|
||||||
|
required final Option<AnalyticFailure> failureOptionInventoryAnalytic,
|
||||||
|
required final Outlet outlet,
|
||||||
|
required final Option<OutletFailure> failureOptionOutlet,
|
||||||
|
final bool isFetching,
|
||||||
|
final bool isFetchingOutlet,
|
||||||
|
}) = _$InventoryReportStateImpl;
|
||||||
|
|
||||||
|
@override
|
||||||
|
InventoryAnalytic get inventoryAnalytic;
|
||||||
|
@override
|
||||||
|
Option<AnalyticFailure> get failureOptionInventoryAnalytic;
|
||||||
|
@override
|
||||||
|
Outlet get outlet;
|
||||||
|
@override
|
||||||
|
Option<OutletFailure> get failureOptionOutlet;
|
||||||
|
@override
|
||||||
|
bool get isFetching;
|
||||||
|
@override
|
||||||
|
bool get isFetchingOutlet;
|
||||||
|
|
||||||
|
/// Create a copy of InventoryReportState
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
_$$InventoryReportStateImplCopyWith<_$InventoryReportStateImpl>
|
||||||
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
part of 'inventory_report_bloc.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class InventoryReportEvent with _$InventoryReportEvent {
|
||||||
|
const factory InventoryReportEvent.fetchedOutlet() = _FetchedOutlet;
|
||||||
|
const factory InventoryReportEvent.fetchedInventory(
|
||||||
|
DateTime dateFrom,
|
||||||
|
DateTime dateTo,
|
||||||
|
) = _FetchedInventory;
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
part of 'inventory_report_bloc.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class InventoryReportState with _$InventoryReportState {
|
||||||
|
const factory InventoryReportState({
|
||||||
|
required InventoryAnalytic inventoryAnalytic,
|
||||||
|
required Option<AnalyticFailure> failureOptionInventoryAnalytic,
|
||||||
|
required Outlet outlet,
|
||||||
|
required Option<OutletFailure> failureOptionOutlet,
|
||||||
|
@Default(false) bool isFetching,
|
||||||
|
@Default(false) bool isFetchingOutlet,
|
||||||
|
}) = _InventoryReportState;
|
||||||
|
|
||||||
|
factory InventoryReportState.initial() => InventoryReportState(
|
||||||
|
inventoryAnalytic: InventoryAnalytic.empty(),
|
||||||
|
failureOptionInventoryAnalytic: none(),
|
||||||
|
outlet: Outlet.empty(),
|
||||||
|
failureOptionOutlet: none(),
|
||||||
|
);
|
||||||
|
}
|
||||||
79
lib/common/utils/pdf_service.dart
Normal file
79
lib/common/utils/pdf_service.dart
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:open_file/open_file.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:pdf/widgets.dart';
|
||||||
|
|
||||||
|
class HelperPdfService {
|
||||||
|
static Future<File> saveDocument({
|
||||||
|
required String name,
|
||||||
|
required Document pdf,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
log("Starting PDF save process for: $name");
|
||||||
|
log("PDF document object: $pdf");
|
||||||
|
|
||||||
|
final bytes = await pdf.save();
|
||||||
|
log("PDF bytes generated successfully, size: ${bytes.length} bytes");
|
||||||
|
|
||||||
|
if (bytes.isEmpty) {
|
||||||
|
log("WARNING: PDF bytes are empty!");
|
||||||
|
return Future.error("PDF bytes are empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
final dir = await getApplicationDocumentsDirectory();
|
||||||
|
log("Documents directory: ${dir.path}");
|
||||||
|
|
||||||
|
final file = File('${dir.path}/$name');
|
||||||
|
log("Saving PDF to: ${file.path}");
|
||||||
|
|
||||||
|
await file.writeAsBytes(bytes);
|
||||||
|
log("PDF saved successfully to: ${file.path}");
|
||||||
|
|
||||||
|
// Verify file was created
|
||||||
|
if (await file.exists()) {
|
||||||
|
final fileSize = await file.length();
|
||||||
|
log("File exists and size is: $fileSize bytes");
|
||||||
|
} else {
|
||||||
|
log("ERROR: File was not created!");
|
||||||
|
return Future.error("File was not created");
|
||||||
|
}
|
||||||
|
|
||||||
|
return file;
|
||||||
|
} catch (e) {
|
||||||
|
log("Failed to save document: $e");
|
||||||
|
log("Error stack trace: ${StackTrace.current}");
|
||||||
|
return Future.error("Failed to save document: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future openFile(File file) async {
|
||||||
|
try {
|
||||||
|
final url = file.path;
|
||||||
|
log("Attempting to open file: $url");
|
||||||
|
|
||||||
|
if (!await file.exists()) {
|
||||||
|
log("ERROR: File does not exist: $url");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final fileSize = await file.length();
|
||||||
|
log("File exists and size is: $fileSize bytes");
|
||||||
|
|
||||||
|
log("Calling OpenFile.open...");
|
||||||
|
final result = await OpenFile.open(url, type: "application/pdf");
|
||||||
|
log("OpenFile result: $result");
|
||||||
|
|
||||||
|
if (result.type == ResultType.done) {
|
||||||
|
log("File opened successfully");
|
||||||
|
} else {
|
||||||
|
log("File opening failed with result: ${result.type}");
|
||||||
|
log("Error message: ${result.message}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log("Failed to open file: $e");
|
||||||
|
log("Error stack trace: ${StackTrace.current}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
72
lib/common/utils/permission.dart
Normal file
72
lib/common/utils/permission.dart
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
|
class PermessionHelper {
|
||||||
|
Future<bool> checkPermission() async {
|
||||||
|
final deviceInfo = await DeviceInfoPlugin().androidInfo;
|
||||||
|
bool permissionStatus;
|
||||||
|
if (deviceInfo.version.sdkInt > 32) {
|
||||||
|
permissionStatus = await Permission.photos.request().isGranted;
|
||||||
|
} else {
|
||||||
|
permissionStatus = await Permission.storage.request().isGranted;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (permissionStatus) {
|
||||||
|
log('Izin penyimpanan sudah diberikan.');
|
||||||
|
} else {
|
||||||
|
if (deviceInfo.version.sdkInt > 32) {
|
||||||
|
log('deviceInfo.version.sdkInt > 32.');
|
||||||
|
permissionStatus = await Permission.photos.request().isGranted;
|
||||||
|
} else {
|
||||||
|
permissionStatus = await Permission.storage.request().isGranted;
|
||||||
|
}
|
||||||
|
// } else {
|
||||||
|
// openAppSettings();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
log('permissionStatus: $permissionStatus');
|
||||||
|
return permissionStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
void permessionPrinter() async {
|
||||||
|
Map<Permission, PermissionStatus> statuses = await [
|
||||||
|
Permission.bluetooth,
|
||||||
|
Permission.bluetoothScan,
|
||||||
|
Permission.bluetoothAdvertise,
|
||||||
|
Permission.bluetoothConnect,
|
||||||
|
].request();
|
||||||
|
|
||||||
|
log("statuses: $statuses");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// final status =
|
||||||
|
// await PermessionHelper().checkPermission();
|
||||||
|
// if (status) {
|
||||||
|
// final pdfFile = await InventoryReport.previewPdf(
|
||||||
|
// searchDateFormatted: widget.searchDateFormatted,
|
||||||
|
// inventory: widget.inventory,
|
||||||
|
// );
|
||||||
|
// log("pdfFile: $pdfFile");
|
||||||
|
// await HelperPdfService.openFile(pdfFile);
|
||||||
|
// } else {
|
||||||
|
// ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
// const SnackBar(
|
||||||
|
// content: Text(
|
||||||
|
// 'Storage permission is required to save PDF'),
|
||||||
|
// backgroundColor: Colors.red,
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// } catch (e) {
|
||||||
|
// log("Error generating PDF: $e");
|
||||||
|
// ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
// SnackBar(
|
||||||
|
// content: Text('Failed to generate PDF: $e'),
|
||||||
|
// backgroundColor: Colors.red,
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
@ -41,6 +41,8 @@ import 'package:apskel_owner_flutter/application/outlet/current_outlet_loader/cu
|
|||||||
as _i337;
|
as _i337;
|
||||||
import 'package:apskel_owner_flutter/application/product/product_loader/product_loader_bloc.dart'
|
import 'package:apskel_owner_flutter/application/product/product_loader/product_loader_bloc.dart'
|
||||||
as _i458;
|
as _i458;
|
||||||
|
import 'package:apskel_owner_flutter/application/report/inventory_report/inventory_report_bloc.dart'
|
||||||
|
as _i346;
|
||||||
import 'package:apskel_owner_flutter/application/user/change_password_form/change_password_form_bloc.dart'
|
import 'package:apskel_owner_flutter/application/user/change_password_form/change_password_form_bloc.dart'
|
||||||
as _i1030;
|
as _i1030;
|
||||||
import 'package:apskel_owner_flutter/application/user/user_edit_form/user_edit_form_bloc.dart'
|
import 'package:apskel_owner_flutter/application/user/user_edit_form/user_edit_form_bloc.dart'
|
||||||
@ -263,6 +265,12 @@ extension GetItInjectableX on _i174.GetIt {
|
|||||||
gh.factory<_i1030.ChangePasswordFormBloc>(
|
gh.factory<_i1030.ChangePasswordFormBloc>(
|
||||||
() => _i1030.ChangePasswordFormBloc(gh<_i635.IUserRepository>()),
|
() => _i1030.ChangePasswordFormBloc(gh<_i635.IUserRepository>()),
|
||||||
);
|
);
|
||||||
|
gh.factory<_i346.InventoryReportBloc>(
|
||||||
|
() => _i346.InventoryReportBloc(
|
||||||
|
gh<_i477.IAnalyticRepository>(),
|
||||||
|
gh<_i197.IOutletRepository>(),
|
||||||
|
),
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
547
lib/presentation/components/report/inventory_report.dart
Normal file
547
lib/presentation/components/report/inventory_report.dart
Normal file
@ -0,0 +1,547 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:pdf/pdf.dart';
|
||||||
|
import 'package:pdf/widgets.dart' as pw;
|
||||||
|
|
||||||
|
import '../../../common/utils/pdf_service.dart';
|
||||||
|
import '../../../domain/analytic/analytic.dart';
|
||||||
|
import '../../../domain/outlet/outlet.dart';
|
||||||
|
|
||||||
|
class InventoryReport {
|
||||||
|
static final primaryColor = PdfColor.fromHex("36175e");
|
||||||
|
|
||||||
|
static Future<File> previewPdf({
|
||||||
|
required String searchDateFormatted,
|
||||||
|
required InventoryAnalytic inventory,
|
||||||
|
required Outlet outlet,
|
||||||
|
}) async {
|
||||||
|
final pdf = pw.Document();
|
||||||
|
final ByteData dataImage = await rootBundle.load('assets/images/logo.png');
|
||||||
|
final Uint8List bytes = dataImage.buffer.asUint8List();
|
||||||
|
|
||||||
|
final image = pw.MemoryImage(bytes);
|
||||||
|
pdf.addPage(
|
||||||
|
pw.MultiPage(
|
||||||
|
pageFormat: PdfPageFormat.a4,
|
||||||
|
margin: pw.EdgeInsets.zero,
|
||||||
|
build: (pw.Context context) {
|
||||||
|
return [
|
||||||
|
pw.Container(
|
||||||
|
padding: pw.EdgeInsets.all(20),
|
||||||
|
child: pw.Row(
|
||||||
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Bagian kiri - Logo dan Info Perusahaan
|
||||||
|
pw.Row(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
// Icon/Logo placeholder (bisa diganti dengan gambar logo)
|
||||||
|
pw.Container(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
child: pw.Image(image),
|
||||||
|
),
|
||||||
|
pw.SizedBox(width: 15),
|
||||||
|
pw.Column(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
pw.Text(
|
||||||
|
'Apskel',
|
||||||
|
style: pw.TextStyle(
|
||||||
|
fontSize: 28,
|
||||||
|
fontWeight: pw.FontWeight.bold,
|
||||||
|
color: primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 4),
|
||||||
|
pw.Text(
|
||||||
|
outlet.name,
|
||||||
|
style: pw.TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: PdfColors.grey700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 2),
|
||||||
|
pw.Text(
|
||||||
|
outlet.address,
|
||||||
|
style: pw.TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: PdfColors.grey600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// Bagian kanan - Info Laporan
|
||||||
|
pw.Column(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
pw.Text(
|
||||||
|
'Laporan Transaksi',
|
||||||
|
style: pw.TextStyle(
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: pw.FontWeight.bold,
|
||||||
|
color: PdfColors.grey800,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 8),
|
||||||
|
pw.Text(
|
||||||
|
searchDateFormatted,
|
||||||
|
style: pw.TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: PdfColors.grey600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 4),
|
||||||
|
pw.Text(
|
||||||
|
'Laporan',
|
||||||
|
style: pw.TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: PdfColors.grey500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 3,
|
||||||
|
color: primaryColor,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Summary
|
||||||
|
pw.Container(
|
||||||
|
padding: pw.EdgeInsets.all(20),
|
||||||
|
child: pw.Column(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildSectionWidget('1. Ringkasan'),
|
||||||
|
pw.SizedBox(height: 30),
|
||||||
|
pw.Row(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
pw.Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: pw.Column(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildSummaryItem(
|
||||||
|
'Total Item',
|
||||||
|
(inventory.summary.totalProducts).toString(),
|
||||||
|
),
|
||||||
|
_buildSummaryItem(
|
||||||
|
'Total Item Masuk',
|
||||||
|
(inventory.products.fold<num>(
|
||||||
|
0,
|
||||||
|
(sum, item) => sum + (item.totalIn),
|
||||||
|
)).toString(),
|
||||||
|
),
|
||||||
|
_buildSummaryItem(
|
||||||
|
'Total Item Keluar',
|
||||||
|
(inventory.products.fold<num>(
|
||||||
|
0,
|
||||||
|
(sum, item) => sum + (item.totalOut),
|
||||||
|
)).toString(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.SizedBox(width: 20),
|
||||||
|
pw.Expanded(
|
||||||
|
flex: 1,
|
||||||
|
child: pw.Column(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildSummaryItem(
|
||||||
|
'Total Ingredient',
|
||||||
|
(inventory.summary.totalIngredients).toString(),
|
||||||
|
),
|
||||||
|
_buildSummaryItem(
|
||||||
|
'Total Ingredient Masuk',
|
||||||
|
(inventory.ingredients.fold<num>(
|
||||||
|
0,
|
||||||
|
(sum, item) => sum + (item.totalIn),
|
||||||
|
)).toString(),
|
||||||
|
),
|
||||||
|
_buildSummaryItem(
|
||||||
|
'Total Ingredient Keluar',
|
||||||
|
(inventory.ingredients.fold<num>(
|
||||||
|
0,
|
||||||
|
(sum, item) => sum + (item.totalOut),
|
||||||
|
)).toString(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Summary Item
|
||||||
|
pw.Container(
|
||||||
|
padding: pw.EdgeInsets.all(20),
|
||||||
|
child: pw.Column(
|
||||||
|
children: [
|
||||||
|
pw.Column(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildSectionWidget('2. Item'),
|
||||||
|
pw.SizedBox(height: 30),
|
||||||
|
pw.Container(
|
||||||
|
decoration: pw.BoxDecoration(
|
||||||
|
color: primaryColor, // Purple color
|
||||||
|
borderRadius: pw.BorderRadius.only(
|
||||||
|
topLeft: pw.Radius.circular(8),
|
||||||
|
topRight: pw.Radius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: pw.Table(
|
||||||
|
columnWidths: const {
|
||||||
|
0: pw.FlexColumnWidth(2.5), // Produk
|
||||||
|
1: pw.FlexColumnWidth(2), // Kategori
|
||||||
|
2: pw.FlexColumnWidth(1), // Stock
|
||||||
|
3: pw.FlexColumnWidth(2), // Masuk
|
||||||
|
4: pw.FlexColumnWidth(2), // Keluar
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
pw.TableRow(
|
||||||
|
children: [
|
||||||
|
_buildHeaderCell('Nama'),
|
||||||
|
_buildHeaderCell('Kategori'),
|
||||||
|
_buildHeaderCell('Stock'),
|
||||||
|
_buildHeaderCell('Masuk'),
|
||||||
|
_buildHeaderCell('Keluar'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.Container(
|
||||||
|
decoration: pw.BoxDecoration(color: PdfColors.white),
|
||||||
|
child: pw.Table(
|
||||||
|
columnWidths: {
|
||||||
|
0: pw.FlexColumnWidth(2.5), // Produk
|
||||||
|
1: pw.FlexColumnWidth(2), // Kategori
|
||||||
|
2: pw.FlexColumnWidth(1), // Stock
|
||||||
|
3: pw.FlexColumnWidth(2), // Masuk
|
||||||
|
4: pw.FlexColumnWidth(2), // Keluar
|
||||||
|
},
|
||||||
|
children: inventory.products
|
||||||
|
.map(
|
||||||
|
(item) => _buildProductDataRow(
|
||||||
|
item,
|
||||||
|
inventory.products.indexOf(item) % 2 == 0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.Container(
|
||||||
|
decoration: pw.BoxDecoration(
|
||||||
|
color: primaryColor, // Purple color
|
||||||
|
borderRadius: pw.BorderRadius.only(
|
||||||
|
bottomLeft: pw.Radius.circular(8),
|
||||||
|
bottomRight: pw.Radius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: pw.Table(
|
||||||
|
columnWidths: const {
|
||||||
|
0: pw.FlexColumnWidth(2.5), // Produk
|
||||||
|
1: pw.FlexColumnWidth(2), // Kategori
|
||||||
|
2: pw.FlexColumnWidth(1), // Stock
|
||||||
|
3: pw.FlexColumnWidth(2), // Masuk
|
||||||
|
4: pw.FlexColumnWidth(2), // Keluar
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
pw.TableRow(
|
||||||
|
children: [
|
||||||
|
_buildTotalCell('TOTAL'),
|
||||||
|
_buildTotalCell(''),
|
||||||
|
_buildTotalCell(
|
||||||
|
(inventory.products.fold<num>(
|
||||||
|
0,
|
||||||
|
(sum, item) => sum + (item.quantity),
|
||||||
|
)).toString(),
|
||||||
|
),
|
||||||
|
_buildTotalCell(
|
||||||
|
(inventory.products.fold<num>(
|
||||||
|
0,
|
||||||
|
(sum, item) => sum + (item.totalIn),
|
||||||
|
)).toString(),
|
||||||
|
),
|
||||||
|
_buildTotalCell(
|
||||||
|
(inventory.products.fold<num>(
|
||||||
|
0,
|
||||||
|
(sum, item) => sum + (item.totalOut),
|
||||||
|
)).toString(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Summary Ingredient
|
||||||
|
pw.Container(
|
||||||
|
padding: pw.EdgeInsets.all(20),
|
||||||
|
child: pw.Column(
|
||||||
|
children: [
|
||||||
|
pw.Column(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
_buildSectionWidget('3. Ingredient'),
|
||||||
|
pw.SizedBox(height: 30),
|
||||||
|
pw.Container(
|
||||||
|
decoration: pw.BoxDecoration(
|
||||||
|
color: primaryColor, // Purple color
|
||||||
|
borderRadius: pw.BorderRadius.only(
|
||||||
|
topLeft: pw.Radius.circular(8),
|
||||||
|
topRight: pw.Radius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: pw.Table(
|
||||||
|
columnWidths: const {
|
||||||
|
0: pw.FlexColumnWidth(2.5), // Name
|
||||||
|
1: pw.FlexColumnWidth(1), // Stock
|
||||||
|
2: pw.FlexColumnWidth(2), // Masuk
|
||||||
|
3: pw.FlexColumnWidth(2), // Keluar
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
pw.TableRow(
|
||||||
|
children: [
|
||||||
|
_buildHeaderCell('Nama'),
|
||||||
|
_buildHeaderCell('Stock'),
|
||||||
|
_buildHeaderCell('Masuk'),
|
||||||
|
_buildHeaderCell('Keluar'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.Container(
|
||||||
|
decoration: pw.BoxDecoration(color: PdfColors.white),
|
||||||
|
child: pw.Table(
|
||||||
|
columnWidths: {
|
||||||
|
0: pw.FlexColumnWidth(2.5), // Name
|
||||||
|
1: pw.FlexColumnWidth(1), // Stock
|
||||||
|
2: pw.FlexColumnWidth(2), // Masuk
|
||||||
|
3: pw.FlexColumnWidth(2), // Keluar
|
||||||
|
},
|
||||||
|
children: inventory.ingredients
|
||||||
|
.map(
|
||||||
|
(item) => _buildIngredientsDataRow(
|
||||||
|
item,
|
||||||
|
inventory.ingredients.indexOf(item) % 2 == 0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.Container(
|
||||||
|
decoration: pw.BoxDecoration(
|
||||||
|
color: primaryColor, // Purple color
|
||||||
|
borderRadius: pw.BorderRadius.only(
|
||||||
|
bottomLeft: pw.Radius.circular(8),
|
||||||
|
bottomRight: pw.Radius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: pw.Table(
|
||||||
|
columnWidths: const {
|
||||||
|
0: pw.FlexColumnWidth(2.5), // Name
|
||||||
|
1: pw.FlexColumnWidth(1), // Stock
|
||||||
|
2: pw.FlexColumnWidth(2), // Masuk
|
||||||
|
3: pw.FlexColumnWidth(2), // Keluar
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
pw.TableRow(
|
||||||
|
children: [
|
||||||
|
_buildTotalCell('TOTAL'),
|
||||||
|
_buildTotalCell(
|
||||||
|
(inventory.ingredients.fold<num>(
|
||||||
|
0,
|
||||||
|
(sum, item) => sum + (item.quantity),
|
||||||
|
)).toString(),
|
||||||
|
),
|
||||||
|
_buildTotalCell(
|
||||||
|
(inventory.ingredients.fold<num>(
|
||||||
|
0,
|
||||||
|
(sum, item) => sum + (item.totalIn),
|
||||||
|
)).toString(),
|
||||||
|
),
|
||||||
|
_buildTotalCell(
|
||||||
|
(inventory.ingredients.fold<num>(
|
||||||
|
0,
|
||||||
|
(sum, item) => sum + (item.totalOut),
|
||||||
|
)).toString(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return HelperPdfService.saveDocument(
|
||||||
|
name:
|
||||||
|
'Apskel POS | Inventory Report | ${DateTime.now().millisecondsSinceEpoch}.pdf',
|
||||||
|
pdf: pdf,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static pw.Widget _buildSectionWidget(String title) {
|
||||||
|
return pw.Text(
|
||||||
|
title,
|
||||||
|
style: pw.TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: pw.FontWeight.bold,
|
||||||
|
color: primaryColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static pw.Widget _buildSummaryItem(
|
||||||
|
String label,
|
||||||
|
String value, {
|
||||||
|
pw.TextStyle? valueStyle,
|
||||||
|
pw.TextStyle? labelStyle,
|
||||||
|
}) {
|
||||||
|
return pw.Container(
|
||||||
|
padding: pw.EdgeInsets.only(bottom: 8),
|
||||||
|
margin: pw.EdgeInsets.only(bottom: 16),
|
||||||
|
decoration: pw.BoxDecoration(
|
||||||
|
border: pw.Border(bottom: pw.BorderSide(color: PdfColors.grey300)),
|
||||||
|
),
|
||||||
|
child: pw.Row(
|
||||||
|
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
pw.Text(label, style: labelStyle),
|
||||||
|
pw.Text(
|
||||||
|
value,
|
||||||
|
style: valueStyle ?? pw.TextStyle(fontWeight: pw.FontWeight.bold),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static pw.Widget _buildHeaderCell(String text) {
|
||||||
|
return pw.Container(
|
||||||
|
padding: pw.EdgeInsets.symmetric(horizontal: 12, vertical: 16),
|
||||||
|
child: pw.Text(
|
||||||
|
text,
|
||||||
|
style: pw.TextStyle(
|
||||||
|
color: PdfColors.white,
|
||||||
|
fontWeight: pw.FontWeight.bold,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
textAlign: pw.TextAlign.center,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static pw.Widget _buildDataCell(
|
||||||
|
String text, {
|
||||||
|
pw.Alignment alignment = pw.Alignment.center,
|
||||||
|
PdfColor? textColor,
|
||||||
|
}) {
|
||||||
|
return pw.Container(
|
||||||
|
padding: pw.EdgeInsets.symmetric(horizontal: 12, vertical: 16),
|
||||||
|
alignment: alignment,
|
||||||
|
child: pw.Text(
|
||||||
|
text,
|
||||||
|
style: pw.TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: textColor ?? PdfColors.black,
|
||||||
|
fontWeight: pw.FontWeight.normal,
|
||||||
|
),
|
||||||
|
textAlign: alignment == pw.Alignment.centerLeft
|
||||||
|
? pw.TextAlign.left
|
||||||
|
: pw.TextAlign.center,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static pw.Widget _buildTotalCell(String text) {
|
||||||
|
return pw.Container(
|
||||||
|
padding: pw.EdgeInsets.symmetric(horizontal: 12, vertical: 16),
|
||||||
|
child: pw.Text(
|
||||||
|
text,
|
||||||
|
style: pw.TextStyle(
|
||||||
|
color: PdfColors.white,
|
||||||
|
fontWeight: pw.FontWeight.bold,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
textAlign: pw.TextAlign.center,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static pw.TableRow _buildProductDataRow(
|
||||||
|
InventoryProduct product,
|
||||||
|
bool isEven,
|
||||||
|
) {
|
||||||
|
return pw.TableRow(
|
||||||
|
decoration: pw.BoxDecoration(
|
||||||
|
color: product.isZeroStock
|
||||||
|
? PdfColors.red100
|
||||||
|
: product.isLowStock
|
||||||
|
? PdfColors.yellow100
|
||||||
|
: isEven
|
||||||
|
? PdfColors.grey50
|
||||||
|
: PdfColors.white,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
_buildDataCell(product.productName, alignment: pw.Alignment.centerLeft),
|
||||||
|
_buildDataCell(
|
||||||
|
product.categoryName,
|
||||||
|
alignment: pw.Alignment.centerLeft,
|
||||||
|
),
|
||||||
|
_buildDataCell(product.quantity.toString()),
|
||||||
|
_buildDataCell(product.totalIn.toString()),
|
||||||
|
_buildDataCell(product.totalOut.toString()),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static pw.TableRow _buildIngredientsDataRow(
|
||||||
|
InventoryIngredient item,
|
||||||
|
bool isEven,
|
||||||
|
) {
|
||||||
|
return pw.TableRow(
|
||||||
|
decoration: pw.BoxDecoration(
|
||||||
|
color: item.isZeroStock
|
||||||
|
? PdfColors.red100
|
||||||
|
: item.isLowStock
|
||||||
|
? PdfColors.yellow100
|
||||||
|
: isEven
|
||||||
|
? PdfColors.grey50
|
||||||
|
: PdfColors.white,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
_buildDataCell(item.ingredientName, alignment: pw.Alignment.centerLeft),
|
||||||
|
_buildDataCell(item.quantity.toString()),
|
||||||
|
_buildDataCell(item.totalIn.toString()),
|
||||||
|
_buildDataCell(item.totalOut.toString()),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +1,34 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
|
|
||||||
|
import '../../../application/report/inventory_report/inventory_report_bloc.dart';
|
||||||
|
import '../../../common/extension/extension.dart';
|
||||||
import '../../../common/theme/theme.dart';
|
import '../../../common/theme/theme.dart';
|
||||||
|
import '../../../common/utils/pdf_service.dart';
|
||||||
|
import '../../../common/utils/permission.dart';
|
||||||
|
import '../../../injection.dart';
|
||||||
import '../../components/appbar/appbar.dart';
|
import '../../components/appbar/appbar.dart';
|
||||||
import '../../components/field/date_range_picker_field.dart';
|
import '../../components/field/date_range_picker_field.dart';
|
||||||
|
import '../../components/report/inventory_report.dart';
|
||||||
|
import '../../components/toast/flushbar.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class DownloadReportPage extends StatefulWidget {
|
class DownloadReportPage extends StatefulWidget implements AutoRouteWrapper {
|
||||||
const DownloadReportPage({super.key});
|
const DownloadReportPage({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DownloadReportPage> createState() => _DownloadReportPageState();
|
State<DownloadReportPage> createState() => _DownloadReportPageState();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget wrappedRoute(BuildContext context) => BlocProvider(
|
||||||
|
create: (context) =>
|
||||||
|
getIt<InventoryReportBloc>()..add(InventoryReportEvent.fetchedOutlet()),
|
||||||
|
child: this,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DownloadReportPageState extends State<DownloadReportPage>
|
class _DownloadReportPageState extends State<DownloadReportPage>
|
||||||
@ -26,10 +44,10 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
|||||||
DateTime? _transactionEndDate;
|
DateTime? _transactionEndDate;
|
||||||
DateTime? _inventoryStartDate;
|
DateTime? _inventoryStartDate;
|
||||||
DateTime? _inventoryEndDate;
|
DateTime? _inventoryEndDate;
|
||||||
DateTime? _salesStartDate;
|
// DateTime? _salesStartDate;
|
||||||
DateTime? _salesEndDate;
|
// DateTime? _salesEndDate;
|
||||||
DateTime? _customerStartDate;
|
// DateTime? _customerStartDate;
|
||||||
DateTime? _customerEndDate;
|
// DateTime? _customerEndDate;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -76,28 +94,9 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
|||||||
DateTime? endDate,
|
DateTime? endDate,
|
||||||
) {
|
) {
|
||||||
if (startDate == null || endDate == null) {
|
if (startDate == null || endDate == null) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
AppFlushbar.showError(context, 'Please select both start and end dates');
|
||||||
const SnackBar(
|
|
||||||
content: Text('Please select both start and end dates'),
|
|
||||||
backgroundColor: AppColor.error,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement download logic here
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
'Downloading $reportType from ${_formatDate(startDate)} to ${_formatDate(endDate)}',
|
|
||||||
),
|
|
||||||
backgroundColor: AppColor.success,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
String _formatDate(DateTime date) {
|
|
||||||
return '${date.day}/${date.month}/${date.year}';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -139,6 +138,7 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
|||||||
],
|
],
|
||||||
startDate: _transactionStartDate,
|
startDate: _transactionStartDate,
|
||||||
endDate: _transactionEndDate,
|
endDate: _transactionEndDate,
|
||||||
|
isLoading: false,
|
||||||
onDateRangeChanged: (start, end) {
|
onDateRangeChanged: (start, end) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_transactionStartDate = start;
|
_transactionStartDate = start;
|
||||||
@ -156,79 +156,115 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
|||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// Inventory Report Card
|
// Inventory Report Card
|
||||||
_ReportOptionCard(
|
BlocBuilder<InventoryReportBloc, InventoryReportState>(
|
||||||
title: 'Inventory Report',
|
builder: (context, state) {
|
||||||
subtitle:
|
return _ReportOptionCard(
|
||||||
'Export inventory and stock data with trends',
|
title: 'Inventory Report',
|
||||||
icon: Icons.inventory_2_outlined,
|
subtitle:
|
||||||
gradient: const [
|
'Export inventory and stock data with trends',
|
||||||
AppColor.secondary,
|
icon: Icons.inventory_2_outlined,
|
||||||
AppColor.secondaryLight,
|
gradient: const [
|
||||||
],
|
AppColor.secondary,
|
||||||
startDate: _inventoryStartDate,
|
AppColor.secondaryLight,
|
||||||
endDate: _inventoryEndDate,
|
],
|
||||||
onDateRangeChanged: (start, end) {
|
startDate: _inventoryStartDate,
|
||||||
setState(() {
|
endDate: _inventoryEndDate,
|
||||||
_inventoryStartDate = start;
|
isLoading: state.isFetching,
|
||||||
_inventoryEndDate = end;
|
onDateRangeChanged: (start, end) {
|
||||||
});
|
setState(() {
|
||||||
|
_inventoryStartDate = start;
|
||||||
|
_inventoryEndDate = end;
|
||||||
|
});
|
||||||
|
if (start != null || end != null) {
|
||||||
|
context.read<InventoryReportBloc>().add(
|
||||||
|
InventoryReportEvent.fetchedInventory(
|
||||||
|
start!,
|
||||||
|
end!,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDownload: () async {
|
||||||
|
try {
|
||||||
|
final status = await PermessionHelper()
|
||||||
|
.checkPermission();
|
||||||
|
if (status) {
|
||||||
|
final pdfFile =
|
||||||
|
await InventoryReport.previewPdf(
|
||||||
|
searchDateFormatted:
|
||||||
|
"${_inventoryStartDate?.toServerDate} - ${_inventoryEndDate?.toServerDate}",
|
||||||
|
inventory: state.inventoryAnalytic,
|
||||||
|
outlet: state.outlet,
|
||||||
|
);
|
||||||
|
log("pdfFile: $pdfFile");
|
||||||
|
await HelperPdfService.openFile(pdfFile);
|
||||||
|
} else {
|
||||||
|
AppFlushbar.showError(
|
||||||
|
context,
|
||||||
|
'Storage permission is required to save PDF',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
log("Error generating PDF: $e");
|
||||||
|
AppFlushbar.showError(
|
||||||
|
context,
|
||||||
|
'Failed to generate PDF: $e',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
delay: 400,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
onDownload: () => _downloadReport(
|
|
||||||
'Inventory Report',
|
|
||||||
_inventoryStartDate,
|
|
||||||
_inventoryEndDate,
|
|
||||||
),
|
|
||||||
delay: 400,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// Sales Report Card
|
// Sales Report Card
|
||||||
_ReportOptionCard(
|
// _ReportOptionCard(
|
||||||
title: 'Sales Report',
|
// title: 'Sales Report',
|
||||||
subtitle: 'Export sales performance and revenue data',
|
// subtitle: 'Export sales performance and revenue data',
|
||||||
icon: Icons.trending_up_outlined,
|
// icon: Icons.trending_up_outlined,
|
||||||
gradient: const [AppColor.info, Color(0xFF64B5F6)],
|
// gradient: const [AppColor.info, Color(0xFF64B5F6)],
|
||||||
startDate: _salesStartDate,
|
// startDate: _salesStartDate,
|
||||||
endDate: _salesEndDate,
|
// endDate: _salesEndDate,
|
||||||
onDateRangeChanged: (start, end) {
|
// onDateRangeChanged: (start, end) {
|
||||||
setState(() {
|
// setState(() {
|
||||||
_salesStartDate = start;
|
// _salesStartDate = start;
|
||||||
_salesEndDate = end;
|
// _salesEndDate = end;
|
||||||
});
|
// });
|
||||||
},
|
// },
|
||||||
onDownload: () => _downloadReport(
|
// onDownload: () => _downloadReport(
|
||||||
'Sales Report',
|
// 'Sales Report',
|
||||||
_salesStartDate,
|
// _salesStartDate,
|
||||||
_salesEndDate,
|
// _salesEndDate,
|
||||||
),
|
// ),
|
||||||
delay: 600,
|
// delay: 600,
|
||||||
),
|
// ),
|
||||||
|
|
||||||
const SizedBox(height: 20),
|
// const SizedBox(height: 20),
|
||||||
|
|
||||||
// Customer Report Card
|
// // Customer Report Card
|
||||||
_ReportOptionCard(
|
// _ReportOptionCard(
|
||||||
title: 'Customer Report',
|
// title: 'Customer Report',
|
||||||
subtitle:
|
// subtitle:
|
||||||
'Export customer data and behavior analytics',
|
// 'Export customer data and behavior analytics',
|
||||||
icon: Icons.people_outline,
|
// icon: Icons.people_outline,
|
||||||
gradient: const [AppColor.warning, Color(0xFFFFB74D)],
|
// gradient: const [AppColor.warning, Color(0xFFFFB74D)],
|
||||||
startDate: _customerStartDate,
|
// startDate: _customerStartDate,
|
||||||
endDate: _customerEndDate,
|
// endDate: _customerEndDate,
|
||||||
onDateRangeChanged: (start, end) {
|
// onDateRangeChanged: (start, end) {
|
||||||
setState(() {
|
// setState(() {
|
||||||
_customerStartDate = start;
|
// _customerStartDate = start;
|
||||||
_customerEndDate = end;
|
// _customerEndDate = end;
|
||||||
});
|
// });
|
||||||
},
|
// },
|
||||||
onDownload: () => _downloadReport(
|
// onDownload: () => _downloadReport(
|
||||||
'Customer Report',
|
// 'Customer Report',
|
||||||
_customerStartDate,
|
// _customerStartDate,
|
||||||
_customerEndDate,
|
// _customerEndDate,
|
||||||
),
|
// ),
|
||||||
delay: 800,
|
// delay: 800,
|
||||||
),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -253,6 +289,7 @@ class _ReportOptionCard extends StatefulWidget {
|
|||||||
final DateTime? endDate;
|
final DateTime? endDate;
|
||||||
final Function(DateTime? startDate, DateTime? endDate) onDateRangeChanged;
|
final Function(DateTime? startDate, DateTime? endDate) onDateRangeChanged;
|
||||||
final VoidCallback onDownload;
|
final VoidCallback onDownload;
|
||||||
|
final bool isLoading;
|
||||||
final int delay;
|
final int delay;
|
||||||
|
|
||||||
const _ReportOptionCard({
|
const _ReportOptionCard({
|
||||||
@ -265,6 +302,7 @@ class _ReportOptionCard extends StatefulWidget {
|
|||||||
required this.onDateRangeChanged,
|
required this.onDateRangeChanged,
|
||||||
required this.onDownload,
|
required this.onDownload,
|
||||||
required this.delay,
|
required this.delay,
|
||||||
|
required this.isLoading,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -431,23 +469,41 @@ class _ReportOptionCardState extends State<_ReportOptionCard>
|
|||||||
),
|
),
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: widget.isLoading
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
? Row(
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
Icon(
|
children: [
|
||||||
Icons.download_rounded,
|
SpinKitCircle(
|
||||||
color: widget.gradient.first,
|
color: widget.gradient.first,
|
||||||
),
|
size: 24,
|
||||||
const SizedBox(width: 8),
|
),
|
||||||
Text(
|
const SizedBox(width: 8),
|
||||||
'Download Report',
|
Text(
|
||||||
style: AppStyle.md.copyWith(
|
'Loading',
|
||||||
color: widget.gradient.first,
|
style: AppStyle.md.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
color: widget.gradient.first,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.download_rounded,
|
||||||
|
color: widget.gradient.first,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(
|
||||||
|
'Download Report',
|
||||||
|
style: AppStyle.md.copyWith(
|
||||||
|
color: widget.gradient.first,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@ -7,12 +7,16 @@
|
|||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <file_selector_linux/file_selector_plugin.h>
|
#include <file_selector_linux/file_selector_plugin.h>
|
||||||
|
#include <open_file_linux/open_file_linux_plugin.h>
|
||||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||||
|
g_autoptr(FlPluginRegistrar) open_file_linux_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "OpenFileLinuxPlugin");
|
||||||
|
open_file_linux_plugin_register_with_registrar(open_file_linux_registrar);
|
||||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
file_selector_linux
|
file_selector_linux
|
||||||
|
open_file_linux
|
||||||
url_launcher_linux
|
url_launcher_linux
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import Foundation
|
|||||||
import connectivity_plus
|
import connectivity_plus
|
||||||
import device_info_plus
|
import device_info_plus
|
||||||
import file_selector_macos
|
import file_selector_macos
|
||||||
|
import open_file_mac
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
@ -18,6 +19,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
|||||||
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
||||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
|
OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
|
|||||||
144
pubspec.lock
144
pubspec.lock
@ -81,6 +81,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.0.4"
|
version: "8.0.4"
|
||||||
|
barcode:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: barcode
|
||||||
|
sha256: "7b6729c37e3b7f34233e2318d866e8c48ddb46c1f7ad01ff7bb2a8de1da2b9f4"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.9"
|
||||||
|
bidi:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: bidi
|
||||||
|
sha256: "77f475165e94b261745cf1032c751e2032b8ed92ccb2bf5716036db79320637d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.13"
|
||||||
bloc:
|
bloc:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -869,6 +885,70 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
open_file:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: open_file
|
||||||
|
sha256: d17e2bddf5b278cb2ae18393d0496aa4f162142ba97d1a9e0c30d476adf99c0e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.5.10"
|
||||||
|
open_file_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_android
|
||||||
|
sha256: "58141fcaece2f453a9684509a7275f231ac0e3d6ceb9a5e6de310a7dff9084aa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.6"
|
||||||
|
open_file_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_ios
|
||||||
|
sha256: "02996f01e5f6863832068e97f8f3a5ef9b613516db6897f373b43b79849e4d07"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
|
open_file_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_linux
|
||||||
|
sha256: d189f799eecbb139c97f8bc7d303f9e720954fa4e0fa1b0b7294767e5f2d7550
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.5"
|
||||||
|
open_file_mac:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_mac
|
||||||
|
sha256: "1440b1e37ceb0642208cfeb2c659c6cda27b25187a90635c9d1acb7d0584d324"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
|
open_file_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_platform_interface
|
||||||
|
sha256: "101b424ca359632699a7e1213e83d025722ab668b9fd1412338221bf9b0e5757"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.3"
|
||||||
|
open_file_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_web
|
||||||
|
sha256: e3dbc9584856283dcb30aef5720558b90f88036360bd078e494ab80a80130c4f
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.4"
|
||||||
|
open_file_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: open_file_windows
|
||||||
|
sha256: d26c31ddf935a94a1a3aa43a23f4fff8a5ff4eea395fe7a8cb819cf55431c875
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.3"
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -957,6 +1037,62 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
|
pdf:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: pdf
|
||||||
|
sha256: "28eacad99bffcce2e05bba24e50153890ad0255294f4dd78a17075a2ba5c8416"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.11.3"
|
||||||
|
permission_handler:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: permission_handler
|
||||||
|
sha256: bc917da36261b00137bbc8896bf1482169cd76f866282368948f032c8c1caae1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "12.0.1"
|
||||||
|
permission_handler_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_android
|
||||||
|
sha256: "1e3bc410ca1bf84662104b100eb126e066cb55791b7451307f9708d4007350e6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "13.0.1"
|
||||||
|
permission_handler_apple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_apple
|
||||||
|
sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.4.7"
|
||||||
|
permission_handler_html:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_html
|
||||||
|
sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.3+5"
|
||||||
|
permission_handler_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_platform_interface
|
||||||
|
sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.3.0"
|
||||||
|
permission_handler_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: permission_handler_windows
|
||||||
|
sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1021,6 +1157,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.0"
|
version: "1.5.0"
|
||||||
|
qr:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: qr
|
||||||
|
sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
recase:
|
recase:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@ -45,6 +45,9 @@ dependencies:
|
|||||||
syncfusion_flutter_datepicker: ^30.2.5
|
syncfusion_flutter_datepicker: ^30.2.5
|
||||||
url_launcher: ^6.3.2
|
url_launcher: ^6.3.2
|
||||||
device_info_plus: ^11.5.0
|
device_info_plus: ^11.5.0
|
||||||
|
pdf: ^3.11.3
|
||||||
|
open_file: ^3.5.10
|
||||||
|
permission_handler: ^12.0.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||||
#include <file_selector_windows/file_selector_windows.h>
|
#include <file_selector_windows/file_selector_windows.h>
|
||||||
|
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||||
#include <url_launcher_windows/url_launcher_windows.h>
|
#include <url_launcher_windows/url_launcher_windows.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
@ -15,6 +16,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||||||
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||||
FileSelectorWindowsRegisterWithRegistrar(
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||||
|
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||||
UrlLauncherWindowsRegisterWithRegistrar(
|
UrlLauncherWindowsRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
connectivity_plus
|
connectivity_plus
|
||||||
file_selector_windows
|
file_selector_windows
|
||||||
|
permission_handler_windows
|
||||||
url_launcher_windows
|
url_launcher_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user