diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 6770a3b..eb0c9de 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -500,8 +500,8 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
- DEVELOPMENT_TEAM = FE8CDVE4RJ;
+ CURRENT_PROJECT_VERSION = 4;
+ DEVELOPMENT_TEAM = GQA553X9YL;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -687,8 +687,8 @@
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
- DEVELOPMENT_TEAM = FE8CDVE4RJ;
+ CURRENT_PROJECT_VERSION = 4;
+ DEVELOPMENT_TEAM = GQA553X9YL;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -714,8 +714,8 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
- DEVELOPMENT_TEAM = FE8CDVE4RJ;
+ CURRENT_PROJECT_VERSION = 4;
+ DEVELOPMENT_TEAM = GQA553X9YL;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 1f7a941..3e71998 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -19,11 +19,11 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- $(FLUTTER_BUILD_NAME)
+ 2.0.0
CFBundleSignature
????
CFBundleVersion
- $(FLUTTER_BUILD_NUMBER)
+ 1
LSRequiresIPhoneOS
NSAppTransportSecurity
diff --git a/lib/config/network_config.dart b/lib/config/network_config.dart
index cdc117a..5e0b74e 100644
--- a/lib/config/network_config.dart
+++ b/lib/config/network_config.dart
@@ -1,4 +1,5 @@
class NetworkConfig {
final baseUrl = 'https://api.nghsco.com/api/';
+ final imageUrl = 'https://api.nghsco.com/storage/statics/';
const NetworkConfig();
}
diff --git a/lib/drawer_navigation_bar.dart b/lib/drawer_navigation_bar.dart
index 7ac0b1a..b499d58 100644
--- a/lib/drawer_navigation_bar.dart
+++ b/lib/drawer_navigation_bar.dart
@@ -6,6 +6,7 @@ import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:qadirneyriz/config/config.dart';
+import 'package:qadirneyriz/global/global_state/global_state.dart';
import 'package:qadirneyriz/screens/aboutUs/screen.dart';
import 'package:qadirneyriz/screens/auth/state/state.dart';
import 'package:qadirneyriz/screens/change_pass/screen.dart';
@@ -17,6 +18,8 @@ import 'package:qadirneyriz/screens/private_meeting/screen.dart';
import 'package:qadirneyriz/screens/report/screen.dart';
import 'package:qadirneyriz/setting/setting.dart';
+import 'package:qadirneyriz/utils/enums/status.dart';
+import 'package:qadirneyriz/widgets/custom_netimage.dart';
class CustomDrawerNavigation extends StatefulWidget {
final int activeTab;
@@ -33,6 +36,7 @@ class _CustomDrawerNavigationState extends State {
final String language = setting.userLocalDb.getUser().language;
String? selectedLanguage; // زبان پیشفرض فارسی
late AuthState state;
+
@override
void initState() {
super.initState();
@@ -66,8 +70,17 @@ class _CustomDrawerNavigationState extends State {
final userRole = setting.userLocalDb.getUser().role;
return Scaffold(
// backgroundColor: Colors.green.withOpacity(.2),
- drawer: Consumer(
- builder: (context, value, child) {
+ drawer: Consumer2(
+ builder: (context, authState, globalState, child) {
+ final String image = globalState.logoImagesStatus == Status.ready
+ ? globalState.logoImagesModel!.data!
+ .firstWhere(
+ (element) => element.key == 'logo',
+ )
+ .value ??
+ ''
+ : '';
+ final String ImageUrl = '${config.network.imageUrl}${image}';
return Drawer(
backgroundColor: config.ui.backGroundColor,
child: SingleChildScrollView(
@@ -75,13 +88,14 @@ class _CustomDrawerNavigationState extends State {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: 10, vertical: 35),
- child: Image.asset(
- 'assets/images/D2.png', // مسیر لوگوی شما
- height: 60,
- ),
- ),
+ padding: const EdgeInsets.symmetric(
+ horizontal: 10, vertical: 35),
+ child: CustomImage(
+ logo: true,
+ width: 80,
+ height: 80,
+ image: ImageUrl,
+ )),
if (userRole == 0 || userRole == 2)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
@@ -174,10 +188,10 @@ class _CustomDrawerNavigationState extends State {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildLanguageButton('fa', 'فارسی', () {
- value.setLocale('fa');
+ authState.setLocale('fa');
}),
_buildLanguageButton('en', 'English', () {
- value.setLocale('en');
+ authState.setLocale('en');
}),
],
),
diff --git a/lib/global/global_state/global_state.dart b/lib/global/global_state/global_state.dart
index 73a0ff1..688edca 100644
--- a/lib/global/global_state/global_state.dart
+++ b/lib/global/global_state/global_state.dart
@@ -1,13 +1,57 @@
import 'package:flutter/material.dart';
+import 'package:qadirneyriz/models/logo_images_model.dart';
import 'package:qadirneyriz/models/meetings/meetings_location_model.dart';
import 'package:qadirneyriz/models/meetings/meetings_managers_model.dart';
import 'package:qadirneyriz/models/meetings/meetings_subjects_model.dart';
import 'package:qadirneyriz/models/meetings/meetings_users_model.dart';
-import 'package:qadirneyriz/screens/meeting/diolog_meetings_filters.dart';
import 'package:qadirneyriz/setting/setting.dart';
import 'package:qadirneyriz/utils/enums/status.dart';
class GlobalState extends ChangeNotifier {
+ // users meetings
+ Status logoImagesStatus = Status.empty;
+ LogoImagesModel? logoImagesModel;
+ Future getLogoImages({bool refresh = false}) async {
+ logoImagesStatus = Status.loading;
+ notifyListeners();
+ if (refresh) {
+ logoImagesStatus = Status.loading;
+ notifyListeners();
+ }
+
+ if (logoImagesModel != null ) {
+ logoImagesStatus = Status.ready;
+ try {
+ logoImagesModel = await setting.globalServices.getLogoImagesApi();
+ if (logoImagesModel != null) {
+ logoImagesStatus = Status.ready;
+ } else {
+ logoImagesStatus = Status.empty;
+ }
+ } catch (e) {
+ logoImagesStatus = Status.error;
+ // print('$e error usersModel');
+ }
+ notifyListeners();
+ } else {
+ try {
+ logoImagesModel = await setting.globalServices.getLogoImagesApi();
+ if (logoImagesModel != null) {
+ logoImagesStatus = Status.ready;
+ } else {
+ logoImagesStatus = Status.empty;
+ }
+ notifyListeners();
+ } catch (e) {
+ logoImagesStatus = Status.error;
+ print('$e error ');
+ }
+ }
+ notifyListeners();
+ print('$logoImagesStatus logoImagesStatus');
+ return logoImagesStatus;
+ }
+
// users meetings
Status usersStatus = Status.empty;
List? usersModel;
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
index 57ea574..0c7d9fe 100644
--- a/lib/l10n/app_en.arb
+++ b/lib/l10n/app_en.arb
@@ -116,6 +116,18 @@
"accepted":"Accepted",
"files":"Files",
"acceptoperetion":"Accept Operetion",
+ "doneprivatemeetings": "Completed private meetings",
+ "adjournedprivatemeetings": "Postponed private meetings",
+ "canceldprivatemeetings": "Canceled private meetings",
+ "privatemeetingswaitingtobeheld": "Private meetings waiting to be held",
+ "privatemeetingmanager": "Private meeting manager",
+ "download": "Download",
+ "downloadPdf":"Download pdf",
+ "downloadxlsx":"Download xlsx",
+ "deletemeeting":"Delete meeting",
+ "meetingdeleted":"Meeting Deleted!",
+ "deleteprivatemeeting":"Delete privatemeeting",
+ "privatemeetingdeleted":"Privatemeeting Deleted",
"areusuretodeletfile": "Are you sure you want to delete this file?",
"changepass":"Change Password",
"profile":"User Account", "doyouredit":"You must make at least one change",
@@ -124,5 +136,6 @@
"deleteaccount": "Delete Account",
"suretodelelteaccount": "Are you sure you want to delete your account?",
"actioncantundo": "This action cannot be undone!",
+
"textaboutus":"The Mizban meeting and appointment management software has been designed and developed with the aim of facilitating and optimizing the processes of organizing organizational and personal meetings under the leadership of Dr. Mohsen Mostafapour. This innovative and user-centric software serves as an efficient tool to enhance coordination and realize the motto **The Codeword of Empathy** within the esteemed **Foulad Ghadir Neyriz** organization. The Mizban project was initiated and launched with the invaluable support and backing of the esteemed CEO, Dr. Mohsen Mostafapour, representing a significant step forward in the organization's path toward growth and excellence."
}
diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb
index 2c2d1cd..42ee3d8 100644
--- a/lib/l10n/app_fa.arb
+++ b/lib/l10n/app_fa.arb
@@ -20,7 +20,7 @@
"meetings":"جلسات",
"events":"ملاقات ها",
"exit":"خروج",
- "nomeetingfortoday":"برای امروز جلسه ایی تعریف نشده است.",
+ "nomeetingfortoday":"برای امروز جلسه ای تعریف نشده است.",
"todaymeetings":"جلسه های امروز",
"empty":"داده ایی وجود ندارد.",
"back":"بازگشست",
@@ -29,11 +29,28 @@
"location":"مکان",
"meetingmanager":"مدیر جلسه",
"subject":"موضوع",
+
+
"donemeetings":"جلسات برگذار شده",
"adjournedmeetings":"جلسات موکول شده",
"canceldmeetings":"جلسات لغو شده",
"meetingswaitingtobeheld":"جلسات منتظر برگذاری",
+
+ "doneprivatemeetings":"ملاقاتهای برگذار شده",
+ "adjournedprivatemeetings":"ملاقاتهای موکول شده",
+ "canceldprivatemeetings":"ملاقاتهای لغو شده",
+ "privatemeetingswaitingtobeheld":"ملاقاتهای منتظر برگذاری",
+ "privatemeetingmanager":"مدیر جلسه",
+ "download":"دانلود",
+
+ "downloadPdf":"دانلود pdf",
+ "downloadxlsx":"دانلود اکسل",
+ "deletemeeting":"حذف جلسه",
+ "meetingdeleted":"جلسه حذف شد!",
+ "deleteprivatemeeting":"حذف ملاقات",
+ "privatemeetingdeleted":"ملاقات حذف شد!",
"selectdate":"انتخاب تاریخ",
+
"editmeeting":"ویرایش جلسه",
"meetingsubject":"موضوع جلسه",
"clock":"ساعت",
diff --git a/lib/main.dart b/lib/main.dart
index af29a7d..e54ae84 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -24,42 +24,6 @@ Future initializeApp() async {
options: DefaultFirebaseOptions.currentPlatform,
);
await setting.userLocalDb.openBox();
-
- // اجرای Firebase و تنظیمات نوتیفیکیشن فقط در اندروید
-
- await requestNotificationPermission();
- await getToken();
- setupMessageListener();
-}
-
-Future requestNotificationPermission() async {
- NotificationSettings settings = await messaging.requestPermission(
- alert: true,
- announcement: false,
- badge: true,
- carPlay: false,
- criticalAlert: false,
- provisional: false,
- sound: true,
- );
-
- if (settings.authorizationStatus == AuthorizationStatus.authorized) {
- print('User granted permission');
- } else {
- print('User declined or has not granted permission');
- }
-}
-
-Future getToken() async {
- await messaging.getToken();
-}
-
-void setupMessageListener() {
- FirebaseMessaging.onMessage.listen((RemoteMessage message) {
- // print('Message received: ${message.notification?.title}');
- // print('Message body: ${message.notification?.body}');
- // You can use a Dialog or Toast to display the message here
- });
}
void main() async {
@@ -84,10 +48,10 @@ class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
- State createState() => _MyAppState();
+ State createState() => FiltersItemInPrivateMeetingsReport();
}
-class _MyAppState extends State {
+class FiltersItemInPrivateMeetingsReport extends State {
late AuthState state;
String language = setting.userLocalDb.getUser().language;
@@ -147,3 +111,5 @@ class _MyAppState extends State {
);
}
}
+
+
diff --git a/lib/models/logo_images_model.dart b/lib/models/logo_images_model.dart
new file mode 100644
index 0000000..4c8c8be
--- /dev/null
+++ b/lib/models/logo_images_model.dart
@@ -0,0 +1,49 @@
+// To parse this JSON data, do
+//
+// final logoImagesModel = logoImagesModelFromJson(jsonString);
+
+import 'dart:convert';
+
+LogoImagesModel logoImagesModelFromJson(String str) => LogoImagesModel.fromJson(json.decode(str));
+
+String logoImagesModelToJson(LogoImagesModel data) => json.encode(data.toJson());
+
+class LogoImagesModel {
+ final List? data;
+
+ LogoImagesModel({
+ this.data,
+ });
+
+ factory LogoImagesModel.fromJson(Map json) => LogoImagesModel(
+ data: json["data"] == null ? [] : List.from(json["data"]!.map((x) => Datum.fromJson(x))),
+ );
+
+ Map toJson() => {
+ "data": data == null ? [] : List.from(data!.map((x) => x.toJson())),
+ };
+}
+
+class Datum {
+ final int? id;
+ final String? key;
+ final String? value;
+
+ Datum({
+ this.id,
+ this.key,
+ this.value,
+ });
+
+ factory Datum.fromJson(Map json) => Datum(
+ id: json["id"],
+ key: json["key"],
+ value: json["value"],
+ );
+
+ Map toJson() => {
+ "id": id,
+ "key": key,
+ "value": value,
+ };
+}
diff --git a/lib/screens/aboutUs/screen.dart b/lib/screens/aboutUs/screen.dart
index e4099f8..4f3fd43 100644
--- a/lib/screens/aboutUs/screen.dart
+++ b/lib/screens/aboutUs/screen.dart
@@ -1,53 +1,129 @@
import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:qadirneyriz/config/config.dart';
+import 'package:qadirneyriz/global/global_state/global_state.dart';
+import 'package:qadirneyriz/setting/setting.dart';
+import 'package:qadirneyriz/utils/enums/status.dart';
import 'package:qadirneyriz/widgets/custom_appbar.dart';
-import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:qadirneyriz/widgets/custom_netimage.dart';
-class AboutUsScreen extends StatelessWidget {
+class AboutUsScreen extends StatefulWidget {
const AboutUsScreen({super.key});
+ @override
+ State createState() => _AboutUsScreenState();
+}
+
+class _AboutUsScreenState extends State {
+ // تابع کمکی برای گرفتن مقدار کلید از دادهها
+ String _getByKey(GlobalState globalState, String key) {
+ if (globalState.logoImagesStatus == Status.ready) {
+ return globalState.logoImagesModel?.data
+ ?.firstWhere((element) => element.key == key)
+ .value ??
+ '';
+ }
+ return '';
+ }
+
+ // تابع کمکی برای ساخت URL
+ String _buildImageUrl(String imagePath) {
+ return '${config.network.imageUrl}$imagePath';
+ }
+
@override
Widget build(BuildContext context) {
- return CustomScrollView(
- slivers: [
- const CustomAppbar(),
- SliverToBoxAdapter(
- child: Image.asset('assets/images/logomizban.png'),
- ),
- SliverToBoxAdapter(
- child: Column(
- children: [
- Padding(
- padding: const EdgeInsets.symmetric(horizontal: 20),
- child: Text(
- textAlign: TextAlign.justify,
- AppLocalizations.of(context)!.textaboutus,
- ),
- ),
- SizedBox(
- height: 10,
- ),
- Column(
- children: [
- Image.asset(
- 'assets/images/D2.png',
- width: 80,
- height: 80,
- ),
- SizedBox(
- height: 8,
- ),
- Text(
- 'نسخه 1.0.0',
- style: TextStyle(fontSize: 12),
+ return Consumer(
+ builder: (context, globalState, child) {
+ // گرفتن مقادیر مربوطه
+ final String textAboutUsFarsi =
+ _getByKey(globalState, 'about_us_description_fa');
+ final String textAboutUsEn =
+ _getByKey(globalState, 'about_us_description_en');
+ final String textAppVersrionFa =
+ _getByKey(globalState, 'app_version_fa');
+ final String textAppVersrionEn =
+ _getByKey(globalState, 'app_version_en');
+ final String aboutUsImage = _getByKey(globalState, 'about_us_image');
+ final String logoImage = _getByKey(globalState, 'logo');
+ final String aboutUsImageUrl = _buildImageUrl(aboutUsImage);
+ final String logoUrl = _buildImageUrl(logoImage);
+
+ // ساخت ویو بر اساس وضعیت
+ switch (globalState.logoImagesStatus) {
+ case Status.ready:
+ return CustomScrollView(
+ slivers: [
+ const CustomAppbar(),
+ SliverToBoxAdapter(
+ child: Column(
+ children: [
+ _buildImageSection(aboutUsImageUrl, 300, 300),
+ _buildAboutUsText(
+ context, textAboutUsFarsi, textAboutUsEn),
+ _buildFooter(
+ logoUrl, textAppVersrionEn, textAppVersrionFa),
+ ],
),
- SizedBox(
- height: 10,
- )
- ],
- )
- ],
+ ),
+ ],
+ );
+
+ default:
+ return const Center(child: CircularProgressIndicator());
+ }
+ },
+ );
+ }
+
+ // ویجت برای بخش تصویر
+ Widget _buildImageSection(String imageUrl, double width, double height) {
+ return Padding(
+ padding: const EdgeInsets.symmetric(vertical: 50),
+ child: CustomImage(
+ image: imageUrl,
+ logo: true,
+ width: width,
+ height: height,
+ boxFit: BoxFit.contain,
+ ),
+ );
+ }
+
+ // ویجت برای متن درباره ما
+ Widget _buildAboutUsText(BuildContext context, String textFa, textEn) {
+ final String lang = setting.userLocalDb.getUser().language;
+ return Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 20),
+ child: Text(
+ lang == 'en' ? textEn : textFa,
+ textAlign: TextAlign.justify,
+ ),
+ );
+ }
+
+ // ویجت برای بخش فوتر (لوگو و نسخه اپلیکیشن)
+ Widget _buildFooter(
+ String logoUrl, String textVersionEn, String textVersionFa) {
+ final String lang = setting.userLocalDb.getUser().language;
+ return Column(
+ children: [
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 10),
+ child: CustomImage(
+ image: logoUrl,
+ logo: true,
+ width: 80,
+ height: 80,
+ boxFit: BoxFit.contain,
),
- )
+ ),
+ const SizedBox(height: 8),
+ Text(
+ lang == 'en' ? textVersionEn : textVersionFa,
+ style: TextStyle(fontSize: 12),
+ ),
+ const SizedBox(height: 10),
],
);
}
diff --git a/lib/screens/auth/state/state.dart b/lib/screens/auth/state/state.dart
index c47e1f9..087093c 100644
--- a/lib/screens/auth/state/state.dart
+++ b/lib/screens/auth/state/state.dart
@@ -21,17 +21,20 @@ class AuthState extends ChangeNotifier {
String? messageLogin;
Map? errorsLogin;
- Future login(
- {required String mobile,
- String? password,
- String? otp,
+ Future login({
+ required String mobile,
+ String? password,
+ String? otp,
}) async {
assert(password != null || otp != null);
statusLogin = Status.loading;
notifyListeners();
try {
final result = await authServises.loginApi(
- mobile: mobile, password: password, otp: otp, );
+ mobile: mobile,
+ password: password,
+ otp: otp,
+ );
if (result == null) {
statusLogin = Status.error;
} else {
@@ -91,4 +94,41 @@ class AuthState extends ChangeNotifier {
// print(statusSendotp);
return statusSendotp;
}
+
+// check login
+
+ Status statusCheckLogin = Status.empty;
+ String? messageCheckLogin;
+ Map? errorsCheckLogin;
+ Future CheckLogin() async {
+ statusCheckLogin = Status.loading;
+ notifyListeners();
+ try {
+ final result = await authServises.checkLoginApi();
+ if (result == null) {
+ statusCheckLogin = Status.error;
+ } else {
+ // print(result);
+ if (result.isOk) {
+ statusCheckLogin = Status.ready;
+ messageCheckLogin = result.message;
+ } else if (result.isOk == false) {
+ errorsCheckLogin = result.errors;
+ messageCheckLogin = result.message;
+ statusCheckLogin = Status.error;
+ } else {
+ statusCheckLogin = Status.error;
+ }
+ notifyListeners();
+ }
+ notifyListeners();
+ } catch (e) {
+ statusCheckLogin = Status.error;
+ // print(e);
+ }
+ notifyListeners();
+ // print(statusCheckLogin);
+ return statusCheckLogin;
+ }
+
}
diff --git a/lib/screens/home/screen.dart b/lib/screens/home/screen.dart
index a7b1775..8743b11 100644
--- a/lib/screens/home/screen.dart
+++ b/lib/screens/home/screen.dart
@@ -4,6 +4,7 @@ import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
+import 'package:qadirneyriz/global/global_state/global_state.dart';
import 'package:qadirneyriz/setting/setting.dart';
import 'package:qadirneyriz/utils/tools/tools.dart';
import 'package:qadirneyriz/widgets/card_meeting.dart';
@@ -44,17 +45,17 @@ class _HomeScreenState extends State {
String dateJalali = Tools.convertToPersianDigits(
'${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}');
- return Consumer(
- builder: (context, value, child) {
- switch (value.todayMettingsStatus) {
+ return Consumer2(
+ builder: (context, homeState, globalState, child) {
+ switch (homeState.todayMettingsStatus) {
case Status.ready:
return RefreshIndicator(
onRefresh: () async {
- await value.getTodayMeetings();
+ await homeState.getTodayMeetings();
},
child: CustomScrollView(
slivers: [
- const CustomAppbar(),
+ CustomAppbar(),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(
@@ -86,7 +87,7 @@ class _HomeScreenState extends State {
Expanded(
child: Text(
style: const TextStyle(fontSize: 13),
- value.todayMeetingsModel!.note ?? ''),
+ homeState.todayMeetingsModel!.note ?? ''),
),
],
),
@@ -104,24 +105,25 @@ class _HomeScreenState extends State {
SliverToBoxAdapter(
child: SizedBox(
height: 170,
- child: value.todayMeetingsModel!.meetings!.isNotEmpty ||
- value.todayMeetingsModel!.privateMeetings!
+ child: homeState
+ .todayMeetingsModel!.meetings!.isNotEmpty ||
+ homeState.todayMeetingsModel!.privateMeetings!
.isNotEmpty
? ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
- itemCount:
- value.todayMeetingsModel!.meetings!.length +
- value.todayMeetingsModel!.privateMeetings!
- .length,
+ itemCount: homeState
+ .todayMeetingsModel!.meetings!.length +
+ homeState.todayMeetingsModel!.privateMeetings!
+ .length,
itemBuilder: (BuildContext context, int index) {
// ترکیب دو لیست
- final meetingsLength =
- value.todayMeetingsModel!.meetings!.length;
+ final meetingsLength = homeState
+ .todayMeetingsModel!.meetings!.length;
if (index < meetingsLength) {
// آیتم از لیست `meetings`
- final meeting = value
+ final meeting = homeState
.todayMeetingsModel!.meetings![index];
return Padding(
padding: const EdgeInsets.only(
@@ -173,7 +175,7 @@ class _HomeScreenState extends State {
));
} else {
// آیتم از لیست `privateMeetings`
- final privateMeeting = value
+ final privateMeeting = homeState
.todayMeetingsModel!
.privateMeetings![index - meetingsLength];
return Padding(
@@ -381,7 +383,7 @@ class _HomeScreenState extends State {
case Status.error:
return CustomErrorWidget(
onPressed: () async {
- await value.getTodayMeetings(refresh: true);
+ await homeState.getTodayMeetings(refresh: true);
},
);
case Status.empty:
diff --git a/lib/screens/home/state.dart b/lib/screens/home/state.dart
index e7627a5..b67bce1 100644
--- a/lib/screens/home/state.dart
+++ b/lib/screens/home/state.dart
@@ -144,7 +144,7 @@ class HomeState extends ChangeNotifier {
// print(e);
}
notifyListeners();
- print(statusEditProfile);
+ // print(statusEditProfile);
return statusEditProfile;
}
}
diff --git a/lib/screens/meeting/screen.dart b/lib/screens/meeting/screen.dart
index 39fd824..d453fe9 100644
--- a/lib/screens/meeting/screen.dart
+++ b/lib/screens/meeting/screen.dart
@@ -176,6 +176,8 @@ class _MeetingsScreenState extends State {
acceptMeeting(state, context, items.id ?? -1);
case 'cancel':
cancelMeeting(state, context, items.id ?? -1);
+ case 'delete':
+ deleteMeeting(state, context, items.id ?? -1);
case 'report':
if (userRole == 1 && items.description != null) {
await context.pushNamed(
@@ -241,8 +243,7 @@ class _MeetingsScreenState extends State {
],
),
),
- if ((userRole == 0 || userRole == 2) &&
- items.accepted == 0)
+ if (userRole == 0 || userRole == 2)
PopupMenuItem(
enabled:
state.statusCancelMeeting != Status.loading,
@@ -279,6 +280,26 @@ class _MeetingsScreenState extends State {
],
),
),
+ if (userRole == 0 || userRole == 2)
+ PopupMenuItem(
+ enabled:
+ state.statusCancelMeeting != Status.loading,
+ value: 'delete',
+ child: Row(
+ children: [
+ Icon(
+ Icons.delete,
+ color: Colors.green,
+ size: 17,
+ ),
+ SizedBox(width: 8),
+ Text(
+ AppLocalizations.of(context)!.deletemeeting,
+ style: TextStyle(fontSize: 12),
+ ),
+ ],
+ ),
+ ),
]),
);
},
@@ -320,6 +341,25 @@ class _MeetingsScreenState extends State {
}
}
+ void deleteMeeting(
+ MeetingsState state, BuildContext context, int cardId) async {
+ final status = await state.deleteMeeting(id: cardId);
+ if (status == Status.ready) {
+ Tools.showCustomSnackBar(
+ text: AppLocalizations.of(context)!.meetingdeleted,
+ isError: false,
+ context,
+ );
+ await meetingsState.getMeetings();
+ } else {
+ Tools.showCustomSnackBar(
+ text: AppLocalizations.of(context)!.error,
+ isError: true,
+ context,
+ );
+ }
+ }
+
void acceptMeeting(
MeetingsState state, BuildContext context, int cardId) async {
final status = await state.acceptMeeting(id: cardId);
diff --git a/lib/screens/meeting/state.dart b/lib/screens/meeting/state.dart
index 27fa1f7..4ea3a75 100644
--- a/lib/screens/meeting/state.dart
+++ b/lib/screens/meeting/state.dart
@@ -258,6 +258,41 @@ class MeetingsState extends ChangeNotifier {
return statusCancelMeeting;
}
+// delete meeting
+ Status statusDeleteMeeting = Status.empty;
+ String? messageDeleteMeeting;
+ Map? errorsDeleteMeeting;
+
+ Future deleteMeeting({
+ required int id,
+ }) async {
+ statusDeleteMeeting = Status.loading;
+ notifyListeners();
+ try {
+ final result = await meetingsApi.deleteMeetingApi(
+ id: id,
+ );
+ if (result.isOk) {
+ statusDeleteMeeting = Status.ready;
+ messageDeleteMeeting = result.message;
+ } else if (result.isOk == false) {
+ print(result.isOk);
+ errorsDeleteMeeting = result.errors;
+ messageDeleteMeeting = result.message;
+ statusDeleteMeeting = Status.error;
+ } else {
+ statusDeleteMeeting = Status.error;
+ }
+ notifyListeners();
+ } catch (e) {
+ statusDeleteMeeting = Status.error;
+ // print(e);
+ }
+ notifyListeners();
+ // print(statusDeleteMeeting);
+ return statusDeleteMeeting;
+ }
+
// accept meeting
Status statusAcceptMeeting = Status.empty;
String? messageAcceptMeeting;
diff --git a/lib/screens/private_meeting/screen.dart b/lib/screens/private_meeting/screen.dart
index 2a3c107..ab17a72 100644
--- a/lib/screens/private_meeting/screen.dart
+++ b/lib/screens/private_meeting/screen.dart
@@ -181,7 +181,10 @@ class _PrivateMeetingsScreenState extends State {
'privatemeetinsammary',
extra: items, // `items` should be a Datum instance
);
-
+ case 'cancel':
+ cancelPrivateMeeting(state, context, items.id ?? -1);
+ case 'delete':
+ deletePrivateMeeting(state, context, items.id ?? -1);
default:
}
},
@@ -221,6 +224,42 @@ class _PrivateMeetingsScreenState extends State {
],
),
),
+ PopupMenuItem(
+ enabled: state.statusCancelMeeting != Status.loading,
+ value: 'cancel',
+ child: Row(
+ children: [
+ Icon(
+ Icons.cancel,
+ color: Colors.green,
+ size: 17,
+ ),
+ SizedBox(width: 8),
+ Text(
+ AppLocalizations.of(context)!.cancelmeeting,
+ style: TextStyle(fontSize: 12),
+ ),
+ ],
+ ),
+ ),
+ if (userRole == 0 || userRole == 2)
+ PopupMenuItem(
+ value: 'delete',
+ child: Row(
+ children: [
+ Icon(
+ Icons.delete,
+ color: Colors.green,
+ size: 17,
+ ),
+ SizedBox(width: 8),
+ Text(
+ AppLocalizations.of(context)!.deleteprivatemeeting,
+ style: TextStyle(fontSize: 12),
+ ),
+ ],
+ ),
+ ),
],
);
},
@@ -262,6 +301,25 @@ class _PrivateMeetingsScreenState extends State {
}
}
+ void deletePrivateMeeting(
+ PrivateMeetingsState state, BuildContext context, int cardId) async {
+ final status = await state.deleteMeeting(id: cardId);
+ if (status == Status.ready) {
+ Tools.showCustomSnackBar(
+ text: AppLocalizations.of(context)!.privatemeetingdeleted,
+ isError: false,
+ context,
+ );
+ await privateMeetingsState.getPrivateMeetings();
+ } else {
+ Tools.showCustomSnackBar(
+ text: AppLocalizations.of(context)!.error,
+ isError: true,
+ context,
+ );
+ }
+ }
+
void acceptPrivateMeeting(
PrivateMeetingsState state, BuildContext context, int cardId) async {
final status = await state.acceptMeeting(id: cardId);
diff --git a/lib/screens/private_meeting/state.dart b/lib/screens/private_meeting/state.dart
index 9e6a329..8913d95 100644
--- a/lib/screens/private_meeting/state.dart
+++ b/lib/screens/private_meeting/state.dart
@@ -108,12 +108,12 @@ class PrivateMeetingsState extends ChangeNotifier {
}
} catch (e) {
privateStatusMeetings = Status.error;
- print('$e');
+ // print('$e');
}
notifyListeners();
}
notifyListeners();
- print(privateStatusMeetings);
+ // print(privateStatusMeetings);
return privateStatusMeetings;
}
@@ -264,6 +264,41 @@ class PrivateMeetingsState extends ChangeNotifier {
return statusCancelMeeting[id]!;
}
+// delete meeting
+ Map statusDeleteMeeting = {};
+ String? messageDeleteMeeting;
+ Map? errorsDeleteMeeting;
+
+ Future deleteMeeting({
+ required int id,
+ }) async {
+ statusDeleteMeeting[id] = Status.loading;
+ notifyListeners();
+ try {
+ final result = await privateMeetingsApi.deletePrivateMeetingApi(
+ id: id,
+ );
+ if (result.isOk) {
+ statusDeleteMeeting[id] = Status.ready;
+ messageDeleteMeeting = result.message;
+ } else if (result.isOk == false) {
+ // print(result.isOk);
+ errorsDeleteMeeting = result.errors;
+ messageDeleteMeeting = result.message;
+ statusDeleteMeeting[id] = Status.error;
+ } else {
+ statusDeleteMeeting[id] = Status.error;
+ }
+ notifyListeners();
+ } catch (e) {
+ statusDeleteMeeting[id] = Status.error;
+ // print(e);
+ }
+ notifyListeners();
+ // print(statusDeleteMeeting);
+ return statusDeleteMeeting[id]!;
+ }
+
// accept meeting
Map statusAcceptMeeting = {};
String? messageAcceptMeeting;
diff --git a/lib/screens/private_meeting_summary/state.dart b/lib/screens/private_meeting_summary/state.dart
index 60cc3b2..476f447 100644
--- a/lib/screens/private_meeting_summary/state.dart
+++ b/lib/screens/private_meeting_summary/state.dart
@@ -97,31 +97,31 @@ class PrivateMeetingSummaryState extends ChangeNotifier {
if (filesStringModel[id] != null && filesStringModel[id]!.isNotEmpty) {
try {
filesStringModel[id] = await meetingsApi.getListStringFils(id: id);
- print('${filesStringModel[id]}');
+ // print('${filesStringModel[id]}');
stringsFilsStatus[id] = Status.ready;
- print('${filesStringModel} filesStringModel[id]');
+ // print('${filesStringModel} filesStringModel[id]');
} catch (e) {
stringsFilsStatus[id] = Status.error;
- print('$e');
+ // print('$e');
}
} else {
stringsFilsStatus[id] = Status.ready;
notifyListeners();
try {
filesStringModel[id] = await meetingsApi.getListStringFils(id: id);
- print('${filesStringModel[id]}');
+ // print('${filesStringModel[id]}');
stringsFilsStatus[id] = Status.ready;
- print('${filesStringModel} filesStringModel[id]');
+ // print('${filesStringModel} filesStringModel[id]');
} catch (e) {
stringsFilsStatus[id] = Status.error;
- print('$e');
+ // print('$e');
}
}
notifyListeners();
- print('${stringsFilsStatus} stringsFilsStatus');
+ // print('${stringsFilsStatus} stringsFilsStatus');
return stringsFilsStatus;
}
@@ -143,7 +143,7 @@ class PrivateMeetingSummaryState extends ChangeNotifier {
statusDeleteFile = Status.ready;
messageDeleteFile = result.message;
} else if (result.isOk == false) {
- print(result.isOk);
+ // print(result.isOk);
errorsDeleteFile = result.errors;
messageDeleteFile = result.message;
statusDeleteFile = Status.error;
@@ -151,10 +151,10 @@ class PrivateMeetingSummaryState extends ChangeNotifier {
notifyListeners();
} catch (e) {
statusDeleteFile = Status.error;
- print(e);
+ // print(e);
}
notifyListeners();
- print(statusDeleteFile);
+ // print(statusDeleteFile);
return statusDeleteFile;
}
diff --git a/lib/screens/report/screen.dart b/lib/screens/report/screen.dart
index 58a72ac..64b26a5 100644
--- a/lib/screens/report/screen.dart
+++ b/lib/screens/report/screen.dart
@@ -36,33 +36,62 @@ class _ReportScreenState extends State {
String dateJalali = Tools.convertToPersianDigits(
'${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}');
// فرمت کردن تاریخ
- return CustomScrollView(
- slivers: [
- const CustomAppbar(),
- SliverToBoxAdapter(
- child: TodayWidget(
- formattedDate: setting.userLocalDb.getUser().language == 'en'
- ? dateMiladi
- : dateJalali),
- ),
- SliverFillRemaining(
- child: FiltersItemInReport(),
- )
- ],
+ return DefaultTabController(
+ length: 2,
+ child: CustomScrollView(
+ slivers: [
+ const CustomAppbar(),
+ SliverToBoxAdapter(
+ child: TodayWidget(
+ formattedDate: setting.userLocalDb.getUser().language == 'en'
+ ? dateMiladi
+ : dateJalali),
+ ),
+ SliverToBoxAdapter(
+ child: TabBar(
+ indicatorColor: config.ui.mainGreen,
+ labelColor: config.ui.mainGreen,
+ unselectedLabelColor: config.ui.mainGreen,
+ tabs: [
+ Tab(
+ child: Text(
+ AppLocalizations.of(context)!.meetings,
+ style: TextStyle(fontSize: 14),
+ ),
+ ),
+ Tab(
+ child: Text(
+ AppLocalizations.of(context)!.privatemeeting,
+ style: TextStyle(fontSize: 14),
+ ),
+ ),
+ ],
+ ),
+ ),
+ SliverFillRemaining(
+ child: TabBarView(children: [
+ FiltersItemInMeetingsReport(),
+ PrivateMeetingsReportsItems(),
+ ]),
+ )
+ ],
+ ),
);
}
}
-class FiltersItemInReport extends StatefulWidget {
- const FiltersItemInReport({
+class FiltersItemInMeetingsReport extends StatefulWidget {
+ const FiltersItemInMeetingsReport({
super.key,
});
@override
- State createState() => _FiltersItemInReportState();
+ State createState() =>
+ _FiltersItemInMeetingsReportState();
}
-class _FiltersItemInReportState extends State {
+class _FiltersItemInMeetingsReportState
+ extends State {
ReportState? reportState;
GlobalState? globalState;
@override
@@ -304,10 +333,15 @@ class _FiltersItemInReportState extends State {
},
),
),
- Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: 20, vertical: 50),
- child: downloadButton(reportState),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ downloadButtonXlsx(reportState),
+ const SizedBox(
+ width: 20,
+ ),
+ downloadButtonPdf(reportState),
+ ],
)
],
),
@@ -332,22 +366,75 @@ class _FiltersItemInReportState extends State {
);
}
- CustomButton downloadButton(ReportState state) {
- switch (state.statusDownload) {
+ CustomButton downloadButtonXlsx(ReportState state) {
+ switch (state.statusDownload['xlsx']) {
+ case Status.loading:
+ return CustomButton(
+ fontSize: 14,
+ borderRadius: 10,
+ hieght: 40,
+ text: AppLocalizations.of(context)!.loading,
+ width: 150,
+ );
+
+ default:
+ return CustomButton(
+ fontSize: 14,
+ borderRadius: 10,
+ hieght: 40,
+ text: AppLocalizations.of(context)!.downloadxlsx,
+ width: 150,
+ onPressed: () async {
+ bool hasPermission = await hasStoragePermission();
+ if (!hasPermission) {
+ Tools.showCustomSnackBar(context,
+ text: 'Permission denied. Please allow storage access.',
+ isError: true);
+ return;
+ }
+
+ // Download the file
+ final status = await state.downloadReport(
+ format: 'xlsx',
+ toDate: reportState!.toDate,
+ fromDate: reportState!.fromDate,
+ location: reportState!.selectedLocationId,
+ subject: reportState!.selectedSubjectId,
+ meetingManager: reportState!.selectedManagersId,
+ status: reportState!.selectedStatusId);
+ // print(status);
+ if (state.statusDownload['xlsx'] == Status.ready) {
+ await OpenFile.open(state.messageDownload);
+ } else {
+ Tools.showCustomSnackBar(
+ context,
+ text: AppLocalizations.of(context)!.error,
+ isError: true,
+ );
+ }
+ },
+ );
+ }
+ }
+
+ CustomButton downloadButtonPdf(ReportState state) {
+ switch (state.statusDownload['pdf']) {
case Status.loading:
return CustomButton(
- borderRadius: 15,
- hieght: 50,
+ fontSize: 14,
+ borderRadius: 10,
+ hieght: 40,
text: AppLocalizations.of(context)!.loading,
- width: double.infinity,
+ width: 150,
);
default:
return CustomButton(
- borderRadius: 15,
- hieght: 50,
- text: AppLocalizations.of(context)!.downloadreport,
- width: double.infinity,
+ borderRadius: 10,
+ fontSize: 14,
+ hieght: 40,
+ text: AppLocalizations.of(context)!.downloadPdf,
+ width: 150,
onPressed: () async {
bool hasPermission = await hasStoragePermission();
if (!hasPermission) {
@@ -359,6 +446,7 @@ class _FiltersItemInReportState extends State {
// Download the file
await state.downloadReport(
+ format: 'pdf',
toDate: reportState!.toDate,
fromDate: reportState!.fromDate,
location: reportState!.selectedLocationId,
@@ -366,7 +454,7 @@ class _FiltersItemInReportState extends State {
meetingManager: reportState!.selectedManagersId,
status: reportState!.selectedStatusId);
- if (state.statusDownload == Status.ready) {
+ if (state.statusDownload['pdf'] == Status.ready) {
await OpenFile.open(state.messageDownload);
// print(status.message);
} else {
@@ -399,6 +487,424 @@ class _FiltersItemInReportState extends State {
}
}
+class PrivateMeetingsReportsItems extends StatefulWidget {
+ const PrivateMeetingsReportsItems({super.key});
+
+ @override
+ State createState() =>
+ _PrivateMeetingsReportsItemsState();
+}
+
+class _PrivateMeetingsReportsItemsState
+ extends State {
+ ReportState? reportState;
+ GlobalState? globalState;
+ @override
+ void initState() {
+ reportState = Provider.of(context, listen: false);
+ globalState = Provider.of(context, listen: false);
+ // Future.delayed(Duration.zero, () async {
+ // await globalState!.getAllFiltersItems();
+ // });
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ List meetingStatuses = [
+ MeetingsStatus(
+ id: 1, title: AppLocalizations.of(context)!.doneprivatemeetings),
+ MeetingsStatus(
+ id: 2, title: AppLocalizations.of(context)!.adjournedprivatemeetings),
+ MeetingsStatus(
+ id: 3, title: AppLocalizations.of(context)!.canceldprivatemeetings),
+ MeetingsStatus(
+ id: 4,
+ title: AppLocalizations.of(context)!.privatemeetingswaitingtobeheld),
+ ];
+ return Consumer2(
+ builder: (context, reportState, globalState, child) {
+ switch (globalState.allFiltersStatus) {
+ case Status.ready:
+ return Column(
+ children: [
+ Expanded(
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+ Column(
+ mainAxisSize: MainAxisSize.max,
+ children: [
+ ExpansionTileCustom(
+ title: AppLocalizations.of(context)!.date,
+ widgets: [
+ Row(
+ crossAxisAlignment: CrossAxisAlignment.end,
+ mainAxisAlignment:
+ MainAxisAlignment.spaceBetween,
+ children: [
+ PickerCustom(
+ showDate: reportState
+ .fromDatePrivateMeeting.isNotEmpty
+ ? reportState.fromDatePrivateMeeting
+ : AppLocalizations.of(context)!
+ .selectdate, // Show selected date or prompt
+ onTap: () {
+ showDialog(
+ context: context,
+ builder: (context) {
+ return Dialog(
+ child: Tools
+ .shamsiDateCalendarWidget(
+ context,
+ (newDate) {
+ String
+ fromDateStringPrivateMeeting =
+ '${newDate.year}/${newDate.month}/${newDate.day}';
+ reportState
+ .setFromDatesPrivateMeeting(
+ fromDateStringPrivateMeeting); // Update the selected date
+ },
+ ),
+ );
+ },
+ );
+ },
+ ),
+ Text(
+ AppLocalizations.of(context)!.to,
+ ),
+ PickerCustom(
+ showDate: reportState
+ .toDatePrivateMeeting.isNotEmpty
+ ? reportState.toDatePrivateMeeting
+ : AppLocalizations.of(context)!
+ .selectdate, // Show selected date or prompt
+ onTap: () {
+ showDialog(
+ context: context,
+ builder: (context) {
+ return Dialog(
+ child: Tools
+ .shamsiDateCalendarWidget(
+ context,
+ (newDate) {
+ String
+ toDateStringPrivateMeeting =
+ '${newDate.year}/${newDate.month}/${newDate.day}';
+ reportState
+ .setToDatesPrivateMeeting(
+ toDateStringPrivateMeeting); // Update the selected date
+ },
+ ),
+ );
+ },
+ );
+ },
+ ),
+ ],
+ )
+ ],
+ ),
+ ExpansionTileCustom(
+ title: AppLocalizations.of(context)!.location,
+ widgets: [
+ ListView.builder(
+ primary: false,
+ physics: NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ itemCount: globalState.locationsModel!.length,
+ itemBuilder:
+ (BuildContext context, int index) {
+ final items =
+ globalState.locationsModel![index];
+ return RadioListTile(
+ toggleable: true,
+ groupValue: reportState
+ .selectedLocationIdPrivateMeeting,
+ value: items.id ?? -1,
+ title: Text(
+ items.address ?? '',
+ maxLines: 1,
+ style: TextStyle(
+ fontWeight: FontWeight.w100,
+ fontSize: 14),
+ overflow: TextOverflow.ellipsis,
+ ),
+ activeColor: config.ui.secendGreen,
+ onChanged: (int? newValue) {
+ reportState
+ .selectLocationPrivateMeeting(
+ newValue ?? null);
+ },
+ );
+ },
+ ),
+ ],
+ ),
+ if (setting.userLocalDb.getUser().role != 1)
+ ExpansionTileCustom(
+ title: AppLocalizations.of(context)!
+ .meetingmanager,
+ widgets: [
+ ListView.builder(
+ primary: false,
+ physics: NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ itemCount: globalState
+ .meetingsManagerModel!.length,
+ itemBuilder:
+ (BuildContext context, int index) {
+ final items = globalState
+ .meetingsManagerModel![index];
+ return RadioListTile(
+ toggleable: true,
+ groupValue: reportState
+ .selectedManagersIdPrivateMeeting,
+ value: items.id ?? -1,
+ title: Text(
+ items.name ?? '',
+ style: TextStyle(
+ fontWeight: FontWeight.w100,
+ fontSize: 14),
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ ),
+ activeColor: config.ui.secendGreen,
+ onChanged: (int? newValue) {
+ reportState
+ .selectManagerPrivateMeeting(
+ newValue ?? null);
+ },
+ );
+ },
+ ),
+ ],
+ ),
+ ExpansionTileCustom(
+ title: AppLocalizations.of(context)!.subject,
+ widgets: [
+ ListView.builder(
+ primary: false,
+ physics: NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ itemCount: globalState.subjectsModel!.length,
+ itemBuilder:
+ (BuildContext context, int index) {
+ final items =
+ globalState.subjectsModel![index];
+ return RadioListTile(
+ toggleable: true,
+ groupValue: reportState
+ .selectedSubjectIdPrivateMeeting,
+ value: items.id ?? -1,
+ title: Text(
+ items.subject ?? '',
+ maxLines: 1,
+ overflow: TextOverflow.ellipsis,
+ style: TextStyle(
+ fontWeight: FontWeight.w100,
+ fontSize: 14),
+ ),
+ activeColor: config.ui.secendGreen,
+ onChanged: (int? newValue) {
+ reportState.selectSubjectPrivateMeeting(
+ newValue ?? null);
+ },
+ );
+ },
+ ),
+ ],
+ ),
+ Divider(),
+ if (setting.userLocalDb.getUser().role != 1)
+ SizedBox(
+ height: 300,
+ child: ListView.builder(
+ physics: NeverScrollableScrollPhysics(),
+ shrinkWrap: true,
+ primary: false,
+ itemCount: meetingStatuses.length,
+ itemBuilder:
+ (BuildContext context, int index) {
+ final items = meetingStatuses[index];
+ return RadioListTile(
+ toggleable: true,
+ groupValue: reportState
+ .selectedStatusIdPrivateMeeting,
+ value: items.id,
+ title: Text(
+ items.title,
+ maxLines: 1,
+ style: TextStyle(
+ fontWeight: FontWeight.w100,
+ fontSize: 14),
+ overflow: TextOverflow.ellipsis,
+ ),
+ activeColor: config.ui.secendGreen,
+ onChanged: (int? newValue) {
+ reportState
+ .selectStatusMeetingPrivateMeeting(
+ newValue ?? null);
+ },
+ );
+ },
+ ),
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ downloadButtonXlsx(reportState),
+ SizedBox(
+ width: 20,
+ ),
+ downloadButtonPdf(reportState),
+ ],
+ )
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ case Status.loading:
+ return const LoadingWidget();
+ case Status.error:
+ return CustomErrorWidget(
+ onPressed: () async {
+ await globalState.getAllFiltersItems(refresh: true);
+ },
+ );
+ default:
+ return Container();
+ }
+ },
+ );
+ }
+
+ CustomButton downloadButtonXlsx(ReportState state) {
+ switch (state.statusDownloadPrivateMeeting['xlsx']) {
+ case Status.loading:
+ return CustomButton(
+ fontSize: 14,
+ borderRadius: 10,
+ hieght: 40,
+ text: AppLocalizations.of(context)!.loading,
+ width: 150,
+ );
+
+ default:
+ return CustomButton(
+ fontSize: 14,
+ borderRadius: 10,
+ hieght: 40,
+ text: AppLocalizations.of(context)!.downloadxlsx,
+ width: 150,
+ onPressed: () async {
+ bool hasPermission = await hasStoragePermission();
+ if (!hasPermission) {
+ Tools.showCustomSnackBar(context,
+ text: 'Permission denied. Please allow storage access.',
+ isError: true);
+ return;
+ }
+
+ // Download the file
+ final status = await state.downloadReportPrivateMeeting(
+ format: 'xlsx',
+ toDate: reportState!.toDatePrivateMeeting,
+ fromDate: reportState!.fromDatePrivateMeeting,
+ location: reportState!.selectedLocationIdPrivateMeeting,
+ subject: reportState!.selectedSubjectIdPrivateMeeting,
+ meetingManager: reportState!.selectedManagersIdPrivateMeeting,
+ status: reportState!.selectedStatusIdPrivateMeeting);
+ print(status);
+ if (state.statusDownloadPrivateMeeting['xlsx'] == Status.ready) {
+ await OpenFile.open(state.messageDownloadPrivateMeeting);
+ } else {
+ Tools.showCustomSnackBar(
+ context,
+ text: AppLocalizations.of(context)!.error,
+ isError: true,
+ );
+ }
+ },
+ );
+ }
+ }
+
+ CustomButton downloadButtonPdf(ReportState state) {
+ switch (state.statusDownloadPrivateMeeting['pdf']) {
+ case Status.loading:
+ return CustomButton(
+ fontSize: 14,
+ borderRadius: 10,
+ hieght: 40,
+ text: AppLocalizations.of(context)!.loading,
+ width: 150,
+ );
+
+ default:
+ return CustomButton(
+ fontSize: 14,
+ borderRadius: 10,
+ hieght: 40,
+ text: AppLocalizations.of(context)!.downloadPdf,
+ width: 150,
+ onPressed: () async {
+ bool hasPermission = await hasStoragePermission();
+ if (!hasPermission) {
+ Tools.showCustomSnackBar(context,
+ text: 'Permission denied. Please allow storage access.',
+ isError: true);
+ return;
+ }
+
+ // Download the file
+ await state.downloadReportPrivateMeeting(
+ format: 'pdf',
+ toDate: reportState!.toDatePrivateMeeting,
+ fromDate: reportState!.fromDatePrivateMeeting,
+ location: reportState!.selectedLocationIdPrivateMeeting,
+ subject: reportState!.selectedSubjectIdPrivateMeeting,
+ meetingManager: reportState!.selectedManagersIdPrivateMeeting,
+ status: reportState!.selectedStatusIdPrivateMeeting);
+
+ if (state.statusDownloadPrivateMeeting['pdf'] == Status.ready) {
+ await OpenFile.open(state.messageDownloadPrivateMeeting);
+ // print(status.message);
+ } else {
+ Tools.showCustomSnackBar(
+ context,
+ text: AppLocalizations.of(context)!.error,
+ isError: true,
+ );
+ }
+ },
+ );
+ }
+ }
+
+ Future hasStoragePermission() async {
+ if (Platform.isAndroid) {
+ final status = await Permission.storage.status;
+ if (status != PermissionStatus.granted) {
+ final result = await Permission.manageExternalStorage.request();
+ if (result == PermissionStatus.granted) {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ return false;
+ }
+}
+
class LineButtomSheet extends StatelessWidget {
const LineButtomSheet({
super.key,
diff --git a/lib/screens/report/state.dart b/lib/screens/report/state.dart
index adda338..668455b 100644
--- a/lib/screens/report/state.dart
+++ b/lib/screens/report/state.dart
@@ -18,17 +18,6 @@ class ReportState extends ChangeNotifier {
notifyListeners();
}
-// clear filters
- void clearFilters() {
- selectedLocationId = null;
- selectedManagersId = null;
- selectedStatusId = null;
- selectedSubjectId = null;
- fromDate = '';
- toDate = '';
- notifyListeners();
- }
-
// is filter Not empty
bool hasActiveFilters() {
return selectedLocationId != null ||
@@ -70,9 +59,9 @@ class ReportState extends ChangeNotifier {
notifyListeners();
}
-// download report
+// download report meeting
- Status statusDownload = Status.empty;
+ Map statusDownload = {};
String? messageDownload;
Future downloadReport(
@@ -81,33 +70,134 @@ class ReportState extends ChangeNotifier {
int? location,
int? subject,
int? meetingManager,
+ required String format,
int? status}) async {
- statusDownload = Status.loading;
+ statusDownload[format] = Status.loading;
notifyListeners();
try {
- final result = await reportApi.downloadReport(
+ final result = await reportApi.downloadReportMeetings(
fromDate: fromDate,
toDate: toDate,
location: location,
subject: subject,
meetingManager: meetingManager,
+ format: format,
status: status);
if (result == null) {
- statusDownload = Status.error;
+ statusDownload[format] = Status.error;
} else {
if (result.isOk) {
- statusDownload = Status.ready;
+ statusDownload[format] = Status.ready;
messageDownload = result.message ?? '';
} else {
- statusDownload = Status.error;
+ statusDownload[format] = Status.error;
+ }
+ }
+ } catch (e) {
+ statusDownload[format] = Status.error;
+ // print(e);
+ }
+ // print(statusDownload[format]);
+ notifyListeners();
+ return statusDownload[format] ?? Status.error;
+ }
+
+// private meetings report items
+
+ String fromDatePrivateMeeting = '';
+ String toDatePrivateMeeting = '';
+
+ void setFromDatesPrivateMeeting(String? newFromDate) {
+ fromDatePrivateMeeting = newFromDate ?? '';
+ notifyListeners();
+ }
+
+ void setToDatesPrivateMeeting(String? newToDate) {
+ toDatePrivateMeeting = newToDate ?? '';
+ notifyListeners();
+ }
+
+ // is filter Not empty
+ bool hasActiveFiltersPrivateMeeting() {
+ return selectedLocationIdPrivateMeeting != null ||
+ selectedManagersIdPrivateMeeting != null ||
+ selectedStatusIdPrivateMeeting != null ||
+ selectedSubjectIdPrivateMeeting != null ||
+ fromDatePrivateMeeting.isNotEmpty ||
+ toDatePrivateMeeting.isNotEmpty;
+ }
+
+// get filters location PrivateMeeting
+
+ int? selectedLocationIdPrivateMeeting;
+ void selectLocationPrivateMeeting(int? locationId) {
+ selectedLocationIdPrivateMeeting = locationId;
+ notifyListeners();
+ }
+
+// get filters subjects PrivateMeeting
+
+ int? selectedSubjectIdPrivateMeeting;
+ void selectSubjectPrivateMeeting(int? subjectId) {
+ selectedSubjectIdPrivateMeeting = subjectId;
+ notifyListeners();
+ }
+// get filters PrivateMeeting
+
+ int? selectedManagersIdPrivateMeeting;
+ void selectManagerPrivateMeeting(int? managerId) {
+ selectedManagersIdPrivateMeeting = managerId;
+ notifyListeners();
+ }
+
+// all PrivateMeeting status filters
+
+ int? selectedStatusIdPrivateMeeting;
+ void selectStatusMeetingPrivateMeeting(int? statusId) {
+ selectedStatusIdPrivateMeeting = statusId;
+ notifyListeners();
+ }
+ // download report PrivateMeeting
+
+ Map statusDownloadPrivateMeeting = {};
+ String? messageDownloadPrivateMeeting;
+
+ Future downloadReportPrivateMeeting(
+ {String? fromDate,
+ String? toDate,
+ int? location,
+ int? subject,
+ int? meetingManager,
+ required String format,
+ int? status}) async {
+ statusDownloadPrivateMeeting[format] = Status.loading;
+ notifyListeners();
+ try {
+ final result = await reportApi.downloadReportPrivateMeetings(
+ format: format,
+ fromDate: fromDate,
+ toDate: toDate,
+ location: location,
+ subject: subject,
+ meetingManager: meetingManager,
+ status: status);
+
+ if (result == null) {
+ statusDownloadPrivateMeeting[format] = Status.error;
+ } else {
+ if (result.isOk) {
+ statusDownloadPrivateMeeting[format] = Status.ready;
+ messageDownloadPrivateMeeting = result.message ?? '';
+ } else {
+ statusDownloadPrivateMeeting[format] = Status.error;
}
}
} catch (e) {
- statusDownload = Status.error;
+ statusDownloadPrivateMeeting[format] = Status.error;
}
notifyListeners();
- return statusDownload;
+ return statusDownloadPrivateMeeting[format] ?? Status.error;
}
}
diff --git a/lib/services/auth/auth.dart b/lib/services/auth/auth.dart
index d4dc85e..a2fef11 100644
--- a/lib/services/auth/auth.dart
+++ b/lib/services/auth/auth.dart
@@ -1,11 +1,13 @@
-import 'package:flutter/foundation.dart'; // برای شناسایی پلتفرم
import 'package:dio/dio.dart';
import 'package:qadirneyriz/config/config.dart';
import 'package:qadirneyriz/main.dart';
import 'package:qadirneyriz/setting/setting.dart';
import 'package:qadirneyriz/utils/result/result.dart';
+import 'dart:io';
class AuthServices {
+ String userAgent =
+ Platform.isAndroid ? 'application/android' : 'application/ios';
Future loginApi({
required String mobile,
String? password,
@@ -18,7 +20,10 @@ class AuthServices {
assert(password != null || otp != null);
try {
- Map headers = {"Accept": "application/json"};
+ Map headers = {
+ "Accept": "application/json",
+ "user-agent": userAgent
+ };
FormData formData;
formData = password != null
? FormData.fromMap(
@@ -26,7 +31,7 @@ class AuthServices {
: FormData.fromMap(
{"mobile": mobile, "otp": otp, "device_id": token});
- print('${formData.fields} resData');
+ // print('${formData.fields} resData');
final res = await Dio().post(
"${config.network.baseUrl}login?lang=${setting.userLocalDb.getUser().language}",
data: formData,
@@ -41,7 +46,7 @@ class AuthServices {
return Result(isOk: true, message: res.data['msg']);
}
} on DioException catch (e) {
- print(e);
+ // print(e);
return Result(
isOk: false,
errors: e.response?.data['errors'],
@@ -52,7 +57,10 @@ class AuthServices {
Future sendOtpApi({required String mobile}) async {
try {
- Map headers = {"Accept": "application/json"};
+ Map headers = {
+ "Accept": "application/json",
+ "user-agent": userAgent,
+ };
FormData formData = FormData.fromMap({"mobile": mobile});
final res = await Dio().post(
@@ -71,4 +79,40 @@ class AuthServices {
}
return const Result(isOk: false);
}
+
+ Future checkLoginApi() async {
+ final userRole = setting.userLocalDb.getUser().role;
+
+ try {
+ Map headers = {"Accept": "application/json"};
+ String dataToken = setting.userLocalDb.getUser().token!;
+
+ if (dataToken != '') {
+ headers['Authorization'] = "Bearer $dataToken";
+ }
+ // print('$dataToken datatokoen');
+
+ // لینک API
+ final apiUrl = userRole != 1
+ ? "${config.network.baseUrl}admin/checkLogin"
+ : "${config.network.baseUrl}user/checkLogin";
+
+ final res = await Dio().get(
+ apiUrl,
+ options: Options(headers: headers),
+ );
+
+ if (res.statusCode == 200 || res.statusCode == 201) {
+ return Result(isOk: true, message: res.data['msg']);
+ }
+ } on DioException catch (e) {
+ return Result(
+ isOk: false,
+ errors: e.response?.data['errors'],
+ message: e.response?.data['msg'],
+ );
+ }
+
+ return const Result(isOk: false);
+ }
}
diff --git a/lib/services/global/global.dart b/lib/services/global/global.dart
index c598dd5..4d3696d 100644
--- a/lib/services/global/global.dart
+++ b/lib/services/global/global.dart
@@ -1,5 +1,6 @@
import 'package:dio/dio.dart';
import 'package:qadirneyriz/config/config.dart';
+import 'package:qadirneyriz/models/logo_images_model.dart';
import 'package:qadirneyriz/models/meetings/meetings_location_model.dart';
import 'package:qadirneyriz/models/meetings/meetings_managers_model.dart';
import 'package:qadirneyriz/models/meetings/meetings_subjects_model.dart';
@@ -81,7 +82,7 @@ class GlobalServices {
}
final String link =
- "${config.network.baseUrl}admin/users?lang=${setting.userLocalDb.getUser().language}";
+ "${config.network.baseUrl}admin/users?is_active=1?lang=${setting.userLocalDb.getUser().language}";
final response = await Dio().get(link,
options: Options(
@@ -188,4 +189,44 @@ class GlobalServices {
}
return const Result(isOk: false);
}
+
+// get logo images
+ Future getLogoImagesApi() async {
+ Map headers = {
+ 'Accept': 'application/json',
+ };
+ String dataToken = setting.userLocalDb.getUser().token!;
+ int role = setting.userLocalDb.getUser().role!;
+
+ // print("DEBUG: Token => $dataToken");
+ // print("DEBUG: Role => $role");
+
+ if (dataToken != '') {
+ headers['Authorization'] = "Bearer $dataToken";
+ }
+
+ // print("DEBUG: Headers => $headers");
+
+ final String link = role != 1
+ ? "${config.network.baseUrl}admin/settings"
+ : "${config.network.baseUrl}user/settings";
+
+ // print("DEBUG: API Link => $link");
+
+ try {
+ final response = await Dio().get(link,
+ options: Options(
+ headers: headers,
+ ));
+
+ // print("DEBUG: Response Data => ${response.data}");
+
+ LogoImagesModel list = LogoImagesModel.fromJson(response.data);
+
+ return list;
+ } catch (e) {
+ // print("DEBUG: Error => $e");
+ rethrow;
+ }
+ }
}
diff --git a/lib/services/meetings/meetings.dart b/lib/services/meetings/meetings.dart
index 500efc5..4079fb7 100644
--- a/lib/services/meetings/meetings.dart
+++ b/lib/services/meetings/meetings.dart
@@ -93,7 +93,7 @@ class MeetingsApi {
}
FormData? formData;
- if (managerId != null) {
+ if (managerId == null) {
formData = FormData.fromMap({
'locations_id': locationId,
'subject_id': subjectId,
@@ -113,7 +113,7 @@ class MeetingsApi {
'date_meeting': dateMeeting,
});
}
- print('${formData.fields} saggggggggg');
+ // print('${formData.fields} saggggggggg');
final res = await Dio().post("${config.network.baseUrl}admin/add-meeting",
data: formData, options: Options(headers: headers));
@@ -121,7 +121,7 @@ class MeetingsApi {
return Result(isOk: true, message: res.data['message']);
}
} on DioException catch (e) {
- print('${e.message}');
+ // print('${e.message}');
return Result(
isOk: false,
errors: e.response!.data['errors'],
@@ -209,6 +209,41 @@ class MeetingsApi {
return const Result(isOk: false);
}
+// delete meeting
+ Future deleteMeetingApi({
+ required int id,
+ }) async {
+ try {
+ Map headers = {"Accept": "application/json"};
+ String? dataToken = setting.userLocalDb.getUser().token;
+
+ if (dataToken != null && dataToken.isNotEmpty) {
+ headers['Authorization'] = "Bearer $dataToken";
+ }
+
+ String url = "${config.network.baseUrl}admin/meetings/$id";
+
+ final res = await Dio().delete(
+ url,
+ options: Options(headers: headers),
+ );
+
+ if (res.statusCode == 200 || res.statusCode == 201) {
+ return Result(isOk: true, message: res.data['message']);
+ }
+ } on DioException catch (e) {
+ if (e.response != null) {
+ return Result(
+ isOk: false,
+ errors: e.response?.data['errors'],
+ message: e.response?.data['message'],
+ );
+ }
+ }
+
+ return const Result(isOk: false);
+ }
+
// accept meeting
Future acceptMeetingApi({
required int id,
@@ -354,7 +389,7 @@ class MeetingsApi {
),
);
- print('${response.data} response.data');
+ // print('${response.data} response.data');
// بررسی ساختار پاسخ و تبدیل دادهها
if (response.data is List) {
@@ -382,7 +417,7 @@ class MeetingsApi {
// Send request
final link =
"${config.network.baseUrl}admin/delete-meeting-minutes/$id/$text";
- print('${link}');
+ // print('${link}');
final res = await Dio().get(
link,
data: formData,
@@ -394,7 +429,7 @@ class MeetingsApi {
return Result(isOk: true, message: res.data['message']);
}
} on DioException catch (e) {
- print(e);
+ // print(e);
return Result(
isOk: false,
errors: e.response?.data['errors'],
diff --git a/lib/services/notification/notification_service.dart b/lib/services/notification/notification_service.dart
index a3cbf8d..deed56d 100644
--- a/lib/services/notification/notification_service.dart
+++ b/lib/services/notification/notification_service.dart
@@ -16,9 +16,9 @@ class NotificationService {
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
- print('User granted permission');
+ // print('User granted permission');
} else {
- print('User declined or has not granted permission');
+ // print('User declined or has not granted permission');
}
}
@@ -32,8 +32,8 @@ class NotificationService {
/// تنظیم Listener برای دریافت نوتیفیکیشنها
void setupMessageListener() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
- print('Message received: ${message.notification?.title}');
- print('Message body: ${message.notification?.body}');
+ // print('Message received: ${message.notification?.title}');
+ // print('Message body: ${message.notification?.body}');
// اینجا میتوانید یک Dialog یا Toast برای نمایش پیام استفاده کنید
});
}
diff --git a/lib/services/private_meetings/private_meetings.dart b/lib/services/private_meetings/private_meetings.dart
index 2aa403c..83e1285 100644
--- a/lib/services/private_meetings/private_meetings.dart
+++ b/lib/services/private_meetings/private_meetings.dart
@@ -151,6 +151,33 @@ class PrivateMeetingsApi {
return const Result(isOk: false);
}
+ // delete private meeting
+ Future deletePrivateMeetingApi({
+ required int id,
+ }) async {
+ try {
+ Map headers = {"Accept": "application/json"};
+ String dataToken = setting.userLocalDb.getUser().token!;
+ if (dataToken != '') {
+ headers['Authorization'] = "Bearer $dataToken";
+ }
+
+ final res = await Dio().post(
+ "${config.network.baseUrl}admin/delete-private-meeting/${id}",
+ options: Options(headers: headers));
+
+ if (res.statusCode == 200 || res.statusCode == 201) {
+ return Result(isOk: true, message: res.data['message']);
+ }
+ } on DioException catch (e) {
+ return Result(
+ isOk: false,
+ errors: e.response!.data['errors'],
+ message: e.response!.data['message']);
+ }
+ return const Result(isOk: false);
+ }
+
// accept private meeting
Future acceptPrivateMeetingApi({
required int id,
diff --git a/lib/services/report/report.dart b/lib/services/report/report.dart
index 599ac69..fd19efb 100644
--- a/lib/services/report/report.dart
+++ b/lib/services/report/report.dart
@@ -6,14 +6,14 @@ import 'package:qadirneyriz/setting/setting.dart';
import 'package:qadirneyriz/utils/result/result.dart';
class ReportApi {
- Future downloadReport(
+ Future downloadReportMeetings(
{String? fromDate,
String? toDate,
int? location,
int? subject,
int? meetingManager,
int? status,
- String format = 'xlsx'}) async {
+ required String format}) async {
try {
final Map headers = {"Accept": "application/json"};
String dataToken = setting.userLocalDb.getUser().token!;
@@ -35,6 +35,7 @@ class ReportApi {
'subject': subject,
'meeting_manager': meetingManager,
'status': status,
+ 'format': format
},
options: Options(headers: headers),
);
@@ -46,6 +47,74 @@ class ReportApi {
isOk: false, message: 'Failed with status code: ${res.statusCode}');
}
} on DioException catch (e) {
+ // print(e);
+ return Result(
+ isOk: false,
+ errors: e.response?.data['errors'],
+ message:
+ e.response?.data['message'] ?? 'An error occurred during download.',
+ );
+ }
+ }
+
+ Future downloadReportPrivateMeetings(
+ {String? fromDate,
+ String? toDate,
+ int? location,
+ int? subject,
+ int? meetingManager,
+ int? status,
+ required String format}) async {
+ try {
+ final Map headers = {"Accept": "application/json"};
+ String dataToken = setting.userLocalDb.getUser().token!;
+ if (dataToken != '') {
+ headers['Authorization'] = "Bearer $dataToken";
+ }
+
+ final Directory tempDir = await getApplicationDocumentsDirectory();
+ final String tempPath = tempDir.path;
+ final String savePath = '$tempPath/reportprivatemeeting.$format';
+
+ // print("Download path: $savePath");
+
+ final String url = '${config.network.baseUrl}private_meetings/export';
+ // print("Download URL: $url");
+
+ final Map params = {
+ 'date_meeting_az': fromDate,
+ 'date_meeting_ta': toDate,
+ 'location': location,
+ 'subject': subject,
+ 'meeting_manager': meetingManager,
+ 'status': status,
+ 'format': format
+ };
+
+ // print("Request parameters: $params");
+
+ final res = await Dio().download(
+ url,
+ savePath,
+ queryParameters: params,
+ options: Options(headers: headers),
+ );
+
+ // print("Response status: ${res.statusCode}");
+ // print("Response headers: ${res.headers}");
+
+ if (res.statusCode == 200 || res.statusCode == 201) {
+ // print("File downloaded successfully: $savePath");
+ return Result(isOk: true, message: savePath);
+ } else {
+ print("Failed with status code: ${res.statusCode}");
+ return Result(
+ isOk: false, message: 'Failed with status code: ${res.statusCode}');
+ }
+ } on DioException catch (e) {
+ print("DioException: $e");
+ print("Error response data: ${e.response?.data}");
+
return Result(
isOk: false,
errors: e.response?.data['errors'],
diff --git a/lib/splash_screen.dart b/lib/splash_screen.dart
index 5b88a74..d14020d 100644
--- a/lib/splash_screen.dart
+++ b/lib/splash_screen.dart
@@ -1,7 +1,13 @@
+import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
+import 'package:provider/provider.dart';
import 'package:qadirneyriz/config/config.dart';
+import 'package:qadirneyriz/global/global_state/global_state.dart';
+import 'package:qadirneyriz/main.dart';
+import 'package:qadirneyriz/screens/auth/state/state.dart';
import 'package:qadirneyriz/setting/setting.dart';
+import 'package:qadirneyriz/utils/enums/status.dart';
import 'package:qadirneyriz/widgets/custom_background.dart';
import 'package:qadirneyriz/widgets/loading_widget.dart';
@@ -13,39 +19,87 @@ class SplashScreen extends StatefulWidget {
}
class _SplashScreenState extends State {
+ late AuthState authState;
+ late GlobalState globalState;
@override
void initState() {
+ authState = Provider.of(context, listen: false);
+ globalState = Provider.of(context, listen: false);
super.initState();
- checkUser();
+ checkUser(authState: authState, globalState: globalState);
}
@override
Widget build(BuildContext context) {
- return Scaffold(
- body: CustomBackground(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Spacer(),
- LoadingWidget(
- color: config.ui.mainGreen,
- size: 30,
+ return Consumer(
+ builder: (context, value, child) {
+ return Scaffold(
+ body: CustomBackground(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Spacer(),
+ LoadingWidget(
+ color: config.ui.mainGreen,
+ size: 30,
+ ),
+ ],
),
- ],
- ),
- ),
+ ),
+ );
+ },
);
}
- void checkUser() async {
+ void checkUser(
+ {required AuthState authState, required GlobalState globalState}) async {
+ await requestNotificationPermission();
+ getToken();
+ setupMessageListener();
String token = setting.userLocalDb.getUser().token ?? '';
- Future.delayed(const Duration(seconds: 4), () {
+ Future.delayed(const Duration(seconds: 4), () async {
+ final Status logoImagesStatus = await globalState.getLogoImages();
if (token != '') {
- context.goNamed('navigate', pathParameters: {'tab': '0'});
+ final Status checkLogin = await authState.CheckLogin();
+ if (checkLogin == Status.ready) {
+ context.goNamed('navigate', pathParameters: {'tab': '0'});
+ } else {
+ context.goNamed('login');
+ }
} else {
context.goNamed('login');
}
});
}
+
+ Future requestNotificationPermission() async {
+ NotificationSettings settings = await messaging.requestPermission(
+ alert: true,
+ announcement: false,
+ badge: true,
+ carPlay: false,
+ criticalAlert: false,
+ provisional: false,
+ sound: true,
+ );
+
+ if (settings.authorizationStatus == AuthorizationStatus.authorized) {
+ // print('User granted permission');
+ } else {
+ // print('User declined or has not granted permission');
+ }
+ }
+
+ Future getToken() async {
+ await messaging.getToken();
+ }
+
+ void setupMessageListener() {
+ FirebaseMessaging.onMessage.listen((RemoteMessage message) {
+ // print('Message received: ${message.notification?.title}');
+ // print('Message body: ${message.notification?.body}');
+ // You can use a Dialog or Toast to display the message here
+ });
+ }
}
diff --git a/lib/widgets/custom_appbar.dart b/lib/widgets/custom_appbar.dart
index cba1e65..bd88d81 100644
--- a/lib/widgets/custom_appbar.dart
+++ b/lib/widgets/custom_appbar.dart
@@ -1,32 +1,62 @@
+// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:flutter/material.dart';
-import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:provider/provider.dart';
import 'package:qadirneyriz/config/config.dart';
+import 'package:qadirneyriz/global/global_state/global_state.dart';
+import 'package:qadirneyriz/utils/enums/status.dart';
+import 'package:qadirneyriz/widgets/custom_netimage.dart';
-class CustomAppbar extends StatelessWidget {
+class CustomAppbar extends StatefulWidget {
final String? title;
- const CustomAppbar({super.key, this.title});
+
+ const CustomAppbar({
+ Key? key,
+ this.title,
+ }) : super(key: key);
+ @override
+ State createState() => _CustomAppbarState();
+}
+
+class _CustomAppbarState extends State {
@override
Widget build(BuildContext context) {
- return SliverAppBar(
- title: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- const SizedBox(),
- Text(
- this.title == null ? '' : this.title ?? '',
- style: const TextStyle(
- fontSize: 12,
- color: Colors.black,
- ),
- ),
- Image.asset(
- 'assets/images/D2.png', // مسیر لوگو رو اینجا قرار بده
- height: 40,
+ return Consumer(
+ builder: (context, globalState, child) {
+ final String image = globalState.logoImagesStatus == Status.ready
+ ? globalState.logoImagesModel!.data!
+ .firstWhere(
+ (element) => element.key == 'logo',
+ )
+ .value ??
+ ''
+ : '';
+ final String ImageUrl = '${config.network.imageUrl}${image}';
+ return SliverAppBar(
+ title: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ const SizedBox(),
+ Text(
+ this.widget.title == null ? '' : this.widget.title ?? '',
+ style: const TextStyle(
+ fontSize: 12,
+ color: Colors.black,
+ ),
+ ),
+ globalState.logoImagesStatus == Status.ready
+ ? CustomImage(
+ logo: true,
+ image: ImageUrl,
+ width: 50,
+ height: 50,
+ )
+ : Container()
+ ],
),
- ],
- ),
- backgroundColor: config.ui.backGroundColor,
+ backgroundColor: config.ui.backGroundColor,
+ );
+ },
);
}
}
diff --git a/lib/widgets/custom_netimage.dart b/lib/widgets/custom_netimage.dart
index 326b1cf..d1a975e 100644
--- a/lib/widgets/custom_netimage.dart
+++ b/lib/widgets/custom_netimage.dart
@@ -2,12 +2,12 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:qadirneyriz/config/config.dart';
-
class CustomImage extends StatelessWidget {
final String? image;
final double? height;
final double? width;
final BoxFit? boxFit;
+ final bool logo;
final double borderRadius; // Border radius
const CustomImage({
@@ -15,6 +15,7 @@ class CustomImage extends StatelessWidget {
required this.image,
this.height,
this.width,
+ this.logo = false,
this.boxFit = BoxFit.cover,
this.borderRadius = 10.0, // Default border radius
});
@@ -25,7 +26,7 @@ class CustomImage extends StatelessWidget {
if (image != null && image != '') {
imageWidget = CachedNetworkImage(
- imageUrl: '${config.network.baseUrl}$image',
+ imageUrl: logo ? '$image' : '${config.network.baseUrl}$image',
width: width,
height: height,
fit: boxFit,
diff --git a/pubspec.yaml b/pubspec.yaml
index ff0034f..9cebed9 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: "A new Flutter project."
publish_to: 'none'
-version: 1.0.3+3
+version: 2.0.0+1
environment:
sdk: ^3.5.3