diff --git a/assets/icons/call.svg b/assets/icons/call.svg
new file mode 100644
index 0000000..e7d1c11
--- /dev/null
+++ b/assets/icons/call.svg
@@ -0,0 +1,8 @@
+
diff --git a/assets/icons/key.svg b/assets/icons/key.svg
new file mode 100644
index 0000000..fe524b4
--- /dev/null
+++ b/assets/icons/key.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/user.svg b/assets/icons/user.svg
new file mode 100644
index 0000000..fbe07ed
--- /dev/null
+++ b/assets/icons/user.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/vec/call.svg.vec b/assets/vec/call.svg.vec
new file mode 100644
index 0000000..d9b7763
Binary files /dev/null and b/assets/vec/call.svg.vec differ
diff --git a/assets/vec/key.svg.vec b/assets/vec/key.svg.vec
new file mode 100644
index 0000000..3252fd9
Binary files /dev/null and b/assets/vec/key.svg.vec differ
diff --git a/lib/data/data_provider/local_storage/hive/hive_provider.dart b/lib/data/data_provider/local_storage/hive/hive_provider.dart
new file mode 100644
index 0000000..c97f027
--- /dev/null
+++ b/lib/data/data_provider/local_storage/hive/hive_provider.dart
@@ -0,0 +1,12 @@
+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 init() async {
+ await Hive.initFlutter();
+ }
+}
diff --git a/lib/data/data_provider/local_storage/hive/hive_types.dart b/lib/data/data_provider/local_storage/hive/hive_types.dart
new file mode 100644
index 0000000..eff0bf2
--- /dev/null
+++ b/lib/data/data_provider/local_storage/hive/hive_types.dart
@@ -0,0 +1 @@
+const int userTypeId = 0;
diff --git a/lib/data/data_provider/local_storage/i_local_storage_provider.dart b/lib/data/data_provider/local_storage/i_local_storage_provider.dart
new file mode 100644
index 0000000..2ccacf8
--- /dev/null
+++ b/lib/data/data_provider/local_storage/i_local_storage_provider.dart
@@ -0,0 +1,3 @@
+abstract class ILocalStorageProvider {
+ Future init();
+}
diff --git a/lib/data/data_source/local_storage/user/user_local_storage.dart b/lib/data/data_source/local_storage/user/user_local_storage.dart
new file mode 100644
index 0000000..0648a2d
--- /dev/null
+++ b/lib/data/data_source/local_storage/user/user_local_storage.dart
@@ -0,0 +1,19 @@
+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 userAuthed();
+}
+
+class UserLocalStorage extends IUserLocalStorage {
+ final user = Hive.box(HiveBoxNames.user.name);
+
+ @override
+ Future userAuthed() async {
+ if (user.isNotEmpty ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/lib/data/model/user/user_model.dart b/lib/data/model/user/user_model.dart
new file mode 100644
index 0000000..37f2b3b
--- /dev/null
+++ b/lib/data/model/user/user_model.dart
@@ -0,0 +1,17 @@
+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});
+}
diff --git a/lib/data/model/user/user_model.g.dart b/lib/data/model/user/user_model.g.dart
new file mode 100644
index 0000000..e786785
--- /dev/null
+++ b/lib/data/model/user/user_model.g.dart
@@ -0,0 +1,44 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'user_model.dart';
+
+// **************************************************************************
+// TypeAdapterGenerator
+// **************************************************************************
+
+class UserModelAdapter extends TypeAdapter {
+ @override
+ final int typeId = 0;
+
+ @override
+ UserModel read(BinaryReader reader) {
+ final numOfFields = reader.readByte();
+ final fields = {
+ for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
+ };
+ return UserModel(
+ token: fields[0] as String?,
+ refreshToken: fields[1] as String?,
+ );
+ }
+
+ @override
+ void write(BinaryWriter writer, UserModel obj) {
+ writer
+ ..writeByte(2)
+ ..writeByte(0)
+ ..write(obj.token)
+ ..writeByte(1)
+ ..write(obj.refreshToken);
+ }
+
+ @override
+ int get hashCode => typeId.hashCode;
+
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ other is UserModelAdapter &&
+ runtimeType == other.runtimeType &&
+ typeId == other.typeId;
+}
diff --git a/lib/domain/entity/user/user_entity.dart b/lib/domain/entity/user/user_entity.dart
new file mode 100644
index 0000000..1988ce3
--- /dev/null
+++ b/lib/domain/entity/user/user_entity.dart
@@ -0,0 +1,6 @@
+class UserEntity {
+ String? token;
+ String? refreshToken;
+
+ UserEntity({this.token, this.refreshToken});
+}
diff --git a/lib/domain/repository/user/user_repository.dart b/lib/domain/repository/user/user_repository.dart
new file mode 100644
index 0000000..599c891
--- /dev/null
+++ b/lib/domain/repository/user/user_repository.dart
@@ -0,0 +1,25 @@
+import 'package:rasadyar_app/data/data_source/local_storage/user/user_local_storage.dart';
+
+abstract class IUserRepository {
+ Future userAuthed();
+ /*Future setUserAuthed(bool value);
+ Future setUserName(String name);
+ Future getUserName();
+ Future setUserPhone(String phone);
+ Future getUserPhone();
+ Future setUserEmail(String email);
+ Future getUserEmail();
+ Future setUserPassword(String password);
+ Future getUserPassword();*/
+}
+
+class UserRepository implements IUserRepository {
+ final IUserLocalStorage _userLocalStorage;
+
+ UserRepository(this._userLocalStorage);
+
+ @override
+ Future userAuthed() async {
+ return await _userLocalStorage.userAuthed();
+ }
+}
diff --git a/lib/domain/service/user/user_service.dart b/lib/domain/service/user/user_service.dart
new file mode 100644
index 0000000..db8005c
--- /dev/null
+++ b/lib/domain/service/user/user_service.dart
@@ -0,0 +1,17 @@
+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();
+ }
+
+ Future isUserAuthed() async {
+ return await _userLocalStorage.userAuthed();
+ }
+}
diff --git a/lib/infrastructure/di/di.dart b/lib/infrastructure/di/di.dart
new file mode 100644
index 0000000..7b43cc5
--- /dev/null
+++ b/lib/infrastructure/di/di.dart
@@ -0,0 +1,35 @@
+import 'package:get_it/get_it.dart';
+import 'package:hive_ce_flutter/hive_flutter.dart';
+import 'package:logger/logger.dart';
+import 'package:rasadyar_app/data/data_provider/local_storage/hive/hive_provider.dart';
+import 'package:rasadyar_app/data/data_source/local_storage/user/user_local_storage.dart';
+import 'package:rasadyar_app/data/model/user/user_model.dart';
+import 'package:rasadyar_app/domain/repository/user/user_repository.dart';
+
+final di = GetIt.instance;
+
+void setupInjection() {
+ di.registerLazySingleton(() => HiveProvider(), instanceName: 'HiveProvider');
+ di.registerSingleton( Logger());
+}
+
+Future setupAllProvider() async {
+ await _setupLocalStorage();
+ await di.allReady();
+}
+
+Future _setupLocalStorage() async {
+ final hiveProvider = di.get(instanceName: 'HiveProvider');
+ await hiveProvider.init();
+ Hive.registerAdapter(UserModelAdapter());
+
+ await Hive.openBox(HiveBoxNames.user.name);
+
+ //user
+ di.registerLazySingleton(() => UserLocalStorage());
+ di.registerLazySingleton(
+ () => UserRepository(di.get()),
+ );
+
+ //
+}
diff --git a/lib/main.dart b/lib/main.dart
index 787cc7e..c62ccab 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,19 +1,16 @@
import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:rasadyar_app/domain/service/user/user_service.dart';
+import 'package:rasadyar_app/infrastructure/di/di.dart';
import 'package:rasadyar_app/presentation/common/app_color.dart';
-import 'package:rasadyar_app/presentation/common/app_fonts.dart';
-import 'package:rasadyar_app/presentation/utils/color_utils.dart';
-import 'package:rasadyar_app/presentation/widget/buttons/elevated.dart';
-import 'package:rasadyar_app/presentation/widget/buttons/fab_outlined.dart';
-import 'package:rasadyar_app/presentation/widget/buttons/outline_elevated.dart';
-import 'package:rasadyar_app/presentation/widget/buttons/text_button.dart';
-import 'package:rasadyar_app/presentation/widget/inputs/r_input.dart';
-import 'package:rasadyar_app/presentation/widget/pagination/pagination_from_until.dart';
-import 'package:rasadyar_app/presentation/widget/pagination/show_more.dart';
-import 'package:rasadyar_app/presentation/widget/tabs/tab.dart';
+import 'package:rasadyar_app/presentation/routes/app_pages.dart';
-import 'presentation/widget/buttons/fab.dart';
+void main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+
+ setupInjection();
+ await setupAllProvider();
-void main() {
runApp(MyApp());
}
@@ -22,264 +19,15 @@ class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
- return MaterialApp(
- title: 'Flutter Demo',
+ return GetMaterialApp(
+ title: 'رصدیار',
theme: ThemeData(
- colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
- ),
- home: Home(),
- );
- }
-}
-
-class Home extends StatefulWidget {
- const Home({super.key});
-
- @override
- State createState() => _HomeState();
-}
-
-class _HomeState extends State {
- List _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.yekan20Regular.copyWith(color: Colors.red),
- ),
- );
- },
- body: Padding(
- padding: const EdgeInsets.all(8.0),
- child: Column(
- spacing: 14,
- children: [
- RTextField(
- hintText: 'حجم کشتار را در روز به قطعه وارد کنید',
- hintStyle: AppFonts.yekan13Regular,
- ),
- RTextField(
- label: 'تلفن مرغداری',
- labelStyle: AppFonts.yekan10Regular,
- ),
- ],
- ),
- ),
- );
- }
-
- ExpansionPanel tabWidget() {
- return ExpansionPanel(
- isExpanded: _isOpen[4],
- headerBuilder: (context, isExpanded) {
- return ListTile(
- title: Text(
- "tab",
- style: AppFonts.yekan20Regular.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.yekan20Regular.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.yekan20Regular.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.yekan20Regular.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.yekan20Regular.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),
- ],
+ colorScheme: ColorScheme.fromSeed(seedColor: AppColor.blueNormal),
),
+ initialRoute: AppPages.initRoutes,
+ initialBinding: BindingsBuilder.put(() => UserService()),
+ getPages: AppPages.pages,
+ locale: Locale('fa'),
);
}
}
diff --git a/lib/presentation/common/assets.dart b/lib/presentation/common/assets.dart
index 185d647..41892cf 100644
--- a/lib/presentation/common/assets.dart
+++ b/lib/presentation/common/assets.dart
@@ -5,19 +5,24 @@ class Assets {
static const String iconsAdd = 'assets/icons/add.svg';
static const String iconsArrowLeft = 'assets/icons/arrow_left.svg';
static const String iconsArrowRight = 'assets/icons/arrow_right.svg';
+ static const String iconsCall = 'assets/icons/call.svg';
static const String iconsDownload = 'assets/icons/download.svg';
static const String iconsEdit = 'assets/icons/edit.svg';
static const String iconsFilter = 'assets/icons/filter.svg';
+ static const String iconsKey = 'assets/icons/key.svg';
static const String iconsScan = 'assets/icons/scan.svg';
static const String iconsTrash = 'assets/icons/trash.svg';
+ static const String iconsUser = 'assets/icons/user.svg';
static const String imagesInnerSplash = 'assets/images/inner_splash.webp';
static const String imagesOutterSplash = 'assets/images/outter_splash.webp';
static const String vecAddSvg = 'assets/vec/add.svg.vec';
static const String vecArrowLeftSvg = 'assets/vec/arrow_left.svg.vec';
static const String vecArrowRightSvg = 'assets/vec/arrow_right.svg.vec';
+ static const String vecCallSvg = 'assets/vec/call.svg.vec';
static const String vecDownloadSvg = 'assets/vec/download.svg.vec';
static const String vecEditSvg = 'assets/vec/edit.svg.vec';
static const String vecFilterSvg = 'assets/vec/filter.svg.vec';
+ static const String vecKeySvg = 'assets/vec/key.svg.vec';
static const String vecScanSvg = 'assets/vec/scan.svg.vec';
static const String vecTrashSvg = 'assets/vec/trash.svg.vec';
diff --git a/lib/presentation/pages/auth/auth_with_otp/logic.dart b/lib/presentation/pages/auth/auth_with_otp/logic.dart
new file mode 100644
index 0000000..5412998
--- /dev/null
+++ b/lib/presentation/pages/auth/auth_with_otp/logic.dart
@@ -0,0 +1,15 @@
+import 'package:get/get.dart';
+
+class AuthWithOtpLogic extends GetxController {
+ @override
+ void onReady() {
+ // TODO: implement onReady
+ super.onReady();
+ }
+
+ @override
+ void onClose() {
+ // TODO: implement onClose
+ super.onClose();
+ }
+}
diff --git a/lib/presentation/pages/auth/auth_with_otp/view.dart b/lib/presentation/pages/auth/auth_with_otp/view.dart
new file mode 100644
index 0000000..6a566f4
--- /dev/null
+++ b/lib/presentation/pages/auth/auth_with_otp/view.dart
@@ -0,0 +1,15 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import 'logic.dart';
+
+class AuthWithOtpPage extends StatelessWidget {
+ const AuthWithOtpPage({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ final AuthWithOtpLogic logic = Get.put(AuthWithOtpLogic());
+
+ return Container();
+ }
+}
diff --git a/lib/presentation/pages/auth/auth_with_use_and_pass/logic.dart b/lib/presentation/pages/auth/auth_with_use_and_pass/logic.dart
new file mode 100644
index 0000000..6de4422
--- /dev/null
+++ b/lib/presentation/pages/auth/auth_with_use_and_pass/logic.dart
@@ -0,0 +1,27 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:rasadyar_app/presentation/widget/captcha/captcha_widget.dart';
+
+class AuthWithUseAndPassLogic extends GetxController {
+ Rx> formKey = GlobalKey().obs;
+ Rx phoneNumberController = TextEditingController().obs;
+ Rx passwordController = TextEditingController().obs;
+ CaptchaController captchaController = CaptchaController();
+
+ RxnString phoneNumber = RxnString(null);
+ RxnString password = RxnString(null);
+ RxBool isOnError = false.obs;
+ RxBool hidePassword = true.obs;
+
+ @override
+ void onReady() {
+ // TODO: implement onReady
+ super.onReady();
+ }
+
+ @override
+ void onClose() {
+ // TODO: implement onClose
+ super.onClose();
+ }
+}
diff --git a/lib/presentation/pages/auth/auth_with_use_and_pass/view.dart b/lib/presentation/pages/auth/auth_with_use_and_pass/view.dart
new file mode 100644
index 0000000..022543e
--- /dev/null
+++ b/lib/presentation/pages/auth/auth_with_use_and_pass/view.dart
@@ -0,0 +1,210 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:logger/logger.dart';
+import 'package:rasadyar_app/infrastructure/di/di.dart';
+import 'package:rasadyar_app/presentation/common/app_color.dart';
+import 'package:rasadyar_app/presentation/common/app_fonts.dart';
+import 'package:rasadyar_app/presentation/common/assets.dart';
+import 'package:rasadyar_app/presentation/widget/buttons/elevated.dart';
+import 'package:rasadyar_app/presentation/widget/captcha/captcha_widget.dart';
+import 'package:rasadyar_app/presentation/widget/vec_widget.dart';
+
+import 'logic.dart';
+
+class AuthWithUseAndPassPage extends GetView {
+ AuthWithUseAndPassPage({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final AuthWithUseAndPassLogic logic = Get.put(AuthWithUseAndPassLogic());
+ return Scaffold(
+ body: SingleChildScrollView(
+ child: Column(
+ children: [SizedBox(height: 80), logoWidget(), loginForm()],
+ ),
+ ),
+ );
+ }
+
+ Widget loginForm() {
+ return ObxValue((data) {
+ return Padding(
+ padding: EdgeInsets.symmetric(horizontal: 30, vertical: 50),
+ child: Form(
+ key: data.value,
+ child: Column(
+ children: [
+ ObxValue((phoneController) {
+ return TextFormField(
+ controller: controller.phoneNumberController.value,
+ decoration: InputDecoration(
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ gapPadding: 11,
+ ),
+ labelText: 'شماره موبایل',
+ labelStyle: AppFonts.yekan13Regular,
+ errorStyle: AppFonts.yekan13Regular.copyWith(
+ color: AppColor.redNormal,
+ ),
+
+ prefixIconConstraints: BoxConstraints(
+ maxHeight: 40,
+ minHeight: 40,
+ maxWidth: 40,
+ minWidth: 40,
+ ),
+ prefixIcon: Padding(
+ padding: const EdgeInsets.fromLTRB(0, 8, 6, 8),
+ child: vecWidget(Assets.vecCallSvg),
+ ),
+ suffix:
+ phoneController.value.text.trim().isNotEmpty
+ ? clearButton(() {
+ phoneController.value.clear();
+ phoneController.refresh();
+ })
+ : null,
+ counterText: '',
+ ),
+ keyboardType: TextInputType.numberWithOptions(
+ decimal: false,
+ signed: false,
+ ),
+
+ maxLines: 1,
+ maxLength: 11,
+ onChanged: (value) {
+ if (controller.isOnError.value) {
+ controller.isOnError.value = !controller.isOnError.value;
+ data.value.currentState?.reset();
+ data.refresh();
+ phoneController.value.text = value;
+ }
+ phoneController.refresh();
+ },
+ textInputAction: TextInputAction.next,
+ validator: (value) {
+ if (value == null) {
+ return '⚠️ شماره موبایل را وارد کنید';
+ } else if (value.length < 11) {
+ return '⚠️ شماره موبایل باید 11 رقم باشد';
+ }
+ return null;
+ },
+ style: AppFonts.yekan13Regular,
+ );
+ }, controller.phoneNumberController),
+
+ SizedBox(height: 26),
+
+ ObxValue((passwordController) {
+ return TextFormField(
+ controller: passwordController.value,
+ obscureText: controller.hidePassword.value,
+ decoration: InputDecoration(
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ gapPadding: 11,
+ ),
+ labelText: 'رمز عبور',
+ labelStyle: AppFonts.yekan13Regular,
+ errorStyle: AppFonts.yekan13Regular.copyWith(
+ color: AppColor.redNormal,
+ ),
+
+ prefixIconConstraints: BoxConstraints(
+ maxHeight: 34,
+ minHeight: 34,
+ maxWidth: 34,
+ minWidth: 34,
+ ),
+ prefixIcon: Padding(
+ padding: const EdgeInsets.fromLTRB(0, 8, 8, 8),
+ child: vecWidget(Assets.vecKeySvg),
+ ),
+ suffix:
+ passwordController.value.text.trim().isNotEmpty
+ ? GestureDetector(
+ onTap: () {
+ controller.hidePassword.value =
+ !controller.hidePassword.value;
+ },
+ child: Icon(
+ controller.hidePassword.value
+ ? CupertinoIcons.eye
+ : CupertinoIcons.eye_slash,
+ ),
+ )
+ : null,
+ counterText: '',
+ ),
+ textInputAction: TextInputAction.done,
+ keyboardType: TextInputType.visiblePassword,
+ maxLines: 1,
+ onChanged: (value) {
+ if (controller.isOnError.value) {
+ controller.isOnError.value = !controller.isOnError.value;
+ data.value.currentState?.reset();
+ passwordController.value.text = value;
+ }
+ passwordController.refresh();
+ },
+ validator: (value) {
+ if (value == null || value.isEmpty) {
+ return '⚠️ رمز عبور را وارد کنید'; // "Please enter the password"
+ }
+ return null;
+ },
+ style: AppFonts.yekan13Regular,
+ );
+ }, controller.passwordController),
+
+ SizedBox(height: 26),
+
+ CaptchaWidget(controller: controller.captchaController),
+
+ SizedBox(height: 23),
+ RElevated(
+ text: 'ورود',
+ onPressed: () {
+ di.get().t(data.value.currentState?.validate());
+ di.get().t(controller.captchaController.validate());
+ if (data.value.currentState?.validate() == true &&
+ controller.captchaController.validate()) {
+ print("==============>ssakldjaskljdklasjd");
+ }
+ },
+ width: Get.width,
+ height: 48,
+ ),
+ ],
+ ),
+ ),
+ );
+ }, controller.formKey);
+ }
+
+ Widget logoWidget() {
+ return Column(
+ children: [
+ Row(),
+ Image.asset(Assets.imagesInnerSplash, width: 120, height: 120),
+ Text(
+ 'سامانه رصدیار',
+ style: AppFonts.yekan16Regular.copyWith(
+ color: AppColor.darkGreyNormal,
+ ),
+ ),
+ ],
+ );
+ }
+
+ Widget clearButton(VoidCallback onTap) {
+ return GestureDetector(
+ onTap: onTap,
+ child: Icon(CupertinoIcons.multiply_circle, size: 24),
+ );
+ }
+}
diff --git a/lib/presentation/pages/splash/logic.dart b/lib/presentation/pages/splash/logic.dart
new file mode 100644
index 0000000..d34910b
--- /dev/null
+++ b/lib/presentation/pages/splash/logic.dart
@@ -0,0 +1,67 @@
+import 'package:flutter/animation.dart';
+import 'package:get/get.dart';
+import 'package:rasadyar_app/presentation/routes/app_pages.dart';
+
+class SplashLogic extends GetxController with GetTickerProviderStateMixin {
+ late final AnimationController scaleController;
+ late final AnimationController rotateController;
+ Rxn> scaleAnimation = Rxn();
+ Rxn> 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(
+ begin: 0.8,
+ end: 1.2,
+ ).animate(scaleController);
+
+ rotationAnimation.value = Tween(
+ 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(AppPaths.authWithUserAndPass);
+ });
+ }
+
+ @override
+ void onClose() {
+ rotateController.dispose();
+ scaleController.dispose();
+ super.onClose();
+ }
+}
diff --git a/lib/presentation/pages/splash/view.dart b/lib/presentation/pages/splash/view.dart
new file mode 100644
index 0000000..75f37c3
--- /dev/null
+++ b/lib/presentation/pages/splash/view.dart
@@ -0,0 +1,48 @@
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+import 'package:rasadyar_app/presentation/common/app_color.dart';
+import 'package:rasadyar_app/presentation/common/assets.dart';
+
+import 'logic.dart';
+
+class SplashPage extends GetView {
+ 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),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/pages/system_design/system_design.dart b/lib/presentation/pages/system_design/system_design.dart
new file mode 100644
index 0000000..51ebace
--- /dev/null
+++ b/lib/presentation/pages/system_design/system_design.dart
@@ -0,0 +1,265 @@
+import 'package:flutter/material.dart';
+import 'package:rasadyar_app/presentation/common/app_color.dart';
+import 'package:rasadyar_app/presentation/common/app_fonts.dart';
+import 'package:rasadyar_app/presentation/utils/color_utils.dart';
+import 'package:rasadyar_app/presentation/widget/buttons/elevated.dart';
+import 'package:rasadyar_app/presentation/widget/buttons/fab.dart';
+import 'package:rasadyar_app/presentation/widget/buttons/fab_outlined.dart';
+import 'package:rasadyar_app/presentation/widget/buttons/outline_elevated.dart';
+import 'package:rasadyar_app/presentation/widget/buttons/text_button.dart';
+import 'package:rasadyar_app/presentation/widget/inputs/r_input.dart';
+import 'package:rasadyar_app/presentation/widget/pagination/pagination_from_until.dart';
+import 'package:rasadyar_app/presentation/widget/pagination/show_more.dart';
+import 'package:rasadyar_app/presentation/widget/tabs/tab.dart';
+
+class SystemDesignPage extends StatefulWidget {
+ const SystemDesignPage({super.key});
+
+ @override
+ State createState() => _SystemDesignPageState();
+}
+
+class _SystemDesignPageState extends State {
+ List _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.yekan20Regular.copyWith(color: Colors.red),
+ ),
+ );
+ },
+ body: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: Column(
+ spacing: 14,
+ children: [
+ RTextField(
+ hintText: 'حجم کشتار را در روز به قطعه وارد کنید',
+ hintStyle: AppFonts.yekan13Regular,
+ ),
+ RTextField(
+ label: 'تلفن مرغداری',
+ labelStyle: AppFonts.yekan10Regular,
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+ ExpansionPanel tabWidget() {
+ return ExpansionPanel(
+ isExpanded: _isOpen[4],
+ headerBuilder: (context, isExpanded) {
+ return ListTile(
+ title: Text(
+ "tab",
+ style: AppFonts.yekan20Regular.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.yekan20Regular.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.yekan20Regular.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.yekan20Regular.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.yekan20Regular.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),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/presentation/routes/app_pages.dart b/lib/presentation/routes/app_pages.dart
new file mode 100644
index 0000000..9faa5bf
--- /dev/null
+++ b/lib/presentation/routes/app_pages.dart
@@ -0,0 +1,33 @@
+import 'package:get/get.dart';
+import 'package:rasadyar_app/presentation/pages/auth/auth_with_otp/logic.dart';
+import 'package:rasadyar_app/presentation/pages/auth/auth_with_otp/view.dart';
+import 'package:rasadyar_app/presentation/pages/auth/auth_with_use_and_pass/logic.dart';
+import 'package:rasadyar_app/presentation/pages/auth/auth_with_use_and_pass/view.dart';
+import 'package:rasadyar_app/presentation/pages/splash/logic.dart';
+import 'package:rasadyar_app/presentation/pages/splash/view.dart';
+
+part 'app_paths.dart';
+
+sealed class AppPages {
+ AppPages._();
+
+ static const String initRoutes = AppPaths.splash;
+
+ static List pages = [
+ GetPage(
+ name: AppPaths.splash,
+ page: () => SplashPage(),
+ binding: BindingsBuilder.put(() => SplashLogic()),
+ ),
+ GetPage(
+ name: AppPaths.authWithOtp,
+ page: () => AuthWithOtpPage(),
+ binding: BindingsBuilder.put(() => AuthWithOtpLogic()),
+ ),
+ GetPage(
+ name: AppPaths.authWithUserAndPass,
+ page: () => AuthWithUseAndPassPage(),
+ binding: BindingsBuilder.put(() => AuthWithUseAndPassLogic()),
+ ),
+ ];
+}
diff --git a/lib/presentation/routes/app_paths.dart b/lib/presentation/routes/app_paths.dart
new file mode 100644
index 0000000..dd68834
--- /dev/null
+++ b/lib/presentation/routes/app_paths.dart
@@ -0,0 +1,9 @@
+part of 'app_pages.dart';
+
+sealed class AppPaths {
+ AppPaths._();
+
+ static const String splash = '/splash';
+ static const String authWithUserAndPass = '/authWithUserAndPass';
+ static const String authWithOtp = '/authWithOtp';
+}
diff --git a/lib/presentation/widget/buttons/elevated.dart b/lib/presentation/widget/buttons/elevated.dart
index c03bc2e..f97ecfc 100644
--- a/lib/presentation/widget/buttons/elevated.dart
+++ b/lib/presentation/widget/buttons/elevated.dart
@@ -36,9 +36,7 @@ class _RElevatedState extends State {
@override
Widget build(BuildContext context) {
return ElevatedButton(
- onPressed: () {
- setState(() {});
- },
+ onPressed: widget.onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: widget.backgroundColor ?? AppColor.blueNormal,
foregroundColor: widget.foregroundColor ?? Colors.white,
diff --git a/lib/presentation/widget/captcha/captcha_widget.dart b/lib/presentation/widget/captcha/captcha_widget.dart
new file mode 100644
index 0000000..fb25167
--- /dev/null
+++ b/lib/presentation/widget/captcha/captcha_widget.dart
@@ -0,0 +1,266 @@
+import 'dart:math';
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:rasadyar_app/presentation/common/app_color.dart';
+import 'package:rasadyar_app/presentation/common/app_fonts.dart';
+
+class CaptchaController {
+ int? captchaCode;
+ TextEditingController textController = TextEditingController();
+ GlobalKey formKey = GlobalKey();
+
+ late Function() refreshCaptcha;
+
+ bool validate() {
+ if (formKey.currentState?.validate() == true) {
+ return true;
+ }
+ return false;
+ }
+
+ String get enteredText => textController.text;
+
+ bool isCorrect() {
+ return textController.text == captchaCode.toString();
+ }
+
+ void clear() {
+ textController.clear();
+ }
+}
+
+class RandomLinePainter extends CustomPainter {
+ final Random random = Random();
+ final Paint linePaint;
+ final List points;
+
+ RandomLinePainter({
+ required this.points,
+ required Color lineColor,
+ double strokeWidth = 2.0,
+ }) : linePaint =
+ Paint()
+ ..color = lineColor
+ ..strokeWidth = strokeWidth
+ ..strokeCap = StrokeCap.round
+ ..style = PaintingStyle.stroke;
+
+ @override
+ void paint(Canvas canvas, Size size) {
+ final path = Path();
+
+ if (points.isNotEmpty) {
+ path.moveTo(points[0].dx, points[0].dy);
+
+ for (int i = 1; i < points.length; i++) {
+ path.lineTo(points[i].dx, points[i].dy);
+ }
+
+ canvas.drawPath(path, linePaint);
+ }
+ }
+
+ @override
+ bool shouldRepaint(RandomLinePainter oldDelegate) => true;
+}
+
+class CaptchaWidget extends StatefulWidget {
+ final CaptchaController controller;
+ final bool autoValidateMode;
+
+ const CaptchaWidget({
+ required this.controller,
+ this.autoValidateMode = false,
+ super.key,
+ });
+
+ @override
+ _CaptchaWidgetState createState() => _CaptchaWidgetState();
+}
+
+class _CaptchaWidgetState extends State {
+ late List points;
+ late List points1;
+ late List points2;
+ bool isOnError = false;
+
+ @override
+ void initState() {
+ super.initState();
+ generateLines();
+ getRandomSixDigitNumber();
+
+ // Set the refresh function in the controller
+ widget.controller.refreshCaptcha = () {
+ getRandomSixDigitNumber();
+ generateLines();
+ setState(() {});
+ };
+ }
+
+ void generateLines() {
+ points = generateRandomLine();
+ points1 = generateRandomLine();
+ points2 = generateRandomLine();
+ setState(() {});
+ }
+
+ List generateRandomLine() {
+ final random = Random();
+ int pointCount = random.nextInt(10) + 5;
+ List points = [];
+
+ double previousY = 0;
+
+ for (int i = 0; i < pointCount; i++) {
+ double x = (i / (pointCount - 1)) * 135;
+
+ if (i == 0) {
+ previousY = 24;
+ } else {
+ double change = (random.nextDouble() * 20) - 10;
+ previousY = max(5, min(43, previousY + change));
+ }
+
+ points.add(Offset(x, previousY));
+ }
+
+ return points;
+ }
+
+ void getRandomSixDigitNumber() {
+ final random = Random();
+ widget.controller.captchaCode = random.nextInt(900000) + 100000;
+ setState(() {});
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ width: 135,
+ height: 48,
+ decoration: BoxDecoration(
+ color: AppColor.whiteNormalHover,
+ border: Border.all(color: Colors.grey.shade300),
+ borderRadius: BorderRadius.circular(8),
+ ),
+ child: Stack(
+ alignment: AlignmentDirectional.center,
+ children: [
+ CustomPaint(
+ painter: RandomLinePainter(
+ points: points,
+ lineColor: Colors.blue,
+ strokeWidth: 1.0,
+ ),
+ size: const Size(double.infinity, double.infinity),
+ ),
+ CustomPaint(
+ painter: RandomLinePainter(
+ points: points1,
+ lineColor: Colors.green,
+ strokeWidth: 1.0,
+ ),
+ size: const Size(double.infinity, double.infinity),
+ ),
+ CustomPaint(
+ painter: RandomLinePainter(
+ points: points2,
+ lineColor: Colors.red,
+ strokeWidth: 1.0,
+ ),
+ size: const Size(double.infinity, double.infinity),
+ ),
+ Text(
+ widget.controller.captchaCode.toString(),
+ style: AppFonts.yekan24Regular,
+ ),
+ ],
+ ),
+ ),
+ const SizedBox(height: 20),
+ IconButton(
+ padding: EdgeInsets.zero,
+ onPressed: widget.controller.refreshCaptcha,
+ icon: Icon(CupertinoIcons.refresh, size: 16),
+ ),
+ Expanded(
+ child: Form(
+ key: widget.controller.formKey,
+ autovalidateMode:
+ widget.autoValidateMode
+ ? AutovalidateMode.onUserInteraction
+ : AutovalidateMode.disabled,
+ child: TextFormField(
+ controller: widget.controller.textController,
+ decoration: InputDecoration(
+ border: OutlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ gapPadding: 11,
+ ),
+ labelText: 'کد امنیتی',
+ labelStyle: AppFonts.yekan13Regular,
+ errorStyle: AppFonts.yekan10Regular.copyWith(
+ color: AppColor.redNormal,
+ fontSize: 8,
+ ),
+ suffixIconConstraints: BoxConstraints(
+ maxHeight: 24,
+ minHeight: 24,
+ maxWidth: 24,
+ minWidth: 24,
+ ),
+
+ suffix:
+ widget.controller.textController.text.trim().isNotEmpty
+ ? clearButton(() {
+ widget.controller.textController.clear();
+ setState(() {});
+ })
+ : null,
+ counterText: '',
+ ),
+ keyboardType: TextInputType.numberWithOptions(
+ decimal: false,
+ signed: false,
+ ),
+ maxLines: 1,
+ maxLength: 6,
+ onChanged: (value) {
+ if (isOnError) {
+ isOnError = !isOnError;
+ widget.controller.formKey.currentState?.reset();
+ widget.controller.textController.text = value;
+ }
+ setState(() {});
+ },
+ validator: (value) {
+ if (value == null || value.isEmpty) {
+ isOnError = true;
+ return 'کد امنیتی را وارد کنید';
+ }
+ if (value != widget.controller.captchaCode.toString()) {
+ isOnError = true;
+ return '⚠️کد امنیتی وارد شده اشتباه است';
+ }
+ return null;
+ },
+ style: AppFonts.yekan13Regular,
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+
+ Widget clearButton(VoidCallback onTap) {
+ return GestureDetector(
+ onTap: onTap,
+ child: Icon(CupertinoIcons.multiply_circle, size: 18),
+ );
+ }
+}
diff --git a/lib/presentation/widget/vec_widget.dart b/lib/presentation/widget/vec_widget.dart
index 8f76b40..3fb78f1 100644
--- a/lib/presentation/widget/vec_widget.dart
+++ b/lib/presentation/widget/vec_widget.dart
@@ -18,6 +18,25 @@ SvgPicture vecWidget(
color != null ? ColorFilter.mode(color, BlendMode.srcIn) : null,
);
}
+
+SvgPicture svgWidget(
+ String assets, {
+ double? width,
+ double? height,
+ BoxFit? fit,
+ Color? color,
+ }) {
+ return SvgPicture.asset(
+ assets,
+ width: width,
+ height: height,
+ fit: fit ?? BoxFit.contain,
+ colorFilter:
+ color != null ? ColorFilter.mode(color, BlendMode.srcIn) : null,
+ );
+}
+
+
Widget vecWidget2(
String assets, {
double? width,
diff --git a/pubspec.lock b/pubspec.lock
index 454e494..f6fe18f 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -21,10 +21,10 @@ packages:
dependency: transitive
description:
name: args
- sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
+ sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
- version: "2.6.0"
+ version: "2.7.0"
async:
dependency: transitive
description:
@@ -247,10 +247,10 @@ packages:
dependency: "direct dev"
description:
name: freezed
- sha256: a6274c34d61b3d68082f2b0e9a641a3ec197e525d269f35b82f62d5b2c6d9f75
+ sha256: "6022db4c7bfa626841b2a10f34dd1e1b68e8f8f9650db6112dcdeeca45ca793c"
url: "https://pub.dev"
source: hosted
- version: "3.0.3"
+ version: "3.0.6"
freezed_annotation:
dependency: "direct main"
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 52bb4ec..e3a7258 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -54,7 +54,6 @@ dev_dependencies:
-
flutter:
uses-material-design: true
diff --git a/runner.sh b/runner.sh
new file mode 100644
index 0000000..e0b9992
--- /dev/null
+++ b/runner.sh
@@ -0,0 +1 @@
+dart run build_runner build --delete-conflicting-outputs
\ No newline at end of file