fix: Init Notification Push iOS Ok
This commit is contained in:
parent
460ad3bbbd
commit
87094d39c3
|
@ -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" />
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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',
|
||||
);
|
||||
}
|
|
@ -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,
|
||||
),
|
||||
]
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
],
|
||||
),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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)),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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',
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
128
lib/main.dart
128
lib/main.dart
|
@ -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> {
|
||||
|
|
|
@ -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,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
// ),
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
});
|
||||
},
|
||||
);
|
||||
|
|
30
pubspec.lock
30
pubspec.lock
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue