fix: Init Notification Push iOS Ok

This commit is contained in:
Ivan Antunes 2024-08-19 08:25:58 -03:00
parent 460ad3bbbd
commit 87094d39c3
16 changed files with 847 additions and 2336 deletions

View File

@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application
android:label="FREHub"
@ -22,7 +23,10 @@
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
android:windowSoftInputMode="adjustResize"
android:showWhenLocked="true"
android:turnScreenOn="true">
<!-- 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
@ -52,6 +56,7 @@
android:resource="@drawable/ic_fre_black" />
<intent-filter android:autoVerify="true">
<action android:name="FLUTTER_NOTIFICATION_CLICK" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

View File

@ -193,6 +193,7 @@ PODS:
- Flutter
- local_auth_darwin (0.0.1):
- Flutter
- FlutterMacOS
- nanopb (2.30910.0):
- nanopb/decode (= 2.30910.0)
- nanopb/encode (= 2.30910.0)
@ -346,7 +347,7 @@ SPEC CHECKSUMS:
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
local_auth_darwin: 4d56c90c2683319835a61274b57620df9c4520ab
local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3
nanopb: 438bc412db1928dac798aa6fd75726007be04262
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
@ -360,7 +361,7 @@ SPEC CHECKSUMS:
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
webview_flutter_wkwebview: be0f0d33777f1bfd0c9fdcb594786704dbf65f36
webview_flutter_wkwebview: 2a23822e9039b7b1bc52e5add778e5d89ad488d1
PODFILE CHECKSUM: d7f4d1b71f8c708247c1078c4aec33a28c763405

View File

@ -1,351 +0,0 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:http/http.dart' as http;
import 'package:hub/backend/notification/message.dart';
import 'package:hub/backend/notification/message_list.dart';
import 'package:hub/backend/notification/permissions.dart';
import 'package:hub/backend/notification/token_monitor.dart';
import 'package:hub/firebase_options.dart';
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await setupFlutterNotifications();
showFlutterNotification(message);
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
print('Handling a background message ${message.messageId}');
}
/// Create a [AndroidNotificationChannel] for heads up notifications
late AndroidNotificationChannel channel;
bool isFlutterLocalNotificationsInitialized = false;
Future<void> setupFlutterNotifications() async {
if (isFlutterLocalNotificationsInitialized) {
return;
}
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description:
'This channel is used for important notifications.', // description
importance: Importance.high,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
/// Create an Android Notification Channel.
///
/// We use this channel in the `AndroidManifest.xml` file to override the
/// default FCM channel to enable heads up notifications.
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
isFlutterLocalNotificationsInitialized = true;
}
void showFlutterNotification(RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
// TODO add a proper drawable resource to android, for now using
// one that already exists in example app.
icon: 'launch_background',
),
),
);
}
}
/// Initialize the [FlutterLocalNotificationsPlugin] package.
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
// Set the background messaging handler early on, as a named top-level function
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
if (!kIsWeb) {
await setupFlutterNotifications();
}
runApp(MessagingExampleApp());
}
/// Entry point for the example application.
class MessagingExampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Messaging Example App',
theme: ThemeData.dark(),
routes: {
'/': (context) => Application(),
'/message': (context) => MessageView(),
},
);
}
}
// Crude counter to make messages unique
int _messageCount = 0;
/// The API endpoint here accepts a raw FCM payload for demonstration purposes.
String constructFCMPayload(String? token) {
_messageCount++;
return jsonEncode({
'token': token,
'data': {
'via': 'FlutterFire Cloud Messaging!!!',
'count': _messageCount.toString(),
},
'notification': {
'title': 'Hello FlutterFire!',
'body': 'This notification (#$_messageCount) was created via FCM!',
},
});
}
/// Renders the example application.
class Application extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Application();
}
class _Application extends State<Application> {
String? _token;
String? initialMessage;
bool _resolved = false;
@override
void initState() {
super.initState();
FirebaseMessaging.instance.getInitialMessage().then(
(value) => setState(
() {
_resolved = true;
initialMessage = value?.data.toString();
},
),
);
FirebaseMessaging.onMessage.listen(showFlutterNotification);
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('A new onMessageOpenedApp event was published!');
Navigator.pushNamed(
context,
'/message',
arguments: MessageArguments(message, true),
);
});
}
Future<void> sendPushMessage() async {
if (_token == null) {
print('Unable to send FCM message, no token exists.');
return;
}
try {
await http.post(
Uri.parse('https://api.rnfirebase.io/messaging/send'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: constructFCMPayload(_token),
);
print('FCM request for device sent!');
} catch (e) {
print(e);
}
}
Future<void> onActionSelected(String value) async {
switch (value) {
case 'subscribe':
{
print(
'FlutterFire Messaging Example: Subscribing to topic "fcm_test".',
);
await FirebaseMessaging.instance.subscribeToTopic('fcm_test');
print(
'FlutterFire Messaging Example: Subscribing to topic "fcm_test" successful.',
);
}
break;
case 'unsubscribe':
{
print(
'FlutterFire Messaging Example: Unsubscribing from topic "fcm_test".',
);
await FirebaseMessaging.instance.unsubscribeFromTopic('fcm_test');
print(
'FlutterFire Messaging Example: Unsubscribing from topic "fcm_test" successful.',
);
}
break;
case 'get_apns_token':
{
if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
print('FlutterFire Messaging Example: Getting APNs token...');
String? token = await FirebaseMessaging.instance.getAPNSToken();
print('FlutterFire Messaging Example: Got APNs token: $token');
} else {
print(
'FlutterFire Messaging Example: Getting an APNs token is only supported on iOS and macOS platforms.',
);
}
}
break;
default:
break;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Cloud Messaging'),
actions: <Widget>[
PopupMenuButton(
onSelected: onActionSelected,
itemBuilder: (BuildContext context) {
return [
const PopupMenuItem(
value: 'subscribe',
child: Text('Subscribe to topic'),
),
const PopupMenuItem(
value: 'unsubscribe',
child: Text('Unsubscribe to topic'),
),
const PopupMenuItem(
value: 'get_apns_token',
child: Text('Get APNs token (Apple only)'),
),
];
},
),
],
),
floatingActionButton: Builder(
builder: (context) => FloatingActionButton(
onPressed: sendPushMessage,
backgroundColor: Colors.white,
child: const Icon(Icons.send),
),
),
body: SingleChildScrollView(
child: Column(
children: [
MetaCard('Permissions', Permissions()),
MetaCard(
'Initial Message',
Column(
children: [
Text(_resolved ? 'Resolved' : 'Resolving'),
Text(initialMessage ?? 'None'),
],
),
),
MetaCard(
'FCM Token',
TokenMonitor((token) {
_token = token;
return token == null
? const CircularProgressIndicator()
: SelectableText(
token,
style: const TextStyle(fontSize: 12),
);
}),
),
ElevatedButton(
onPressed: () {
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage? message) {
if (message != null) {
Navigator.pushNamed(
context,
'/message',
arguments: MessageArguments(message, true),
);
}
});
},
child: const Text('getInitialMessage()'),
),
MetaCard('Message Stream', MessageList()),
],
),
),
);
}
}
/// UI Widget for displaying metadata.
class MetaCard extends StatelessWidget {
final String _title;
final Widget _children;
// ignore: public_member_api_docs
MetaCard(this._title, this._children);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
margin: const EdgeInsets.only(left: 8, right: 8, top: 8),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Container(
margin: const EdgeInsets.only(bottom: 16),
child: Text(_title, style: const TextStyle(fontSize: 18)),
),
_children,
],
),
),
),
);
}
}

View File

@ -1,101 +0,0 @@
// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// File generated by FlutterFire CLI.
// ignore_for_file: lines_longer_than_80_chars, avoid_classes_with_only_static_members
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
import 'package:flutter/foundation.dart'
show defaultTargetPlatform, kIsWeb, TargetPlatform;
/// Default [FirebaseOptions] for use with your Firebase apps.
///
/// Example:
/// ```dart
/// import 'firebase_options.dart';
/// // ...
/// await Firebase.initializeApp(
/// options: DefaultFirebaseOptions.currentPlatform,
/// );
/// ```
class DefaultFirebaseOptions {
static FirebaseOptions get currentPlatform {
if (kIsWeb) {
return web;
}
switch (defaultTargetPlatform) {
case TargetPlatform.android:
return android;
case TargetPlatform.iOS:
return ios;
case TargetPlatform.macOS:
return macos;
case TargetPlatform.windows:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for windows - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
case TargetPlatform.linux:
throw UnsupportedError(
'DefaultFirebaseOptions have not been configured for linux - '
'you can reconfigure this by running the FlutterFire CLI again.',
);
default:
throw UnsupportedError(
'DefaultFirebaseOptions are not supported for this platform.',
);
}
}
static const FirebaseOptions web = FirebaseOptions(
apiKey: 'AIzaSyB7wZb2tO1-Fs6GbDADUSTs2Qs3w08Hovw',
appId: '1:406099696497:web:87e25e51afe982cd3574d0',
messagingSenderId: '406099696497',
projectId: 'flutterfire-e2e-tests',
authDomain: 'flutterfire-e2e-tests.firebaseapp.com',
databaseURL:
'https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app',
storageBucket: 'flutterfire-e2e-tests.appspot.com',
measurementId: 'G-JN95N1JV2E',
);
static const FirebaseOptions android = FirebaseOptions(
apiKey: 'AIzaSyCdRjCVZlhrq72RuEklEyyxYlBRCYhI2Sw',
appId: '1:406099696497:android:74ebb073d7727cd43574d0',
messagingSenderId: '406099696497',
projectId: 'flutterfire-e2e-tests',
databaseURL:
'https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app',
storageBucket: 'flutterfire-e2e-tests.appspot.com',
);
static const FirebaseOptions ios = FirebaseOptions(
apiKey: 'AIzaSyDooSUGSf63Ghq02_iIhtnmwMDs4HlWS6c',
appId: '1:406099696497:ios:1b423b89c63b82053574d0',
messagingSenderId: '406099696497',
projectId: 'flutterfire-e2e-tests',
databaseURL:
'https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app',
storageBucket: 'flutterfire-e2e-tests.appspot.com',
androidClientId:
'406099696497-17qn06u8a0dc717u8ul7s49ampk13lul.apps.googleusercontent.com',
iosClientId:
'406099696497-irb7edfevfkhi6t5s9kbuq1mt1og95rg.apps.googleusercontent.com',
iosBundleId: 'io.flutter.plugins.firebase.messaging',
);
static const FirebaseOptions macos = FirebaseOptions(
apiKey: 'AIzaSyDooSUGSf63Ghq02_iIhtnmwMDs4HlWS6c',
appId: '1:406099696497:ios:1b423b89c63b82053574d0',
messagingSenderId: '406099696497',
projectId: 'flutterfire-e2e-tests',
databaseURL:
'https://flutterfire-e2e-tests-default-rtdb.europe-west1.firebasedatabase.app',
storageBucket: 'flutterfire-e2e-tests.appspot.com',
androidClientId:
'406099696497-17qn06u8a0dc717u8ul7s49ampk13lul.apps.googleusercontent.com',
iosClientId:
'406099696497-irb7edfevfkhi6t5s9kbuq1mt1og95rg.apps.googleusercontent.com',
iosBundleId: 'io.flutter.plugins.firebase.messaging',
);
}

View File

@ -1,163 +0,0 @@
// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// ignore_for_file: require_trailing_commas
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
/// Message route arguments.
class MessageArguments {
/// The RemoteMessage
final RemoteMessage message;
/// Whether this message caused the application to open.
final bool openedApplication;
// ignore: public_member_api_docs
MessageArguments(this.message, this.openedApplication);
}
/// Displays information about a [RemoteMessage].
class MessageView extends StatelessWidget {
/// A single data row.
Widget row(String title, String? value) {
return Padding(
padding: const EdgeInsets.only(left: 8, right: 8, top: 8),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('$title: '),
Expanded(child: Text(value ?? 'N/A')),
],
),
);
}
@override
Widget build(BuildContext context) {
final MessageArguments args =
ModalRoute.of(context)!.settings.arguments! as MessageArguments;
RemoteMessage message = args.message;
RemoteNotification? notification = message.notification;
return Scaffold(
appBar: AppBar(
title: Text(message.messageId ?? 'N/A'),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8),
child: Column(
children: [
row('Triggered application open',
args.openedApplication.toString()),
row('Message ID', message.messageId),
row('Sender ID', message.senderId),
row('Category', message.category),
row('Collapse Key', message.collapseKey),
row('Content Available', message.contentAvailable.toString()),
row('Data', message.data.toString()),
row('From', message.from),
row('Message ID', message.messageId),
row('Sent Time', message.sentTime?.toString()),
row('Thread ID', message.threadId),
row('Time to Live (TTL)', message.ttl?.toString()),
if (notification != null) ...[
Padding(
padding: const EdgeInsets.only(top: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Remote Notification',
style: TextStyle(fontSize: 18),
),
row(
'Title',
notification.title,
),
row(
'Body',
notification.body,
),
if (notification.android != null) ...[
const SizedBox(height: 16),
const Text(
'Android Properties',
style: TextStyle(fontSize: 18),
),
row(
'Channel ID',
notification.android!.channelId,
),
row(
'Click Action',
notification.android!.clickAction,
),
row(
'Color',
notification.android!.color,
),
row(
'Count',
notification.android!.count?.toString(),
),
row(
'Image URL',
notification.android!.imageUrl,
),
row(
'Link',
notification.android!.link,
),
row(
'Priority',
notification.android!.priority.toString(),
),
row(
'Small Icon',
notification.android!.smallIcon,
),
row(
'Sound',
notification.android!.sound,
),
row(
'Ticker',
notification.android!.ticker,
),
row(
'Visibility',
notification.android!.visibility.toString(),
),
],
if (notification.apple != null) ...[
const Text(
'Apple Properties',
style: TextStyle(fontSize: 18),
),
row(
'Subtitle',
notification.apple!.subtitle,
),
row(
'Badge',
notification.apple!.badge,
),
row(
'Sound',
notification.apple!.sound?.name,
),
]
],
),
)
]
],
),
)),
);
}
}

View File

@ -1,53 +0,0 @@
// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// ignore_for_file: require_trailing_commas
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'message.dart';
/// Listens for incoming foreground messages and displays them in a list.
class MessageList extends StatefulWidget {
@override
State<StatefulWidget> createState() => _MessageList();
}
class _MessageList extends State<MessageList> {
List<RemoteMessage> _messages = [];
@override
void initState() {
super.initState();
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
setState(() {
_messages = [..._messages, message];
});
});
}
@override
Widget build(BuildContext context) {
if (_messages.isEmpty) {
return const Text('No messages received');
}
return ListView.builder(
shrinkWrap: true,
itemCount: _messages.length,
itemBuilder: (context, index) {
RemoteMessage message = _messages[index];
return ListTile(
title: Text(
message.messageId ?? 'no RemoteMessage.messageId available'),
subtitle:
Text(message.sentTime?.toString() ?? DateTime.now().toString()),
onTap: () => Navigator.pushNamed(context, '/message',
arguments: MessageArguments(message, false)),
);
});
}
}

View File

@ -1,383 +0,0 @@
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:http/http.dart' as http;
import 'package:hub/backend/notification/message.dart';
import 'package:hub/backend/notification/message_list.dart';
import 'package:hub/backend/notification/permissions.dart';
import 'package:hub/backend/notification/token_monitor.dart';
import 'package:hub/firebase_options.dart';
// import 'firebase_options.dart';
// import 'message.dart';
// import 'message_list.dart';
// import 'permissions.dart';
// import 'token_monitor.dart';
/// Working example of FirebaseMessaging.
/// Please use this in order to verify messages are working in foreground, background & terminated state.
/// Setup your app following this guide:
/// https://firebase.google.com/docs/cloud-messaging/flutter/client#platform-specific_setup_and_requirements):
///
/// Once you've completed platform specific requirements, follow these instructions:
/// 1. Install melos tool by running `flutter pub global activate melos`.
/// 2. Run `melos bootstrap` in FlutterFire project.
/// 3. In your terminal, root to ./packages/firebase_messaging/firebase_messaging/example directory.
/// 4. Run `flutterfire configure` in the example/ directory to setup your app with your Firebase project.
/// 5. Open `token_monitor.dart` and change `vapidKey` to yours.
/// 6. Run the app on an actual device for iOS, android is fine to run on an emulator.
/// 7. Use the following script to send a message to your device: scripts/send-message.js. To run this script,
/// you will need nodejs installed on your computer. Then the following:
/// a. Download a service account key (JSON file) from your Firebase console, rename it to "google-services.json" and add to the example/scripts directory.
/// b. Ensure your device/emulator is running, and run the FirebaseMessaging example app using `flutter run`.
/// c. Copy the token that is printed in the console and paste it here: https://github.com/firebase/flutterfire/blob/01b4d357e1/packages/firebase_messaging/firebase_messaging/example/lib/main.dart#L32
/// c. From your terminal, root to example/scripts directory & run `npm install`.
/// d. Run `npm run send-message` in the example/scripts directory and your app will receive messages in any state; foreground, background, terminated.
/// Note: Flutter API documentation for receiving messages: https://firebase.google.com/docs/cloud-messaging/flutter/receive
/// Note: If you find your messages have stopped arriving, it is extremely likely they are being throttled by the platform. iOS in particular
/// are aggressive with their throttling policy.
///
/// To verify that your messages are being received, you ought to see a notification appearon your device/emulator via the flutter_local_notifications plugin.
/// Define a top-level named handler which background/terminated messages will
/// call. Be sure to annotate the handler with `@pragma('vm:entry-point')` above the function declaration.
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await setupFlutterNotifications();
showFlutterNotification(message);
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
print('Handling a background message ${message.messageId}');
}
/// Create a [AndroidNotificationChannel] for heads up notifications
late AndroidNotificationChannel channel;
bool isFlutterLocalNotificationsInitialized = false;
Future<void> setupFlutterNotifications() async {
if (isFlutterLocalNotificationsInitialized) {
return;
}
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description:
'This channel is used for important notifications.', // description
importance: Importance.high,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
/// Create an Android Notification Channel.
///
/// We use this channel in the `AndroidManifest.xml` file to override the
/// default FCM channel to enable heads up notifications.
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
isFlutterLocalNotificationsInitialized = true;
}
void showFlutterNotification(RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
// TODO add a proper drawable resource to android, for now using
// one that already exists in example app.
icon: 'launch_background',
),
),
);
}
}
/// Initialize the [FlutterLocalNotificationsPlugin] package.
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
// Set the background messaging handler early on, as a named top-level function
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
if (!kIsWeb) {
await setupFlutterNotifications();
}
runApp(MessagingExampleApp());
}
/// Entry point for the example application.
class MessagingExampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Messaging Example App',
theme: ThemeData.dark(),
routes: {
'/': (context) => Application(),
'/message': (context) => MessageView(),
},
);
}
}
// Crude counter to make messages unique
int _messageCount = 0;
/// The API endpoint here accepts a raw FCM payload for demonstration purposes.
String constructFCMPayload(String? token) {
_messageCount++;
return jsonEncode({
'token': token,
'data': {
'via': 'FlutterFire Cloud Messaging!!!',
'count': _messageCount.toString(),
},
'notification': {
'title': 'Hello FlutterFire!',
'body': 'This notification (#$_messageCount) was created via FCM!',
},
});
}
/// Renders the example application.
class Application extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Application();
}
class _Application extends State<Application> {
String? _token;
String? initialMessage;
bool _resolved = false;
@override
void initState() {
super.initState();
FirebaseMessaging.instance.getInitialMessage().then(
(value) => setState(
() {
_resolved = true;
initialMessage = value?.data.toString();
},
),
);
FirebaseMessaging.onMessage.listen(showFlutterNotification);
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('A new onMessageOpenedApp event was published!');
Navigator.pushNamed(
context,
'/message',
arguments: MessageArguments(message, true),
);
});
}
Future<void> sendPushMessage() async {
if (_token == null) {
print('Unable to send FCM message, no token exists.');
return;
}
try {
await http.post(
Uri.parse('https://api.rnfirebase.io/messaging/send'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: constructFCMPayload(_token),
);
print('FCM request for device sent!');
} catch (e) {
print(e);
}
}
Future<void> onActionSelected(String value) async {
switch (value) {
case 'subscribe':
{
print(
'FlutterFire Messaging Example: Subscribing to topic "fcm_test".',
);
await FirebaseMessaging.instance.subscribeToTopic('fcm_test');
print(
'FlutterFire Messaging Example: Subscribing to topic "fcm_test" successful.',
);
}
break;
case 'unsubscribe':
{
print(
'FlutterFire Messaging Example: Unsubscribing from topic "fcm_test".',
);
await FirebaseMessaging.instance.unsubscribeFromTopic('fcm_test');
print(
'FlutterFire Messaging Example: Unsubscribing from topic "fcm_test" successful.',
);
}
break;
case 'get_apns_token':
{
if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
print('FlutterFire Messaging Example: Getting APNs token...');
String? token = await FirebaseMessaging.instance.getAPNSToken();
print('FlutterFire Messaging Example: Got APNs token: $token');
} else {
print(
'FlutterFire Messaging Example: Getting an APNs token is only supported on iOS and macOS platforms.',
);
}
}
break;
default:
break;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Cloud Messaging'),
actions: <Widget>[
PopupMenuButton(
onSelected: onActionSelected,
itemBuilder: (BuildContext context) {
return [
const PopupMenuItem(
value: 'subscribe',
child: Text('Subscribe to topic'),
),
const PopupMenuItem(
value: 'unsubscribe',
child: Text('Unsubscribe to topic'),
),
const PopupMenuItem(
value: 'get_apns_token',
child: Text('Get APNs token (Apple only)'),
),
];
},
),
],
),
floatingActionButton: Builder(
builder: (context) => FloatingActionButton(
onPressed: sendPushMessage,
backgroundColor: Colors.white,
child: const Icon(Icons.send),
),
),
body: SingleChildScrollView(
child: Column(
children: [
MetaCard('Permissions', Permissions()),
MetaCard(
'Initial Message',
Column(
children: [
Text(_resolved ? 'Resolved' : 'Resolving'),
Text(initialMessage ?? 'None'),
],
),
),
MetaCard(
'FCM Token',
TokenMonitor((token) {
_token = token;
return token == null
? const CircularProgressIndicator()
: SelectableText(
token,
style: const TextStyle(fontSize: 12),
);
}),
),
ElevatedButton(
onPressed: () {
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage? message) {
if (message != null) {
Navigator.pushNamed(
context,
'/message',
arguments: MessageArguments(message, true),
);
}
});
},
child: const Text('getInitialMessage()'),
),
MetaCard('Message Stream', MessageList()),
],
),
),
);
}
}
/// UI Widget for displaying metadata.
class MetaCard extends StatelessWidget {
final String _title;
final Widget _children;
// ignore: public_member_api_docs
MetaCard(this._title, this._children);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
margin: const EdgeInsets.only(left: 8, right: 8, top: 8),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Container(
margin: const EdgeInsets.only(bottom: 16),
child: Text(_title, style: const TextStyle(fontSize: 18)),
),
_children,
],
),
),
),
);
}
}

View File

@ -1,120 +0,0 @@
// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// ignore_for_file: require_trailing_commas
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
/// Requests & displays the current user permissions for this device.
class Permissions extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Permissions();
}
class _Permissions extends State<Permissions> {
bool _requested = false;
bool _fetching = false;
late NotificationSettings _settings;
Future<void> requestPermissions() async {
setState(() {
_fetching = true;
});
NotificationSettings settings =
await FirebaseMessaging.instance.requestPermission(
announcement: true,
carPlay: true,
criticalAlert: true,
);
setState(() {
_requested = true;
_fetching = false;
_settings = settings;
});
}
Future<void> checkPermissions() async {
setState(() {
_fetching = true;
});
NotificationSettings settings =
await FirebaseMessaging.instance.getNotificationSettings();
setState(() {
_requested = true;
_fetching = false;
_settings = settings;
});
}
Widget row(String title, String value) {
return Container(
margin: const EdgeInsets.only(bottom: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('$title:', style: const TextStyle(fontWeight: FontWeight.bold)),
Text(value),
],
),
);
}
@override
Widget build(BuildContext context) {
if (_fetching) {
return const CircularProgressIndicator();
}
if (!_requested) {
return ElevatedButton(
onPressed: requestPermissions,
child: const Text('Request Permissions'));
}
return Column(children: [
row('Authorization Status', statusMap[_settings.authorizationStatus]!),
if (defaultTargetPlatform == TargetPlatform.iOS) ...[
row('Alert', settingsMap[_settings.alert]!),
row('Announcement', settingsMap[_settings.announcement]!),
row('Badge', settingsMap[_settings.badge]!),
row('Car Play', settingsMap[_settings.carPlay]!),
row('Lock Screen', settingsMap[_settings.lockScreen]!),
row('Notification Center', settingsMap[_settings.notificationCenter]!),
row('Show Previews', previewMap[_settings.showPreviews]!),
row('Sound', settingsMap[_settings.sound]!),
],
ElevatedButton(
onPressed: checkPermissions, child: const Text('Reload Permissions')),
]);
}
}
/// Maps a [AuthorizationStatus] to a string value.
const statusMap = {
AuthorizationStatus.authorized: 'Authorized',
AuthorizationStatus.denied: 'Denied',
AuthorizationStatus.notDetermined: 'Not Determined',
AuthorizationStatus.provisional: 'Provisional',
};
/// Maps a [AppleNotificationSetting] to a string value.
const settingsMap = {
AppleNotificationSetting.disabled: 'Disabled',
AppleNotificationSetting.enabled: 'Enabled',
AppleNotificationSetting.notSupported: 'Not Supported',
};
/// Maps a [AppleShowPreviewSetting] to a string value.
const previewMap = {
AppleShowPreviewSetting.always: 'Always',
AppleShowPreviewSetting.never: 'Never',
AppleShowPreviewSetting.notSupported: 'Not Supported',
AppleShowPreviewSetting.whenAuthenticated: 'Only When Authenticated',
};

View File

@ -1,50 +0,0 @@
// Copyright 2022, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// ignore_for_file: require_trailing_commas
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
/// Manages & returns the users FCM token.
///
/// Also monitors token refreshes and updates state.
class TokenMonitor extends StatefulWidget {
// ignore: public_member_api_docs
const TokenMonitor(this._builder, {super.key});
final Widget Function(String? token) _builder;
@override
State<StatefulWidget> createState() => _TokenMonitor();
}
class _TokenMonitor extends State<TokenMonitor> {
String? _token;
late Stream<String> _tokenStream;
void setToken(String? token) {
print('FCM Token: $token');
setState(() {
_token = token;
});
}
@override
void initState() {
super.initState();
FirebaseMessaging.instance
.getToken(
vapidKey:
'BNKkaUWxyP_yC_lki1kYazgca0TNhuzt2drsOrL6WrgGbqnMnr8ZMLzg_rSPDm6HKphABS0KzjPfSqCXHXEd06Y')
.then(setToken);
_tokenStream = FirebaseMessaging.instance.onTokenRefresh;
_tokenStream.listen(setToken);
}
@override
Widget build(BuildContext context) {
return widget._builder(_token);
}
}

View File

@ -0,0 +1,157 @@
import 'dart:convert';
import 'dart:developer';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:hub/app_state.dart';
import 'package:hub/backend/api_requests/api_calls.dart';
import 'package:hub/backend/api_requests/api_manager.dart';
import 'package:hub/components/templates_components/message_notificaion_modal_template_component/message_notification_widget.dart';
import 'package:hub/shared/utils/log_util.dart';
class PushNotification {
static final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
static final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
Future<void> initialize() async {
await _requestPermissions();
// Mensagens
_backgroundMessage();
_forgroundMessage();
_openMessage();
// Token
_refreshToken();
_updateDeviceToken();
}
Future<void> _updateDeviceToken() async {
try {
final String? deviceToken = await _firebaseMessaging.getToken();
if (deviceToken != null) {
AppState().token = deviceToken;
final ApiCallResponse? response = await PhpGroup.updToken.call(token: AppState().token, devid: AppState().devUUID, useruuid: AppState().userUUID);
if (PhpGroup.updToken.error((response?.jsonBody ?? '')) == false) {
log('Token Atualizado com Sucesso!');
} else {
log('Falha ao Atualizar Token: ${response?.jsonBody}');
}
} else {
log('Falha ao Pegar Token do Firebase');
}
} catch (e, s) {
LogUtil.requestAPIFailed("updToken.php", "", "Atualizar Token", e, s);
}
}
Future<void> _requestPermissions() async {
NotificationSettings settings = await _firebaseMessaging.requestPermission(
alert: true,
badge: true,
sound: true,
provisional: true,
criticalAlert: false,
carPlay: false,
announcement: false
);
log('Permisão de Notificação: ${settings.authorizationStatus == AuthorizationStatus.authorized ? "Liberado" : "Negado"}');
}
void _backgroundMessage() {
FirebaseMessaging.onBackgroundMessage((RemoteMessage message) => _printNotification(message, 'background'));
}
void _forgroundMessage() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) => _printNotification(message, 'forground'));
}
void _openMessage() {
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) => _processNotification(message));
}
void _refreshToken() {
_firebaseMessaging.onTokenRefresh.listen((token) => log('Novo Token: $token'));
}
Future<void> _printNotification(RemoteMessage message, String type) async {
print("Tipo da Notificação: $type");
print("Mensagem: $message");
}
Future<void> _processNotification(RemoteMessage message) async {
switch (message.category) {
case 'mensagem':
_showMessageNotificationDialog(message.data, AppState().context!, message.notification?.body ?? '');
}
}
void _showMessageNotificationDialog(Map<String, dynamic> message, BuildContext context, String extra) {
showDialog(
useSafeArea: true,
barrierDismissible: true,
context: context,
builder: (BuildContext context) {
String localId = '';
try {
localId = jsonDecode(message['local'])['CLI_ID'];
} catch (e) {
localId = message['local']['CLI_ID'].toString();
}
return GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Dialog(
backgroundColor: Colors.transparent,
child: GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: MessageNotificationModalTemplateComponentWidget(
id: localId,
from: message['remetente'].toString(),
to: message['destinatario'].toString() == 'O'
? 'Morador'
: 'Visitante',
message: extra.isEmpty ? 'Unknown' : extra.toString(),
),
),
),
),
),
);
},
);
}
Future<void> _showMessage(RemoteMessage message) async {
print("Dados: ${message.data}");
print("From: ${message.from}");
print("Notification: ${message.notification?.body}");
print("Category: ${message.category}");
showDialog(
context: AppState().context!,
builder: (context) => Dialog(
child: Container(
child: Text("Notificação"),
),
)
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_web_plugins/url_strategy.dart';
import 'package:hub/app_state.dart';
import 'package:hub/backend/push_notification/push_notification.dart';
import 'package:hub/firebase_options.dart';
import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/internationalization.dart';
@ -18,105 +19,22 @@ import 'package:provider/provider.dart';
import 'package:responsive_framework/responsive_framework.dart';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await setupFlutterNotifications();
showFlutterNotification(message);
log('Handling a background message ${message.messageId}');
}
late AndroidNotificationChannel channel;
late DarwinInitializationSettings iosSettings;
late InitializationSettings initializationSettings;
late AndroidInitializationSettings initializationSettingsAndroid;
bool isFlutterLocalNotificationsInitialized = false;
@pragma('vm:entry-point')
Future<void> setupFlutterNotifications() async {
if (isFlutterLocalNotificationsInitialized) {
return;
}
channel = const AndroidNotificationChannel(
'high_importance_channel',
'High Importance Notifications',
description: 'This channel is used for important notifications.',
importance: Importance.high,
);
initializationSettingsAndroid =
const AndroidInitializationSettings('mipmap/ic_fre_black');
iosSettings = const DarwinInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: iosSettings,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel)
.then((_) async => await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: (response) async {
log('Notification: ${response.payload}');
},
onDidReceiveBackgroundNotificationResponse: (response) async {
log('Notification: ${response.payload}');
},
));
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
isFlutterLocalNotificationsInitialized = true;
}
void showFlutterNotification(RemoteMessage message) {
log('Handling a background message ${message.messageId}');
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
if (notification != null && android != null && !kIsWeb) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
icon: 'launch_background',
),
),
);
}
}
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
// FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
// if (!kIsWeb) {
// await setupFlutterNotifications();
// }
if (!kIsWeb) {
await setupFlutterNotifications();
}
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
await init().then((_) {
runApp(ChangeNotifierProvider(
create: (context) => AppState(),
@ -126,42 +44,30 @@ void main() async {
}
Future<void> init() async {
log('Setting up Crashlytics...');
final crashlyticsInstance = FirebaseCrashlytics.instance;
if (crashlyticsInstance.isCrashlyticsCollectionEnabled) {
FlutterError.onError = crashlyticsInstance.recordFlutterError;
WidgetsBinding.instance.addPostFrameCallback((_) async => await PushNotification().initialize());
if (kDebugMode) {
log("Aplicativo em Debug Mode, crashlytics desabilitado!");
} else {
log('Crashlytics instance is null');
final crashlyticsInstance = FirebaseCrashlytics.instance;
if (crashlyticsInstance.isCrashlyticsCollectionEnabled) {
FlutterError.onError = crashlyticsInstance.recordFlutterError;
}
}
log('Crashlytics set up.');
log('Initializing FlutterFlowTheme...');
await FlutterFlowTheme.initialize();
log('FlutterFlowTheme initialized.');
log('Initializing FFLocalizations...');
await FFLocalizations.initialize();
log('FFLocalizations initialized.');
log('Initializing app state...');
final appState = AppState();
await appState.initializePersistedState();
log('App state initialized.');
log('Initializing GoRouter...');
GoRouter.optionURLReflectsImperativeAPIs = true;
usePathUrlStrategy();
log('GoRouter initialized.');
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
static _MyAppState of(BuildContext context) =>
context.findAncestorStateOfType<_MyAppState>()!;
static _MyAppState of(BuildContext context) => context.findAncestorStateOfType<_MyAppState>()!;
}
class _MyAppState extends State<MyApp> {

View File

@ -1,11 +1,7 @@
// import 'package:hub/backend/push_notification/pushNotification.dart';
import 'dart:developer';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart';
import 'package:hub/actions/actions.dart';
import 'package:hub/backend/schema/enums/enums.dart';
import 'package:hub/components/organism_components/bottom_arrow_linked_locals_component/bottom_arrow_linked_locals_component_widget.dart';
@ -18,28 +14,9 @@ import 'package:hub/flutter_flow/flutter_flow_theme.dart';
import 'package:hub/flutter_flow/flutter_flow_util.dart';
import 'package:hub/flutter_flow/flutter_flow_widgets.dart';
import 'package:hub/flutter_flow/nav/nav.dart';
import 'package:hub/main.dart';
import 'package:hub/pages/home_page/home_page_model.dart';
import 'package:provider/provider.dart';
// Crude counter to make messages unique
int _messageCount = 0;
/// The API endpoint here accepts a raw FCM payload for demonstration purposes.
String constructFCMPayload(String? token) {
_messageCount++;
return jsonEncode({
'token': token,
'data': {
'via': 'FlutterFire Cloud Messaging!!!',
'count': _messageCount.toString(),
},
'notification': {
'title': 'Hello FlutterFire!',
'body': 'This notification (#$_messageCount) was created via FCM!',
},
});
}
class HomePageWidget extends StatefulWidget {
const HomePageWidget({super.key});
@ -52,9 +29,6 @@ class _HomePageWidgetState extends State<HomePageWidget> {
late HomePageModel _model;
bool localStatus = false;
final scaffoldKey = GlobalKey<ScaffoldState>();
String? _token;
String? initialMessage;
bool _resolved = false;
Future<void> checkLocalStatus() async {
localStatus = await checkLocals(
@ -69,25 +43,6 @@ class _HomePageWidgetState extends State<HomePageWidget> {
super.initState();
_model = createModel(context, () => HomePageModel());
FirebaseMessaging.instance
.getInitialMessage()
.then(
(value) => setState(
() {
_resolved = true;
initialMessage = value?.data.toString();
log('getInitialMessage resolved');
},
),
)
.whenComplete(() => log('getInitialMessage completed'));
FirebaseMessaging.onMessage.listen(showFlutterNotification).onDone(() {
log('onMessage completed');
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
log('A new onMessageOpenedApp event was published!');
});
AppState().context = context;
WidgetsBinding.instance.addPostFrameCallback((_) async {
@ -133,69 +88,6 @@ class _HomePageWidgetState extends State<HomePageWidget> {
super.dispose();
}
Future<void> sendPushMessage() async {
if (_token == null) {
log('Unable to send FCM message, no token exists.');
return;
}
try {
await post(
Uri.parse('https://api.rnfirebase.io/messaging/send'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: constructFCMPayload(_token),
);
log('FCM request for device sent!');
} catch (e) {
log(e.toString());
}
}
Future<void> onActionSelected(String value) async {
switch (value) {
case 'subscribe':
{
log(
'FlutterFire Messaging Example: Subscribing to topic "fcm_test".',
);
await FirebaseMessaging.instance.subscribeToTopic('fcm_test');
log(
'FlutterFire Messaging Example: Subscribing to topic "fcm_test" successful.',
);
}
break;
case 'unsubscribe':
{
log(
'FlutterFire Messaging Example: Unsubscribing from topic "fcm_test".',
);
await FirebaseMessaging.instance.unsubscribeFromTopic('fcm_test');
log(
'FlutterFire Messaging Example: Unsubscribing from topic "fcm_test" successful.',
);
}
break;
case 'get_apns_token':
{
if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
log('FlutterFire Messaging Example: Getting APNs token...');
String? token = await FirebaseMessaging.instance.getAPNSToken();
log('FlutterFire Messaging Example: Got APNs token: $token');
} else {
log(
'FlutterFire Messaging Example: Getting an APNs token is only supported on iOS and macOS platforms.',
);
}
}
break;
default:
break;
}
}
@override
Widget build(BuildContext context) {
context.watch<AppState>();
@ -691,233 +583,6 @@ class _HomePageWidgetState extends State<HomePageWidget> {
),
),
);
// body: Container(
// decoration: BoxDecoration(
// color: FlutterFlowTheme.of(context).primaryBackground,
// ),
// child: SingleChildScrollView(
// child: Column(
// mainAxisSize: MainAxisSize.max,
// mainAxisAlignment: MainAxisAlignment.start,
// children: [
// Wrap(
// spacing: 0.0,
// runSpacing: 0.0,
// alignment: WrapAlignment.start,
// crossAxisAlignment: WrapCrossAlignment.start,
// direction: Axis.horizontal,
// runAlignment: WrapAlignment.start,
// verticalDirection: VerticalDirection.down,
// clipBehavior: Clip.none,
// children: [
// Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Expanded(
// child: Container(
// width: 100.0,
// height: 100.0,
// decoration: const BoxDecoration(
// color: Color(0xFF1AAB5F),
// ),
// child: Row(
// mainAxisSize: MainAxisSize.min,
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Align(
// alignment: const AlignmentDirectional(0.0, 1.0),
// child: Container(
// height: 50.0,
// decoration: const BoxDecoration(),
// child: Align(
// alignment: const AlignmentDirectional(0.0, 0.0),
// child: Row(
// mainAxisSize: MainAxisSize.max,
// children: [
// Align(
// alignment:
// const AlignmentDirectional(-1.0, 0.0),
// child: Padding(
// padding: const EdgeInsetsDirectional
// .fromSTEB(
// 10.0, 0.0, 0.0, 0.0),
// child: FlutterFlowIconButton(
// borderRadius: 20.0,
// borderWidth: 1.0,
// buttonSize: 40.0,
// fillColor:
// FlutterFlowTheme.of(context)
// .primary,
// icon: const Icon(
// Icons.menu_rounded,
// color: Colors.white,
// size: 28.0,
// ),
// onPressed: () async {
// scaffoldKey.currentState!
// .openDrawer();
// },
// ),
// ),
// ),
// Align(
// alignment:
// const AlignmentDirectional(-1.0, 0.0),
// child: Padding(
// padding: const EdgeInsetsDirectional
// .fromSTEB(
// 60.0, 15.0, 0.0, 0.0),
// child: ClipRRect(
// borderRadius:
// BorderRadius.circular(8.0),
// child: Image.network(
// 'https://storage.googleapis.com/flutterflow-io-6f20.appspot.com/projects/flutter-freaccess-hub-0xgz9q/assets/8r2vsbd9i03k/logo.png',
// width: 50.0,
// height: 200.0,
// fit: BoxFit.none,
// ),
// ),
// ),
// ),
// Align(
// alignment:
// const AlignmentDirectional(0.0, 0.0),
// child: Padding(
// padding: const EdgeInsetsDirectional
// .fromSTEB(
// 0.0, 15.0, 0.0, 0.0),
// child: Text(
// FFLocalizations.of(context)
// .getText(
// 'rg9pzkpz' /* FRE ACCESS */,
// ),
// style:
// FlutterFlowTheme.of(context)
// .bodyMedium
// .override(
// fontFamily:
// FlutterFlowTheme.of(
// context)
// .bodyMediumFamily,
// color: FlutterFlowTheme
// .of(context)
// .info,
// letterSpacing: 0.0,
// useGoogleFonts: GoogleFonts
// .asMap()
// .containsKey(
// FlutterFlowTheme.of(
// context)
// .bodyMediumFamily),
// ),
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// ),
// Align(
// alignment: const AlignmentDirectional(0.0, 1.0),
// child: Container(
// width: 100.0,
// height: 50.0,
// decoration: const BoxDecoration(),
// child: Align(
// alignment: const AlignmentDirectional(1.0, 1.0),
// child: FlutterFlowIconButton(
// borderRadius: 20.0,
// borderWidth: 1.0,
// buttonSize: 40.0,
// icon: Icon(
// Icons.notifications_sharp,
// color:
// FlutterFlowTheme.of(context).info,
// size: 24.0,
// ),
// onPressed: () {
// print('IconButton pressed ...');
// },
// ),
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// ],
// ),
// wrapWithModel(
// model: _model.localComponentModel,
// updateCallback: () => setState(() {}),
// child: const LocalProfileComponentWidget(),
// ),
// Wrap(
// spacing: 0.0,
// runSpacing: 0.0,
// alignment: WrapAlignment.start,
// crossAxisAlignment: WrapCrossAlignment.start,
// direction: Axis.horizontal,
// runAlignment: WrapAlignment.start,
// verticalDirection: VerticalDirection.down,
// clipBehavior: Clip.none,
// children: [
// wrapWithModel(
// model: _model.menuComponentModel,
// updateCallback: () => setState(() {}),
// child: const MenuComponentWidget(),
// ),
// Align(
// alignment: const AlignmentDirectional(0.0, 0.0),
// child: wrapWithModel(
// model: _model.messageWellComponentModel,
// updateCallback: () => setState(() {}),
// child: const MessageWellComponentWidget(),
// ),
// ),
// ],
// ),
// ],
// ),
// ],
// ),
// ),
// ),
// ),
// );
}
}
/// UI Widget for displaying metadata.
class MetaCard extends StatelessWidget {
final String _title;
final Widget _children;
// ignore: public_member_api_docs
MetaCard(this._title, this._children);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
margin: const EdgeInsets.only(left: 8, right: 8, top: 8),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Container(
margin: const EdgeInsets.only(bottom: 16),
child: Text(_title, style: const TextStyle(fontSize: 18)),
),
_children,
],
),
),
),
);
}
}

View File

@ -421,30 +421,30 @@ Widget liberationHistoryItemCard(
);
},
).then((_) {
PushNotificationManager _pushNotificationService =
PushNotificationManager();
_pushNotificationService.onMessageReceived.listen((received) {
if (received.data['click_action'] == 'cancel_request') {
_pushNotificationService.dispose();
showSnackbar(
context,
FFLocalizations.of(context).getVariableText(
enText: 'Successfully resolved visit',
ptText: 'Visita resolvida com sucesso'),
false);
context.pushReplacementNamed(
'liberationHistory',
extra: <String, dynamic>{
kTransitionInfoKey: const TransitionInfo(
hasTransition: true,
transitionType: PageTransitionType.scale,
alignment: Alignment.bottomCenter,
),
},
);
}
});
// PushNotificationManager _pushNotificationService =
// PushNotificationManager();
//
// _pushNotificationService.onMessageReceived.listen((received) {
// if (received.data['click_action'] == 'cancel_request') {
// _pushNotificationService.dispose();
// showSnackbar(
// context,
// FFLocalizations.of(context).getVariableText(
// enText: 'Successfully resolved visit',
// ptText: 'Visita resolvida com sucesso'),
// false);
// context.pushReplacementNamed(
// 'liberationHistory',
// extra: <String, dynamic>{
// kTransitionInfoKey: const TransitionInfo(
// hasTransition: true,
// transitionType: PageTransitionType.scale,
// alignment: Alignment.bottomCenter,
// ),
// },
// );
// }
// });
});
},
);

View File

@ -825,18 +825,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.4"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.3"
leak_tracker_testing:
dependency: transitive
description:
@ -913,10 +913,10 @@ packages:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev"
source: hosted
version: "0.11.1"
version: "0.8.0"
maybe_just_nothing:
dependency: transitive
description:
@ -929,10 +929,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.15.0"
version: "1.12.0"
mime:
dependency: transitive
description:
@ -1294,10 +1294,10 @@ packages:
dependency: transitive
description:
name: sqflite_common
sha256: c5e5b2a142a893a752cb36ae5888680248686725a54afceff31f9a3a76bc53c2
sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4"
url: "https://pub.dev"
source: hosted
version: "2.5.4+1"
version: "2.5.4"
stack_trace:
dependency: transitive
description:
@ -1350,10 +1350,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.0"
timeago:
dependency: "direct main"
description:
@ -1526,10 +1526,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.dev"
source: hosted
version: "14.2.4"
version: "14.2.1"
web:
dependency: transitive
description:
@ -1611,5 +1611,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.5.0 <4.0.0"
dart: ">=3.4.0 <4.0.0"
flutter: ">=3.22.0"