feat : auth for new module

This commit is contained in:
MrM
2025-06-03 22:52:21 +03:30
parent ae18a5f648
commit 2b4c019c55
16 changed files with 314 additions and 133 deletions

View File

@@ -5,10 +5,14 @@ class DioErrorHandler {
void handle(DioException error) { void handle(DioException error) {
switch (error.response?.statusCode) { switch (error.response?.statusCode) {
case 401: case 401:
_handle401(); _handleGeneric(error);
break; break;
case 403: case 403:
_handle403(); _handleGeneric(error);
break;
case 410:
_handle410();
break; break;
default: default:
_handleGeneric(error); _handleGeneric(error);
@@ -16,21 +20,22 @@ class DioErrorHandler {
} }
//wrong password/user name => "detail": "No active account found with the given credentials" - 401 //wrong password/user name => "detail": "No active account found with the given credentials" - 401
void _handle401() { void _handle410() {
Get.showSnackbar( Get.showSnackbar(_errorSnackBar('نام کاربری یا رمز عبور اشتباه است'));
_errorSnackBar('نام کاربری یا رمز عبور اشتباه است'),
);
} }
//wrong captcha => "detail": "Captcha code is incorrect" - 403 //wrong captcha => "detail": "Captcha code is incorrect" - 403
void _handle403() { void _handle403() {}
Get.showSnackbar(
_errorSnackBar('کد امنیتی اشتباه است'),
);
}
void _handleGeneric(DioException error) { void _handleGeneric(DioException error) {
// General error handling Get.showSnackbar(
_errorSnackBar(
error.response?.data.keys.first == 'is_user'
? 'کاربر با این شماره تلفن وجود ندارد'
: error.response?.data[error.response?.data.keys.first] ??
'خطا در برقراری ارتباط با سرور',
),
);
} }
GetSnackBar _errorSnackBar(String message) { GetSnackBar _errorSnackBar(String message) {

View File

@@ -12,7 +12,7 @@ class DioRemoteManager {
ApiEnvironment env = ApiEnvironment.dam, ApiEnvironment env = ApiEnvironment.dam,
]) async { ]) async {
if (_currentEnv != env) { if (_currentEnv != env) {
_currentClient = DioRemote(env.baseUrl); _currentClient = DioRemote(baseUrl: env.baseUrl);
await _currentClient?.init(); await _currentClient?.init();
_currentEnv = env; _currentEnv = env;
} }

View File

@@ -1,7 +1,6 @@
import 'package:rasadyar_auth/data/common/constant.dart'; import 'package:rasadyar_auth/data/common/constant.dart';
import 'package:rasadyar_auth/data/common/dio_error_handler.dart'; import 'package:rasadyar_auth/data/common/dio_error_handler.dart';
import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart'; import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart';
import 'package:rasadyar_auth/data/services/token_storage_service.dart';
import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_core/core.dart';
import '../common/dio_manager.dart'; import '../common/dio_manager.dart';
@@ -10,12 +9,16 @@ GetIt diAuth = GetIt.instance;
Future<void> setupAuthDI() async { Future<void> setupAuthDI() async {
diAuth.registerLazySingleton(() => DioRemoteManager()); diAuth.registerLazySingleton(() => DioRemoteManager());
diAuth.registerLazySingleton<DioRemote>(() => DioRemote());
/* final manager = diAuth.get<DioRemoteManager>();
final dioRemote = await manager.setEnvironment(ApiEnvironment.dam);*/
final manager = diAuth.get<DioRemoteManager>(); final dioRemote = diAuth.get<DioRemote>();
final dioRemote = await manager.setEnvironment(ApiEnvironment.dam); await dioRemote.init();
diAuth.registerCachedFactory<AuthRepositoryImpl>( diAuth.registerCachedFactory<AuthRepositoryImpl>(
() => AuthRepositoryImpl(dioRemote), () => AuthRepositoryImpl(dioRemote),
); );
diAuth.registerLazySingleton<DioErrorHandler>(() => DioErrorHandler()); diAuth.registerLazySingleton<DioErrorHandler>(() => DioErrorHandler());
} }

View File

@@ -19,6 +19,12 @@ class UserLocalModel extends HiveObject {
@HiveField(5) @HiveField(5)
Module? module; Module? module;
@HiveField(6)
String? backend;
@HiveField(7)
String? apiKey;
UserLocalModel({ UserLocalModel({
this.username, this.username,
this.password, this.password,
@@ -26,6 +32,8 @@ class UserLocalModel extends HiveObject {
this.refreshToken, this.refreshToken,
this.name, this.name,
this.module, this.module,
this.backend,
this.apiKey,
}); });
UserLocalModel copyWith({ UserLocalModel copyWith({
@@ -35,6 +43,9 @@ class UserLocalModel extends HiveObject {
String? refreshToken, String? refreshToken,
String? name, String? name,
Module? module, Module? module,
String? backend,
String? apiKey,
}) { }) {
return UserLocalModel( return UserLocalModel(
username: username ?? this.username, username: username ?? this.username,
@@ -43,6 +54,8 @@ class UserLocalModel extends HiveObject {
refreshToken: refreshToken ?? this.refreshToken, refreshToken: refreshToken ?? this.refreshToken,
name: name ?? this.name, name: name ?? this.name,
module: module ?? this.module, module: module ?? this.module,
backend: backend ?? this.backend,
apiKey: apiKey ?? this.apiKey,
); );
} }
} }

View File

@@ -23,13 +23,15 @@ class UserLocalModelAdapter extends TypeAdapter<UserLocalModel> {
refreshToken: fields[3] as String?, refreshToken: fields[3] as String?,
name: fields[4] as String?, name: fields[4] as String?,
module: fields[5] as Module?, module: fields[5] as Module?,
backend: fields[6] as String?,
apiKey: fields[7] as String?,
); );
} }
@override @override
void write(BinaryWriter writer, UserLocalModel obj) { void write(BinaryWriter writer, UserLocalModel obj) {
writer writer
..writeByte(6) ..writeByte(8)
..writeByte(0) ..writeByte(0)
..write(obj.username) ..write(obj.username)
..writeByte(1) ..writeByte(1)
@@ -41,7 +43,11 @@ class UserLocalModelAdapter extends TypeAdapter<UserLocalModel> {
..writeByte(4) ..writeByte(4)
..write(obj.name) ..write(obj.name)
..writeByte(5) ..writeByte(5)
..write(obj.module); ..write(obj.module)
..writeByte(6)
..write(obj.backend)
..writeByte(7)
..write(obj.apiKey);
} }
@override @override

View File

@@ -0,0 +1,18 @@
import 'package:rasadyar_core/core.dart';
part 'user_info_model.freezed.dart';
part 'user_info_model.g.dart';
@freezed
abstract class UserInfoModel with _$UserInfoModel {
const factory UserInfoModel({
bool? isUser,
String? address,
String? backend,
String? apiKey,
}) = _UserInfoModel ;
factory UserInfoModel.fromJson(Map<String, dynamic> json) =>
_$UserInfoModelFromJson(json);
}

View File

@@ -0,0 +1,30 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'user_profile_model.freezed.dart';
part 'user_profile_model.g.dart';
@freezed
abstract class UserProfileModel with _$UserProfileModel {
const factory UserProfileModel({
String? accessToken,
String? expiresIn,
String? scope,
String? expireTime,
String? mobile,
String? fullname,
String? firstname,
String? lastname,
String? city,
String? province,
String? nationalCode,
String? nationalId,
String? birthday,
String? image,
int? baseOrder,
List<String>? role,
}) = _UserProfileModel;
factory UserProfileModel.fromJson(Map<String, dynamic> json) =>
_$UserProfileModelFromJson(json);
}

View File

@@ -1,12 +1,11 @@
import 'package:rasadyar_auth/data/models/response/user_info/user_info_model.dart';
import '../models/response/auth/auth_response_model.dart'; import '../models/response/auth/auth_response_model.dart';
import '../models/response/captcha/captcha_response_model.dart'; import '../models/response/captcha/captcha_response_model.dart';
import '../models/response/user_profile_model/user_profile_model.dart';
abstract class AuthRepository { abstract class AuthRepository {
Future<AuthResponseModel?> login({ Future<UserProfileModel?> login({required Map<String, dynamic> authRequest});
required Map<String, dynamic> authRequest,
});
Future<CaptchaResponseModel?> captcha(); Future<CaptchaResponseModel?> captcha();
@@ -14,10 +13,9 @@ abstract class AuthRepository {
Future<bool> hasAuthenticated(); Future<bool> hasAuthenticated();
Future<AuthResponseModel?> loginWithRefreshToken({ Future<AuthResponseModel?> loginWithRefreshToken({
required Map<String, dynamic> authRequest, required Map<String, dynamic> authRequest,
}); });
Future<UserInfoModel?> getUserInfo(String phoneNumber);
} }

View File

@@ -1,3 +1,5 @@
import 'package:rasadyar_auth/data/models/response/user_info/user_info_model.dart';
import 'package:rasadyar_auth/data/models/response/user_profile_model/user_profile_model.dart';
import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_core/core.dart';
import '../models/response/auth/auth_response_model.dart'; import '../models/response/auth/auth_response_model.dart';
@@ -11,13 +13,13 @@ class AuthRepositoryImpl implements AuthRepository {
AuthRepositoryImpl(this._httpClient); AuthRepositoryImpl(this._httpClient);
@override @override
Future<AuthResponseModel?> login({ Future<UserProfileModel?> login({
required Map<String, dynamic> authRequest, required Map<String, dynamic> authRequest,
}) async { }) async {
var res = await _httpClient.post<AuthResponseModel>( var res = await _httpClient.post<UserProfileModel?>(
'$_BASE_URL/login/', '/api/login/',
data: authRequest, data: authRequest,
fromJson: AuthResponseModel.fromJson, fromJson: UserProfileModel.fromJson,
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
); );
return res.data; return res.data;
@@ -59,4 +61,19 @@ class AuthRepositoryImpl implements AuthRepository {
return response.data ?? false; return response.data ?? false;
} }
@override
Future<UserInfoModel?> getUserInfo(String phoneNumber) async {
var res = await _httpClient.post<UserInfoModel?>(
'https://userbackend.rasadyaar.ir/api/send_otp/',
data: {
"mobile": phoneNumber,
"state": ""
},
fromJson: UserInfoModel.fromJson,
headers: {'Content-Type': 'application/json'},
);
return res.data;
}
} }

View File

@@ -8,6 +8,8 @@ class TokenStorageService extends GetxService {
static const String _boxName = 'secureBox'; static const String _boxName = 'secureBox';
static const String _accessTokenKey = 'accessToken'; static const String _accessTokenKey = 'accessToken';
static const String _refreshTokenKey = 'refreshToken'; static const String _refreshTokenKey = 'refreshToken';
static const String _baseUrlKey = 'baseUrl';
static const String _apiKey = 'apiKey';
static const String _moduleKey = 'moduleSelected'; static const String _moduleKey = 'moduleSelected';
final FlutterSecureStorage _secureStorage = FlutterSecureStorage(); final FlutterSecureStorage _secureStorage = FlutterSecureStorage();
@@ -15,6 +17,7 @@ class TokenStorageService extends GetxService {
RxnString accessToken = RxnString(); RxnString accessToken = RxnString();
RxnString refreshToken = RxnString(); RxnString refreshToken = RxnString();
RxnString baseurl= RxnString();
Rxn<Module> appModule = Rxn(null); Rxn<Module> appModule = Rxn(null);
Future<void> init() async { Future<void> init() async {
@@ -34,6 +37,7 @@ class TokenStorageService extends GetxService {
accessToken.value = _localStorage.read<String?>(boxName: _boxName, key: _accessTokenKey); accessToken.value = _localStorage.read<String?>(boxName: _boxName, key: _accessTokenKey);
refreshToken.value = _localStorage.read<String?>(boxName: _boxName, key: _refreshTokenKey); refreshToken.value = _localStorage.read<String?>(boxName: _boxName, key: _refreshTokenKey);
appModule.value = _localStorage.read<Module?>(boxName: _boxName, key: _moduleKey); appModule.value = _localStorage.read<Module?>(boxName: _boxName, key: _moduleKey);
baseurl.value = _localStorage.read<String?>(boxName: _boxName, key: _baseUrlKey);
} }
Future<void> saveAccessToken(String token) async { Future<void> saveAccessToken(String token) async {
@@ -59,4 +63,16 @@ class TokenStorageService extends GetxService {
accessToken.value = null; accessToken.value = null;
refreshToken.value = null; refreshToken.value = null;
} }
Future<void> saveBaseUrl(String url) async {
await _localStorage.save(boxName: _boxName, key: _baseUrlKey, value: url);
baseurl.value = url;
baseurl.refresh();
}
Future<void> saveApiKey(String key) async {
await _localStorage.save(boxName: _boxName, key: _apiKey, value: key);
}
} }

View File

@@ -5,6 +5,8 @@ import 'package:rasadyar_auth/auth.dart';
import 'package:rasadyar_auth/data/common/dio_error_handler.dart'; import 'package:rasadyar_auth/data/common/dio_error_handler.dart';
import 'package:rasadyar_auth/data/models/request/login_request/login_request_model.dart'; import 'package:rasadyar_auth/data/models/request/login_request/login_request_model.dart';
import 'package:rasadyar_auth/data/models/response/auth/auth_response_model.dart'; import 'package:rasadyar_auth/data/models/response/auth/auth_response_model.dart';
import 'package:rasadyar_auth/data/models/response/user_info/user_info_model.dart';
import 'package:rasadyar_auth/data/models/response/user_profile_model/user_profile_model.dart';
import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart'; import 'package:rasadyar_auth/data/repositories/auth_repository_imp.dart';
import 'package:rasadyar_auth/data/services/token_storage_service.dart'; import 'package:rasadyar_auth/data/services/token_storage_service.dart';
import 'package:rasadyar_auth/data/utils/safe_call.dart'; import 'package:rasadyar_auth/data/utils/safe_call.dart';
@@ -34,6 +36,7 @@ class AuthLogic extends GetxController {
RxnString phoneNumber = RxnString(null); RxnString phoneNumber = RxnString(null);
RxBool isLoading = false.obs; RxBool isLoading = false.obs;
RxBool isDisabled = true.obs;
TokenStorageService tokenStorageService = Get.find<TokenStorageService>(); TokenStorageService tokenStorageService = Get.find<TokenStorageService>();
Rx<AuthType> authType = AuthType.useAndPass.obs; Rx<AuthType> authType = AuthType.useAndPass.obs;
@@ -108,7 +111,7 @@ class AuthLogic extends GetxController {
); );
} }
Future<void> submitLoginForm() async { /*Future<void> submitLoginForm() async {
if (!_isFormValid()) return; if (!_isFormValid()) return;
iLog('module222 : ${_module.toString()}'); iLog('module222 : ${_module.toString()}');
final loginRequestModel = _buildLoginRequest(); final loginRequestModel = _buildLoginRequest();
@@ -128,5 +131,73 @@ class AuthLogic extends GetxController {
}, },
); );
isLoading.value = false; isLoading.value = false;
}*/
Future<void> submitLoginForm2() async {
if (!_isFormValid()) return;
isLoading.value = true;
await safeCall<UserProfileModel?>(
call: () => authRepository.login(
authRequest: {
"username": phoneNumberController.value.text,
"password": passwordController.value.text,
},
),
onSuccess: (result) async {
await tokenStorageService.saveModule(_module);
await tokenStorageService.saveAccessToken(result?.accessToken ?? '');
await tokenStorageService.saveRefreshToken(result?.accessToken ?? '');
},
onError: (error, stackTrace) {
if (error is DioException) {
diAuth.get<DioErrorHandler>().handle(error);
}
captchaController.getCaptcha();
},
);
isLoading.value = false;
}
Future<void> getUserInfo(String value) async {
isLoading.value = true;
await safeCall<UserInfoModel?>(
call: () async => await authRepository.getUserInfo(value),
onSuccess: (result) async {
if (result != null) {
diAuth.registerSingleton<DioRemote>(
DioRemote(baseUrl: result.backend),
instanceName: 'newDioRemote',
);
await tokenStorageService.saveApiKey(result.apiKey ?? '');
await tokenStorageService.saveBaseUrl(result.backend ?? '');
}
},
onError: (error, stackTrace) {
if (error is DioException) {
diAuth.get<DioErrorHandler>().handle(error);
}
captchaController.getCaptcha();
},
);
isLoading.value = false;
}
GetSnackBar _errorSnackBar(String message) {
return GetSnackBar(
titleText: Text(
'خطا',
style: AppFonts.yekan14.copyWith(color: Colors.white),
),
messageText: Text(
message,
style: AppFonts.yekan12.copyWith(color: Colors.white),
),
backgroundColor: AppColor.error,
margin: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
borderRadius: 12,
duration: Duration(milliseconds: 3500),
snackPosition: SnackPosition.TOP,
);
} }
} }

View File

@@ -27,7 +27,7 @@ class AuthPage extends GetView<AuthLogic> {
} }
}, controller.authType), }, controller.authType),
SizedBox(height: 50), /* SizedBox(height: 50),
RichText( RichText(
text: TextSpan( text: TextSpan(
children: [ children: [
@@ -80,7 +80,7 @@ class AuthPage extends GetView<AuthLogic> {
], ],
), ),
); );
}, controller.authType), }, controller.authType),*/
], ],
), ),
), ),
@@ -94,118 +94,109 @@ class AuthPage extends GetView<AuthLogic> {
key: controller.formKey, key: controller.formKey,
child: Column( child: Column(
children: [ children: [
ObxValue( RTextField(
(phoneController) => label: 'نام کاربری',
RTextField( maxLength: 11,
label: 'نام کاربری', maxLines: 1,
maxLength: 11, controller: controller.phoneNumberController.value,
maxLines: 1, keyboardType: TextInputType.number,
controller: phoneController.value, initText: controller.phoneNumberController.value.text,
keyboardType: TextInputType.text, onChanged: (value) async {
initText: phoneController.value.text, controller.phoneNumberController.value.text = value;
onChanged: (value) { controller.phoneNumberController.refresh();
phoneController.value.text = value; if (value.length == 11) {
phoneController.refresh(); await controller.getUserInfo(value);
}, }
prefixIcon: Padding( },
padding: const EdgeInsets.fromLTRB(0, 8, 6, 8), prefixIcon: Padding(
child: Assets.vec.callSvg.svg( padding: const EdgeInsets.fromLTRB(0, 8, 6, 8),
width: 12, child: Assets.vec.callSvg.svg(width: 12, height: 12),
height: 12, ),
), suffixIcon:
), controller.phoneNumberController.value.text.trim().isNotEmpty
suffixIcon: ? clearButton(() {
phoneController.value.text controller.phoneNumberController.value.clear();
.trim() controller.phoneNumberController.refresh();
.isNotEmpty
? clearButton(() {
phoneController.value.clear();
phoneController.refresh();
}) })
: null, : null,
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return '⚠️ شماره موبایل را وارد کنید'; return '⚠️ شماره موبایل را وارد کنید';
} } else if (value.length < 11) {
/*else if (value.length < 11) { return '⚠️ شماره موبایل باید 11 رقم باشد';
return '⚠️ شماره موبایل باید 11 رقم باشد'; }
}*/ return null;
return null; },
}, style: AppFonts.yekan13,
style: AppFonts.yekan13, errorStyle: AppFonts.yekan13.copyWith(color: AppColor.redNormal),
errorStyle: AppFonts.yekan13.copyWith( labelStyle: AppFonts.yekan13,
color: AppColor.redNormal, boxConstraints: const BoxConstraints(
), maxHeight: 40,
labelStyle: AppFonts.yekan13, minHeight: 40,
boxConstraints: const BoxConstraints( maxWidth: 40,
maxHeight: 40, minWidth: 40,
minHeight: 40, ),
maxWidth: 40,
minWidth: 40,
),
),
controller.phoneNumberController,
), ),
const SizedBox(height: 26), const SizedBox(height: 26),
ObxValue( ObxValue(
(passwordController) => (passwordController) => RTextField(
RTextField( label: 'رمز عبور',
label: 'رمز عبور', filled: false,
filled: false, obscure: true,
controller: passwordController.value, controller: passwordController.value,
variant: RTextFieldVariant.password, variant: RTextFieldVariant.password,
initText: passwordController.value.text, initText: passwordController.value.text,
onChanged: (value) { onChanged: (value) {
passwordController.refresh(); passwordController.refresh();
}, },
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return '⚠️ رمز عبور را وارد کنید'; return '⚠️ رمز عبور را وارد کنید';
} }
return null; return null;
}, },
style: AppFonts.yekan13, style: AppFonts.yekan13,
errorStyle: AppFonts.yekan13.copyWith( errorStyle: AppFonts.yekan13.copyWith(
color: AppColor.redNormal, color: AppColor.redNormal,
), ),
labelStyle: AppFonts.yekan13, labelStyle: AppFonts.yekan13,
prefixIcon: Padding( prefixIcon: Padding(
padding: const EdgeInsets.fromLTRB(0, 8, 8, 8), padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
child: Assets.vec.keySvg.svg( child: Assets.vec.keySvg.svg(width: 12, height: 12),
width: 12, ),
height: 12, boxConstraints: const BoxConstraints(
), maxHeight: 34,
), minHeight: 34,
boxConstraints: const BoxConstraints( maxWidth: 34,
maxHeight: 34, minWidth: 34,
minHeight: 34, ),
maxWidth: 34, ),
minWidth: 34,
),
),
controller.passwordController, controller.passwordController,
), ),
SizedBox(height: 26), SizedBox(height: 26),
CaptchaWidget(), CaptchaWidget(),
SizedBox(height: 23), SizedBox(height: 23),
ObxValue((data) {
Obx(() {
return RElevated( return RElevated(
text: 'ورود', text: 'ورود',
isLoading: data.value, isLoading: controller.isLoading.value,
onPressed: () async { onPressed: controller.isDisabled.value
await controller.submitLoginForm(); ? null
}, : () async {
await controller.submitLoginForm2();
},
width: Get.width, width: Get.width,
height: 48, height: 48,
); );
}, controller.isLoading), }),
], ],
), ),
), ),
); );
} }
/* /*
Widget sendCodeForm() { Widget sendCodeForm() {
return ObxValue((data) { return ObxValue((data) {
return Form( return Form(

View File

@@ -2,6 +2,7 @@ import 'dart:math';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:rasadyar_auth/presentation/pages/auth/logic.dart';
import 'package:rasadyar_auth/presentation/widget/clear_button.dart'; import 'package:rasadyar_auth/presentation/widget/clear_button.dart';
import 'package:rasadyar_core/core.dart'; import 'package:rasadyar_core/core.dart';
@@ -64,9 +65,19 @@ class CaptchaWidget extends GetView<CaptchaWidgetLogic> {
validator: (value) { validator: (value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return 'کد امنیتی را وارد کنید'; return 'کد امنیتی را وارد کنید';
} else if (controller.captchaKey.value != null && controller.captchaKey.value != value) {
return 'کد امنیتی اشتباه است';
} }
return null; return null;
}, },
onChanged: (pass) {
if(pass.length== 6) {
if(controller.formKey.currentState?.validate()??false) {
Get.find<AuthLogic>().isDisabled.value = false;
}
}
},
style: AppFonts.yekan13, style: AppFonts.yekan13,
); );
}, controller.textController), }, controller.textController),
@@ -82,10 +93,10 @@ class _CaptchaLinePainter extends CustomPainter {
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
final random = Random(); final random = Random();
final paint1 = Paint() final paint1 = Paint()
..color = Color.fromRGBO(random.nextInt(255), random.nextInt(255), random.nextInt(255), 1) ..color = Colors.deepOrange
..strokeWidth = 2; ..strokeWidth = 2;
final paint2 = Paint() final paint2 = Paint()
..color = Color.fromRGBO(random.nextInt(255), random.nextInt(255), random.nextInt(255), 1) ..color =Colors.blue
..strokeWidth = 2; ..strokeWidth = 2;
// First line: top-left to bottom-right // First line: top-left to bottom-right

View File

@@ -1,6 +1,5 @@
library; library;
//other packages //other packages
export 'package:flutter_localizations/flutter_localizations.dart'; export 'package:flutter_localizations/flutter_localizations.dart';
export 'package:flutter_map/flutter_map.dart'; export 'package:flutter_map/flutter_map.dart';
@@ -9,13 +8,17 @@ export 'package:flutter_rating_bar/flutter_rating_bar.dart';
export 'package:flutter_slidable/flutter_slidable.dart'; export 'package:flutter_slidable/flutter_slidable.dart';
export 'package:font_awesome_flutter/font_awesome_flutter.dart'; export 'package:font_awesome_flutter/font_awesome_flutter.dart';
export 'package:hive_ce_flutter/hive_flutter.dart'; export 'package:hive_ce_flutter/hive_flutter.dart';
//freezed //freezed
export 'package:freezed_annotation/freezed_annotation.dart'; export 'package:freezed_annotation/freezed_annotation.dart';
export 'package:geolocator/geolocator.dart'; export 'package:geolocator/geolocator.dart';
export 'package:get/get.dart'; export 'package:get/get.dart' hide FormData, MultipartFile, Response;
//di //di
export 'package:get_it/get_it.dart'; export 'package:get_it/get_it.dart';
export 'injection/di.dart'; export 'injection/di.dart';
export 'package:dio/dio.dart';
export 'package:pretty_dio_logger/pretty_dio_logger.dart';
//local storage //local storage
export 'package:hive_ce_flutter/hive_flutter.dart'; export 'package:hive_ce_flutter/hive_flutter.dart';
@@ -26,13 +29,12 @@ export 'infrastructure/local/hive_local_storage.dart';
//export 'package:encrypt/encrypt.dart' show Encrypted; //export 'package:encrypt/encrypt.dart' show Encrypted;
//Map and location //Map and location
export 'package:latlong2/latlong.dart' ; export 'package:latlong2/latlong.dart';
export 'package:persian_datetime_picker/persian_datetime_picker.dart'; export 'package:persian_datetime_picker/persian_datetime_picker.dart';
export 'package:rasadyar_core/presentation/common/common.dart'; export 'package:rasadyar_core/presentation/common/common.dart';
export 'package:rasadyar_core/presentation/utils/utils.dart'; export 'package:rasadyar_core/presentation/utils/utils.dart';
export 'package:rasadyar_core/presentation/widget/widget.dart'; export 'package:rasadyar_core/presentation/widget/widget.dart';
//network //network
export 'infrastructure/remote/dio_form_data.dart'; export 'infrastructure/remote/dio_form_data.dart';
export 'infrastructure/remote/dio_remote.dart'; export 'infrastructure/remote/dio_remote.dart';

View File

@@ -7,14 +7,14 @@ import 'package:rasadyar_core/infrastructure/remote/interfaces/i_form_data.dart'
import 'interfaces/i_http_client.dart'; import 'interfaces/i_http_client.dart';
class DioRemote implements IHttpClient { class DioRemote implements IHttpClient {
final String baseUrl; String? baseUrl;
late final Dio _dio; late final Dio _dio;
DioRemote(this.baseUrl); DioRemote({this.baseUrl});
@override @override
Future<void> init() async { Future<void> init() async {
final dio = Dio(BaseOptions(baseUrl: baseUrl)); final dio = Dio(BaseOptions(baseUrl: baseUrl??''));
if (kDebugMode) { if (kDebugMode) {
dio.interceptors.add(PrettyDioLogger( dio.interceptors.add(PrettyDioLogger(
requestHeader: true, requestHeader: true,

View File

@@ -1,2 +1,2 @@
#!/bin/bash #!/bin/bash
dart create --template=package ../packages/livestock dart create --template=package ../packages/chicken