瀏覽代碼

android notification done

master
amin 1 年之前
父節點
當前提交
8039bbf63a
共有 21 個檔案被更改,包括 430 行新增157 行删除
  1. +5
    -0
      android/app/build.gradle
  2. +29
    -0
      android/app/google-services.json
  3. +12
    -6
      android/app/src/main/AndroidManifest.xml
  4. +3
    -0
      android/settings.gradle
  5. +50
    -0
      ios/Runner/AppDelegate.swift
  6. +30
    -0
      ios/Runner/GoogleService-Info.plist
  7. +60
    -20
      lib/main.dart
  8. +3
    -1
      lib/screens/auth/login_screen.dart
  9. +4
    -2
      lib/screens/auth/otp_screen.dart
  10. +5
    -4
      lib/screens/auth/state/state.dart
  11. +103
    -112
      lib/screens/home/screen.dart
  12. +3
    -2
      lib/screens/meeting/screen.dart
  13. +3
    -4
      lib/screens/private_meeting/screen.dart
  14. +3
    -2
      lib/screens/report/screen.dart
  15. +10
    -4
      lib/services/auth/auth.dart
  16. +40
    -0
      lib/services/notification/notification_service.dart
  17. +4
    -0
      macos/Flutter/GeneratedPluginRegistrant.swift
  18. +56
    -0
      pubspec.lock
  19. +3
    -0
      pubspec.yaml
  20. +3
    -0
      windows/flutter/generated_plugin_registrant.cc
  21. +1
    -0
      windows/flutter/generated_plugins.cmake

+ 5
- 0
android/app/build.gradle 查看文件

@@ -1,5 +1,8 @@
plugins {
id "com.android.application"
// START: FlutterFire Configuration
id 'com.google.gms.google-services'
// END: FlutterFire Configuration
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
@@ -42,3 +45,5 @@ android {
flutter {
source = "../.."
}

apply plugin: 'com.google.gms.google-services'

+ 29
- 0
android/app/google-services.json 查看文件

@@ -0,0 +1,29 @@
{
"project_info": {
"project_number": "392489806594",
"project_id": "folad-neiriz",
"storage_bucket": "folad-neiriz.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:392489806594:android:76b6661258b6f56f3b301b",
"android_client_info": {
"package_name": "com.example.qadirneyriz"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyAuDK456j4fFdNqrzQRDYyWRcB0VkQ2bCY"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

+ 12
- 6
android/app/src/main/AndroidManifest.xml 查看文件

@@ -1,10 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:label="Mizban"
android:name="${applicationName}"
@@ -18,10 +20,6 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
@@ -31,11 +29,19 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<service
android:name="io.flutter.plugins.firebase.messaging.FlutterFirebaseMessagingService"
android:exported="true"
tools:replace="android:exported">
</service>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="high_importance_channel" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and


+ 3
- 0
android/settings.gradle 查看文件

@@ -19,6 +19,9 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.1.0" apply false
// START: FlutterFire Configuration
id "com.google.gms.google-services" version "4.3.15" apply false
// END: FlutterFire Configuration
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
}



+ 50
- 0
ios/Runner/AppDelegate.swift 查看文件

@@ -1,5 +1,7 @@
import Flutter
import UIKit
import Firebase
import FirebaseMessaging

@main
@objc class AppDelegate: FlutterAppDelegate {
@@ -7,7 +9,55 @@ import UIKit
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// مقداردهی Firebase
FirebaseApp.configure()
// ثبت Plugin های Flutter
GeneratedPluginRegistrant.register(with: self)

// تنظیمات Notification Center
UNUserNotificationCenter.current().delegate = self
Messaging.messaging().delegate = self

// درخواست مجوز نوتیفیکیشن
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
if let error = error {
print("Error requesting notification permissions: \(error)")
}
print("Permission granted: \(granted)")
}
// ثبت دستگاه برای دریافت Remote Notifications
application.registerForRemoteNotifications()
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

// متد دریافت APNs Token و ارسال آن به Firebase
override func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
Messaging.messaging().apnsToken = deviceToken
}
}

// افزودن پروتکل‌های UNUserNotificationCenterDelegate و MessagingDelegate
extension AppDelegate: UNUserNotificationCenterDelegate, MessagingDelegate {
// مدیریت دریافت توکن Firebase
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
print("Firebase FCM Token: \(fcmToken ?? "No Token")")
// اگر نیاز به ارسال توکن به سرور دارید، اینجا انجام دهید.
}
// مدیریت پیام‌های دریافت‌شده هنگام باز بودن اپلیکیشن
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
let userInfo = notification.request.content.userInfo
print("Foreground Notification Received: \(userInfo)")
completionHandler([.banner, .sound, .badge])
}
}

+ 30
- 0
ios/Runner/GoogleService-Info.plist 查看文件

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>API_KEY</key>
<string>AIzaSyDmiLNq_t5wyqDE2VW1wGyt6kArchRvLAQ</string>
<key>GCM_SENDER_ID</key>
<string>392489806594</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.example.qadirneyriz</string>
<key>PROJECT_ID</key>
<string>folad-neiriz</string>
<key>STORAGE_BUCKET</key>
<string>folad-neiriz.firebasestorage.app</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:392489806594:ios:feeba2107eb852ec3b301b</string>
</dict>
</plist>

+ 60
- 20
lib/main.dart 查看文件

@@ -1,3 +1,5 @@
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:hive_flutter/hive_flutter.dart';
@@ -13,9 +15,52 @@ import 'package:qadirneyriz/screens/private_meeting/state.dart';
import 'package:qadirneyriz/screens/report/state.dart';
import 'package:qadirneyriz/setting/setting.dart';

void main() async {
final FirebaseMessaging messaging = FirebaseMessaging.instance;

Future<void> initializeApp() async {
await Firebase.initializeApp();
await Hive.initFlutter();
await setting.userLocalDb.openBox();
await requestNotificationPermission();
await getToken();
setupMessageListener();
}

Future<void> 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<void> getToken() async {
String? token = await messaging.getToken();
print("Device Token: $token");
// You can send the token to your server here if needed
}

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 {
WidgetsFlutterBinding.ensureInitialized();
await initializeApp(); // Initialize Firebase and other services
runApp(
MultiProvider(
providers: [
@@ -41,51 +86,46 @@ class MyApp extends StatefulWidget {
class _MyAppState extends State<MyApp> {
late AuthState state;
String language = setting.userLocalDb.getUser().language;

@override
void initState() {
super.initState();
Future.delayed(Duration.zero, () async {
state = Provider.of(context, listen: false);
state = Provider.of<AuthState>(context, listen: false);
setState(() {
language = state.language;
});
});
super.initState();
}

// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return Consumer<AuthState>(
builder: (context, value, child) {
return MaterialApp.router(
theme: ThemeData(
colorScheme: ColorScheme.light(
// تغییر رنگ اصلی تایم پیکر
primary: config.ui.mainGreen,
// تغییر رنگ متن
),
buttonTheme: ButtonThemeData(
colorScheme: ColorScheme.light(
primary: Colors.green, // رنگ دکمه‌ها
),
),
useMaterial3: true,
fontFamily: 'Font',
scaffoldBackgroundColor: Colors.white),
colorScheme: ColorScheme.light(primary: config.ui.mainGreen),
buttonTheme: ButtonThemeData(
colorScheme: ColorScheme.light(primary: Colors.green),
),
useMaterial3: true,
fontFamily: 'Font',
scaffoldBackgroundColor: Colors.white,
),
debugShowCheckedModeBanner: false,
routerDelegate: router.routerDelegate,
routeInformationParser: router.routeInformationParser,
routeInformationProvider: router.routeInformationProvider,
localizationsDelegates: const [
AppLocalizations.delegate, // Add this line
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
locale: Locale(value.language),
supportedLocales: const [
Locale('en'), // English
Locale('fa'), // Persian
Locale('en'),
Locale('fa'),
],
);
},


+ 3
- 1
lib/screens/auth/login_screen.dart 查看文件

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:qadirneyriz/config/config.dart';
import 'package:qadirneyriz/main.dart';
import 'package:qadirneyriz/screens/auth/state/state.dart';
import 'package:qadirneyriz/utils/enums/status.dart';
import 'package:qadirneyriz/utils/tools/tools.dart';
@@ -151,8 +152,9 @@ class _LoginScreenState extends State<LoginScreen> {
isError: true,
context,
);
} else {
} else { String? token = await messaging.getToken();
final status = await state.login(
fcm_token: token??'',
mobile: phoneController.text,
password: passwordController.text);
if (status == Status.ready) {


+ 4
- 2
lib/screens/auth/otp_screen.dart 查看文件

@@ -3,6 +3,7 @@ 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/main.dart';
import 'package:qadirneyriz/screens/auth/state/state.dart';
import 'package:qadirneyriz/utils/enums/status.dart';
import 'package:qadirneyriz/utils/timer/apt_simple_timer_with_controller.dart';
@@ -182,9 +183,10 @@ class _OtpScreenState extends State<OtpScreen> {
}

void otpCheckCode(onSubmitted, AuthState value) async {
String? token = await messaging.getToken();
if (onSubmitted.length == 4) {
final status =
await value.login(mobile: widget.phoneNumber, otp: onSubmitted);
final status = await value.login(
mobile: widget.phoneNumber, otp: onSubmitted, fcm_token: token ?? '');
if (status == Status.ready) {
context.goNamed('navigate', pathParameters: {'tab': '0'});
} else if (status == Status.error) {


+ 5
- 4
lib/screens/auth/state/state.dart 查看文件

@@ -22,13 +22,16 @@ class AuthState extends ChangeNotifier {
Map? errorsLogin;

Future<Status> login(
{required String mobile, String? password, String? otp}) async {
{required String mobile,
String? password,
String? otp,
required String fcm_token}) 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, fcm_token: fcm_token);
if (result == null) {
statusLogin = Status.error;
} else {
@@ -88,6 +91,4 @@ class AuthState extends ChangeNotifier {
// print(statusSendotp);
return statusSendotp;
}


}

+ 103
- 112
lib/screens/home/screen.dart 查看文件

@@ -38,8 +38,9 @@ class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
DateTime now = DateTime.now();
String dateMiladi =
Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now));
String dateMiladi = setting.userLocalDb.getUser().language == 'fa'
? Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now))
: DateFormat('yyyy-MM-dd').format(now);
String dateJalali = Tools.convertToPersianDigits(
'${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}');

@@ -123,29 +124,38 @@ class _HomeScreenState extends State<HomeScreen> {
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(
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(
left: setting.userLocalDb
.getUser()
.language ==
'fa'
? 20
: 280,
top: 20,
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(10),
color: Colors.green),
borderRadius:
BorderRadius.circular(10),
color: Colors.green,
),
child: Padding(
padding:
const EdgeInsets.all(5.0),
@@ -156,13 +166,11 @@ class _HomeScreenState extends State<HomeScreen> {
fontSize: 12,
color: Colors.white),
),
)),
left: 30,
top: 20,
),
],
),
);
),
),
),
],
));
} else {
// آیتم از لیست `privateMeetings`
final privateMeeting = value
@@ -192,6 +200,12 @@ class _HomeScreenState extends State<HomeScreen> {
toTime: privateMeeting.taHour ?? '',
),
Positioned(
left: setting.userLocalDb
.getUser()
.language ==
'fa'
? 20
: 250,
child: Container(
decoration: BoxDecoration(
borderRadius:
@@ -208,7 +222,6 @@ class _HomeScreenState extends State<HomeScreen> {
color: Colors.white),
),
)),
left: 30,
top: 20,
),
],
@@ -343,86 +356,7 @@ class _HomeScreenState extends State<HomeScreen> {
const SizedBox(
height: 30,
),
Consumer<HomeState>(
builder: (context, value, child) {
switch (value.statusLogOut) {
case Status.loading:
return const LoadingWidget();

default:
return Row(
mainAxisAlignment:
MainAxisAlignment
.center,
crossAxisAlignment:
CrossAxisAlignment
.center,
children: [
CustomButton(
fontSize: 13,
color: config
.ui.mainGreen,
onPressed: () {
Navigator.pop(
context);
},
hieght: 50,

// width: 150,
text: AppLocalizations
.of(context)!
.no,
),
const SizedBox(
width: 10,
),
CustomButton(
fontSize: 13,
hieght: 50,
// width: 150,
text: AppLocalizations
.of(context)!
.logout,
textColor:
Colors.black,
color: const Color(
0xffD0D5ED),

onPressed: () async {
final status =
await value
.logOut();
if (status ==
Status.error) {
Tools.showCustomSnackBar(
context,
text: value
.messageLogOut ??
AppLocalizations.of(
context)!
.error,
isError:
true);
} else if (status ==
Status.ready) {
context
.pushReplacementNamed(
'login');
Tools.showCustomSnackBar(
context,
text: value
.messageLogOut ??
'Done successfully',
isError:
false);
}
},
),
],
);
}
},
),
logOutButton(),
const SizedBox(
height: 40,
)
@@ -458,6 +392,63 @@ class _HomeScreenState extends State<HomeScreen> {
},
);
}

Consumer<HomeState> logOutButton() {
return Consumer<HomeState>(
builder: (context, value, child) {
switch (value.statusLogOut) {
case Status.loading:
return const LoadingWidget();

default:
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CustomButton(
fontSize: 13,
color: config.ui.mainGreen,
onPressed: () {
Navigator.pop(context);
},
hieght: 50,

// width: 150,
text: AppLocalizations.of(context)!.no,
),
const SizedBox(
width: 10,
),
CustomButton(
fontSize: 13,
hieght: 50,
// width: 150,
text: AppLocalizations.of(context)!.logout,
textColor: Colors.black,
color: const Color(0xffD0D5ED),

onPressed: () async {
final status = await value.logOut();
if (status == Status.error) {
Tools.showCustomSnackBar(context,
text: value.messageLogOut ??
AppLocalizations.of(context)!.error,
isError: true);
} else if (status == Status.ready) {
setting.userLocalDb.logOut();
context.pushReplacementNamed('login');
Tools.showCustomSnackBar(context,
text: value.messageLogOut ?? 'Done successfully',
isError: false);
}
},
),
],
);
}
},
);
}
}

class ItemInGrid extends StatelessWidget {


+ 3
- 2
lib/screens/meeting/screen.dart 查看文件

@@ -67,8 +67,9 @@ class _MeetingsScreenState extends State<MeetingsScreen> {
@override
Widget build(BuildContext context) {
DateTime now = DateTime.now();
String dateMiladi =
Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now));
String dateMiladi = setting.userLocalDb.getUser().language == 'fa'
? Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now))
: DateFormat('yyyy-MM-dd').format(now);
String dateJalali = Tools.convertToPersianDigits(
'${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}');
// فرمت کردن تاریخ


+ 3
- 4
lib/screens/private_meeting/screen.dart 查看文件

@@ -64,8 +64,9 @@ class _PrivateMeetingsScreenState extends State<PrivateMeetingsScreen> {
@override
Widget build(BuildContext context) {
DateTime now = DateTime.now();
String dateMiladi =
Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now));
String dateMiladi = setting.userLocalDb.getUser().language == 'fa'
? Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now))
: DateFormat('yyyy-MM-dd').format(now);
String dateJalali = Tools.convertToPersianDigits(
'${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}');

@@ -315,8 +316,6 @@ class PrivateMeetingWidget extends StatelessWidget {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
child: Container(
width: 500,
height: 190,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [


+ 3
- 2
lib/screens/report/screen.dart 查看文件

@@ -30,8 +30,9 @@ class _ReportScreenState extends State<ReportScreen> {
@override
Widget build(BuildContext context) {
DateTime now = DateTime.now();
String dateMiladi =
Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now));
String dateMiladi = setting.userLocalDb.getUser().language == 'fa'
? Tools.convertToPersianDigits(DateFormat('yyyy-MM-dd').format(now))
: DateFormat('yyyy-MM-dd').format(now);
String dateJalali = Tools.convertToPersianDigits(
'${setting.timeNow.day} ${Tools.getMonthName(setting.timeNow.month)} ${setting.timeNow.year}');
// فرمت کردن تاریخ


+ 10
- 4
lib/services/auth/auth.dart 查看文件

@@ -5,15 +5,20 @@ import 'package:qadirneyriz/utils/result/result.dart';

class AuthServices {
Future<Result?> loginApi(
{required String mobile, String? password, String? otp}) async {
{required String mobile,
String? password,
String? otp,
required String fcm_token}) async {
assert(password != null || otp != null);
try {
Map<String, String> headers = {"Accept": "application/json"};
FormData? formData;
formData = password != null
? FormData.fromMap({"mobile": mobile, "password": password})
: FormData.fromMap({"mobile": mobile, "otp": otp});

? FormData.fromMap(
{"mobile": mobile, "password": password, "device_id": fcm_token})
: FormData.fromMap(
{"mobile": mobile, "otp": otp, "device_id": fcm_token});
print('${formData.fields} resData');
final res = await Dio().post("${config.network.baseUrl}login",
data: formData, options: Options(headers: headers));

@@ -26,6 +31,7 @@ class AuthServices {
return Result(isOk: true, message: res.data['msg']);
}
} on DioException catch (e) {
print(e);
return Result(
isOk: false,
errors: e.response!.data['errors'],


+ 40
- 0
lib/services/notification/notification_service.dart 查看文件

@@ -0,0 +1,40 @@
import 'package:firebase_messaging/firebase_messaging.dart';

class NotificationService {
final FirebaseMessaging _messaging = FirebaseMessaging.instance;

/// درخواست دسترسی به نوتیفیکیشن
Future<void> 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<void> getToken() async {
String? token = await _messaging.getToken();
print("Device Token: $token");
// اینجا می‌توانید توکن را به سرور خود ارسال کنید
}

/// تنظیم Listener برای دریافت نوتیفیکیشن‌ها
void setupMessageListener() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Message received: ${message.notification?.title}');
print('Message body: ${message.notification?.body}');
// اینجا می‌توانید یک Dialog یا Toast برای نمایش پیام استفاده کنید
});
}
}

+ 4
- 0
macos/Flutter/GeneratedPluginRegistrant.swift 查看文件

@@ -5,11 +5,15 @@
import FlutterMacOS
import Foundation

import firebase_core
import firebase_messaging
import open_file_mac
import path_provider_foundation
import sqflite

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))


+ 56
- 0
pubspec.lock 查看文件

@@ -9,6 +9,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "72.0.0"
_flutterfire_internals:
dependency: transitive
description:
name: _flutterfire_internals
sha256: "71c01c1998c40b3af1944ad0a5f374b4e6fef7f3d2df487f3970dbeadaeb25a1"
url: "https://pub.dev"
source: hosted
version: "1.3.46"
_macros:
dependency: transitive
description: dart
@@ -262,6 +270,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.1.3"
firebase_core:
dependency: "direct main"
description:
name: firebase_core
sha256: "2438a75ad803e818ad3bd5df49137ee619c46b6fc7101f4dbc23da07305ce553"
url: "https://pub.dev"
source: hosted
version: "3.8.0"
firebase_core_platform_interface:
dependency: transitive
description:
name: firebase_core_platform_interface
sha256: e30da58198a6d4b49d5bce4e852f985c32cb10db329ebef9473db2b9f09ce810
url: "https://pub.dev"
source: hosted
version: "5.3.0"
firebase_core_web:
dependency: transitive
description:
name: firebase_core_web
sha256: f967a7138f5d2ffb1ce15950e2a382924239eaa521150a8f144af34e68b3b3e5
url: "https://pub.dev"
source: hosted
version: "2.18.1"
firebase_messaging:
dependency: "direct main"
description:
name: firebase_messaging
sha256: "4d0968ecb860d7baa15a6e2af3469ec5b0d959e51c59ce84a52b0f7632a4aa5a"
url: "https://pub.dev"
source: hosted
version: "15.1.5"
firebase_messaging_platform_interface:
dependency: transitive
description:
name: firebase_messaging_platform_interface
sha256: a2cb3e7d71d40b6612e2d4e0daa0ae759f6a9d07f693f904d14d22aadf70be10
url: "https://pub.dev"
source: hosted
version: "4.5.48"
firebase_messaging_web:
dependency: transitive
description:
name: firebase_messaging_web
sha256: "1554e190f0cd9d6fe59f61ae0275ac12006fdb78b07669f1a260d1a9e6de3a1f"
url: "https://pub.dev"
source: hosted
version: "3.9.4"
fixnum:
dependency: transitive
description:


+ 3
- 0
pubspec.yaml 查看文件

@@ -34,6 +34,9 @@ dependencies:
file_picker: ^8.1.3
permission_handler: ^11.3.1
open_file: ^3.5.9
firebase_core: ^3.8.0
firebase_messaging: ^15.1.5


dev_dependencies:
flutter_test:


+ 3
- 0
windows/flutter/generated_plugin_registrant.cc 查看文件

@@ -6,9 +6,12 @@

#include "generated_plugin_registrant.h"

#include <firebase_core/firebase_core_plugin_c_api.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>

void RegisterPlugins(flutter::PluginRegistry* registry) {
FirebaseCorePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
PermissionHandlerWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
}

+ 1
- 0
windows/flutter/generated_plugins.cmake 查看文件

@@ -3,6 +3,7 @@
#

list(APPEND FLUTTER_PLUGIN_LIST
firebase_core
permission_handler_windows
)



Loading…
取消
儲存