Compare commits

...

2 Commits

Author SHA1 Message Date
efrilm
98b152cbc2 printer checker 2025-11-04 22:22:13 +07:00
efrilm
1b24bae23a printer receipt 2025-11-04 22:13:15 +07:00
34 changed files with 4298 additions and 76 deletions

View File

@ -0,0 +1,38 @@
import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../../domain/printer/printer.dart';
part 'bluetooth_connect_event.dart';
part 'bluetooth_connect_state.dart';
part 'bluetooth_connect_bloc.freezed.dart';
@injectable
class BluetoothConnectBloc
extends Bloc<BluetoothConnectEvent, BluetoothConnectState> {
final IPrinterRepository _printerRepository;
BluetoothConnectBloc(this._printerRepository)
: super(BluetoothConnectState.initial()) {
on<BluetoothConnectEvent>(_onBluetoothConnectEvent);
}
Future<void> _onBluetoothConnectEvent(
BluetoothConnectEvent event,
Emitter<BluetoothConnectState> emit,
) {
return event.map(
connect: (e) async {
emit(state.copyWith(isConnecting: true, failureOrSuccee: none()));
final result = await _printerRepository.connectBluetooth(e.macAddress);
result.fold(
(failure) => emit(state.copyWith(isConnecting: false)),
(success) => emit(state.copyWith(isConnecting: false)),
);
},
);
}
}

View File

@ -0,0 +1,404 @@
// 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 'bluetooth_connect_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 _$BluetoothConnectEvent {
String get macAddress => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String macAddress) connect,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String macAddress)? connect,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String macAddress)? connect,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Connect value) connect,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Connect value)? connect,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Connect value)? connect,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
/// Create a copy of BluetoothConnectEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$BluetoothConnectEventCopyWith<BluetoothConnectEvent> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $BluetoothConnectEventCopyWith<$Res> {
factory $BluetoothConnectEventCopyWith(
BluetoothConnectEvent value,
$Res Function(BluetoothConnectEvent) then,
) = _$BluetoothConnectEventCopyWithImpl<$Res, BluetoothConnectEvent>;
@useResult
$Res call({String macAddress});
}
/// @nodoc
class _$BluetoothConnectEventCopyWithImpl<
$Res,
$Val extends BluetoothConnectEvent
>
implements $BluetoothConnectEventCopyWith<$Res> {
_$BluetoothConnectEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of BluetoothConnectEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? macAddress = null}) {
return _then(
_value.copyWith(
macAddress: null == macAddress
? _value.macAddress
: macAddress // ignore: cast_nullable_to_non_nullable
as String,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$ConnectImplCopyWith<$Res>
implements $BluetoothConnectEventCopyWith<$Res> {
factory _$$ConnectImplCopyWith(
_$ConnectImpl value,
$Res Function(_$ConnectImpl) then,
) = __$$ConnectImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({String macAddress});
}
/// @nodoc
class __$$ConnectImplCopyWithImpl<$Res>
extends _$BluetoothConnectEventCopyWithImpl<$Res, _$ConnectImpl>
implements _$$ConnectImplCopyWith<$Res> {
__$$ConnectImplCopyWithImpl(
_$ConnectImpl _value,
$Res Function(_$ConnectImpl) _then,
) : super(_value, _then);
/// Create a copy of BluetoothConnectEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? macAddress = null}) {
return _then(
_$ConnectImpl(
null == macAddress
? _value.macAddress
: macAddress // ignore: cast_nullable_to_non_nullable
as String,
),
);
}
}
/// @nodoc
class _$ConnectImpl implements _Connect {
const _$ConnectImpl(this.macAddress);
@override
final String macAddress;
@override
String toString() {
return 'BluetoothConnectEvent.connect(macAddress: $macAddress)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$ConnectImpl &&
(identical(other.macAddress, macAddress) ||
other.macAddress == macAddress));
}
@override
int get hashCode => Object.hash(runtimeType, macAddress);
/// Create a copy of BluetoothConnectEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$ConnectImplCopyWith<_$ConnectImpl> get copyWith =>
__$$ConnectImplCopyWithImpl<_$ConnectImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String macAddress) connect,
}) {
return connect(macAddress);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String macAddress)? connect,
}) {
return connect?.call(macAddress);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String macAddress)? connect,
required TResult orElse(),
}) {
if (connect != null) {
return connect(macAddress);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Connect value) connect,
}) {
return connect(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Connect value)? connect,
}) {
return connect?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Connect value)? connect,
required TResult orElse(),
}) {
if (connect != null) {
return connect(this);
}
return orElse();
}
}
abstract class _Connect implements BluetoothConnectEvent {
const factory _Connect(final String macAddress) = _$ConnectImpl;
@override
String get macAddress;
/// Create a copy of BluetoothConnectEvent
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$ConnectImplCopyWith<_$ConnectImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$BluetoothConnectState {
Option<Either<PrinterFailure, bool>> get failureOrSuccee =>
throw _privateConstructorUsedError;
bool get isConnecting => throw _privateConstructorUsedError;
/// Create a copy of BluetoothConnectState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$BluetoothConnectStateCopyWith<BluetoothConnectState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $BluetoothConnectStateCopyWith<$Res> {
factory $BluetoothConnectStateCopyWith(
BluetoothConnectState value,
$Res Function(BluetoothConnectState) then,
) = _$BluetoothConnectStateCopyWithImpl<$Res, BluetoothConnectState>;
@useResult
$Res call({
Option<Either<PrinterFailure, bool>> failureOrSuccee,
bool isConnecting,
});
}
/// @nodoc
class _$BluetoothConnectStateCopyWithImpl<
$Res,
$Val extends BluetoothConnectState
>
implements $BluetoothConnectStateCopyWith<$Res> {
_$BluetoothConnectStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of BluetoothConnectState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? failureOrSuccee = null, Object? isConnecting = null}) {
return _then(
_value.copyWith(
failureOrSuccee: null == failureOrSuccee
? _value.failureOrSuccee
: failureOrSuccee // ignore: cast_nullable_to_non_nullable
as Option<Either<PrinterFailure, bool>>,
isConnecting: null == isConnecting
? _value.isConnecting
: isConnecting // ignore: cast_nullable_to_non_nullable
as bool,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$BluetoothConnectStateImplCopyWith<$Res>
implements $BluetoothConnectStateCopyWith<$Res> {
factory _$$BluetoothConnectStateImplCopyWith(
_$BluetoothConnectStateImpl value,
$Res Function(_$BluetoothConnectStateImpl) then,
) = __$$BluetoothConnectStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
Option<Either<PrinterFailure, bool>> failureOrSuccee,
bool isConnecting,
});
}
/// @nodoc
class __$$BluetoothConnectStateImplCopyWithImpl<$Res>
extends
_$BluetoothConnectStateCopyWithImpl<$Res, _$BluetoothConnectStateImpl>
implements _$$BluetoothConnectStateImplCopyWith<$Res> {
__$$BluetoothConnectStateImplCopyWithImpl(
_$BluetoothConnectStateImpl _value,
$Res Function(_$BluetoothConnectStateImpl) _then,
) : super(_value, _then);
/// Create a copy of BluetoothConnectState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? failureOrSuccee = null, Object? isConnecting = null}) {
return _then(
_$BluetoothConnectStateImpl(
failureOrSuccee: null == failureOrSuccee
? _value.failureOrSuccee
: failureOrSuccee // ignore: cast_nullable_to_non_nullable
as Option<Either<PrinterFailure, bool>>,
isConnecting: null == isConnecting
? _value.isConnecting
: isConnecting // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$BluetoothConnectStateImpl implements _BluetoothConnectState {
_$BluetoothConnectStateImpl({
required this.failureOrSuccee,
this.isConnecting = false,
});
@override
final Option<Either<PrinterFailure, bool>> failureOrSuccee;
@override
@JsonKey()
final bool isConnecting;
@override
String toString() {
return 'BluetoothConnectState(failureOrSuccee: $failureOrSuccee, isConnecting: $isConnecting)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$BluetoothConnectStateImpl &&
(identical(other.failureOrSuccee, failureOrSuccee) ||
other.failureOrSuccee == failureOrSuccee) &&
(identical(other.isConnecting, isConnecting) ||
other.isConnecting == isConnecting));
}
@override
int get hashCode => Object.hash(runtimeType, failureOrSuccee, isConnecting);
/// Create a copy of BluetoothConnectState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$BluetoothConnectStateImplCopyWith<_$BluetoothConnectStateImpl>
get copyWith =>
__$$BluetoothConnectStateImplCopyWithImpl<_$BluetoothConnectStateImpl>(
this,
_$identity,
);
}
abstract class _BluetoothConnectState implements BluetoothConnectState {
factory _BluetoothConnectState({
required final Option<Either<PrinterFailure, bool>> failureOrSuccee,
final bool isConnecting,
}) = _$BluetoothConnectStateImpl;
@override
Option<Either<PrinterFailure, bool>> get failureOrSuccee;
@override
bool get isConnecting;
/// Create a copy of BluetoothConnectState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$BluetoothConnectStateImplCopyWith<_$BluetoothConnectStateImpl>
get copyWith => throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,6 @@
part of 'bluetooth_connect_bloc.dart';
@freezed
class BluetoothConnectEvent with _$BluetoothConnectEvent {
const factory BluetoothConnectEvent.connect(String macAddress) = _Connect;
}

View File

@ -0,0 +1,12 @@
part of 'bluetooth_connect_bloc.dart';
@freezed
class BluetoothConnectState with _$BluetoothConnectState {
factory BluetoothConnectState({
required Option<Either<PrinterFailure, bool>> failureOrSuccee,
@Default(false) bool isConnecting,
}) = _BluetoothConnectState;
factory BluetoothConnectState.initial() =>
BluetoothConnectState(failureOrSuccee: none());
}

View File

@ -0,0 +1,95 @@
import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../common/function/app_function.dart';
import '../../../domain/printer/printer.dart';
part 'printer_form_event.dart';
part 'printer_form_state.dart';
part 'printer_form_bloc.freezed.dart';
@injectable
class PrinterFormBloc extends Bloc<PrinterFormEvent, PrinterFormState> {
final IPrinterRepository _printerRepository;
PrinterFormBloc(this._printerRepository) : super(PrinterFormState.initial()) {
on<PrinterFormEvent>(_onPrinterFormEvent);
}
Future<void> _onPrinterFormEvent(
PrinterFormEvent event,
Emitter<PrinterFormState> emit,
) {
return event.map(
codeChanged: (e) async {
emit(state.copyWith(code: e.code));
},
nameChanged: (e) async {
emit(state.copyWith(name: e.name));
},
addressChanged: (e) async {
emit(state.copyWith(address: e.address));
},
typeChanged: (e) async {
emit(state.copyWith(type: e.type));
},
paperChanged: (e) async {
emit(state.copyWith(paper: e.paper));
},
created: (e) async {
Either<PrinterFailure, Unit> failureOrPrinter;
emit(state.copyWith(isCreating: true, failureOrCreateSuccess: none()));
final request = Printer(
id: generateRandomNumber(),
code: state.code,
name: state.name,
address: state.address,
paper: state.paper,
type: state.type,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
failureOrPrinter = await _printerRepository.createPrinter(request);
emit(
state.copyWith(
isCreating: false,
failureOrCreateSuccess: optionOf(failureOrPrinter),
),
);
},
updated: (e) async {
Either<PrinterFailure, Unit> failureOrPrinter;
emit(state.copyWith(isUpdate: true, failureOrUpdateSuccess: none()));
final request = Printer(
id: generateRandomNumber(),
code: state.code,
name: state.name,
address: state.address,
paper: state.paper,
type: state.type,
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
failureOrPrinter = await _printerRepository.updatePrinter(
request,
e.id,
);
emit(
state.copyWith(
isUpdate: false,
failureOrUpdateSuccess: optionOf(failureOrPrinter),
),
);
},
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
part of 'printer_form_bloc.dart';
@freezed
class PrinterFormEvent with _$PrinterFormEvent {
const factory PrinterFormEvent.codeChanged(String code) = _CodeChanged;
const factory PrinterFormEvent.nameChanged(String name) = _NameChanged;
const factory PrinterFormEvent.addressChanged(String address) =
_AddressChanged;
const factory PrinterFormEvent.typeChanged(String type) = _TypeChanged;
const factory PrinterFormEvent.paperChanged(String paper) = _PaperChanged;
const factory PrinterFormEvent.created() = _Created;
const factory PrinterFormEvent.updated(int id) = _Updated;
}

View File

@ -0,0 +1,26 @@
part of 'printer_form_bloc.dart';
@freezed
class PrinterFormState with _$PrinterFormState {
factory PrinterFormState({
required String code,
required String name,
required String address,
required String paper,
required String type,
required Option<Either<PrinterFailure, Unit>> failureOrCreateSuccess,
required Option<Either<PrinterFailure, Unit>> failureOrUpdateSuccess,
@Default(false) isCreating,
@Default(false) isUpdate,
}) = _PrinterFormState;
factory PrinterFormState.initial() => PrinterFormState(
code: '',
name: '',
address: '',
paper: '58',
type: 'Bluetooth',
failureOrCreateSuccess: none(),
failureOrUpdateSuccess: none(),
);
}

View File

@ -0,0 +1,46 @@
import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/printer/printer.dart';
part 'printer_loader_event.dart';
part 'printer_loader_state.dart';
part 'printer_loader_bloc.freezed.dart';
@injectable
class PrinterLoaderBloc extends Bloc<PrinterLoaderEvent, PrinterLoaderState> {
final IPrinterRepository _printerRepository;
PrinterLoaderBloc(this._printerRepository)
: super(PrinterLoaderState.initial()) {
on<PrinterLoaderEvent>(_onPrinterLoaderEvent);
}
Future<void> _onPrinterLoaderEvent(
PrinterLoaderEvent event,
Emitter<PrinterLoaderState> emit,
) {
return event.map(
getByCode: (e) async {
emit(state.copyWith(isFetching: true, failureOption: none()));
final result = await _printerRepository.getPrinterByCode(e.code);
await result.fold(
(failure) async {
emit(
state.copyWith(
isFetching: false,
failureOption: optionOf(failure),
),
);
},
(printer) async {
emit(state.copyWith(isFetching: false, printer: printer));
},
);
},
);
}
}

View File

@ -0,0 +1,437 @@
// 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 'printer_loader_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 _$PrinterLoaderEvent {
String get code => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String code) getByCode,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String code)? getByCode,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String code)? getByCode,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_GetByCode value) getByCode,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_GetByCode value)? getByCode,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_GetByCode value)? getByCode,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
/// Create a copy of PrinterLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$PrinterLoaderEventCopyWith<PrinterLoaderEvent> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $PrinterLoaderEventCopyWith<$Res> {
factory $PrinterLoaderEventCopyWith(
PrinterLoaderEvent value,
$Res Function(PrinterLoaderEvent) then,
) = _$PrinterLoaderEventCopyWithImpl<$Res, PrinterLoaderEvent>;
@useResult
$Res call({String code});
}
/// @nodoc
class _$PrinterLoaderEventCopyWithImpl<$Res, $Val extends PrinterLoaderEvent>
implements $PrinterLoaderEventCopyWith<$Res> {
_$PrinterLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of PrinterLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? code = null}) {
return _then(
_value.copyWith(
code: null == code
? _value.code
: code // ignore: cast_nullable_to_non_nullable
as String,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$GetByCodeImplCopyWith<$Res>
implements $PrinterLoaderEventCopyWith<$Res> {
factory _$$GetByCodeImplCopyWith(
_$GetByCodeImpl value,
$Res Function(_$GetByCodeImpl) then,
) = __$$GetByCodeImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({String code});
}
/// @nodoc
class __$$GetByCodeImplCopyWithImpl<$Res>
extends _$PrinterLoaderEventCopyWithImpl<$Res, _$GetByCodeImpl>
implements _$$GetByCodeImplCopyWith<$Res> {
__$$GetByCodeImplCopyWithImpl(
_$GetByCodeImpl _value,
$Res Function(_$GetByCodeImpl) _then,
) : super(_value, _then);
/// Create a copy of PrinterLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? code = null}) {
return _then(
_$GetByCodeImpl(
null == code
? _value.code
: code // ignore: cast_nullable_to_non_nullable
as String,
),
);
}
}
/// @nodoc
class _$GetByCodeImpl implements _GetByCode {
const _$GetByCodeImpl(this.code);
@override
final String code;
@override
String toString() {
return 'PrinterLoaderEvent.getByCode(code: $code)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$GetByCodeImpl &&
(identical(other.code, code) || other.code == code));
}
@override
int get hashCode => Object.hash(runtimeType, code);
/// Create a copy of PrinterLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$GetByCodeImplCopyWith<_$GetByCodeImpl> get copyWith =>
__$$GetByCodeImplCopyWithImpl<_$GetByCodeImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String code) getByCode,
}) {
return getByCode(code);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String code)? getByCode,
}) {
return getByCode?.call(code);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String code)? getByCode,
required TResult orElse(),
}) {
if (getByCode != null) {
return getByCode(code);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_GetByCode value) getByCode,
}) {
return getByCode(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_GetByCode value)? getByCode,
}) {
return getByCode?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_GetByCode value)? getByCode,
required TResult orElse(),
}) {
if (getByCode != null) {
return getByCode(this);
}
return orElse();
}
}
abstract class _GetByCode implements PrinterLoaderEvent {
const factory _GetByCode(final String code) = _$GetByCodeImpl;
@override
String get code;
/// Create a copy of PrinterLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$GetByCodeImplCopyWith<_$GetByCodeImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$PrinterLoaderState {
Printer get printer => throw _privateConstructorUsedError;
Option<PrinterFailure> get failureOption =>
throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
/// Create a copy of PrinterLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$PrinterLoaderStateCopyWith<PrinterLoaderState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $PrinterLoaderStateCopyWith<$Res> {
factory $PrinterLoaderStateCopyWith(
PrinterLoaderState value,
$Res Function(PrinterLoaderState) then,
) = _$PrinterLoaderStateCopyWithImpl<$Res, PrinterLoaderState>;
@useResult
$Res call({
Printer printer,
Option<PrinterFailure> failureOption,
bool isFetching,
});
$PrinterCopyWith<$Res> get printer;
}
/// @nodoc
class _$PrinterLoaderStateCopyWithImpl<$Res, $Val extends PrinterLoaderState>
implements $PrinterLoaderStateCopyWith<$Res> {
_$PrinterLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of PrinterLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? printer = null,
Object? failureOption = null,
Object? isFetching = null,
}) {
return _then(
_value.copyWith(
printer: null == printer
? _value.printer
: printer // ignore: cast_nullable_to_non_nullable
as Printer,
failureOption: null == failureOption
? _value.failureOption
: failureOption // ignore: cast_nullable_to_non_nullable
as Option<PrinterFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
)
as $Val,
);
}
/// Create a copy of PrinterLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$PrinterCopyWith<$Res> get printer {
return $PrinterCopyWith<$Res>(_value.printer, (value) {
return _then(_value.copyWith(printer: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$PrinterLoaderStateImplCopyWith<$Res>
implements $PrinterLoaderStateCopyWith<$Res> {
factory _$$PrinterLoaderStateImplCopyWith(
_$PrinterLoaderStateImpl value,
$Res Function(_$PrinterLoaderStateImpl) then,
) = __$$PrinterLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
Printer printer,
Option<PrinterFailure> failureOption,
bool isFetching,
});
@override
$PrinterCopyWith<$Res> get printer;
}
/// @nodoc
class __$$PrinterLoaderStateImplCopyWithImpl<$Res>
extends _$PrinterLoaderStateCopyWithImpl<$Res, _$PrinterLoaderStateImpl>
implements _$$PrinterLoaderStateImplCopyWith<$Res> {
__$$PrinterLoaderStateImplCopyWithImpl(
_$PrinterLoaderStateImpl _value,
$Res Function(_$PrinterLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of PrinterLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? printer = null,
Object? failureOption = null,
Object? isFetching = null,
}) {
return _then(
_$PrinterLoaderStateImpl(
printer: null == printer
? _value.printer
: printer // ignore: cast_nullable_to_non_nullable
as Printer,
failureOption: null == failureOption
? _value.failureOption
: failureOption // ignore: cast_nullable_to_non_nullable
as Option<PrinterFailure>,
isFetching: null == isFetching
? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable
as bool,
),
);
}
}
/// @nodoc
class _$PrinterLoaderStateImpl implements _PrinterLoaderState {
_$PrinterLoaderStateImpl({
required this.printer,
required this.failureOption,
this.isFetching = false,
});
@override
final Printer printer;
@override
final Option<PrinterFailure> failureOption;
@override
@JsonKey()
final bool isFetching;
@override
String toString() {
return 'PrinterLoaderState(printer: $printer, failureOption: $failureOption, isFetching: $isFetching)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$PrinterLoaderStateImpl &&
(identical(other.printer, printer) || other.printer == printer) &&
(identical(other.failureOption, failureOption) ||
other.failureOption == failureOption) &&
(identical(other.isFetching, isFetching) ||
other.isFetching == isFetching));
}
@override
int get hashCode =>
Object.hash(runtimeType, printer, failureOption, isFetching);
/// Create a copy of PrinterLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$PrinterLoaderStateImplCopyWith<_$PrinterLoaderStateImpl> get copyWith =>
__$$PrinterLoaderStateImplCopyWithImpl<_$PrinterLoaderStateImpl>(
this,
_$identity,
);
}
abstract class _PrinterLoaderState implements PrinterLoaderState {
factory _PrinterLoaderState({
required final Printer printer,
required final Option<PrinterFailure> failureOption,
final bool isFetching,
}) = _$PrinterLoaderStateImpl;
@override
Printer get printer;
@override
Option<PrinterFailure> get failureOption;
@override
bool get isFetching;
/// Create a copy of PrinterLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$PrinterLoaderStateImplCopyWith<_$PrinterLoaderStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,6 @@
part of 'printer_loader_bloc.dart';
@freezed
class PrinterLoaderEvent with _$PrinterLoaderEvent {
const factory PrinterLoaderEvent.getByCode(String code) = _GetByCode;
}

View File

@ -0,0 +1,13 @@
part of 'printer_loader_bloc.dart';
@freezed
class PrinterLoaderState with _$PrinterLoaderState {
factory PrinterLoaderState({
required Printer printer,
required Option<PrinterFailure> failureOption,
@Default(false) bool isFetching,
}) = _PrinterLoaderState;
factory PrinterLoaderState.initial() =>
PrinterLoaderState(printer: Printer.empty(), failureOption: none());
}

View File

@ -1,4 +1,5 @@
import 'dart:developer';
import 'dart:math' hide log;
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
@ -69,3 +70,8 @@ Future<void> loadPermissionBluetooth() async {
await Permission.bluetoothConnect.request();
}
}
int generateRandomNumber() {
final random = Random();
return 1 + random.nextInt(10000);
}

View File

@ -1 +0,0 @@
part of '../printer.dart';

View File

@ -0,0 +1,26 @@
part of '../printer.dart';
@freezed
class Printer with _$Printer {
const factory Printer({
required int id,
required String code,
required String name,
required String address,
required String paper,
required String type,
required DateTime createdAt,
required DateTime updatedAt,
}) = _Printer;
factory Printer.empty() => Printer(
id: 0,
code: '',
name: '',
address: '',
paper: '',
type: '',
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
}

View File

@ -6,6 +6,6 @@ import '../../common/api/api_failure.dart';
part 'printer.freezed.dart';
part 'entities/print_entity.dart';
part 'entities/printer_entity.dart';
part 'failures/printer_failure.dart';
part 'repositories/i_printer_repository.dart';

View File

@ -15,6 +15,298 @@ 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 _$Printer {
int get id => throw _privateConstructorUsedError;
String get code => throw _privateConstructorUsedError;
String get name => throw _privateConstructorUsedError;
String get address => throw _privateConstructorUsedError;
String get paper => throw _privateConstructorUsedError;
String get type => throw _privateConstructorUsedError;
DateTime get createdAt => throw _privateConstructorUsedError;
DateTime get updatedAt => throw _privateConstructorUsedError;
/// Create a copy of Printer
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$PrinterCopyWith<Printer> get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $PrinterCopyWith<$Res> {
factory $PrinterCopyWith(Printer value, $Res Function(Printer) then) =
_$PrinterCopyWithImpl<$Res, Printer>;
@useResult
$Res call({
int id,
String code,
String name,
String address,
String paper,
String type,
DateTime createdAt,
DateTime updatedAt,
});
}
/// @nodoc
class _$PrinterCopyWithImpl<$Res, $Val extends Printer>
implements $PrinterCopyWith<$Res> {
_$PrinterCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of Printer
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? code = null,
Object? name = null,
Object? address = null,
Object? paper = null,
Object? type = null,
Object? createdAt = null,
Object? updatedAt = null,
}) {
return _then(
_value.copyWith(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
code: null == code
? _value.code
: code // ignore: cast_nullable_to_non_nullable
as String,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
address: null == address
? _value.address
: address // ignore: cast_nullable_to_non_nullable
as String,
paper: null == paper
? _value.paper
: paper // ignore: cast_nullable_to_non_nullable
as String,
type: null == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
as String,
createdAt: null == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,
updatedAt: null == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$PrinterImplCopyWith<$Res> implements $PrinterCopyWith<$Res> {
factory _$$PrinterImplCopyWith(
_$PrinterImpl value,
$Res Function(_$PrinterImpl) then,
) = __$$PrinterImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
int id,
String code,
String name,
String address,
String paper,
String type,
DateTime createdAt,
DateTime updatedAt,
});
}
/// @nodoc
class __$$PrinterImplCopyWithImpl<$Res>
extends _$PrinterCopyWithImpl<$Res, _$PrinterImpl>
implements _$$PrinterImplCopyWith<$Res> {
__$$PrinterImplCopyWithImpl(
_$PrinterImpl _value,
$Res Function(_$PrinterImpl) _then,
) : super(_value, _then);
/// Create a copy of Printer
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? code = null,
Object? name = null,
Object? address = null,
Object? paper = null,
Object? type = null,
Object? createdAt = null,
Object? updatedAt = null,
}) {
return _then(
_$PrinterImpl(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
code: null == code
? _value.code
: code // ignore: cast_nullable_to_non_nullable
as String,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
address: null == address
? _value.address
: address // ignore: cast_nullable_to_non_nullable
as String,
paper: null == paper
? _value.paper
: paper // ignore: cast_nullable_to_non_nullable
as String,
type: null == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
as String,
createdAt: null == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,
updatedAt: null == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,
),
);
}
}
/// @nodoc
class _$PrinterImpl implements _Printer {
const _$PrinterImpl({
required this.id,
required this.code,
required this.name,
required this.address,
required this.paper,
required this.type,
required this.createdAt,
required this.updatedAt,
});
@override
final int id;
@override
final String code;
@override
final String name;
@override
final String address;
@override
final String paper;
@override
final String type;
@override
final DateTime createdAt;
@override
final DateTime updatedAt;
@override
String toString() {
return 'Printer(id: $id, code: $code, name: $name, address: $address, paper: $paper, type: $type, createdAt: $createdAt, updatedAt: $updatedAt)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$PrinterImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.code, code) || other.code == code) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.address, address) || other.address == address) &&
(identical(other.paper, paper) || other.paper == paper) &&
(identical(other.type, type) || other.type == type) &&
(identical(other.createdAt, createdAt) ||
other.createdAt == createdAt) &&
(identical(other.updatedAt, updatedAt) ||
other.updatedAt == updatedAt));
}
@override
int get hashCode => Object.hash(
runtimeType,
id,
code,
name,
address,
paper,
type,
createdAt,
updatedAt,
);
/// Create a copy of Printer
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$PrinterImplCopyWith<_$PrinterImpl> get copyWith =>
__$$PrinterImplCopyWithImpl<_$PrinterImpl>(this, _$identity);
}
abstract class _Printer implements Printer {
const factory _Printer({
required final int id,
required final String code,
required final String name,
required final String address,
required final String paper,
required final String type,
required final DateTime createdAt,
required final DateTime updatedAt,
}) = _$PrinterImpl;
@override
int get id;
@override
String get code;
@override
String get name;
@override
String get address;
@override
String get paper;
@override
String get type;
@override
DateTime get createdAt;
@override
DateTime get updatedAt;
/// Create a copy of Printer
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$PrinterImplCopyWith<_$PrinterImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$PrinterFailure {
@optionalTypeArgs

View File

@ -6,4 +6,8 @@ abstract class IPrinterRepository {
Future<Either<PrinterFailure, bool>> isBluetoothEnabled();
Future<Either<PrinterFailure, List<BluetoothInfo>>>
getPairedBluetoothDevices();
Future<Either<PrinterFailure, Unit>> createPrinter(Printer printer);
Future<Either<PrinterFailure, Unit>> updatePrinter(Printer printer, int id);
Future<Either<PrinterFailure, Unit>> deletePrinter(int id);
Future<Either<PrinterFailure, Printer>> getPrinterByCode(String code);
}

View File

@ -0,0 +1,140 @@
import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:data_channel/data_channel.dart';
import 'package:injectable/injectable.dart';
import 'package:sqflite/sql.dart';
import '../../../common/database/database_helper.dart';
import '../../../domain/printer/printer.dart';
import '../printer_dtos.dart';
@injectable
class PrinterLocalDataProvider {
final DatabaseHelper _databaseHelper;
final _logName = 'PrinterLocalDataProvider';
PrinterLocalDataProvider(this._databaseHelper);
Future<DC<PrinterFailure, Unit>> createPrinter(PrinterDto printer) async {
final db = await _databaseHelper.database;
try {
log('Creating printer: ${printer.toString()}', name: _logName);
final printerExist = await findPrinterByCode(printer.code);
if (printerExist.hasData) {
return DC.error(
PrinterFailure.dynamicErrorMessage('Printer Telah Terdaftar'),
);
}
await db.insert(
'printers',
printer.toMapCreating(),
conflictAlgorithm: ConflictAlgorithm.abort,
);
log('Success created printer', name: _logName);
return DC.data(unit);
} catch (e) {
log('Error creating printer', name: _logName, error: e);
return DC.error(
PrinterFailure.dynamicErrorMessage('Error creating printer'),
);
}
}
Future<DC<PrinterFailure, Unit>> updatePrinter(
PrinterDto printer,
int id,
) async {
final db = await _databaseHelper.database;
try {
log('Updating printer: ${printer.toString()}', name: _logName);
final updatedRows = await db.update(
'printers',
printer.toMapForUpdate(),
where: 'id = ?',
whereArgs: [id],
);
if (updatedRows == 0) {
return DC.error(
PrinterFailure.dynamicErrorMessage('Printer not found'),
);
}
log('Success updated printer', name: _logName);
return DC.data(unit);
} catch (e) {
log('Error updating printer', name: _logName, error: e);
return DC.error(
PrinterFailure.dynamicErrorMessage('Error updating printer'),
);
}
}
Future<DC<PrinterFailure, Unit>> deletePrinter(int id) async {
final db = await _databaseHelper.database;
try {
log('Updatinf printer: ${id.toString()}', name: _logName);
final deletedRows = await db.delete(
'printers',
where: 'id = ?',
whereArgs: [id],
);
if (deletedRows == 0) {
return DC.error(
PrinterFailure.dynamicErrorMessage('Printer not found'),
);
}
log('Success deleted printer', name: _logName);
return DC.data(unit);
} catch (e) {
log('Error deleting printer', name: _logName, error: e);
return DC.error(
PrinterFailure.dynamicErrorMessage('Error deleting printer'),
);
}
}
Future<DC<PrinterFailure, PrinterDto>> findPrinterByCode(String code) async {
final db = await _databaseHelper.database;
try {
log('Getting printer by code: $code', name: _logName);
final result = await db.query(
'printers',
where: 'code = ?',
whereArgs: [code],
);
if (result.isEmpty) {
log('Printer with code $code not found');
return DC.error(PrinterFailure.empty());
}
final printer = PrinterDto.fromJson(result.first);
return DC.data(printer);
} catch (e) {
log('findPrinterByCode', name: _logName, error: e);
return DC.error(
PrinterFailure.dynamicErrorMessage('Error getting printer'),
);
}
}
}

View File

@ -0,0 +1,68 @@
part of '../printer_dtos.dart';
@freezed
class PrinterDto with _$PrinterDto {
const PrinterDto._();
const factory PrinterDto({
@JsonKey(name: 'id') required int id,
@JsonKey(name: 'code') required String code,
@JsonKey(name: 'name') required String name,
@JsonKey(name: 'address') required String address,
@JsonKey(name: 'paper') required String paper,
@JsonKey(name: 'type') required String type,
@JsonKey(name: 'created_at') required DateTime createdAt,
@JsonKey(name: 'updated_at') required DateTime updatedAt,
}) = _PrinterDto;
factory PrinterDto.fromJson(Map<String, dynamic> json) =>
_$PrinterDtoFromJson(json);
// Optional mapper to domain
Printer toDomain() => Printer(
id: id,
code: code,
name: name,
address: address,
paper: paper,
type: type,
createdAt: createdAt,
updatedAt: updatedAt,
);
factory PrinterDto.fromDomain(Printer printer) => PrinterDto(
id: printer.id,
code: printer.code,
name: printer.name,
address: printer.address,
paper: printer.paper,
type: printer.type,
createdAt: printer.createdAt,
updatedAt: printer.updatedAt,
);
Map<String, dynamic> toMapCreating() {
final now = DateTime.now().toIso8601String();
return {
'id': generateRandomNumber(),
'code': code,
'name': name,
'address': address,
'paper': paper,
'type': type,
'created_at': now,
'updated_at': now,
};
}
Map<String, dynamic> toMapForUpdate() {
return {
'code': code,
'name': name,
'address': address,
'paper': paper,
'type': type,
'updated_at': DateTime.now().toIso8601String(),
};
}
}

View File

@ -0,0 +1,9 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import '../../common/function/app_function.dart';
import '../../domain/printer/printer.dart';
part 'printer_dtos.freezed.dart';
part 'printer_dtos.g.dart';
part 'dtos/printer_dto.dart';

View File

@ -0,0 +1,356 @@
// 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 'printer_dtos.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',
);
PrinterDto _$PrinterDtoFromJson(Map<String, dynamic> json) {
return _PrinterDto.fromJson(json);
}
/// @nodoc
mixin _$PrinterDto {
@JsonKey(name: 'id')
int get id => throw _privateConstructorUsedError;
@JsonKey(name: 'code')
String get code => throw _privateConstructorUsedError;
@JsonKey(name: 'name')
String get name => throw _privateConstructorUsedError;
@JsonKey(name: 'address')
String get address => throw _privateConstructorUsedError;
@JsonKey(name: 'paper')
String get paper => throw _privateConstructorUsedError;
@JsonKey(name: 'type')
String get type => throw _privateConstructorUsedError;
@JsonKey(name: 'created_at')
DateTime get createdAt => throw _privateConstructorUsedError;
@JsonKey(name: 'updated_at')
DateTime get updatedAt => throw _privateConstructorUsedError;
/// Serializes this PrinterDto to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
/// Create a copy of PrinterDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$PrinterDtoCopyWith<PrinterDto> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $PrinterDtoCopyWith<$Res> {
factory $PrinterDtoCopyWith(
PrinterDto value,
$Res Function(PrinterDto) then,
) = _$PrinterDtoCopyWithImpl<$Res, PrinterDto>;
@useResult
$Res call({
@JsonKey(name: 'id') int id,
@JsonKey(name: 'code') String code,
@JsonKey(name: 'name') String name,
@JsonKey(name: 'address') String address,
@JsonKey(name: 'paper') String paper,
@JsonKey(name: 'type') String type,
@JsonKey(name: 'created_at') DateTime createdAt,
@JsonKey(name: 'updated_at') DateTime updatedAt,
});
}
/// @nodoc
class _$PrinterDtoCopyWithImpl<$Res, $Val extends PrinterDto>
implements $PrinterDtoCopyWith<$Res> {
_$PrinterDtoCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of PrinterDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? code = null,
Object? name = null,
Object? address = null,
Object? paper = null,
Object? type = null,
Object? createdAt = null,
Object? updatedAt = null,
}) {
return _then(
_value.copyWith(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
code: null == code
? _value.code
: code // ignore: cast_nullable_to_non_nullable
as String,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
address: null == address
? _value.address
: address // ignore: cast_nullable_to_non_nullable
as String,
paper: null == paper
? _value.paper
: paper // ignore: cast_nullable_to_non_nullable
as String,
type: null == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
as String,
createdAt: null == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,
updatedAt: null == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,
)
as $Val,
);
}
}
/// @nodoc
abstract class _$$PrinterDtoImplCopyWith<$Res>
implements $PrinterDtoCopyWith<$Res> {
factory _$$PrinterDtoImplCopyWith(
_$PrinterDtoImpl value,
$Res Function(_$PrinterDtoImpl) then,
) = __$$PrinterDtoImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
@JsonKey(name: 'id') int id,
@JsonKey(name: 'code') String code,
@JsonKey(name: 'name') String name,
@JsonKey(name: 'address') String address,
@JsonKey(name: 'paper') String paper,
@JsonKey(name: 'type') String type,
@JsonKey(name: 'created_at') DateTime createdAt,
@JsonKey(name: 'updated_at') DateTime updatedAt,
});
}
/// @nodoc
class __$$PrinterDtoImplCopyWithImpl<$Res>
extends _$PrinterDtoCopyWithImpl<$Res, _$PrinterDtoImpl>
implements _$$PrinterDtoImplCopyWith<$Res> {
__$$PrinterDtoImplCopyWithImpl(
_$PrinterDtoImpl _value,
$Res Function(_$PrinterDtoImpl) _then,
) : super(_value, _then);
/// Create a copy of PrinterDto
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? id = null,
Object? code = null,
Object? name = null,
Object? address = null,
Object? paper = null,
Object? type = null,
Object? createdAt = null,
Object? updatedAt = null,
}) {
return _then(
_$PrinterDtoImpl(
id: null == id
? _value.id
: id // ignore: cast_nullable_to_non_nullable
as int,
code: null == code
? _value.code
: code // ignore: cast_nullable_to_non_nullable
as String,
name: null == name
? _value.name
: name // ignore: cast_nullable_to_non_nullable
as String,
address: null == address
? _value.address
: address // ignore: cast_nullable_to_non_nullable
as String,
paper: null == paper
? _value.paper
: paper // ignore: cast_nullable_to_non_nullable
as String,
type: null == type
? _value.type
: type // ignore: cast_nullable_to_non_nullable
as String,
createdAt: null == createdAt
? _value.createdAt
: createdAt // ignore: cast_nullable_to_non_nullable
as DateTime,
updatedAt: null == updatedAt
? _value.updatedAt
: updatedAt // ignore: cast_nullable_to_non_nullable
as DateTime,
),
);
}
}
/// @nodoc
@JsonSerializable()
class _$PrinterDtoImpl extends _PrinterDto {
const _$PrinterDtoImpl({
@JsonKey(name: 'id') required this.id,
@JsonKey(name: 'code') required this.code,
@JsonKey(name: 'name') required this.name,
@JsonKey(name: 'address') required this.address,
@JsonKey(name: 'paper') required this.paper,
@JsonKey(name: 'type') required this.type,
@JsonKey(name: 'created_at') required this.createdAt,
@JsonKey(name: 'updated_at') required this.updatedAt,
}) : super._();
factory _$PrinterDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$PrinterDtoImplFromJson(json);
@override
@JsonKey(name: 'id')
final int id;
@override
@JsonKey(name: 'code')
final String code;
@override
@JsonKey(name: 'name')
final String name;
@override
@JsonKey(name: 'address')
final String address;
@override
@JsonKey(name: 'paper')
final String paper;
@override
@JsonKey(name: 'type')
final String type;
@override
@JsonKey(name: 'created_at')
final DateTime createdAt;
@override
@JsonKey(name: 'updated_at')
final DateTime updatedAt;
@override
String toString() {
return 'PrinterDto(id: $id, code: $code, name: $name, address: $address, paper: $paper, type: $type, createdAt: $createdAt, updatedAt: $updatedAt)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$PrinterDtoImpl &&
(identical(other.id, id) || other.id == id) &&
(identical(other.code, code) || other.code == code) &&
(identical(other.name, name) || other.name == name) &&
(identical(other.address, address) || other.address == address) &&
(identical(other.paper, paper) || other.paper == paper) &&
(identical(other.type, type) || other.type == type) &&
(identical(other.createdAt, createdAt) ||
other.createdAt == createdAt) &&
(identical(other.updatedAt, updatedAt) ||
other.updatedAt == updatedAt));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(
runtimeType,
id,
code,
name,
address,
paper,
type,
createdAt,
updatedAt,
);
/// Create a copy of PrinterDto
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$PrinterDtoImplCopyWith<_$PrinterDtoImpl> get copyWith =>
__$$PrinterDtoImplCopyWithImpl<_$PrinterDtoImpl>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$$PrinterDtoImplToJson(this);
}
}
abstract class _PrinterDto extends PrinterDto {
const factory _PrinterDto({
@JsonKey(name: 'id') required final int id,
@JsonKey(name: 'code') required final String code,
@JsonKey(name: 'name') required final String name,
@JsonKey(name: 'address') required final String address,
@JsonKey(name: 'paper') required final String paper,
@JsonKey(name: 'type') required final String type,
@JsonKey(name: 'created_at') required final DateTime createdAt,
@JsonKey(name: 'updated_at') required final DateTime updatedAt,
}) = _$PrinterDtoImpl;
const _PrinterDto._() : super._();
factory _PrinterDto.fromJson(Map<String, dynamic> json) =
_$PrinterDtoImpl.fromJson;
@override
@JsonKey(name: 'id')
int get id;
@override
@JsonKey(name: 'code')
String get code;
@override
@JsonKey(name: 'name')
String get name;
@override
@JsonKey(name: 'address')
String get address;
@override
@JsonKey(name: 'paper')
String get paper;
@override
@JsonKey(name: 'type')
String get type;
@override
@JsonKey(name: 'created_at')
DateTime get createdAt;
@override
@JsonKey(name: 'updated_at')
DateTime get updatedAt;
/// Create a copy of PrinterDto
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$PrinterDtoImplCopyWith<_$PrinterDtoImpl> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -0,0 +1,31 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'printer_dtos.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_$PrinterDtoImpl _$$PrinterDtoImplFromJson(Map<String, dynamic> json) =>
_$PrinterDtoImpl(
id: (json['id'] as num).toInt(),
code: json['code'] as String,
name: json['name'] as String,
address: json['address'] as String,
paper: json['paper'] as String,
type: json['type'] as String,
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
);
Map<String, dynamic> _$$PrinterDtoImplToJson(_$PrinterDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'code': instance.code,
'name': instance.name,
'address': instance.address,
'paper': instance.paper,
'type': instance.type,
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
};

View File

@ -6,11 +6,14 @@ import 'package:injectable/injectable.dart';
import 'package:print_bluetooth_thermal/print_bluetooth_thermal.dart';
import '../../../domain/printer/printer.dart';
import '../datasource/local_data_provider.dart';
import '../printer_dtos.dart';
@Injectable(as: IPrinterRepository)
class PrinterRepository implements IPrinterRepository {
final PrinterLocalDataProvider _localDataProvider;
final _logName = 'PrinterRepository';
PrinterRepository();
PrinterRepository(this._localDataProvider);
@override
Future<Either<PrinterFailure, bool>> connectBluetooth(
@ -117,4 +120,78 @@ class PrinterRepository implements IPrinterRepository {
);
}
}
@override
Future<Either<PrinterFailure, Unit>> createPrinter(Printer printer) async {
try {
final result = await _localDataProvider.createPrinter(
PrinterDto.fromDomain(printer),
);
if (result.hasError) {
return left(result.error!);
}
return right(unit);
} catch (e) {
log('createPrinterError', name: _logName, error: e);
return left(const PrinterFailure.unexpectedError());
}
}
@override
Future<Either<PrinterFailure, Unit>> deletePrinter(int id) async {
try {
final result = await _localDataProvider.deletePrinter(id);
if (result.hasError) {
return left(result.error!);
}
return right(unit);
} catch (e) {
log('deletePrinterError', name: _logName, error: e);
return left(const PrinterFailure.unexpectedError());
}
}
@override
Future<Either<PrinterFailure, Printer>> getPrinterByCode(String code) async {
try {
final result = await _localDataProvider.findPrinterByCode(code);
if (result.hasError) {
return left(result.error!);
}
final printer = result.data!.toDomain();
return right(printer);
} catch (e) {
log('getPrinterByCodeError', name: _logName, error: e);
return left(const PrinterFailure.unexpectedError());
}
}
@override
Future<Either<PrinterFailure, Unit>> updatePrinter(
Printer printer,
int id,
) async {
try {
final result = await _localDataProvider.updatePrinter(
PrinterDto.fromDomain(printer),
id,
);
if (result.hasError) {
return left(result.error!);
}
return right(unit);
} catch (e) {
log('updatePrinterError', name: _logName, error: e);
return left(const PrinterFailure.unexpectedError());
}
}
}

View File

@ -42,10 +42,16 @@ import 'package:apskel_pos_flutter_v2/application/payment/payment_form/payment_f
as _i194;
import 'package:apskel_pos_flutter_v2/application/payment_method/payment_method_loader/payment_method_loader_bloc.dart'
as _i952;
import 'package:apskel_pos_flutter_v2/application/printer/bluetooth/bluetooth_connect/bluetooth_connect_bloc.dart'
as _i489;
import 'package:apskel_pos_flutter_v2/application/printer/bluetooth/bluetooth_loader/bluetooth_loader_bloc.dart'
as _i903;
import 'package:apskel_pos_flutter_v2/application/printer/printer_bloc.dart'
as _i96;
import 'package:apskel_pos_flutter_v2/application/printer/printer_form/printer_form_bloc.dart'
as _i787;
import 'package:apskel_pos_flutter_v2/application/printer/printer_loader/printer_loader_bloc.dart'
as _i1028;
import 'package:apskel_pos_flutter_v2/application/product/product_loader/product_loader_bloc.dart'
as _i13;
import 'package:apskel_pos_flutter_v2/application/refund/refund_form/refund_form_bloc.dart'
@ -118,6 +124,8 @@ import 'package:apskel_pos_flutter_v2/infrastructure/payment_method/datasources/
as _i833;
import 'package:apskel_pos_flutter_v2/infrastructure/payment_method/repositories/payment_method_repository.dart'
as _i167;
import 'package:apskel_pos_flutter_v2/infrastructure/printer/datasource/local_data_provider.dart'
as _i149;
import 'package:apskel_pos_flutter_v2/infrastructure/printer/repositories/printer_repository.dart'
as _i881;
import 'package:apskel_pos_flutter_v2/infrastructure/product/datasources/local_data_provider.dart'
@ -169,26 +177,40 @@ extension GetItInjectableX on _i174.GetIt {
() => _i171.NetworkClient(gh<_i895.Connectivity>()),
);
gh.factory<_i923.Env>(() => _i923.DevEnv(), registerFor: {_dev});
gh.factory<_i104.IPrinterRepository>(() => _i881.PrinterRepository());
gh.factory<_i708.CategoryLocalDataProvider>(
() => _i708.CategoryLocalDataProvider(gh<_i487.DatabaseHelper>()),
);
gh.factory<_i464.ProductLocalDataProvider>(
() => _i464.ProductLocalDataProvider(gh<_i487.DatabaseHelper>()),
);
gh.factory<_i149.PrinterLocalDataProvider>(
() => _i149.PrinterLocalDataProvider(gh<_i487.DatabaseHelper>()),
);
gh.factory<_i204.AuthLocalDataProvider>(
() => _i204.AuthLocalDataProvider(gh<_i460.SharedPreferences>()),
);
gh.factory<_i693.OutletLocalDatasource>(
() => _i693.OutletLocalDatasource(gh<_i460.SharedPreferences>()),
);
gh.factory<_i903.BluetoothLoaderBloc>(
() => _i903.BluetoothLoaderBloc(gh<_i104.IPrinterRepository>()),
);
gh.lazySingleton<_i457.ApiClient>(
() => _i457.ApiClient(gh<_i361.Dio>(), gh<_i923.Env>()),
);
gh.factory<_i104.IPrinterRepository>(
() => _i881.PrinterRepository(gh<_i149.PrinterLocalDataProvider>()),
);
gh.factory<_i923.Env>(() => _i923.ProdEnv(), registerFor: {_prod});
gh.factory<_i903.BluetoothLoaderBloc>(
() => _i903.BluetoothLoaderBloc(gh<_i104.IPrinterRepository>()),
);
gh.factory<_i489.BluetoothConnectBloc>(
() => _i489.BluetoothConnectBloc(gh<_i104.IPrinterRepository>()),
);
gh.factory<_i787.PrinterFormBloc>(
() => _i787.PrinterFormBloc(gh<_i104.IPrinterRepository>()),
);
gh.factory<_i1028.PrinterLoaderBloc>(
() => _i1028.PrinterLoaderBloc(gh<_i104.IPrinterRepository>()),
);
gh.factory<_i360.OrderRemoteDataProvider>(
() => _i360.OrderRemoteDataProvider(gh<_i457.ApiClient>()),
);

View File

@ -9,7 +9,10 @@ import '../application/order/order_form/order_form_bloc.dart';
import '../application/order/order_loader/order_loader_bloc.dart';
import '../application/outlet/outlet_loader/outlet_loader_bloc.dart';
import '../application/payment_method/payment_method_loader/payment_method_loader_bloc.dart';
import '../application/printer/bluetooth/bluetooth_connect/bluetooth_connect_bloc.dart';
import '../application/printer/bluetooth/bluetooth_loader/bluetooth_loader_bloc.dart';
import '../application/printer/printer_form/printer_form_bloc.dart';
import '../application/printer/printer_loader/printer_loader_bloc.dart';
import '../application/product/product_loader/product_loader_bloc.dart';
import '../application/table/table_form/table_form_bloc.dart';
import '../application/table/table_loader/table_loader_bloc.dart';
@ -47,6 +50,9 @@ class _AppWidgetState extends State<AppWidget> {
BlocProvider(create: (context) => getIt<CustomerLoaderBloc>()),
BlocProvider(create: (context) => getIt<VoidFormBloc>()),
BlocProvider(create: (context) => getIt<BluetoothLoaderBloc>()),
BlocProvider(create: (context) => getIt<BluetoothConnectBloc>()),
BlocProvider(create: (context) => getIt<PrinterFormBloc>()),
BlocProvider(create: (context) => getIt<PrinterLoaderBloc>()),
],
child: MaterialApp.router(
debugShowCheckedModeBanner: false,

View File

@ -4,8 +4,10 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../application/checkout/checkout_form/checkout_form_bloc.dart';
import '../../../application/outlet/outlet_loader/outlet_loader_bloc.dart';
import '../../../application/printer/bluetooth/bluetooth_connect/bluetooth_connect_bloc.dart';
import '../../../application/printer/bluetooth/bluetooth_loader/bluetooth_loader_bloc.dart';
import '../../../common/extension/extension.dart';
import '../../../common/function/app_function.dart';
import '../../../common/theme/theme.dart';
import '../../../common/types/order_type.dart';
import '../../../domain/delivery/delivery.dart';

View File

@ -12,6 +12,7 @@ class PrinterBluetoothDialog extends StatefulWidget {
class _PrinterBluetoothDialogState extends State<PrinterBluetoothDialog> {
@override
void initState() {
loadPermissionBluetooth();
context.read<BluetoothLoaderBloc>().add(BluetoothLoaderEvent.fetched());
super.initState();
}
@ -38,33 +39,42 @@ class _PrinterBluetoothDialogState extends State<PrinterBluetoothDialog> {
mainAxisAlignment: MainAxisAlignment.start,
children: state.bluetoothDevices
.map(
(item) => Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: AppColor.border, width: 1),
(item) => GestureDetector(
onTap: () {
context.read<BluetoothConnectBloc>().add(
BluetoothConnectEvent.connect(item.macAdress),
);
widget.onSelected(item.macAdress);
context.router.maybePop();
},
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: AppColor.border, width: 1),
),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
item.name,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.primary,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
item.name,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.primary,
),
),
),
SpaceHeight(4),
Text(
item.macAdress,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
SpaceHeight(4),
Text(
item.macAdress,
style: AppStyle.sm.copyWith(
color: AppColor.textSecondary,
),
),
),
],
],
),
),
),
)

View File

@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import '../../../common/theme/theme.dart';
import '../../../domain/auth/auth.dart';
import '../../../domain/order/order.dart';
import '../../../domain/printer/printer.dart';
import '../../../domain/table/table.dart';
class AppFlushbar {
@ -80,4 +81,18 @@ class AppFlushbar {
localStorageError: (value) => 'Terjadi kesalahan, silahkan coba lagi',
),
);
static void showPrinterFailureToast(
BuildContext context,
PrinterFailure failure,
) => showError(
context,
failure.map(
serverError: (value) => value.failure.toStringFormatted(context),
dynamicErrorMessage: (value) => value.erroMessage,
unexpectedError: (value) => 'Terjadi kesalahan, silahkan coba lagi',
empty: (value) => 'Tidak ada data',
localStorageError: (value) => 'Terjadi kesalahan, silahkan coba lagi',
),
);
}

View File

@ -0,0 +1,103 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../../../application/printer/printer_loader/printer_loader_bloc.dart';
import '../../../../../../../common/theme/theme.dart';
import '../../../../../../components/card/error_card.dart';
import '../../../../../../components/loader/loader_with_text.dart';
import '../../widgets/printer_card.dart';
import 'setting_printer_form.dart';
class SettingPrinterChecker extends StatefulWidget {
const SettingPrinterChecker({super.key});
@override
State<SettingPrinterChecker> createState() => _SettingPrinterCheckerState();
}
class _SettingPrinterCheckerState extends State<SettingPrinterChecker> {
bool isEdit = false;
@override
initState() {
context.read<PrinterLoaderBloc>().add(
const PrinterLoaderEvent.getByCode('checker'),
);
super.initState();
}
@override
Widget build(BuildContext context) {
return Material(
color: AppColor.background,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
BlocBuilder<PrinterLoaderBloc, PrinterLoaderState>(
builder: (context, state) {
if (state.isFetching) {
return const Center(child: LoaderWithText());
}
if (state.printer.code == '') {
return SettingPrinterForm(
code: 'checker',
onSuccess: () {
context.read<PrinterLoaderBloc>().add(
PrinterLoaderEvent.getByCode('checker'),
);
},
);
}
return state.failureOption.fold(
() => isEdit
? SettingPrinterForm(
code: 'checker',
printer: state.printer,
onCancel: () {
setState(() {
isEdit = false;
});
},
onSuccess: () {
context.read<PrinterLoaderBloc>().add(
PrinterLoaderEvent.getByCode('checker'),
);
setState(() {
isEdit = false;
});
},
)
: PrinterCard(
printer: state.printer,
onEdit: () {
setState(() {
isEdit = true;
});
},
),
(f) => f.maybeMap(
orElse: () => ErrorCard(
title: 'Error',
message: 'Terjadi Kesalahan',
onTap: () {},
),
empty: (value) => SettingPrinterForm(
code: 'checker',
onSuccess: () {
context.read<PrinterLoaderBloc>().add(
PrinterLoaderEvent.getByCode('checker'),
);
},
),
),
);
},
),
],
),
),
);
}
}

View File

@ -1,58 +1,223 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../../../application/printer/printer_form/printer_form_bloc.dart';
import '../../../../../../../common/data/printer_data.dart';
import '../../../../../../../common/extension/extension.dart';
import '../../../../../../../common/theme/theme.dart';
import '../../../../../../../domain/printer/printer.dart';
import '../../../../../../components/button/button.dart';
import '../../../../../../components/dialog/dialog.dart';
import '../../../../../../components/field/field.dart';
import '../../../../../../components/spaces/space.dart';
import '../../../../../../components/toast/flushbar.dart';
class SettingPrinterForm extends StatelessWidget {
class SettingPrinterForm extends StatefulWidget {
final String code;
const SettingPrinterForm({super.key, required this.code});
final Printer? printer;
final Function()? onCancel;
final Function()? onSuccess;
const SettingPrinterForm({
super.key,
required this.code,
this.printer,
this.onCancel,
this.onSuccess,
});
@override
State<SettingPrinterForm> createState() => _SettingPrinterFormState();
}
class _SettingPrinterFormState extends State<SettingPrinterForm> {
final TextEditingController _nameController = TextEditingController();
void setup() {
if (widget.printer != null) {
context.read<PrinterFormBloc>().add(
PrinterFormEvent.typeChanged(widget.printer!.type),
);
context.read<PrinterFormBloc>().add(
PrinterFormEvent.addressChanged(widget.printer!.address),
);
context.read<PrinterFormBloc>().add(
PrinterFormEvent.codeChanged(widget.printer!.code),
);
context.read<PrinterFormBloc>().add(
PrinterFormEvent.nameChanged(widget.printer!.name),
);
context.read<PrinterFormBloc>().add(
PrinterFormEvent.paperChanged(widget.printer!.paper),
);
_nameController.text = widget.printer!.name;
}
}
@override
void initState() {
setup();
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(16.0),
),
child: Column(
children: [
AppDropdownSearch<String>(
label: 'Tipe',
hintText: 'Printer Tipe',
items: printerTypes,
itemAsString: (value) => value,
),
SpaceHeight(12),
SizedBox(
width: double.infinity,
child: AppElevatedButton.outlined(
onPressed: () {
showDialog(
context: context,
builder: (context) =>
PrinterBluetoothDialog(onSelected: (value) {}),
);
},
label: 'Cari',
return MultiBlocListener(
listeners: [
BlocListener<PrinterFormBloc, PrinterFormState>(
listenWhen: (p, c) =>
p.failureOrCreateSuccess != c.failureOrCreateSuccess,
listener: (context, state) {
state.failureOrCreateSuccess.fold(
() => null,
(either) => either.fold(
(f) => AppFlushbar.showPrinterFailureToast(context, f),
(either) {
widget.onSuccess?.call();
AppFlushbar.showSuccess(
context,
'Printer ${widget.code.toTitleCase()} berhasil ditambahkan',
);
},
),
);
},
),
BlocListener<PrinterFormBloc, PrinterFormState>(
listenWhen: (p, c) =>
p.failureOrUpdateSuccess != c.failureOrUpdateSuccess,
listener: (context, state) {
state.failureOrUpdateSuccess.fold(
() => null,
(either) => either.fold(
(f) => AppFlushbar.showPrinterFailureToast(context, f),
(either) {
widget.onSuccess?.call();
AppFlushbar.showSuccess(
context,
'Printer ${widget.code.toTitleCase()} berhasil diubah',
);
},
),
);
},
),
],
child: BlocBuilder<PrinterFormBloc, PrinterFormState>(
builder: (context, state) {
return Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(16.0),
),
),
SpaceHeight(12),
AppTextFormField(label: 'Nama Printer'),
SpaceHeight(12),
AppDropdownSearch<String>(
label: 'Kertas',
hintText: 'Kertas Tipe',
items: paperTypes,
itemAsString: (value) => "$value mm",
),
SpaceHeight(20),
AppElevatedButton.filled(onPressed: () {}, label: 'Simpan'),
],
child: Column(
children: [
AppDropdownSearch<String>(
label: 'Tipe',
hintText: 'Printer Tipe',
items: printerTypes,
itemAsString: (value) => value,
selectedItem: state.type,
onChanged: (value) {
context.read<PrinterFormBloc>().add(
PrinterFormEvent.typeChanged(value!),
);
},
),
SpaceHeight(12),
state.type == 'Bluetooth'
? SizedBox(
width: double.infinity,
child: AppElevatedButton.outlined(
onPressed: () {
showDialog(
context: context,
builder: (context) => PrinterBluetoothDialog(
onSelected: (value) {
context.read<PrinterFormBloc>().add(
PrinterFormEvent.addressChanged(value),
);
},
),
);
},
label: state.address != '' ? state.address : 'Cari',
),
)
: AppTextFormField(
label: 'Network',
onChanged: (value) {
context.read<PrinterFormBloc>().add(
PrinterFormEvent.addressChanged(value),
);
},
),
SpaceHeight(12),
AppTextFormField(
label: 'Nama Printer',
controller: _nameController,
onChanged: (value) {
context.read<PrinterFormBloc>().add(
PrinterFormEvent.nameChanged(value),
);
},
),
SpaceHeight(12),
AppDropdownSearch<String>(
label: 'Kertas',
hintText: 'Kertas Tipe',
items: paperTypes,
itemAsString: (value) => "$value mm",
selectedItem: state.paper,
onChanged: (value) {
context.read<PrinterFormBloc>().add(
PrinterFormEvent.paperChanged(value!),
);
},
),
SpaceHeight(20),
Row(
children: [
if (widget.printer != null) ...[
Expanded(
child: AppElevatedButton.outlined(
onPressed: widget.onCancel,
label: 'Batal',
),
),
SpaceWidth(12),
],
Expanded(
child: AppElevatedButton.filled(
onPressed: () {
if (widget.printer == null) {
if (!state.isCreating) {
context.read<PrinterFormBloc>().add(
PrinterFormEvent.codeChanged(widget.code),
);
context.read<PrinterFormBloc>().add(
PrinterFormEvent.created(),
);
}
} else {
context.read<PrinterFormBloc>().add(
PrinterFormEvent.updated(widget.printer!.id),
);
}
},
label: widget.printer == null ? 'Simpan' : 'Ubah',
isLoading: widget.printer == null
? state.isCreating
: state.isUpdate,
),
),
],
),
],
),
);
},
),
);
}

View File

@ -1,18 +1,102 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../../../../application/printer/printer_loader/printer_loader_bloc.dart';
import '../../../../../../../common/theme/theme.dart';
import '../../../../../../components/card/error_card.dart';
import '../../../../../../components/loader/loader_with_text.dart';
import '../../widgets/printer_card.dart';
import 'setting_printer_form.dart';
class SettingPrinterReceipt extends StatelessWidget {
class SettingPrinterReceipt extends StatefulWidget {
const SettingPrinterReceipt({super.key});
@override
State<SettingPrinterReceipt> createState() => _SettingPrinterReceiptState();
}
class _SettingPrinterReceiptState extends State<SettingPrinterReceipt> {
bool isEdit = false;
@override
initState() {
context.read<PrinterLoaderBloc>().add(
const PrinterLoaderEvent.getByCode('receipt'),
);
super.initState();
}
@override
Widget build(BuildContext context) {
return Material(
color: AppColor.background,
child: Padding(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(children: [SettingPrinterForm(code: 'receipt')]),
child: Column(
children: [
BlocBuilder<PrinterLoaderBloc, PrinterLoaderState>(
builder: (context, state) {
if (state.isFetching) {
return const Center(child: LoaderWithText());
}
if (state.printer.code == '') {
return SettingPrinterForm(
code: 'receipt',
onSuccess: () {
context.read<PrinterLoaderBloc>().add(
PrinterLoaderEvent.getByCode('receipt'),
);
},
);
}
return state.failureOption.fold(
() => isEdit
? SettingPrinterForm(
code: 'receipt',
printer: state.printer,
onCancel: () {
setState(() {
isEdit = false;
});
},
onSuccess: () {
context.read<PrinterLoaderBloc>().add(
PrinterLoaderEvent.getByCode('receipt'),
);
setState(() {
isEdit = false;
});
},
)
: PrinterCard(
printer: state.printer,
onEdit: () {
setState(() {
isEdit = true;
});
},
),
(f) => f.maybeMap(
orElse: () => ErrorCard(
title: "Error",
message: "Terjadi kesalahan saat memuat printer",
onTap: () {},
),
empty: (value) => SettingPrinterForm(
code: 'receipt',
onSuccess: () {
context.read<PrinterLoaderBloc>().add(
PrinterLoaderEvent.getByCode('receipt'),
);
},
),
),
);
},
),
],
),
),
);
}

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import '../../../../../components/page/page_title.dart';
import '../../../../../components/tab/custom_tabbar.dart';
import 'printer/setting_printer_checker.dart';
import 'printer/setting_printer_receipt.dart';
class SettingPrinterSection extends StatelessWidget {
@ -27,7 +28,7 @@ class SettingPrinterSection extends StatelessWidget {
],
tabViews: [
SettingPrinterReceipt(),
Text('Checker Printer'),
SettingPrinterChecker(),
Text('Kitchen Printer'),
Text('Bar Printer'),
Text('Tiket Printer'),

View File

@ -0,0 +1,113 @@
import 'package:flutter/material.dart';
import '../../../../../../common/theme/theme.dart';
import '../../../../../../domain/printer/printer.dart';
import '../../../../../components/spaces/space.dart';
class PrinterCard extends StatelessWidget {
final Printer printer;
final VoidCallback? onEdit;
final VoidCallback? onDelete;
final VoidCallback? onTestPrint;
const PrinterCard({
super.key,
required this.printer,
this.onEdit,
this.onDelete,
this.onTestPrint,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(12),
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: AppColor.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 6,
offset: const Offset(0, 2),
),
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Printer icon
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: AppColor.disabled.withOpacity(0.3),
borderRadius: BorderRadius.circular(8),
),
child: const Icon(Icons.print_outlined),
),
const SpaceWidth(12),
// Printer info
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
printer.name,
style: AppStyle.lg.copyWith(
fontWeight: FontWeight.w600,
color: AppColor.primary,
),
),
const SpaceHeight(4),
Text(
"${printer.paper} mm | ${printer.type}",
style: AppStyle.sm,
),
const SpaceHeight(2),
Text(
printer.address,
style: AppStyle.sm.copyWith(color: AppColor.textSecondary),
),
],
),
),
// Popup menu
PopupMenuButton<String>(
color: AppColor.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
onSelected: (value) {
switch (value) {
case 'edit':
onEdit?.call();
break;
case 'delete':
onDelete?.call();
break;
case 'test':
onTestPrint?.call();
break;
}
},
itemBuilder: (context) => [
PopupMenuItem(
value: 'edit',
child: Text('Edit', style: AppStyle.md),
),
PopupMenuItem(
value: 'delete',
child: Text('Hapus', style: AppStyle.md),
),
PopupMenuItem(
value: 'test',
child: Text('Test Print', style: AppStyle.md),
),
],
),
],
),
);
}
}