| @@ -1 +1 @@ | |||||
| {"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}} | |||||
| {"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"}]} | |||||
| @@ -1,23 +0,0 @@ | |||||
| { | |||||
| "images" : [ | |||||
| { | |||||
| "idiom" : "universal", | |||||
| "filename" : "LaunchImage.png", | |||||
| "scale" : "1x" | |||||
| }, | |||||
| { | |||||
| "idiom" : "universal", | |||||
| "filename" : "LaunchImage@2x.png", | |||||
| "scale" : "2x" | |||||
| }, | |||||
| { | |||||
| "idiom" : "universal", | |||||
| "filename" : "LaunchImage@3x.png", | |||||
| "scale" : "3x" | |||||
| } | |||||
| ], | |||||
| "info" : { | |||||
| "version" : 1, | |||||
| "author" : "xcode" | |||||
| } | |||||
| } | |||||
| @@ -1,5 +0,0 @@ | |||||
| # Launch Screen Assets | |||||
| You can customize the launch screen with your own desired assets by replacing the image files in this directory. | |||||
| You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. | |||||
| @@ -8,6 +8,7 @@ import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/config/config.dart'; | import 'package:qadirneyriz/config/config.dart'; | ||||
| import 'package:qadirneyriz/screens/aboutUs/screen.dart'; | import 'package:qadirneyriz/screens/aboutUs/screen.dart'; | ||||
| import 'package:qadirneyriz/screens/auth/state/state.dart'; | import 'package:qadirneyriz/screens/auth/state/state.dart'; | ||||
| import 'package:qadirneyriz/screens/change_pass/screen.dart'; | |||||
| import 'package:qadirneyriz/screens/home/screen.dart'; | import 'package:qadirneyriz/screens/home/screen.dart'; | ||||
| import 'package:qadirneyriz/screens/home/state.dart'; | import 'package:qadirneyriz/screens/home/state.dart'; | ||||
| import 'package:qadirneyriz/screens/meeting/screen.dart'; | import 'package:qadirneyriz/screens/meeting/screen.dart'; | ||||
| @@ -45,6 +46,7 @@ class _CustomDrawerNavigationState extends State<CustomDrawerNavigation> { | |||||
| const MeetingsScreen(), | const MeetingsScreen(), | ||||
| const PrivateMeetingsScreen(), | const PrivateMeetingsScreen(), | ||||
| const ReportScreen(), | const ReportScreen(), | ||||
| const ChangePassScreen(), | |||||
| const AboutUsScreen() | const AboutUsScreen() | ||||
| // Add more screens here | // Add more screens here | ||||
| ]; | ]; | ||||
| @@ -66,49 +68,56 @@ class _CustomDrawerNavigationState extends State<CustomDrawerNavigation> { | |||||
| builder: (context, value, child) { | builder: (context, value, child) { | ||||
| return Drawer( | return Drawer( | ||||
| backgroundColor: config.ui.backGroundColor, | backgroundColor: config.ui.backGroundColor, | ||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: <Widget>[ | |||||
| Padding( | |||||
| padding: const EdgeInsets.only(left: 16.0, top: 40), | |||||
| child: Image.asset( | |||||
| 'assets/images/iconinappbar.png', // مسیر لوگوی شما | |||||
| height: 60, | |||||
| child: SingleChildScrollView( | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: <Widget>[ | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric( | |||||
| horizontal: 10, vertical: 35), | |||||
| child: Image.asset( | |||||
| 'assets/images/D2.png', // مسیر لوگوی شما | |||||
| height: 60, | |||||
| ), | |||||
| ), | ), | ||||
| ), | |||||
| if (userRole == 0 || userRole == 2) | |||||
| Row( | |||||
| children: [ | |||||
| Expanded( | |||||
| child: Consumer<HomeState>( | |||||
| builder: (context, value, child) { | |||||
| return NewSessionButton( | |||||
| title: AppLocalizations.of(context)!.newmeeting, | |||||
| icon: Icons.person_outlined, | |||||
| onPressed: () async { | |||||
| await context.pushNamed('meetingadd'); | |||||
| value.getTodayMeetings(); | |||||
| if (userRole == 0 || userRole == 2) | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 5), | |||||
| child: Row( | |||||
| children: [ | |||||
| Expanded( | |||||
| child: Consumer<HomeState>( | |||||
| builder: (context, value, child) { | |||||
| return NewSessionButton( | |||||
| title: | |||||
| AppLocalizations.of(context)!.newmeeting, | |||||
| icon: Icons.person_outlined, | |||||
| onPressed: () async { | |||||
| await context.pushNamed('meetingadd'); | |||||
| value.getTodayMeetings(); | |||||
| }, | |||||
| ); | |||||
| }, | }, | ||||
| ); | |||||
| }, | |||||
| ), | |||||
| ), | |||||
| Expanded( | |||||
| child: NewSessionButton( | |||||
| title: | |||||
| AppLocalizations.of(context)!.newprivatemeeting, | |||||
| icon: Icons.people_outlined, | |||||
| onPressed: () { | |||||
| context.pushNamed('privatemeetingadd'); | |||||
| }, | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| Expanded( | |||||
| child: NewSessionButton( | |||||
| title: AppLocalizations.of(context)! | |||||
| .newprivatemeeting, | |||||
| icon: Icons.people_outlined, | |||||
| onPressed: () { | |||||
| context.pushNamed('privatemeetingadd'); | |||||
| }, | |||||
| ), | |||||
| ), | |||||
| ], | |||||
| ), | ), | ||||
| ], | |||||
| ), | |||||
| Expanded( | |||||
| child: Padding( | |||||
| ), | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric(vertical: 50), | padding: const EdgeInsets.symmetric(vertical: 50), | ||||
| child: ListView( | child: ListView( | ||||
| shrinkWrap: true, | |||||
| physics: const NeverScrollableScrollPhysics(), | |||||
| padding: EdgeInsets.zero, | padding: EdgeInsets.zero, | ||||
| children: <Widget>[ | children: <Widget>[ | ||||
| _buildDrawerItem( | _buildDrawerItem( | ||||
| @@ -131,40 +140,44 @@ class _CustomDrawerNavigationState extends State<CustomDrawerNavigation> { | |||||
| text: AppLocalizations.of(context)!.reports, | text: AppLocalizations.of(context)!.reports, | ||||
| index: 3, | index: 3, | ||||
| ), | ), | ||||
| _buildDrawerItem( | |||||
| icon: FontAwesomeIcons.person, | |||||
| text: AppLocalizations.of(context)!.profile, | |||||
| index: 4, | |||||
| ), | |||||
| _buildDrawerItem( | _buildDrawerItem( | ||||
| icon: FontAwesomeIcons.info, | icon: FontAwesomeIcons.info, | ||||
| text: AppLocalizations.of(context)!.aboutus, | text: AppLocalizations.of(context)!.aboutus, | ||||
| index: 4, | |||||
| index: 5, | |||||
| ), | ), | ||||
| ], | ], | ||||
| ), | ), | ||||
| ), | ), | ||||
| ), | |||||
| Padding( | |||||
| padding: const EdgeInsets.all(8.0), | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| color: config.ui.secendGreen.withOpacity(.1), | |||||
| borderRadius: BorderRadius.circular(10), | |||||
| ), | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.all(8.0), | |||||
| child: Row( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |||||
| children: [ | |||||
| _buildLanguageButton('fa', 'فارسی', () { | |||||
| value.setLocale('fa'); | |||||
| }), | |||||
| _buildLanguageButton('en', 'English', () { | |||||
| value.setLocale('en'); | |||||
| }), | |||||
| ], | |||||
| Padding( | |||||
| padding: const EdgeInsets.all(8.0), | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| color: config.ui.secendGreen.withOpacity(.1), | |||||
| borderRadius: BorderRadius.circular(10), | |||||
| ), | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.all(8.0), | |||||
| child: Row( | |||||
| mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |||||
| children: [ | |||||
| _buildLanguageButton('fa', 'فارسی', () { | |||||
| value.setLocale('fa'); | |||||
| }), | |||||
| _buildLanguageButton('en', 'English', () { | |||||
| value.setLocale('en'); | |||||
| }), | |||||
| ], | |||||
| ), | |||||
| ), | ), | ||||
| ), | ), | ||||
| ), | ), | ||||
| ), | |||||
| const Divider(), | |||||
| ], | |||||
| ], | |||||
| ), | |||||
| ), | ), | ||||
| ); | ); | ||||
| }, | }, | ||||
| @@ -20,7 +20,6 @@ | |||||
| "meetings": "Meetings", | "meetings": "Meetings", | ||||
| "events": "Appointments", | "events": "Appointments", | ||||
| "exit": "Exit", | "exit": "Exit", | ||||
| "appname": "Foolad Ghadir Neyriz", | |||||
| "nomeetingfortoday": "No meeting is scheduled for today.", | "nomeetingfortoday": "No meeting is scheduled for today.", | ||||
| "todaymeetings": "Today's Meetings", | "todaymeetings": "Today's Meetings", | ||||
| "empty": "No data available.", | "empty": "No data available.", | ||||
| @@ -118,5 +117,9 @@ | |||||
| "files":"Files", | "files":"Files", | ||||
| "acceptoperetion":"Accept Operetion", | "acceptoperetion":"Accept Operetion", | ||||
| "areusuretodeletfile": "Are you sure you want to delete this file?", | "areusuretodeletfile": "Are you sure you want to delete this file?", | ||||
| "changepass":"Change Password", | |||||
| "profile":"User Account", "doyouredit":"You must make at least one change", | |||||
| "changename":"Change Username", | |||||
| "newpass":"Your New Password", | |||||
| "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." | "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." | ||||
| } | } | ||||
| @@ -20,7 +20,6 @@ | |||||
| "meetings":"جلسات", | "meetings":"جلسات", | ||||
| "events":"ملاقات ها", | "events":"ملاقات ها", | ||||
| "exit":"خروج", | "exit":"خروج", | ||||
| "appname":"فولاد غدیر نی ریز", | |||||
| "nomeetingfortoday":"برای امروز جلسه ایی تعریف نشده است.", | "nomeetingfortoday":"برای امروز جلسه ایی تعریف نشده است.", | ||||
| "todaymeetings":"جلسه های امروز", | "todaymeetings":"جلسه های امروز", | ||||
| "empty":"داده ایی وجود ندارد.", | "empty":"داده ایی وجود ندارد.", | ||||
| @@ -115,6 +114,11 @@ | |||||
| "accepted":"تایید شده", | "accepted":"تایید شده", | ||||
| "files":"فایل ها", | "files":"فایل ها", | ||||
| "acceptoperetion":"تایید عملیات", | "acceptoperetion":"تایید عملیات", | ||||
| "changepass":"تغییر رمزعبور", | |||||
| "profile":"حساب کاربری", | |||||
| "doyouredit":"باید حداقل یکی از تغییرات را انجام دهید!", | |||||
| "changename":"تغییر نام کاربری", | |||||
| "newpass":"رمزعبور جدید شما", | |||||
| "areusuretodeletfile":"آیا اطمینان دارید که میخواهید این فایل را حذف کنید؟", | "areusuretodeletfile":"آیا اطمینان دارید که میخواهید این فایل را حذف کنید؟", | ||||
| "textaboutus":"نرمافزار مدیریت جلسات و ملاقاتهای “میزبان” با هدف تسهیل و بهینهسازی فرآیندهای برگزاری جلسات سازمانی و شخصی جناب آقای دکتر محسن مصطفی پور طراحی و توسعه یافته تا ابزاری کارآمد و نوآورانه برای تحقق بیشتر اسم رمز همدلی در مجموعه معظم فولاد غدیر نی ریز باشد . این نرم افزار با حمایت ، همت و پشتیبانی بیدریغ مدیریت محترم عامل ( دکتر محسن مصطفی پور ) ایجاد ، توسعه و راه اندازی شده است." | "textaboutus":"نرمافزار مدیریت جلسات و ملاقاتهای “میزبان” با هدف تسهیل و بهینهسازی فرآیندهای برگزاری جلسات سازمانی و شخصی جناب آقای دکتر محسن مصطفی پور طراحی و توسعه یافته تا ابزاری کارآمد و نوآورانه برای تحقق بیشتر اسم رمز همدلی در مجموعه معظم فولاد غدیر نی ریز باشد . این نرم افزار با حمایت ، همت و پشتیبانی بیدریغ مدیریت محترم عامل ( دکتر محسن مصطفی پور ) ایجاد ، توسعه و راه اندازی شده است." | ||||
| } | } | ||||
| @@ -84,8 +84,8 @@ class _MyAppState extends State<MyApp> { | |||||
| ], | ], | ||||
| locale: Locale(value.language), | locale: Locale(value.language), | ||||
| supportedLocales: const [ | supportedLocales: const [ | ||||
| Locale('fa'), // Persian | |||||
| Locale('en'), // English | Locale('en'), // English | ||||
| Locale('fa'), // Persian | |||||
| ], | ], | ||||
| ); | ); | ||||
| }, | }, | ||||
| @@ -1,79 +1,105 @@ | |||||
| import 'dart:convert'; | import 'dart:convert'; | ||||
| class TodayMeetingModel { | class TodayMeetingModel { | ||||
| List<Meeting>? meetings; | |||||
| String? note; | |||||
| TodayMeetingModel({ | |||||
| this.meetings, | |||||
| this.note, | |||||
| }); | |||||
| factory TodayMeetingModel.fromRawJson(String str) => TodayMeetingModel.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory TodayMeetingModel.fromJson(Map<String, dynamic> json) => TodayMeetingModel( | |||||
| meetings: json["meetings"] == null ? [] : List<Meeting>.from(json["meetings"]!.map((x) => Meeting.fromJson(x))), | |||||
| List<Meeting>? meetings; | |||||
| List<Meeting>? privateMeetings; | |||||
| String? note; | |||||
| TodayMeetingModel({ | |||||
| this.meetings, | |||||
| this.privateMeetings, | |||||
| this.note, | |||||
| }); | |||||
| factory TodayMeetingModel.fromRawJson(String str) => | |||||
| TodayMeetingModel.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory TodayMeetingModel.fromJson(Map<String, dynamic> json) => | |||||
| TodayMeetingModel( | |||||
| meetings: json["meetings"] == null | |||||
| ? [] | |||||
| : List<Meeting>.from( | |||||
| json["meetings"]!.map((x) => Meeting.fromJson(x))), | |||||
| privateMeetings: json["private_meetings"] == null | |||||
| ? [] | |||||
| : List<Meeting>.from( | |||||
| json["private_meetings"]!.map((x) => Meeting.fromJson(x))), | |||||
| note: json["note"], | note: json["note"], | ||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "meetings": meetings == null ? [] : List<dynamic>.from(meetings!.map((x) => x.toJson())), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "meetings": meetings == null | |||||
| ? [] | |||||
| : List<dynamic>.from(meetings!.map((x) => x.toJson())), | |||||
| "private_meetings": privateMeetings == null | |||||
| ? [] | |||||
| : List<dynamic>.from(privateMeetings!.map((x) => x.toJson())), | |||||
| "note": note, | "note": note, | ||||
| }; | |||||
| }; | |||||
| } | } | ||||
| class Meeting { | class Meeting { | ||||
| int? id; | |||||
| int? locationsId; | |||||
| int? subjectId; | |||||
| int? managerId; | |||||
| int? ownerId; | |||||
| String? azHour; | |||||
| String? taHour; | |||||
| dynamic description; | |||||
| int? status; | |||||
| int? accepted; | |||||
| DateTime? dateMeeting; | |||||
| DateTime? endDate; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| String? dateJalali; | |||||
| String? statusTxt; | |||||
| String? az; | |||||
| String? ta; | |||||
| Location? location; | |||||
| Subject? subject; | |||||
| Meeting({ | |||||
| this.id, | |||||
| this.locationsId, | |||||
| this.subjectId, | |||||
| this.managerId, | |||||
| this.ownerId, | |||||
| this.azHour, | |||||
| this.taHour, | |||||
| this.description, | |||||
| this.status, | |||||
| this.accepted, | |||||
| this.dateMeeting, | |||||
| this.endDate, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| this.dateJalali, | |||||
| this.statusTxt, | |||||
| this.az, | |||||
| this.ta, | |||||
| this.location, | |||||
| this.subject, | |||||
| }); | |||||
| factory Meeting.fromRawJson(String str) => Meeting.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Meeting.fromJson(Map<String, dynamic> json) => Meeting( | |||||
| int? id; | |||||
| int? locationsId; | |||||
| int? subjectId; | |||||
| int? managerId; | |||||
| int? ownerId; | |||||
| String? azHour; | |||||
| String? taHour; | |||||
| dynamic description; | |||||
| int? status; | |||||
| int? accepted; | |||||
| DateTime? dateMeeting; | |||||
| DateTime? endDate; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| String? dateJalali; | |||||
| String? statusTxt; | |||||
| String? az; | |||||
| String? ta; | |||||
| List<dynamic>? minutes; | |||||
| Location? location; | |||||
| Subject? subject; | |||||
| String? visitName; | |||||
| String? visitMobile; | |||||
| String? visitRole; | |||||
| String? visitCompany; | |||||
| Meeting({ | |||||
| this.id, | |||||
| this.locationsId, | |||||
| this.subjectId, | |||||
| this.managerId, | |||||
| this.ownerId, | |||||
| this.azHour, | |||||
| this.taHour, | |||||
| this.description, | |||||
| this.status, | |||||
| this.accepted, | |||||
| this.dateMeeting, | |||||
| this.endDate, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| this.dateJalali, | |||||
| this.statusTxt, | |||||
| this.az, | |||||
| this.ta, | |||||
| this.minutes, | |||||
| this.location, | |||||
| this.subject, | |||||
| this.visitName, | |||||
| this.visitMobile, | |||||
| this.visitRole, | |||||
| this.visitCompany, | |||||
| }); | |||||
| factory Meeting.fromRawJson(String str) => Meeting.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Meeting.fromJson(Map<String, dynamic> json) => Meeting( | |||||
| id: json["id"], | id: json["id"], | ||||
| locationsId: json["locations_id"], | locationsId: json["locations_id"], | ||||
| subjectId: json["subject_id"], | subjectId: json["subject_id"], | ||||
| @@ -84,19 +110,36 @@ class Meeting { | |||||
| description: json["description"], | description: json["description"], | ||||
| status: json["status"], | status: json["status"], | ||||
| accepted: json["accepted"], | accepted: json["accepted"], | ||||
| dateMeeting: json["date_meeting"] == null ? null : DateTime.parse(json["date_meeting"]), | |||||
| endDate: json["end_date"] == null ? null : DateTime.parse(json["end_date"]), | |||||
| createdAt: json["created_at"] == null ? null : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null ? null : DateTime.parse(json["updated_at"]), | |||||
| dateMeeting: json["date_meeting"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["date_meeting"]), | |||||
| endDate: | |||||
| json["end_date"] == null ? null : DateTime.parse(json["end_date"]), | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| dateJalali: json["date_jalali"], | dateJalali: json["date_jalali"], | ||||
| statusTxt: json["status_txt"], | statusTxt: json["status_txt"], | ||||
| az: json["az"], | az: json["az"], | ||||
| ta: json["ta"], | ta: json["ta"], | ||||
| location: json["location"] == null ? null : Location.fromJson(json["location"]), | |||||
| subject: json["subject"] == null ? null : Subject.fromJson(json["subject"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| minutes: json["minutes"] == null | |||||
| ? [] | |||||
| : List<dynamic>.from(json["minutes"]!.map((x) => x)), | |||||
| location: json["location"] == null | |||||
| ? null | |||||
| : Location.fromJson(json["location"]), | |||||
| subject: | |||||
| json["subject"] == null ? null : Subject.fromJson(json["subject"]), | |||||
| visitName: json["visit_name"], | |||||
| visitMobile: json["visit_mobile"], | |||||
| visitRole: json["visit_role"], | |||||
| visitCompany: json["visit_company"], | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | "id": id, | ||||
| "locations_id": locationsId, | "locations_id": locationsId, | ||||
| "subject_id": subjectId, | "subject_id": subjectId, | ||||
| @@ -115,79 +158,94 @@ class Meeting { | |||||
| "status_txt": statusTxt, | "status_txt": statusTxt, | ||||
| "az": az, | "az": az, | ||||
| "ta": ta, | "ta": ta, | ||||
| "minutes": | |||||
| minutes == null ? [] : List<dynamic>.from(minutes!.map((x) => x)), | |||||
| "location": location?.toJson(), | "location": location?.toJson(), | ||||
| "subject": subject?.toJson(), | "subject": subject?.toJson(), | ||||
| }; | |||||
| "visit_name": visitName, | |||||
| "visit_mobile": visitMobile, | |||||
| "visit_role": visitRole, | |||||
| "visit_company": visitCompany, | |||||
| }; | |||||
| } | } | ||||
| class Location { | class Location { | ||||
| int? id; | |||||
| String? address; | |||||
| String? addressEn; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| Location({ | |||||
| this.id, | |||||
| this.address, | |||||
| this.addressEn, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory Location.fromRawJson(String str) => Location.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Location.fromJson(Map<String, dynamic> json) => Location( | |||||
| int? id; | |||||
| String? address; | |||||
| String? addressEn; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| Location({ | |||||
| this.id, | |||||
| this.address, | |||||
| this.addressEn, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory Location.fromRawJson(String str) => | |||||
| Location.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Location.fromJson(Map<String, dynamic> json) => Location( | |||||
| id: json["id"], | id: json["id"], | ||||
| address: json["address"], | address: json["address"], | ||||
| addressEn: json["address_en"], | addressEn: json["address_en"], | ||||
| createdAt: json["created_at"] == null ? null : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null ? null : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | "id": id, | ||||
| "address": address, | "address": address, | ||||
| "address_en": addressEn, | "address_en": addressEn, | ||||
| "created_at": createdAt?.toIso8601String(), | "created_at": createdAt?.toIso8601String(), | ||||
| "updated_at": updatedAt?.toIso8601String(), | "updated_at": updatedAt?.toIso8601String(), | ||||
| }; | |||||
| }; | |||||
| } | } | ||||
| class Subject { | class Subject { | ||||
| int? id; | |||||
| dynamic subject; | |||||
| dynamic subjectEn; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| int? id; | |||||
| String? subject; | |||||
| dynamic subjectEn; | |||||
| DateTime? createdAt; | |||||
| DateTime? updatedAt; | |||||
| Subject({ | |||||
| this.id, | |||||
| this.subject, | |||||
| this.subjectEn, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| Subject({ | |||||
| this.id, | |||||
| this.subject, | |||||
| this.subjectEn, | |||||
| this.createdAt, | |||||
| this.updatedAt, | |||||
| }); | |||||
| factory Subject.fromRawJson(String str) => Subject.fromJson(json.decode(str)); | |||||
| factory Subject.fromRawJson(String str) => Subject.fromJson(json.decode(str)); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| String toRawJson() => json.encode(toJson()); | |||||
| factory Subject.fromJson(Map<String, dynamic> json) => Subject( | |||||
| factory Subject.fromJson(Map<String, dynamic> json) => Subject( | |||||
| id: json["id"], | id: json["id"], | ||||
| subject: json["subject"], | subject: json["subject"], | ||||
| subjectEn: json["subject_en"], | subjectEn: json["subject_en"], | ||||
| createdAt: json["created_at"] == null ? null : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null ? null : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| createdAt: json["created_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["created_at"]), | |||||
| updatedAt: json["updated_at"] == null | |||||
| ? null | |||||
| : DateTime.parse(json["updated_at"]), | |||||
| ); | |||||
| Map<String, dynamic> toJson() => { | |||||
| "id": id, | "id": id, | ||||
| "subject": subject, | "subject": subject, | ||||
| "subject_en": subjectEn, | "subject_en": subjectEn, | ||||
| "created_at": createdAt?.toIso8601String(), | "created_at": createdAt?.toIso8601String(), | ||||
| "updated_at": updatedAt?.toIso8601String(), | "updated_at": updatedAt?.toIso8601String(), | ||||
| }; | |||||
| }; | |||||
| } | } | ||||
| @@ -29,14 +29,20 @@ class AboutUsScreen extends StatelessWidget { | |||||
| Column( | Column( | ||||
| children: [ | children: [ | ||||
| Image.asset( | Image.asset( | ||||
| 'assets/images/logoaboutus.png', | |||||
| width: 100, | |||||
| height: 100, | |||||
| 'assets/images/D2.png', | |||||
| width: 80, | |||||
| height: 80, | |||||
| ), | |||||
| SizedBox( | |||||
| height: 8, | |||||
| ), | ), | ||||
| Text( | Text( | ||||
| 'نسخه 1.0.0', | 'نسخه 1.0.0', | ||||
| style: TextStyle(fontSize: 12), | style: TextStyle(fontSize: 12), | ||||
| ), | ), | ||||
| SizedBox( | |||||
| height: 10, | |||||
| ) | |||||
| ], | ], | ||||
| ) | ) | ||||
| ], | ], | ||||
| @@ -0,0 +1,165 @@ | |||||
| import 'package:flutter/material.dart'; | |||||
| import 'package:provider/provider.dart'; | |||||
| import 'package:qadirneyriz/config/config.dart'; | |||||
| import 'package:qadirneyriz/screens/home/state.dart'; | |||||
| import 'package:qadirneyriz/setting/setting.dart'; | |||||
| import 'package:qadirneyriz/utils/enums/status.dart'; | |||||
| import 'package:qadirneyriz/utils/tools/tools.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_appbar.dart'; | |||||
| import 'package:flutter_gen/gen_l10n/app_localizations.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_button.dart'; | |||||
| import 'package:qadirneyriz/widgets/custom_textfield.dart'; | |||||
| class ChangePassScreen extends StatefulWidget { | |||||
| const ChangePassScreen({super.key}); | |||||
| @override | |||||
| State<ChangePassScreen> createState() => _ChangePassScreenState(); | |||||
| } | |||||
| class _ChangePassScreenState extends State<ChangePassScreen> { | |||||
| TextEditingController nameController = TextEditingController(); | |||||
| TextEditingController passController = TextEditingController(); | |||||
| @override | |||||
| Widget build(BuildContext context) { | |||||
| final phone = setting.userLocalDb.getUser().mobile ?? ''; | |||||
| final name = setting.userLocalDb.getUser().name ?? ''; | |||||
| return Consumer<HomeState>( | |||||
| builder: (context, value, child) { | |||||
| return CustomScrollView( | |||||
| slivers: <Widget>[ | |||||
| CustomAppbar( | |||||
| title: AppLocalizations.of(context)!.profile, | |||||
| ), | |||||
| SliverToBoxAdapter( | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| color: config.ui.secendGreen, | |||||
| boxShadow: [ | |||||
| BoxShadow( | |||||
| color: config.ui.mainGray.withOpacity(.2), | |||||
| spreadRadius: 10, | |||||
| offset: const Offset(0, 5), | |||||
| blurRadius: 8) | |||||
| ], | |||||
| borderRadius: BorderRadius.only( | |||||
| bottomLeft: Radius.circular(50), | |||||
| bottomRight: Radius.circular(50))), | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.all(30.0), | |||||
| child: Column( | |||||
| mainAxisAlignment: MainAxisAlignment.center, | |||||
| children: [ | |||||
| Container( | |||||
| decoration: BoxDecoration( | |||||
| color: Colors.white.withOpacity(.2), | |||||
| shape: BoxShape.circle), | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.all(20.0), | |||||
| child: Icon( | |||||
| Icons.person, | |||||
| size: 50, | |||||
| color: Colors.white, | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| SizedBox( | |||||
| height: 10, | |||||
| ), | |||||
| Text( | |||||
| name, | |||||
| style: TextStyle( | |||||
| fontSize: 16, | |||||
| color: Colors.white, | |||||
| fontWeight: FontWeight.bold), | |||||
| ), | |||||
| SizedBox( | |||||
| height: 2, | |||||
| ), | |||||
| Text( | |||||
| phone, | |||||
| style: TextStyle( | |||||
| fontSize: 16, | |||||
| color: Colors.white, | |||||
| fontWeight: FontWeight.bold), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| ), | |||||
| SliverToBoxAdapter( | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.symmetric(vertical: 70), | |||||
| child: Column( | |||||
| children: [ | |||||
| CustomTextField( | |||||
| label: AppLocalizations.of(context)!.changename, | |||||
| hintText: name, | |||||
| textEditingController: nameController, | |||||
| textInputType: TextInputType.visiblePassword), | |||||
| CustomTextField( | |||||
| label: AppLocalizations.of(context)!.changepass, | |||||
| hintText: AppLocalizations.of(context)!.newpass, | |||||
| isPass: true, | |||||
| textEditingController: passController, | |||||
| textInputType: TextInputType.visiblePassword), | |||||
| SizedBox( | |||||
| height: 60, | |||||
| ), | |||||
| chnagePassMethod(value) | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| } | |||||
| Widget chnagePassMethod(HomeState state) { | |||||
| switch (state.statusEditProfile) { | |||||
| case Status.loading: | |||||
| return CustomButton( | |||||
| hieght: 50, text: AppLocalizations.of(context)!.loading); | |||||
| default: | |||||
| return CustomButton( | |||||
| hieght: 50, | |||||
| text: AppLocalizations.of(context)!.submit, | |||||
| onPressed: () async { | |||||
| if (nameController.text == '' && passController.text == '') { | |||||
| Tools.showCustomSnackBar( | |||||
| text: AppLocalizations.of(context)!.doyouredit, | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else { | |||||
| final status = await state.editProfile( | |||||
| name: nameController.text, pass: passController.text); | |||||
| if (status == Status.ready) { | |||||
| Tools.showCustomSnackBar( | |||||
| text: AppLocalizations.of(context)!.editdone, | |||||
| isError: false, | |||||
| context, | |||||
| ); | |||||
| setState(() {}); | |||||
| } else { | |||||
| Tools.showCustomSnackBar( | |||||
| text: state.errorsEditProfile == null | |||||
| ? state.messageEditProfile ?? | |||||
| AppLocalizations.of(context)!.haserror | |||||
| : Tools.combineErrorMessages( | |||||
| state.errorsEditProfile ?? {}), | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } | |||||
| } | |||||
| }, | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -38,9 +38,10 @@ class _HomeScreenState extends State<HomeScreen> { | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| DateTime now = DateTime.now(); | DateTime now = DateTime.now(); | ||||
| String dateMiladi = DateFormat('yyyy-MM-dd').format(now); | |||||
| String dateJalali = | |||||
| '${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}'; // فرمت کردن تاریخ | |||||
| String dateMiladi = | |||||
| Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now)); | |||||
| String dateJalali = Tools.convertToPersianDigits( | |||||
| '${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}'); | |||||
| return Consumer<HomeState>( | return Consumer<HomeState>( | ||||
| builder: (context, value, child) { | builder: (context, value, child) { | ||||
| @@ -102,31 +103,118 @@ class _HomeScreenState extends State<HomeScreen> { | |||||
| SliverToBoxAdapter( | SliverToBoxAdapter( | ||||
| child: SizedBox( | child: SizedBox( | ||||
| height: 170, | height: 170, | ||||
| child: value.todayMeetingsModel!.meetings!.isNotEmpty | |||||
| child: value.todayMeetingsModel!.meetings!.isNotEmpty || | |||||
| value.todayMeetingsModel!.privateMeetings! | |||||
| .isNotEmpty | |||||
| ? ListView.builder( | ? ListView.builder( | ||||
| scrollDirection: Axis.horizontal, | scrollDirection: Axis.horizontal, | ||||
| shrinkWrap: true, | |||||
| itemCount: | itemCount: | ||||
| value.todayMeetingsModel!.meetings!.length, | |||||
| value.todayMeetingsModel!.meetings!.length + | |||||
| value.todayMeetingsModel!.privateMeetings! | |||||
| .length, | |||||
| itemBuilder: (BuildContext context, int index) { | itemBuilder: (BuildContext context, int index) { | ||||
| final items = | |||||
| value.todayMeetingsModel!.meetings![index]; | |||||
| return Padding( | |||||
| padding: | |||||
| const EdgeInsets.only(right: 5, left: 1), | |||||
| child: CustomCardMeeting( | |||||
| status: items.accepted ?? 0, | |||||
| titel: items.subject != null | |||||
| ? items.subject!.subject ?? '' | |||||
| : '', | |||||
| fromTime: items.azHour ?? '', | |||||
| toTime: items.taHour ?? "", | |||||
| location: items.location != null | |||||
| ? items.location!.address ?? '' | |||||
| : '', | |||||
| date: items.dateJalali ?? '', | |||||
| cardId: items.id ?? 0, | |||||
| ), | |||||
| ); | |||||
| // ترکیب دو لیست | |||||
| final meetingsLength = | |||||
| value.todayMeetingsModel!.meetings!.length; | |||||
| if (index < meetingsLength) { | |||||
| // آیتم از لیست `meetings` | |||||
| final meeting = value | |||||
| .todayMeetingsModel!.meetings![index]; | |||||
| return Padding( | |||||
| padding: const EdgeInsets.only( | |||||
| right: 5, left: 1), | |||||
| child: Stack( | |||||
| children: [ | |||||
| CustomCardMeeting( | |||||
| status: meeting.accepted ?? 0, | |||||
| titel: meeting.subject != null | |||||
| ? meeting.subject!.subject ?? '' | |||||
| : '', | |||||
| fromTime: meeting.azHour ?? '', | |||||
| toTime: meeting.taHour ?? "", | |||||
| location: meeting.location != null | |||||
| ? meeting.location!.address ?? '' | |||||
| : '', | |||||
| date: meeting.dateJalali ?? '', | |||||
| cardId: meeting.id ?? 0, | |||||
| ), | |||||
| Positioned( | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| borderRadius: | |||||
| BorderRadius.circular(10), | |||||
| color: Colors.green), | |||||
| child: Padding( | |||||
| padding: | |||||
| const EdgeInsets.all(5.0), | |||||
| child: Text( | |||||
| AppLocalizations.of(context)! | |||||
| .meetings, | |||||
| style: TextStyle( | |||||
| fontSize: 12, | |||||
| color: Colors.white), | |||||
| ), | |||||
| )), | |||||
| left: 30, | |||||
| top: 20, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ); | |||||
| } else { | |||||
| // آیتم از لیست `privateMeetings` | |||||
| final privateMeeting = value | |||||
| .todayMeetingsModel! | |||||
| .privateMeetings![index - meetingsLength]; | |||||
| return Padding( | |||||
| padding: const EdgeInsets.only( | |||||
| right: 5, left: 1), | |||||
| child: Stack( | |||||
| children: [ | |||||
| CustomCardMeeting( | |||||
| cardId: privateMeeting.id ?? -1, | |||||
| titel: privateMeeting.subject != null | |||||
| ? privateMeeting | |||||
| .subject!.subject ?? | |||||
| '' | |||||
| : '', | |||||
| location: | |||||
| privateMeeting.location != null | |||||
| ? privateMeeting | |||||
| .location!.address ?? | |||||
| '' | |||||
| : '', | |||||
| status: privateMeeting.accepted ?? 0, | |||||
| fromTime: "${privateMeeting.azHour}", | |||||
| date: privateMeeting.dateJalali ?? '', | |||||
| toTime: privateMeeting.taHour ?? '', | |||||
| ), | |||||
| Positioned( | |||||
| child: Container( | |||||
| decoration: BoxDecoration( | |||||
| borderRadius: | |||||
| BorderRadius.circular(10), | |||||
| color: Colors.green), | |||||
| child: Padding( | |||||
| padding: | |||||
| const EdgeInsets.all(5.0), | |||||
| child: Text( | |||||
| AppLocalizations.of(context)! | |||||
| .privatemeeting, | |||||
| style: TextStyle( | |||||
| fontSize: 12, | |||||
| color: Colors.white), | |||||
| ), | |||||
| )), | |||||
| left: 30, | |||||
| top: 20, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ); | |||||
| } | |||||
| }, | }, | ||||
| ) | ) | ||||
| : Center( | : Center( | ||||
| @@ -46,7 +46,6 @@ class HomeState extends ChangeNotifier { | |||||
| return todayMettingsStatus; | return todayMettingsStatus; | ||||
| } | } | ||||
| // log out | |||||
| // log out | // log out | ||||
| Status statusLogOut = Status.empty; | Status statusLogOut = Status.empty; | ||||
| String? messageLogOut; | String? messageLogOut; | ||||
| @@ -80,4 +79,38 @@ class HomeState extends ChangeNotifier { | |||||
| // print(statusLogOut); | // print(statusLogOut); | ||||
| return statusLogOut; | return statusLogOut; | ||||
| } | } | ||||
| // edit profile | |||||
| Status statusEditProfile = Status.empty; | |||||
| String? messageEditProfile; | |||||
| Map? errorsEditProfile; | |||||
| Future<Status> editProfile({String? name, String? pass}) async { | |||||
| statusEditProfile = Status.loading; | |||||
| notifyListeners(); | |||||
| try { | |||||
| final result = await homeApi.editProfile(name: name, password: pass); | |||||
| if (result == null) { | |||||
| statusEditProfile = Status.error; | |||||
| } else { | |||||
| if (result.isOk) { | |||||
| statusEditProfile = Status.ready; | |||||
| messageEditProfile = result.message; | |||||
| } else if (result.isOk == false) { | |||||
| errorsEditProfile = result.errors; | |||||
| messageEditProfile = result.message; | |||||
| statusEditProfile = Status.error; | |||||
| } else { | |||||
| statusEditProfile = Status.error; | |||||
| } | |||||
| } | |||||
| notifyListeners(); | |||||
| } catch (e) { | |||||
| statusEditProfile = Status.error; | |||||
| // print(e); | |||||
| } | |||||
| notifyListeners(); | |||||
| print(statusEditProfile); | |||||
| return statusEditProfile; | |||||
| } | |||||
| } | } | ||||
| @@ -67,9 +67,11 @@ class _MeetingsScreenState extends State<MeetingsScreen> { | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| DateTime now = DateTime.now(); | DateTime now = DateTime.now(); | ||||
| String dateMiladi = DateFormat('yyyy-MM-dd').format(now); | |||||
| String dateJalali = | |||||
| '${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}'; // فرمت کردن تاریخ | |||||
| String dateMiladi = | |||||
| Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now)); | |||||
| String dateJalali = Tools.convertToPersianDigits( | |||||
| '${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}'); | |||||
| // فرمت کردن تاریخ | |||||
| return Consumer<MeetingsState>( | return Consumer<MeetingsState>( | ||||
| builder: (context, value, child) { | builder: (context, value, child) { | ||||
| return RefreshIndicator( | return RefreshIndicator( | ||||
| @@ -298,14 +298,16 @@ class _MeetingSummaryScreenState extends State<MeetingSummaryScreen> { | |||||
| isError: true, | isError: true, | ||||
| context, | context, | ||||
| ); | ); | ||||
| } else if (state.selectedFiles == null) { | |||||
| // call add new subject | |||||
| Tools.showCustomSnackBar( | |||||
| text: AppLocalizations.of(context)!.enterfile, | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else { | |||||
| } | |||||
| // else if (state.selectedFiles == null) { | |||||
| // // call add new subject | |||||
| // Tools.showCustomSnackBar( | |||||
| // text: AppLocalizations.of(context)!.enterfile, | |||||
| // isError: true, | |||||
| // context, | |||||
| // ); | |||||
| // } | |||||
| else { | |||||
| final status = await state.addMinuteMeeting( | final status = await state.addMinuteMeeting( | ||||
| id: widget.meetingItem.id ?? -1, | id: widget.meetingItem.id ?? -1, | ||||
| description: _textControllerDescription.text, | description: _textControllerDescription.text, | ||||
| @@ -64,9 +64,11 @@ class _PrivateMeetingsScreenState extends State<PrivateMeetingsScreen> { | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| DateTime now = DateTime.now(); | DateTime now = DateTime.now(); | ||||
| String dateMiladi = DateFormat('yyyy-MM-dd').format(now); | |||||
| String dateJalali = | |||||
| '${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}'; | |||||
| String dateMiladi = | |||||
| Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now)); | |||||
| String dateJalali = Tools.convertToPersianDigits( | |||||
| '${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}'); | |||||
| return Consumer<PrivateMeetingsState>( | return Consumer<PrivateMeetingsState>( | ||||
| builder: (context, value, child) { | builder: (context, value, child) { | ||||
| return RefreshIndicator( | return RefreshIndicator( | ||||
| @@ -286,147 +288,154 @@ class PrivateMeetingWidget extends StatelessWidget { | |||||
| final String subject; | final String subject; | ||||
| final String location; | final String location; | ||||
| final int status; | final int status; | ||||
| final bool hasMoreButton; | |||||
| final void Function()? onAcceptButton; | final void Function()? onAcceptButton; | ||||
| final void Function()? onCancelButton; | final void Function()? onCancelButton; | ||||
| final void Function(String)? onSelectedMoreButton; | final void Function(String)? onSelectedMoreButton; | ||||
| final List<PopupMenuEntry<String>> Function(BuildContext)? | final List<PopupMenuEntry<String>> Function(BuildContext)? | ||||
| itemBuilderMoreButton; | itemBuilderMoreButton; | ||||
| const PrivateMeetingWidget({ | |||||
| Key? key, | |||||
| required this.date, | |||||
| required this.time, | |||||
| required this.subject, | |||||
| required this.location, | |||||
| required this.status, | |||||
| this.onAcceptButton, | |||||
| this.onCancelButton, | |||||
| this.onSelectedMoreButton, | |||||
| this.itemBuilderMoreButton, | |||||
| }) : super(key: key); | |||||
| const PrivateMeetingWidget( | |||||
| {Key? key, | |||||
| required this.date, | |||||
| required this.time, | |||||
| required this.subject, | |||||
| required this.location, | |||||
| required this.status, | |||||
| this.hasMoreButton = true, | |||||
| this.onAcceptButton, | |||||
| this.onCancelButton, | |||||
| this.onSelectedMoreButton, | |||||
| this.itemBuilderMoreButton, | |||||
| th}) | |||||
| : super(key: key); | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| return Padding( | return Padding( | ||||
| padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), | padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), | ||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.end, | |||||
| children: [ | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 10), | |||||
| child: Text( | |||||
| this.date, | |||||
| style: TextStyle(fontSize: 12), | |||||
| child: Container( | |||||
| width: 500, | |||||
| height: 190, | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.end, | |||||
| children: [ | |||||
| Padding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 10), | |||||
| child: Text( | |||||
| this.date, | |||||
| style: TextStyle(fontSize: 12), | |||||
| ), | |||||
| ), | ), | ||||
| ), | |||||
| Divider(), | |||||
| SizedBox( | |||||
| height: 5, | |||||
| ), | |||||
| Container( | |||||
| decoration: BoxDecoration( | |||||
| boxShadow: [ | |||||
| BoxShadow( | |||||
| color: config.ui.mainGray.withOpacity(.1), | |||||
| spreadRadius: .1, | |||||
| offset: const Offset(0, 2), | |||||
| blurRadius: 6) | |||||
| ], | |||||
| color: const Color(0xffF4F9F6), | |||||
| borderRadius: BorderRadius.circular(10)), | |||||
| child: Padding( | |||||
| padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10), | |||||
| child: Column( | |||||
| children: [ | |||||
| Row( | |||||
| children: [ | |||||
| Text(this.time), | |||||
| SizedBox( | |||||
| width: 15, | |||||
| ), | |||||
| Container( | |||||
| width: 3, | |||||
| height: 45, | |||||
| decoration: BoxDecoration( | |||||
| color: Colors.green, | |||||
| Divider(), | |||||
| SizedBox( | |||||
| height: 5, | |||||
| ), | |||||
| Container( | |||||
| decoration: BoxDecoration( | |||||
| boxShadow: [ | |||||
| BoxShadow( | |||||
| color: config.ui.mainGray.withOpacity(.1), | |||||
| spreadRadius: .1, | |||||
| offset: const Offset(0, 2), | |||||
| blurRadius: 6) | |||||
| ], | |||||
| color: const Color(0xffF4F9F6), | |||||
| borderRadius: BorderRadius.circular(10)), | |||||
| child: Padding( | |||||
| padding: | |||||
| const EdgeInsets.symmetric(horizontal: 15, vertical: 10), | |||||
| child: Column( | |||||
| children: [ | |||||
| Row( | |||||
| children: [ | |||||
| Text(this.time), | |||||
| SizedBox( | |||||
| width: 15, | |||||
| ), | ), | ||||
| ), | |||||
| SizedBox( | |||||
| width: 5, | |||||
| ), | |||||
| Expanded( | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| Container( | |||||
| width: 3, | |||||
| height: 45, | |||||
| decoration: BoxDecoration( | |||||
| color: Colors.green, | |||||
| ), | |||||
| ), | |||||
| SizedBox( | |||||
| width: 5, | |||||
| ), | |||||
| Expanded( | |||||
| child: Column( | |||||
| crossAxisAlignment: CrossAxisAlignment.start, | |||||
| children: [ | |||||
| Text( | |||||
| this.subject, | |||||
| ), | |||||
| SizedBox( | |||||
| height: 5, | |||||
| ), | |||||
| Text( | |||||
| this.location, | |||||
| style: TextStyle( | |||||
| fontSize: 12, color: Color(0xff9AA8C7)), | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| if (hasMoreButton) _moreButton(context) | |||||
| ], | |||||
| ), | |||||
| if (this.status == 0) | |||||
| Padding( | |||||
| padding: const EdgeInsets.only(top: 15), | |||||
| child: Row( | |||||
| mainAxisAlignment: MainAxisAlignment.center, | |||||
| children: [ | children: [ | ||||
| Text( | |||||
| this.subject, | |||||
| CustomButton( | |||||
| hieght: 30, | |||||
| text: AppLocalizations.of(context)!.accept, | |||||
| borderRadius: 5, | |||||
| color: Color(0xff00A848), | |||||
| fontSize: 12, | |||||
| onPressed: this.onAcceptButton, | |||||
| ), | ), | ||||
| SizedBox( | SizedBox( | ||||
| height: 5, | |||||
| width: 7, | |||||
| ), | |||||
| CustomButton( | |||||
| hieght: 30, | |||||
| text: AppLocalizations.of(context)!.cancel, | |||||
| color: Colors.red, | |||||
| textColor: Colors.white, | |||||
| fontSize: 12, | |||||
| borderRadius: 5, | |||||
| onPressed: this.onCancelButton, | |||||
| ), | ), | ||||
| Text( | |||||
| this.location, | |||||
| style: TextStyle( | |||||
| fontSize: 12, color: Color(0xff9AA8C7)), | |||||
| SizedBox( | |||||
| width: 90, | |||||
| ), | ), | ||||
| ], | ], | ||||
| ), | ), | ||||
| ), | ), | ||||
| _moreButton(context) | |||||
| ], | |||||
| ), | |||||
| if (this.status == 0) | |||||
| Padding( | |||||
| padding: const EdgeInsets.only(top: 15), | |||||
| child: Row( | |||||
| mainAxisAlignment: MainAxisAlignment.center, | |||||
| children: [ | |||||
| CustomButton( | |||||
| hieght: 30, | |||||
| text: AppLocalizations.of(context)!.accept, | |||||
| borderRadius: 5, | |||||
| color: Color(0xff00A848), | |||||
| fontSize: 12, | |||||
| onPressed: this.onAcceptButton, | |||||
| ), | |||||
| SizedBox( | |||||
| width: 7, | |||||
| ), | |||||
| CustomButton( | |||||
| hieght: 30, | |||||
| text: AppLocalizations.of(context)!.cancel, | |||||
| color: Colors.red, | |||||
| textColor: Colors.white, | |||||
| fontSize: 12, | |||||
| borderRadius: 5, | |||||
| onPressed: this.onCancelButton, | |||||
| ), | |||||
| SizedBox( | |||||
| width: 90, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ), | |||||
| if (this.status == 1 || this.status == 2) | |||||
| Padding( | |||||
| padding: const EdgeInsets.only(top: 10), | |||||
| child: Row( | |||||
| children: [ | |||||
| SizedBox( | |||||
| width: 60, | |||||
| ), | |||||
| PrivateMeetingLabel( | |||||
| status: this.status, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| if (this.status == 1 || this.status == 2) | |||||
| Padding( | |||||
| padding: const EdgeInsets.only(top: 10), | |||||
| child: Row( | |||||
| children: [ | |||||
| SizedBox( | |||||
| width: 60, | |||||
| ), | |||||
| PrivateMeetingLabel( | |||||
| status: this.status, | |||||
| ), | |||||
| ], | |||||
| ), | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ), | ), | ||||
| ), | |||||
| ) | |||||
| ], | |||||
| ) | |||||
| ], | |||||
| ), | |||||
| ), | ), | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -310,14 +310,16 @@ class _PrivateMeetingSummaryScreenState | |||||
| isError: true, | isError: true, | ||||
| context, | context, | ||||
| ); | ); | ||||
| } else if (state.selectedFiles == null) { | |||||
| // call add new subject | |||||
| Tools.showCustomSnackBar( | |||||
| text: AppLocalizations.of(context)!.enterfile, | |||||
| isError: true, | |||||
| context, | |||||
| ); | |||||
| } else { | |||||
| } | |||||
| // else if (state.selectedFiles == null) { | |||||
| // // call add new subject | |||||
| // Tools.showCustomSnackBar( | |||||
| // text: AppLocalizations.of(context)!.enterfile, | |||||
| // isError: true, | |||||
| // context, | |||||
| // ); | |||||
| // } | |||||
| else { | |||||
| final status = await state.addMinuteMeeting( | final status = await state.addMinuteMeeting( | ||||
| id: widget.itemInPrivateMeeting.id ?? -1, | id: widget.itemInPrivateMeeting.id ?? -1, | ||||
| description: _textControllerDescription.text, | description: _textControllerDescription.text, | ||||
| @@ -30,9 +30,11 @@ class _ReportScreenState extends State<ReportScreen> { | |||||
| @override | @override | ||||
| Widget build(BuildContext context) { | Widget build(BuildContext context) { | ||||
| DateTime now = DateTime.now(); | DateTime now = DateTime.now(); | ||||
| String dateMiladi = DateFormat('yyyy-MM-dd').format(now); | |||||
| String dateJalali = | |||||
| '${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}'; // فرمت کردن تاریخ | |||||
| String dateMiladi = | |||||
| Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now)); | |||||
| String dateJalali = Tools.convertToPersianDigits( | |||||
| '${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}'); | |||||
| // فرمت کردن تاریخ | |||||
| return CustomScrollView( | return CustomScrollView( | ||||
| slivers: <Widget>[ | slivers: <Widget>[ | ||||
| const CustomAppbar(), | const CustomAppbar(), | ||||
| @@ -271,7 +273,7 @@ class _FiltersItemInReportState extends State<FiltersItemInReport> { | |||||
| Divider(), | Divider(), | ||||
| if (setting.userLocalDb.getUser().role != 1) | if (setting.userLocalDb.getUser().role != 1) | ||||
| SizedBox( | SizedBox( | ||||
| height: 250, | |||||
| height: 300, | |||||
| child: ListView.builder( | child: ListView.builder( | ||||
| physics: NeverScrollableScrollPhysics(), | physics: NeverScrollableScrollPhysics(), | ||||
| shrinkWrap: true, | shrinkWrap: true, | ||||
| @@ -52,4 +52,38 @@ class HomeApi { | |||||
| } | } | ||||
| return const Result(isOk: false); | return const Result(isOk: false); | ||||
| } | } | ||||
| // edit profile | |||||
| Future<Result?> editProfile({String? name, String? password}) async { | |||||
| try { | |||||
| Map<String, String> headers = {"Accept": "application/json"}; | |||||
| String dataToken = setting.userLocalDb.getUser().token!; | |||||
| if (dataToken != '') { | |||||
| headers['Authorization'] = "Bearer $dataToken"; | |||||
| } | |||||
| final res = await Dio().post("${config.network.baseUrl}edit-profile", | |||||
| options: Options( | |||||
| headers: headers, | |||||
| ), | |||||
| queryParameters: {'name': name, 'password': password}); | |||||
| if (res.statusCode == 200 || res.statusCode == 201) { | |||||
| if (name != null) { | |||||
| setting.userLocalDb.saveUserField('name', name); | |||||
| } | |||||
| return const Result(isOk: true); | |||||
| } | |||||
| } on DioException catch (e) { | |||||
| // print(e); | |||||
| // print(e.response!.data); | |||||
| return Result( | |||||
| isOk: false, | |||||
| errors: e.response!.data['errors'], | |||||
| message: e.response!.data['message']); | |||||
| } | |||||
| return const Result(isOk: false); | |||||
| } | |||||
| } | } | ||||
| @@ -14,5 +14,5 @@ class LocalUser { | |||||
| this.mobile, | this.mobile, | ||||
| this.access, | this.access, | ||||
| this.role, | this.role, | ||||
| this.language = 'fa'}); | |||||
| this.language = 'en'}); | |||||
| } | } | ||||
| @@ -39,7 +39,7 @@ class UserLocalDb { | |||||
| String mobile = box!.get('mobile', defaultValue: ''); | String mobile = box!.get('mobile', defaultValue: ''); | ||||
| int role = box!.get('role', defaultValue: 0); | int role = box!.get('role', defaultValue: 0); | ||||
| List access = box!.get('access', defaultValue: []); | List access = box!.get('access', defaultValue: []); | ||||
| String language = box!.get('language', defaultValue: 'fa'); | |||||
| String language = box!.get('language', defaultValue: 'en'); | |||||
| return LocalUser( | return LocalUser( | ||||
| name: name, | name: name, | ||||
| @@ -117,4 +117,15 @@ class Tools { | |||||
| String formattedMinute = minute < 10 ? '0$minute' : '$minute'; | String formattedMinute = minute < 10 ? '0$minute' : '$minute'; | ||||
| return '$formattedHour:$formattedMinute'; | return '$formattedHour:$formattedMinute'; | ||||
| } | } | ||||
| static String convertToPersianDigits(String input) { | |||||
| const englishDigits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; | |||||
| const persianDigits = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']; | |||||
| for (int i = 0; i < englishDigits.length; i++) { | |||||
| input = input.replaceAll(englishDigits[i], persianDigits[i]); | |||||
| } | |||||
| return input; | |||||
| } | |||||
| } | } | ||||
| @@ -73,7 +73,7 @@ class CustomCardMeeting extends StatelessWidget { | |||||
| child: Text( | child: Text( | ||||
| titel, | titel, | ||||
| maxLines: 1, | maxLines: 1, | ||||
| style: const TextStyle(fontSize: 14), | |||||
| style: const TextStyle(fontSize: 13), | |||||
| overflow: TextOverflow.ellipsis, | overflow: TextOverflow.ellipsis, | ||||
| ), | ), | ||||
| ) | ) | ||||
| @@ -96,7 +96,7 @@ class CustomCardMeeting extends StatelessWidget { | |||||
| child: Text( | child: Text( | ||||
| location, | location, | ||||
| maxLines: 1, | maxLines: 1, | ||||
| style: const TextStyle(fontSize: 14), | |||||
| style: const TextStyle(fontSize: 13), | |||||
| overflow: TextOverflow.ellipsis, | overflow: TextOverflow.ellipsis, | ||||
| ), | ), | ||||
| ), | ), | ||||
| @@ -119,7 +119,7 @@ class CustomCardMeeting extends StatelessWidget { | |||||
| child: Text( | child: Text( | ||||
| date, | date, | ||||
| maxLines: 1, | maxLines: 1, | ||||
| style: const TextStyle(fontSize: 14), | |||||
| style: const TextStyle(fontSize: 13), | |||||
| overflow: TextOverflow.ellipsis, | overflow: TextOverflow.ellipsis, | ||||
| ), | ), | ||||
| ), | ), | ||||
| @@ -143,7 +143,7 @@ class CustomCardMeeting extends StatelessWidget { | |||||
| Text( | Text( | ||||
| '$fromTime ${AppLocalizations.of(context)!.to} $toTime', | '$fromTime ${AppLocalizations.of(context)!.to} $toTime', | ||||
| maxLines: 1, | maxLines: 1, | ||||
| style: const TextStyle(fontSize: 14), | |||||
| style: const TextStyle(fontSize: 13), | |||||
| overflow: TextOverflow.ellipsis, | overflow: TextOverflow.ellipsis, | ||||
| ), | ), | ||||
| ], | ], | ||||
| @@ -14,17 +14,15 @@ class CustomAppbar extends StatelessWidget { | |||||
| children: [ | children: [ | ||||
| const SizedBox(), | const SizedBox(), | ||||
| Text( | Text( | ||||
| this.title == null | |||||
| ? AppLocalizations.of(context)!.appname | |||||
| : this.title ?? '', | |||||
| this.title == null ? '' : this.title ?? '', | |||||
| style: const TextStyle( | style: const TextStyle( | ||||
| fontSize: 12, | fontSize: 12, | ||||
| color: Colors.black, | color: Colors.black, | ||||
| ), | ), | ||||
| ), | ), | ||||
| Image.asset( | Image.asset( | ||||
| 'assets/images/iconinappbar.png', // مسیر لوگو رو اینجا قرار بده | |||||
| height: 60, | |||||
| 'assets/images/D2.png', // مسیر لوگو رو اینجا قرار بده | |||||
| height: 40, | |||||
| ), | ), | ||||
| ], | ], | ||||
| ), | ), | ||||
| @@ -12,7 +12,7 @@ class CustomBackground extends StatelessWidget { | |||||
| height: double.infinity, | height: double.infinity, | ||||
| decoration: BoxDecoration( | decoration: BoxDecoration( | ||||
| image: DecorationImage( | image: DecorationImage( | ||||
| image: AssetImage('assets/images/001.jpg'), // اصلاح شده | |||||
| image: AssetImage('assets/images/001.png'), // اصلاح شده | |||||
| fit: BoxFit.cover, // تصویر را به صورت تمام صفحه تطبیق میدهد | fit: BoxFit.cover, // تصویر را به صورت تمام صفحه تطبیق میدهد | ||||
| colorFilter: opacity != null | colorFilter: opacity != null | ||||
| ? ColorFilter.mode( | ? ColorFilter.mode( | ||||