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">
|
||||
<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
|
||||
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;
|
||||
import 'package:apskel_owner_flutter/application/product/product_loader/product_loader_bloc.dart'
|
||||
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'
|
||||
as _i1030;
|
||||
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>(
|
||||
() => _i1030.ChangePasswordFormBloc(gh<_i635.IUserRepository>()),
|
||||
);
|
||||
gh.factory<_i346.InventoryReportBloc>(
|
||||
() => _i346.InventoryReportBloc(
|
||||
gh<_i477.IAnalyticRepository>(),
|
||||
gh<_i197.IOutletRepository>(),
|
||||
),
|
||||
);
|
||||
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: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/utils/pdf_service.dart';
|
||||
import '../../../common/utils/permission.dart';
|
||||
import '../../../injection.dart';
|
||||
import '../../components/appbar/appbar.dart';
|
||||
import '../../components/field/date_range_picker_field.dart';
|
||||
import '../../components/report/inventory_report.dart';
|
||||
import '../../components/toast/flushbar.dart';
|
||||
|
||||
@RoutePage()
|
||||
class DownloadReportPage extends StatefulWidget {
|
||||
class DownloadReportPage extends StatefulWidget implements AutoRouteWrapper {
|
||||
const DownloadReportPage({super.key});
|
||||
|
||||
@override
|
||||
State<DownloadReportPage> createState() => _DownloadReportPageState();
|
||||
|
||||
@override
|
||||
Widget wrappedRoute(BuildContext context) => BlocProvider(
|
||||
create: (context) =>
|
||||
getIt<InventoryReportBloc>()..add(InventoryReportEvent.fetchedOutlet()),
|
||||
child: this,
|
||||
);
|
||||
}
|
||||
|
||||
class _DownloadReportPageState extends State<DownloadReportPage>
|
||||
@ -26,10 +44,10 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
||||
DateTime? _transactionEndDate;
|
||||
DateTime? _inventoryStartDate;
|
||||
DateTime? _inventoryEndDate;
|
||||
DateTime? _salesStartDate;
|
||||
DateTime? _salesEndDate;
|
||||
DateTime? _customerStartDate;
|
||||
DateTime? _customerEndDate;
|
||||
// DateTime? _salesStartDate;
|
||||
// DateTime? _salesEndDate;
|
||||
// DateTime? _customerStartDate;
|
||||
// DateTime? _customerEndDate;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -76,28 +94,9 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
||||
DateTime? endDate,
|
||||
) {
|
||||
if (startDate == null || endDate == null) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Please select both start and end dates'),
|
||||
backgroundColor: AppColor.error,
|
||||
),
|
||||
);
|
||||
AppFlushbar.showError(context, 'Please select both start and end dates');
|
||||
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
|
||||
@ -139,6 +138,7 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
||||
],
|
||||
startDate: _transactionStartDate,
|
||||
endDate: _transactionEndDate,
|
||||
isLoading: false,
|
||||
onDateRangeChanged: (start, end) {
|
||||
setState(() {
|
||||
_transactionStartDate = start;
|
||||
@ -156,7 +156,9 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Inventory Report Card
|
||||
_ReportOptionCard(
|
||||
BlocBuilder<InventoryReportBloc, InventoryReportState>(
|
||||
builder: (context, state) {
|
||||
return _ReportOptionCard(
|
||||
title: 'Inventory Report',
|
||||
subtitle:
|
||||
'Export inventory and stock data with trends',
|
||||
@ -167,68 +169,102 @@ class _DownloadReportPageState extends State<DownloadReportPage>
|
||||
],
|
||||
startDate: _inventoryStartDate,
|
||||
endDate: _inventoryEndDate,
|
||||
isLoading: state.isFetching,
|
||||
onDateRangeChanged: (start, end) {
|
||||
setState(() {
|
||||
_inventoryStartDate = start;
|
||||
_inventoryEndDate = end;
|
||||
});
|
||||
},
|
||||
onDownload: () => _downloadReport(
|
||||
'Inventory Report',
|
||||
_inventoryStartDate,
|
||||
_inventoryEndDate,
|
||||
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,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Sales Report Card
|
||||
_ReportOptionCard(
|
||||
title: 'Sales Report',
|
||||
subtitle: 'Export sales performance and revenue data',
|
||||
icon: Icons.trending_up_outlined,
|
||||
gradient: const [AppColor.info, Color(0xFF64B5F6)],
|
||||
startDate: _salesStartDate,
|
||||
endDate: _salesEndDate,
|
||||
onDateRangeChanged: (start, end) {
|
||||
setState(() {
|
||||
_salesStartDate = start;
|
||||
_salesEndDate = end;
|
||||
});
|
||||
},
|
||||
onDownload: () => _downloadReport(
|
||||
'Sales Report',
|
||||
_salesStartDate,
|
||||
_salesEndDate,
|
||||
),
|
||||
delay: 600,
|
||||
),
|
||||
// _ReportOptionCard(
|
||||
// title: 'Sales Report',
|
||||
// subtitle: 'Export sales performance and revenue data',
|
||||
// icon: Icons.trending_up_outlined,
|
||||
// gradient: const [AppColor.info, Color(0xFF64B5F6)],
|
||||
// startDate: _salesStartDate,
|
||||
// endDate: _salesEndDate,
|
||||
// onDateRangeChanged: (start, end) {
|
||||
// setState(() {
|
||||
// _salesStartDate = start;
|
||||
// _salesEndDate = end;
|
||||
// });
|
||||
// },
|
||||
// onDownload: () => _downloadReport(
|
||||
// 'Sales Report',
|
||||
// _salesStartDate,
|
||||
// _salesEndDate,
|
||||
// ),
|
||||
// delay: 600,
|
||||
// ),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
// const SizedBox(height: 20),
|
||||
|
||||
// Customer Report Card
|
||||
_ReportOptionCard(
|
||||
title: 'Customer Report',
|
||||
subtitle:
|
||||
'Export customer data and behavior analytics',
|
||||
icon: Icons.people_outline,
|
||||
gradient: const [AppColor.warning, Color(0xFFFFB74D)],
|
||||
startDate: _customerStartDate,
|
||||
endDate: _customerEndDate,
|
||||
onDateRangeChanged: (start, end) {
|
||||
setState(() {
|
||||
_customerStartDate = start;
|
||||
_customerEndDate = end;
|
||||
});
|
||||
},
|
||||
onDownload: () => _downloadReport(
|
||||
'Customer Report',
|
||||
_customerStartDate,
|
||||
_customerEndDate,
|
||||
),
|
||||
delay: 800,
|
||||
),
|
||||
// // Customer Report Card
|
||||
// _ReportOptionCard(
|
||||
// title: 'Customer Report',
|
||||
// subtitle:
|
||||
// 'Export customer data and behavior analytics',
|
||||
// icon: Icons.people_outline,
|
||||
// gradient: const [AppColor.warning, Color(0xFFFFB74D)],
|
||||
// startDate: _customerStartDate,
|
||||
// endDate: _customerEndDate,
|
||||
// onDateRangeChanged: (start, end) {
|
||||
// setState(() {
|
||||
// _customerStartDate = start;
|
||||
// _customerEndDate = end;
|
||||
// });
|
||||
// },
|
||||
// onDownload: () => _downloadReport(
|
||||
// 'Customer Report',
|
||||
// _customerStartDate,
|
||||
// _customerEndDate,
|
||||
// ),
|
||||
// delay: 800,
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -253,6 +289,7 @@ class _ReportOptionCard extends StatefulWidget {
|
||||
final DateTime? endDate;
|
||||
final Function(DateTime? startDate, DateTime? endDate) onDateRangeChanged;
|
||||
final VoidCallback onDownload;
|
||||
final bool isLoading;
|
||||
final int delay;
|
||||
|
||||
const _ReportOptionCard({
|
||||
@ -265,6 +302,7 @@ class _ReportOptionCard extends StatefulWidget {
|
||||
required this.onDateRangeChanged,
|
||||
required this.onDownload,
|
||||
required this.delay,
|
||||
required this.isLoading,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -431,7 +469,25 @@ class _ReportOptionCardState extends State<_ReportOptionCard>
|
||||
),
|
||||
elevation: 0,
|
||||
),
|
||||
child: Row(
|
||||
child: widget.isLoading
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SpinKitCircle(
|
||||
color: widget.gradient.first,
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
'Loading',
|
||||
style: AppStyle.md.copyWith(
|
||||
color: widget.gradient.first,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
|
||||
@ -7,12 +7,16 @@
|
||||
#include "generated_plugin_registrant.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>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
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 =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_linux
|
||||
open_file_linux
|
||||
url_launcher_linux
|
||||
)
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import Foundation
|
||||
import connectivity_plus
|
||||
import device_info_plus
|
||||
import file_selector_macos
|
||||
import open_file_mac
|
||||
import package_info_plus
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
@ -18,6 +19,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
|
||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
|
||||
144
pubspec.lock
144
pubspec.lock
@ -81,6 +81,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -869,6 +885,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -957,6 +1037,62 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
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:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1021,6 +1157,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
qr:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: qr
|
||||
sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
recase:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@ -45,6 +45,9 @@ dependencies:
|
||||
syncfusion_flutter_datepicker: ^30.2.5
|
||||
url_launcher: ^6.3.2
|
||||
device_info_plus: ^11.5.0
|
||||
pdf: ^3.11.3
|
||||
open_file: ^3.5.10
|
||||
permission_handler: ^12.0.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include <connectivity_plus/connectivity_plus_windows_plugin.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>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
@ -15,6 +16,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
connectivity_plus
|
||||
file_selector_windows
|
||||
permission_handler_windows
|
||||
url_launcher_windows
|
||||
)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user