feat : auth package

This commit is contained in:
2025-05-11 11:49:51 +03:30
parent 8cc4a7517c
commit 9ec761e6eb
34 changed files with 665 additions and 475 deletions

View File

@@ -1,12 +0,0 @@
import 'package:hive_ce_flutter/hive_flutter.dart';
import 'package:rasadyar_app/data/data_provider/local_storage/i_local_storage_provider.dart';
enum HiveBoxNames { user, settings, auth }
class HiveProvider extends ILocalStorageProvider {
@override
Future<void> init() async {
await Hive.initFlutter();
}
}

View File

@@ -1 +0,0 @@
const int userTypeId = 0;

View File

@@ -1,3 +0,0 @@
abstract class ILocalStorageProvider {
Future<void> init();
}

View File

@@ -1,19 +0,0 @@
import 'package:hive_ce_flutter/hive_flutter.dart';
import 'package:rasadyar_app/data/data_provider/local_storage/hive/hive_provider.dart';
abstract class IUserLocalStorage {
Future<bool> userAuthed();
}
class UserLocalStorage extends IUserLocalStorage {
final user = Hive.box(HiveBoxNames.user.name);
@override
Future<bool> userAuthed() async {
if (user.isNotEmpty ) {
return true;
} else {
return false;
}
}
}

View File

@@ -1,17 +0,0 @@
import 'package:hive_ce/hive.dart';
import '../../data_provider/local_storage/hive/hive_types.dart';
part 'user_model.g.dart';
@HiveType(typeId: userTypeId)
class UserModel extends HiveObject{
@HiveField(0)
String? token;
@HiveField(1)
String? refreshToken;
UserModel({this.token, this.refreshToken});
}

View File

@@ -1,17 +0,0 @@
import 'package:rasadyar_app/data/data_source/local_storage/user/user_local_storage.dart';
abstract class IUserRepository {
Future<bool> userAuthed();
}
class UserRepository implements IUserRepository {
final IUserLocalStorage _userLocalStorage;
UserRepository(this._userLocalStorage);
@override
Future<bool> userAuthed() async {
return await _userLocalStorage.userAuthed();
}
}

View File

@@ -1,17 +0,0 @@
import 'package:get/get.dart';
import 'package:rasadyar_app/domain/repository/user/user_repository.dart';
import 'package:rasadyar_app/infrastructure/di/di.dart';
class UserService extends GetxService {
late IUserRepository _userLocalStorage;
@override
void onInit() {
return super.onInit();
// _userLocalStorage = di.get<UserRepository>();
}
Future<bool> isUserAuthed() async {
return await _userLocalStorage.userAuthed();
}
}

View File

@@ -1,15 +1,10 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_app/domain/service/user/user_service.dart';
import 'package:rasadyar_app/presentation/routes/app_pages.dart';
import 'package:rasadyar_core/core.dart';
import 'package:rasadyar_core/infrastructure/di/di.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
setupInjection();
await setupAllProvider();
runApp(MyApp());
// runApp(DevicePreview(builder: (context) => ForDevicePreview(),));
}
@@ -46,7 +41,7 @@ class MyApp extends StatelessWidget {
colorScheme: ColorScheme.fromSeed(seedColor: AppColor.blueNormal),
),
initialRoute: AppPages.initRoutes,
initialBinding: BindingsBuilder.put(() => UserService()),
// initialBinding: BindingsBuilder.put(() => UserService()),
getPages: AppPages.pages,
locale: const Locale("fa", "IR"),
supportedLocales: const [

View File

@@ -0,0 +1,23 @@
import 'package:auth/src/domain/entity/auth_response_entity.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'auth_response_dto.freezed.dart';
part 'auth_response_dto.g.dart';
@freezed
abstract class AuthResponseDto with _$AuthResponseDto {
const factory AuthResponseDto({
String? refresh,
String? access,
@JsonKey(name: 'otp_status') bool? otpStatus,
}) = _AuthResponseDto;
factory AuthResponseDto.fromJson(Map<String, dynamic> json) =>
_$AuthResponseDtoFromJson(json);
AuthResponseEntity toEntity() => AuthResponseEntity(
access: access,
otpStatus: otpStatus,
refresh: refresh,
);
}

View File

@@ -0,0 +1,21 @@
import 'package:rasadyar_core/core.dart';
part 'login_request_model.freezed.dart';
part 'login_request_model.g.dart';
@freezed
abstract class LoginRequestModel with _$LoginRequestModel {
const factory LoginRequestModel({
required String username,
required String password,
required String captchaCode,
required String captchaKey,
}) = _LoginRequestModel;
factory LoginRequestModel.fromJson(Map<String, dynamic> json) =>
_$LoginRequestModelFromJson(json);
const LoginRequestModel._();
String get formattedCaptchaKey => 'rest_captcha_$captchaKey.0';
}

View File

@@ -0,0 +1,157 @@
// dart format width=80
// 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 'login_request_model.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$LoginRequestModel {
String get username; String get password; String get captchaCode; String get captchaKey;
/// Create a copy of LoginRequestModel
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$LoginRequestModelCopyWith<LoginRequestModel> get copyWith => _$LoginRequestModelCopyWithImpl<LoginRequestModel>(this as LoginRequestModel, _$identity);
/// Serializes this LoginRequestModel to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is LoginRequestModel&&(identical(other.username, username) || other.username == username)&&(identical(other.password, password) || other.password == password)&&(identical(other.captchaCode, captchaCode) || other.captchaCode == captchaCode)&&(identical(other.captchaKey, captchaKey) || other.captchaKey == captchaKey));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,username,password,captchaCode,captchaKey);
@override
String toString() {
return 'LoginRequestModel(username: $username, password: $password, captchaCode: $captchaCode, captchaKey: $captchaKey)';
}
}
/// @nodoc
abstract mixin class $LoginRequestModelCopyWith<$Res> {
factory $LoginRequestModelCopyWith(LoginRequestModel value, $Res Function(LoginRequestModel) _then) = _$LoginRequestModelCopyWithImpl;
@useResult
$Res call({
String username, String password, String captchaCode, String captchaKey
});
}
/// @nodoc
class _$LoginRequestModelCopyWithImpl<$Res>
implements $LoginRequestModelCopyWith<$Res> {
_$LoginRequestModelCopyWithImpl(this._self, this._then);
final LoginRequestModel _self;
final $Res Function(LoginRequestModel) _then;
/// Create a copy of LoginRequestModel
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? username = null,Object? password = null,Object? captchaCode = null,Object? captchaKey = null,}) {
return _then(_self.copyWith(
username: null == username ? _self.username : username // ignore: cast_nullable_to_non_nullable
as String,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable
as String,captchaCode: null == captchaCode ? _self.captchaCode : captchaCode // ignore: cast_nullable_to_non_nullable
as String,captchaKey: null == captchaKey ? _self.captchaKey : captchaKey // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _LoginRequestModel extends LoginRequestModel {
const _LoginRequestModel({required this.username, required this.password, required this.captchaCode, required this.captchaKey}): super._();
factory _LoginRequestModel.fromJson(Map<String, dynamic> json) => _$LoginRequestModelFromJson(json);
@override final String username;
@override final String password;
@override final String captchaCode;
@override final String captchaKey;
/// Create a copy of LoginRequestModel
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$LoginRequestModelCopyWith<_LoginRequestModel> get copyWith => __$LoginRequestModelCopyWithImpl<_LoginRequestModel>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$LoginRequestModelToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LoginRequestModel&&(identical(other.username, username) || other.username == username)&&(identical(other.password, password) || other.password == password)&&(identical(other.captchaCode, captchaCode) || other.captchaCode == captchaCode)&&(identical(other.captchaKey, captchaKey) || other.captchaKey == captchaKey));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,username,password,captchaCode,captchaKey);
@override
String toString() {
return 'LoginRequestModel(username: $username, password: $password, captchaCode: $captchaCode, captchaKey: $captchaKey)';
}
}
/// @nodoc
abstract mixin class _$LoginRequestModelCopyWith<$Res> implements $LoginRequestModelCopyWith<$Res> {
factory _$LoginRequestModelCopyWith(_LoginRequestModel value, $Res Function(_LoginRequestModel) _then) = __$LoginRequestModelCopyWithImpl;
@override @useResult
$Res call({
String username, String password, String captchaCode, String captchaKey
});
}
/// @nodoc
class __$LoginRequestModelCopyWithImpl<$Res>
implements _$LoginRequestModelCopyWith<$Res> {
__$LoginRequestModelCopyWithImpl(this._self, this._then);
final _LoginRequestModel _self;
final $Res Function(_LoginRequestModel) _then;
/// Create a copy of LoginRequestModel
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? username = null,Object? password = null,Object? captchaCode = null,Object? captchaKey = null,}) {
return _then(_LoginRequestModel(
username: null == username ? _self.username : username // ignore: cast_nullable_to_non_nullable
as String,password: null == password ? _self.password : password // ignore: cast_nullable_to_non_nullable
as String,captchaCode: null == captchaCode ? _self.captchaCode : captchaCode // ignore: cast_nullable_to_non_nullable
as String,captchaKey: null == captchaKey ? _self.captchaKey : captchaKey // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
// dart format on

View File

@@ -0,0 +1,23 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'login_request_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_LoginRequestModel _$LoginRequestModelFromJson(Map<String, dynamic> json) =>
_LoginRequestModel(
username: json['username'] as String,
password: json['password'] as String,
captchaCode: json['captchaCode'] as String,
captchaKey: json['captchaKey'] as String,
);
Map<String, dynamic> _$LoginRequestModelToJson(_LoginRequestModel instance) =>
<String, dynamic>{
'username': instance.username,
'password': instance.password,
'captchaCode': instance.captchaCode,
'captchaKey': instance.captchaKey,
};

View File

@@ -0,0 +1,41 @@
import 'package:rasadyar_core/core.dart';
part 'user_local_model.g.dart';
@HiveType(typeId: 0)
class UserLocalModel extends HiveObject {
@HiveField(0)
String? username;
@HiveField(1)
String? password;
@HiveField(2)
String? token;
@HiveField(3)
String? refreshToken;
@HiveField(4)
String? name;
UserLocalModel({
this.username,
this.password,
this.token,
this.refreshToken,
this.name,
});
UserLocalModel copyWith({
String? username,
String? password,
String? token,
String? refreshToken,
String? name,
}) {
return UserLocalModel(
username: username ?? this.username,
password: password ?? this.password,
token: token ?? this.token,
refreshToken: refreshToken ?? this.refreshToken,
name: name ?? this.name,
);
}
}

View File

@@ -0,0 +1,12 @@
class AuthResponseEntity {
final String? access;
final String? refresh;
final bool? otpStatus;
AuthResponseEntity({this.access, this.refresh, this.otpStatus});
@override
String toString() {
return 'AuthResponseEntity{accessToken: $access, refreshToken: $refresh, expiresIn: $otpStatus}';
}
}

View File

@@ -0,0 +1,7 @@
import 'package:auth/src/domain/entity/auth_response_entity.dart';
abstract class AuthRepository {
Future<AuthResponseEntity> signIn({
required Map<String, dynamic> authRequest,
});
}

View File

@@ -9,7 +9,7 @@ enum AuthStatus { init }
enum OtpStatus { init, sent, verified, reSend }
class AuthWithUseAndPassLogic extends GetxController {
class AuthLogic extends GetxController {
Rx<GlobalKey<FormState>> formKey = GlobalKey<FormState>().obs;
Rx<GlobalKey<FormState>> formKeyOtp = GlobalKey<FormState>().obs;
Rx<GlobalKey<FormState>> formKeySentOtp = GlobalKey<FormState>().obs;

View File

@@ -5,8 +5,10 @@ import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class AuthWithUseAndPassPage extends GetView<AuthWithUseAndPassLogic> {
const AuthWithUseAndPassPage({super.key});
class AuthPage extends GetView<AuthLogic> {
const AuthPage({super.key});
@override
Widget build(BuildContext context) {

View File

@@ -1,68 +0,0 @@
import 'package:flutter/animation.dart';
import 'package:get/get.dart';
import 'package:rasadyar_app/presentation/routes/app_pages.dart';
import 'package:inspection/inspection.dart';
class SplashLogic extends GetxController with GetTickerProviderStateMixin {
late final AnimationController scaleController;
late final AnimationController rotateController;
Rxn<Animation<double>> scaleAnimation = Rxn();
Rxn<Animation<double>> rotationAnimation = Rxn();
@override
void onInit() {
super.onInit();
scaleController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1500),
);
rotateController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 8000),
);
scaleAnimation.value = Tween<double>(
begin: 0.8,
end: 1.2,
).animate(scaleController);
rotationAnimation.value = Tween<double>(
begin: 0.0,
end: 1,
).animate(rotateController);
rotateController.forward();
rotateController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
rotateController.repeat();
} else if (status == AnimationStatus.dismissed) {
rotateController.forward();
}
});
scaleController.forward();
scaleController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
scaleController.reverse();
} else if (status == AnimationStatus.dismissed) {
scaleController.forward();
}
});
}
@override
void onReady() {
super.onReady();
Future.delayed(const Duration(seconds: 1), () {
Get.offAllNamed(InspectionRoutes.inspection);
});
}
@override
void onClose() {
rotateController.dispose();
scaleController.dispose();
super.onClose();
}
}

View File

@@ -1,47 +0,0 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_core/core.dart';
import 'logic.dart';
class SplashPage extends GetView<SplashLogic> {
const SplashPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.blueDarker,
body: Center(
child: Stack(
alignment: Alignment.center,
children: [
ObxValue((data) {
return ScaleTransition(
scale: data.value!,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 1),
child: Image.asset(
Assets.imagesInnerSplash,
width: 190,
height: 190,
),
),
);
}, controller.scaleAnimation),
ObxValue((data) {
return RotationTransition(
turns: data.value!,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 1),
child: Image.asset(Assets.imagesOutterSplash),
),
);
}, controller.rotationAnimation),
],
),
),
);
}
}

View File

@@ -1,255 +0,0 @@
import 'package:flutter/material.dart';
import 'package:rasadyar_core/core.dart';
class SystemDesignPage extends StatefulWidget {
const SystemDesignPage({super.key});
@override
State<SystemDesignPage> createState() => _SystemDesignPageState();
}
class _SystemDesignPageState extends State<SystemDesignPage> {
List<bool> _isOpen = [false, false, false, false, false, false];
void _handleAdd() {
print("Add FAB pressed");
}
void _handleEdit() {
print("Edit FAB pressed");
}
void _handleDelete() {
print("Delete FAB pressed");
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("System design"), centerTitle: true),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ExpansionPanelList(
expansionCallback: (panelIndex, isExpanded) {
setState(() {
_isOpen[panelIndex] = isExpanded;
});
},
children: [
buttonWidget(),
fabWidget(),
outlinedFabWidget(),
paginationWidget(),
tabWidget(),
inputsWidget(),
],
),
),
),
);
}
ExpansionPanel inputsWidget() {
return ExpansionPanel(
isExpanded: _isOpen[5],
headerBuilder: (context, isExpanded) {
return ListTile(
title: Text(
"inputs",
style: AppFonts.yekan20.copyWith(color: Colors.red),
),
);
},
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
spacing: 14,
children: [
RTextField(
hintText: 'حجم کشتار را در روز به قطعه وارد کنید',
hintStyle: AppFonts.yekan13,
),
RTextField(
label: 'تلفن مرغداری',
labelStyle: AppFonts.yekan10,
),
],
),
),
);
}
ExpansionPanel tabWidget() {
return ExpansionPanel(
isExpanded: _isOpen[4],
headerBuilder: (context, isExpanded) {
return ListTile(
title: Text(
"tab",
style: AppFonts.yekan20.copyWith(color: Colors.red),
),
);
},
body: Column(
spacing: 14,
children: [
CupertinoSegmentedControlDemo(),
CupertinoSegmentedControlDemo2(),
],
),
);
}
ExpansionPanel paginationWidget() {
return ExpansionPanel(
isExpanded: _isOpen[3],
headerBuilder: (context, isExpanded) {
return ListTile(
title: Text(
"پیجینیشن",
style: AppFonts.yekan20.copyWith(color: Colors.red),
),
);
},
body: Column(spacing: 14, children: [RShowMore(), PaginationFromUntil()]),
);
}
ExpansionPanel outlinedFabWidget() {
return ExpansionPanel(
isExpanded: _isOpen[2],
headerBuilder: (context, isExpanded) {
return ListTile(
title: Text(
"Outlined Fab ",
style: AppFonts.yekan20.copyWith(color: Colors.green),
),
);
},
body: Column(
spacing: 14,
children: [
Row(),
/*
RFabOutlined.smallAdd(onPressed: () {}),
RFabOutlined.smallAdd(onPressed: null),
RFabOutlined.smallAddNoBorder(onPressed: () {}),
RFabOutlined.smallAddNoBorder(onPressed: null),
RFabOutlined.add(onPressed: () {}),
RFabOutlined.add(onPressed: null),
RFabOutlined.addNoBorder(onPressed: () {}),
RFabOutlined.addNoBorder(onPressed: null),*/
],
),
);
}
ExpansionPanel fabWidget() {
return ExpansionPanel(
isExpanded: _isOpen[1],
headerBuilder: (context, isExpanded) {
return ListTile(
title: Text(
"Fab",
style: AppFonts.yekan20.copyWith(color: Colors.green),
),
);
},
body: Column(
spacing: 14,
children: [
Row(),
/* RFab.smallAdd(onPressed: () {}),
RFab.smallAdd(onPressed: null),
RFab.add(onPressed: () {}),
RFab.add(onPressed: null),
RFab.smallEdit(onPressed: null),
RFab.smallEdit(onPressed: () {}),
RFab.edit(onPressed: () {}),
RFab.edit(onPressed: null),
RFab.smallDelete(onPressed: () {}),
RFab.smallDelete(onPressed: null),
RFab.delete(onPressed: () {}),
RFab.delete(onPressed: null),
RFab.smallAction(onPressed: () {}),
RFab.smallAction(onPressed: null),
RFab.action(onPressed: () {}),
RFab.action(onPressed: null),
RFab.smallFilter(onPressed: () {}),
RFab.smallFilter(onPressed: null),
RFab.filter(onPressed: () {}),
RFab.filter(onPressed: null),
RFab.smallDownload(onPressed: () {}),
RFab.smallDownload(onPressed: null),
RFab.download(onPressed: () {}),
RFab.download(onPressed: null),
RFab.smallExcel(onPressed: () {}),
RFab.smallExcel(onPressed: null),
RFab.excel(onPressed: () {}),
RFab.excel(onPressed: null),
RFab.smallBack(onPressed: () {}),
RFab.smallBack(onPressed: null),
RFab.back(onPressed: () {}),
RFab.back(onPressed: null),*/
],
),
);
}
ExpansionPanel buttonWidget() {
return ExpansionPanel(
isExpanded: _isOpen[0],
headerBuilder: (context, isExpanded) {
return ListTile(
title: Text(
"دکمه ها",
style: AppFonts.yekan20.copyWith(color: Colors.green),
),
);
},
body: Column(
spacing: 14,
children: [
Row(),
RElevated(text: 'ثبت', onPressed: () {}),
RElevated(text: 'ثبت', onPressed: null),
ROutlinedElevated(text: 'ثبت', onPressed: () {}),
ROutlinedElevated(
text: 'ثبتwwww',
onPressed: () {},
backgroundColor: AppColor.blueNormal.disabledColor,
pressedBackgroundColor: AppColor.blueNormal,
),
ROutlinedElevated(text: 'ثبت', onPressed: null),
RTextButton(text: 'ثبت', onPressed: () {}),
RTextButton(text: 'ثبت', onPressed: null),
],
),
);
}
}

View File

@@ -1,15 +1,33 @@
name: auth
description: A starting point for Dart libraries or applications.
publish_to: 'none'
version: 1.0.0
# repository: https://github.com/my_org/my_repo
environment:
sdk: ^3.7.2
# Add regular dependencies here.
dependencies:
# path: ^1.8.0
rasadyar_core:
path: ../core
dev_dependencies:
lints: ^5.0.0
test: ^1.24.0
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
##code generation
build_runner: ^2.4.15
hive_ce_generator: ^1.9.1
freezed: ^3.0.3
json_serializable: ^6.9.4
##test
mocktail: ^1.0.4
get_test: ^4.0.1
flutter:
uses-material-design: true

View File

@@ -11,6 +11,13 @@ export 'package:flutter_slidable/flutter_slidable.dart';
export 'package:font_awesome_flutter/font_awesome_flutter.dart';
export 'package:flutter_rating_bar/flutter_rating_bar.dart';
export 'package:persian_datetime_picker/persian_datetime_picker.dart';
//freezed
export 'package:freezed_annotation/freezed_annotation.dart';
//local storage
export 'package:hive_ce_flutter/hive_flutter.dart';
//Map and location
export 'package:latlong2/latlong.dart';
export 'package:flutter_map/flutter_map.dart';
@@ -19,3 +26,4 @@ export 'package:flutter_map_animations/flutter_map_animations.dart';

View File

@@ -1,37 +1,37 @@
import 'package:flutter/foundation.dart';
import 'package:logger/logger.dart';
import 'package:rasadyar_core/infrastructure/di/di.dart';
import 'package:rasadyar_core/injection/di.dart';
void iLog(dynamic message) {
if(kDebugMode){
di.get<Logger>().i(message.toString());
diCore.get<Logger>().i(message.toString());
}
}
void eLog(dynamic message) {
if(kDebugMode){
di.get<Logger>().e(message.toString());
diCore.get<Logger>().e(message.toString());
}
}
void dLog(dynamic message) {
if(kDebugMode){
di.get<Logger>().d(message.toString());
diCore.get<Logger>().d(message.toString());
}
}
void fLog(dynamic message){
if(kDebugMode){
di.get<Logger>().f(message.toString());
diCore.get<Logger>().f(message.toString());
}
}
void tLog(dynamic message) {
if(kDebugMode){
di.get<Logger>().t(message.toString());
diCore.get<Logger>().t(message.toString());
}
}

View File

@@ -0,0 +1,61 @@
import 'package:hive_ce_flutter/hive_flutter.dart';
import 'i_local_storage.dart';
class HiveLocalStorage implements ILocalStorage {
HiveLocalStorage() {
Hive.initFlutter();
}
final Map<String, Box> _boxes = {};
@override
Future init() async => await Hive.initFlutter();
@override
Future<void> openBox<T>(String boxName) async {
if (!_boxes.containsKey(boxName)) {
final box = await Hive.openBox<T>(boxName);
_boxes[boxName] = box;
}
}
@override
Future<void> delete(String boxName, String key) async {
Box<dynamic>? box = await getBox(boxName);
await box.delete(key);
}
@override
Future<T?> read<T>(String boxName, String key) async {
Box? box = await getBox(boxName);
return box.get(key) as T?;
}
@override
Future<void> save(String boxName, String key, value) async {
Box<dynamic>? box = await getBox(boxName);
await box.put(key, value);
}
@override
Future<void> add(String boxName, value) async {
Box<dynamic>? box = await getBox(boxName);
await box.add(value);
}
@override
Future<void> addAll(String boxName, Iterable values) async {
Box<dynamic>? box = await getBox(boxName);
await box.addAll(values);
}
Future<Box<T>> getBox<T>(String boxName) async {
final box = _boxes[boxName];
if (box is Box<T>) {
return box;
} else {
throw Exception('Box $boxName is not of expected type $T');
}
}
}

View File

@@ -0,0 +1,11 @@
abstract class ILocalStorage<E>{
Future<void> init();
Future<void> openBox<T>(String boxName);
Future<void> save(String boxName, String key, dynamic value);
Future<T?> read<T>(String boxName, String key);
Future<void> delete(String boxName, String key);
Future<void> add(String boxName, E value);
Future<void> addAll(String boxName, Iterable<E> values);
}

View File

@@ -0,0 +1,23 @@
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'interfaces/i_form_data.dart';
class DioFormData implements IFormData {
final FormData _formData = FormData();
@override
void addFile(String field, Uint8List bytes, String filename) {
_formData.files.add(MapEntry(
field,
MultipartFile.fromBytes(bytes, filename: filename),
));
}
@override
void addField(String key, String value) {
_formData.fields.add(MapEntry(key, value));
}
FormData get raw => _formData;
}

View File

@@ -0,0 +1,126 @@
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'package:rasadyar_core/infrastructure/remote/interfaces/i_form_data.dart';
import 'package:rasadyar_core/infrastructure/remote/interfaces/i_http_response.dart';
import 'package:rasadyar_core/infrastructure/remote/interfaces/i_remote.dart';
import 'dio_form_data.dart';
import 'dio_response.dart';
import 'interfaces/i_http_client.dart';
class DioRemote implements IRemote, IHttpClient {
final String baseUrl;
late final Dio _dio;
DioRemote(this.baseUrl);
@override
Future<void> init() async {
final dio = Dio(BaseOptions(baseUrl: baseUrl));
dio.interceptors.add(PrettyDioLogger());
_dio = dio;
}
@override
Future<IHttpResponse> get(
String path, {
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
ProgressCallback? onReceiveProgress,
}) async {
final response = await _dio.get(
path,
queryParameters: queryParameters,
options: Options(headers: headers),
onReceiveProgress: onReceiveProgress,
);
return DioHttpResponse(response);
}
@override
Future<IHttpResponse> post(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final response = await _dio.post(
path,
data: data,
queryParameters: queryParameters,
options: Options(headers: headers),
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
return DioHttpResponse(response);
}
@override
Future<IHttpResponse> put(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
}) async {
final response = await _dio.put(
path,
data: data,
queryParameters: queryParameters,
options: Options(headers: headers),
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
return DioHttpResponse(response);
}
@override
Future<IHttpResponse> delete(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
}) async {
final response = await _dio.delete(
path,
data: data,
queryParameters: queryParameters,
options: Options(headers: headers),
);
return DioHttpResponse(response);
}
@override
Future<IHttpResponse<Uint8List>> download(
String url, {
ProgressCallback? onReceiveProgress,
}) async {
final response = await _dio.get<Uint8List>(
url,
options: Options(responseType: ResponseType.bytes),
onReceiveProgress: onReceiveProgress,
);
return DioHttpResponse(response);
}
@override
Future<IHttpResponse> upload(
String path, {
required IFormData formData,
Map<String, String>? headers,
ProgressCallback? onSendProgress,
}) async {
final response = await _dio.post(
path,
data: (formData as DioFormData).raw,
options: Options(headers: headers, contentType: 'multipart/form-data'),
onSendProgress: onSendProgress,
);
return DioHttpResponse(response);
}
}

View File

@@ -0,0 +1,21 @@
import 'interfaces/i_http_response.dart';
import 'package:dio/dio.dart';
class DioHttpResponse<T> implements IHttpResponse<T> {
final Response<T> _response;
DioHttpResponse(this._response);
@override
T? get data => _response.data;
@override
int get statusCode => _response.statusCode ?? 0;
@override
Map<String, List<String>> get headers =>
_response.headers.map.map((k, v) => MapEntry(k, v));
@override
bool get isSuccessful => statusCode >= 200 && statusCode < 300;
}

View File

@@ -0,0 +1,6 @@
import 'package:flutter/foundation.dart';
abstract class IFormData{
void addFile(String field, Uint8List bytes, String filename);
void addField(String key, String value);
}

View File

@@ -0,0 +1,51 @@
import 'dart:typed_data';
import 'package:dio/dio.dart';
import 'package:rasadyar_core/infrastructure/remote/dio_form_data.dart';
import 'i_http_response.dart';
import 'i_form_data.dart';
abstract class IHttpClient {
Future<IHttpResponse> get(
String path, {
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
ProgressCallback? onReceiveProgress,
});
Future<IHttpResponse> post(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
});
Future<IHttpResponse> put(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
});
Future<IHttpResponse> delete(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Map<String, String>? headers,
});
Future<IHttpResponse<Uint8List>> download(
String url, {
ProgressCallback? onReceiveProgress,
});
Future<IHttpResponse> upload(
String path, {
required IFormData formData,
Map<String, String>? headers,
ProgressCallback? onSendProgress,
});
}

View File

@@ -0,0 +1,6 @@
abstract class IHttpResponse<T> {
T? get data;
int get statusCode;
Map<String, List<String>> get headers;
bool get isSuccessful;
}

View File

@@ -0,0 +1,4 @@
abstract class IRemote<T>{
Future<T> init();
}

View File

@@ -193,6 +193,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.0"
dio:
dependency: "direct main"
description:
name: dio
sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9"
url: "https://pub.dev"
source: hosted
version: "5.8.0+1"
dio_web_adapter:
dependency: transitive
description:
name: dio_web_adapter
sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
fake_async:
dependency: transitive
description:
@@ -797,6 +813,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.1"
pretty_dio_logger:
dependency: "direct main"
description:
name: pretty_dio_logger
sha256: "36f2101299786d567869493e2f5731de61ce130faa14679473b26905a92b6407"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
proj4dart:
dependency: transitive
description:

View File

@@ -26,8 +26,8 @@ dependencies:
rxdart: ^0.28.0
## local storage
hive_ce: ^2.10.1
hive_ce_flutter: ^2.2.0
hive_ce: ^2.11.1
hive_ce_flutter: ^2.3.0
##code generation
freezed_annotation: ^3.0.0
@@ -58,7 +58,11 @@ dependencies:
#location
latlong2: ^0.9.1
geolocator: ^14.0.0
#network
dio: ^5.8.0+1
#networkLogger
pretty_dio_logger: ^1.4.0
dev_dependencies:
flutter_test:
@@ -66,7 +70,7 @@ dev_dependencies:
flutter_lints: ^5.0.0
##code generation
build_runner: ^2.4.15
hive_ce_generator: ^1.8.2
hive_ce_generator: ^1.9.1
freezed: ^3.0.3
json_serializable: ^6.9.4
@@ -75,5 +79,7 @@ dev_dependencies:
get_test: ^4.0.1
flutter:
uses-material-design: true