Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3caa3e676e |
@@ -3,6 +3,8 @@ plugins {
|
||||
id("kotlin-android")
|
||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
// Firebase Cloud Messaging: legge android/app/google-services.json.
|
||||
id("com.google.gms.google-services")
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -11,6 +13,9 @@ android {
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
// Richiesto da flutter_local_notifications (notifiche mostrate quando
|
||||
// l'app e' aperta).
|
||||
isCoreLibraryDesugaringEnabled = true
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
@@ -42,3 +47,8 @@ android {
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Libreria di supporto richiesta dal desugaring (flutter_local_notifications).
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
|
||||
}
|
||||
|
||||
@@ -4,4 +4,9 @@
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<!-- Solo per lo sviluppo: il backend locale (Docker) risponde in HTTP,
|
||||
e da Android 9 il traffico in chiaro e' bloccato di default.
|
||||
Questo file vale solo per la build di debug: la release resta in HTTPS. -->
|
||||
<application android:usesCleartextTraffic="true" />
|
||||
</manifest>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- Notifiche push: da Android 13 (API 33) il permesso va chiesto a runtime.
|
||||
Lo fa PushService.registerAfterLogin() dopo il login. -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
||||
<application
|
||||
android:label="yogibook_app"
|
||||
android:name="${applicationName}"
|
||||
|
||||
@@ -21,6 +21,8 @@ plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "8.11.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.2.20" apply false
|
||||
// Necessario per Firebase (legge android/app/google-services.json).
|
||||
id("com.google.gms.google-services") version "4.4.2" apply false
|
||||
}
|
||||
|
||||
include(":app")
|
||||
|
||||
@@ -4,11 +4,15 @@ import 'package:intl/date_symbol_data_local.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'screens/login_page.dart';
|
||||
import 'services/push_service.dart';
|
||||
import 'state/app_state.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await initializeDateFormatting('it_IT');
|
||||
|
||||
await PushService.initFirebase();
|
||||
await PushService.enableForegroundNotifications();
|
||||
runApp(
|
||||
ChangeNotifierProvider(create: (_) => AppState(), child: const MyApp()),
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
|
||||
import '../models/school.dart';
|
||||
import '../services/push_api.dart';
|
||||
import '../services/vanguard_api.dart';
|
||||
import '../widgets/yogibook_background.dart';
|
||||
|
||||
@@ -41,12 +42,54 @@ class _AccountPageState extends State<AccountPage> {
|
||||
bool _obscurePw = true;
|
||||
bool _obscurePw2 = true;
|
||||
|
||||
bool? _pushEnabled;
|
||||
bool _savingPush = false;
|
||||
|
||||
final _picker = ImagePicker();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadProfile();
|
||||
_loadPushPreference();
|
||||
}
|
||||
|
||||
Future<void> _loadPushPreference() async {
|
||||
try {
|
||||
final attive = await PushApi.fetchPreference(token: widget.token);
|
||||
if (!mounted) return;
|
||||
setState(() => _pushEnabled = attive);
|
||||
} catch (_) {
|
||||
if (!mounted) return;
|
||||
setState(() => _pushEnabled = null);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _togglePush(bool valore) async {
|
||||
final precedente = _pushEnabled;
|
||||
|
||||
setState(() {
|
||||
_pushEnabled = valore;
|
||||
_savingPush = true;
|
||||
});
|
||||
|
||||
try {
|
||||
final salvato = await PushApi.updatePreference(
|
||||
token: widget.token,
|
||||
enabled: valore,
|
||||
);
|
||||
if (!mounted) return;
|
||||
setState(() => _pushEnabled = salvato);
|
||||
_snack(
|
||||
salvato ? 'Notifiche attivate.' : 'Notifiche disattivate.',
|
||||
);
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
setState(() => _pushEnabled = precedente);
|
||||
_snack('Errore nel salvataggio: $e');
|
||||
} finally {
|
||||
if (mounted) setState(() => _savingPush = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -252,6 +295,8 @@ class _AccountPageState extends State<AccountPage> {
|
||||
const SizedBox(height: 20),
|
||||
_profileCard(),
|
||||
const SizedBox(height: 16),
|
||||
_notificationsCard(),
|
||||
const SizedBox(height: 16),
|
||||
_passwordCard(),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
@@ -409,6 +454,47 @@ class _AccountPageState extends State<AccountPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _notificationsCard() {
|
||||
if (_pushEnabled == null) {
|
||||
return _card(
|
||||
title: 'Notifiche',
|
||||
children: const [
|
||||
Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: CircularProgressIndicator(strokeWidth: 2),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Expanded(child: Text('Carico le impostazioni...')),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return _card(
|
||||
title: 'Notifiche',
|
||||
children: [
|
||||
SwitchListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
activeThumbColor: kGreen,
|
||||
value: _pushEnabled!,
|
||||
onChanged: _savingPush ? null : _togglePush,
|
||||
title: const Text(
|
||||
'Notifiche push',
|
||||
style: TextStyle(fontWeight: FontWeight.w700),
|
||||
),
|
||||
subtitle: const Text(
|
||||
'Promemoria delle lezioni del giorno, scadenza abbonamento e '
|
||||
'certificato medico.',
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _passwordCard() {
|
||||
return _card(
|
||||
title: 'Cambia password',
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../services/push_service.dart';
|
||||
import '../services/vanguard_api.dart';
|
||||
import '../models/school.dart';
|
||||
import 'home_page.dart';
|
||||
@@ -47,6 +50,8 @@ class _LoginPageState extends State<LoginPage> {
|
||||
password: passwordController.text.trim(),
|
||||
);
|
||||
|
||||
unawaited(PushService.registerAfterLogin(token));
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
// Bypass SelectSchoolPage: scuola unica, si va dritti alla Home.
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import '../config/api_config.dart';
|
||||
|
||||
class PushApi {
|
||||
static Map<String, String> _headers(String token) => {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer $token',
|
||||
};
|
||||
|
||||
static Future<String> registerDevice({
|
||||
required String token,
|
||||
required String deviceToken,
|
||||
required String platform,
|
||||
String? appVersion,
|
||||
}) async {
|
||||
final uri = Uri.parse('${ApiConfig.laravelApiBase}/register_device.php');
|
||||
|
||||
final res = await http.post(
|
||||
uri,
|
||||
headers: _headers(token),
|
||||
body: jsonEncode({
|
||||
'device_token': deviceToken,
|
||||
'platform': platform,
|
||||
if (appVersion != null) 'app_version': appVersion,
|
||||
}),
|
||||
);
|
||||
|
||||
final data = _decode(res.body, res.statusCode);
|
||||
|
||||
return (data['push_enabled'] ?? 'Y').toString();
|
||||
}
|
||||
|
||||
static Future<void> unregisterDevice({
|
||||
required String token,
|
||||
required String deviceToken,
|
||||
}) async {
|
||||
final uri = Uri.parse('${ApiConfig.laravelApiBase}/register_device.php');
|
||||
|
||||
final res = await http.delete(
|
||||
uri,
|
||||
headers: _headers(token),
|
||||
body: jsonEncode({'device_token': deviceToken}),
|
||||
);
|
||||
|
||||
_decode(res.body, res.statusCode);
|
||||
}
|
||||
|
||||
static Future<bool> fetchPreference({required String token}) async {
|
||||
final uri = Uri.parse('${ApiConfig.laravelApiBase}/push_preference.php');
|
||||
|
||||
final res = await http.get(uri, headers: _headers(token));
|
||||
final data = _decode(res.body, res.statusCode);
|
||||
|
||||
return (data['push_enabled'] ?? 'Y').toString().toUpperCase() == 'Y';
|
||||
}
|
||||
|
||||
static Future<bool> updatePreference({
|
||||
required String token,
|
||||
required bool enabled,
|
||||
}) async {
|
||||
final uri = Uri.parse('${ApiConfig.laravelApiBase}/push_preference.php');
|
||||
|
||||
final res = await http.post(
|
||||
uri,
|
||||
headers: _headers(token),
|
||||
body: jsonEncode({'enabled': enabled}),
|
||||
);
|
||||
|
||||
final data = _decode(res.body, res.statusCode);
|
||||
|
||||
return (data['push_enabled'] ?? 'Y').toString().toUpperCase() == 'Y';
|
||||
}
|
||||
|
||||
static Map<String, dynamic> _decode(String body, int statusCode) {
|
||||
Map<String, dynamic> data;
|
||||
|
||||
try {
|
||||
data = jsonDecode(body) as Map<String, dynamic>;
|
||||
} catch (_) {
|
||||
throw Exception('Risposta non valida ($statusCode): $body');
|
||||
}
|
||||
|
||||
if (statusCode != 200 || data['success'] != true) {
|
||||
throw Exception(data['error'] ?? data['message'] ?? 'Errore notifiche');
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
|
||||
import 'push_api.dart';
|
||||
|
||||
class PushService {
|
||||
static String? _deviceToken;
|
||||
|
||||
static bool _firebaseReady = false;
|
||||
|
||||
static final FlutterLocalNotificationsPlugin _locali =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
||||
static const AndroidNotificationChannel _canale = AndroidNotificationChannel(
|
||||
'yogibook_notifiche',
|
||||
'Notifiche YogiBook',
|
||||
description: 'Promemoria delle lezioni, scadenze abbonamento e certificato',
|
||||
importance: Importance.high,
|
||||
);
|
||||
|
||||
static Future<void> initFirebase() async {
|
||||
if (_firebaseReady) return;
|
||||
|
||||
try {
|
||||
await Firebase.initializeApp();
|
||||
FirebaseMessaging.onBackgroundMessage(_backgroundHandler);
|
||||
await _preparaNotificheLocali();
|
||||
_firebaseReady = true;
|
||||
} catch (e) {
|
||||
debugPrint('Firebase non inizializzato: $e');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> _preparaNotificheLocali() async {
|
||||
const impostazioni = InitializationSettings(
|
||||
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
|
||||
iOS: DarwinInitializationSettings(
|
||||
requestAlertPermission: false,
|
||||
requestBadgePermission: false,
|
||||
requestSoundPermission: false,
|
||||
),
|
||||
);
|
||||
|
||||
await _locali.initialize(settings: impostazioni);
|
||||
|
||||
await _locali
|
||||
.resolvePlatformSpecificImplementation<
|
||||
AndroidFlutterLocalNotificationsPlugin
|
||||
>()
|
||||
?.createNotificationChannel(_canale);
|
||||
|
||||
FirebaseMessaging.onMessage.listen(_mostraInPrimoPiano);
|
||||
}
|
||||
|
||||
static Future<void> _mostraInPrimoPiano(RemoteMessage messaggio) async {
|
||||
if (kIsWeb || !Platform.isAndroid) return;
|
||||
|
||||
final notifica = messaggio.notification;
|
||||
if (notifica == null) return;
|
||||
|
||||
await _locali.show(
|
||||
id: notifica.hashCode,
|
||||
title: notifica.title,
|
||||
body: notifica.body,
|
||||
notificationDetails: NotificationDetails(
|
||||
android: AndroidNotificationDetails(
|
||||
_canale.id,
|
||||
_canale.name,
|
||||
channelDescription: _canale.description,
|
||||
importance: Importance.high,
|
||||
priority: Priority.high,
|
||||
icon: '@mipmap/ic_launcher',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> registerAfterLogin(String authToken) async {
|
||||
if (!_firebaseReady) return;
|
||||
|
||||
try {
|
||||
final messaging = FirebaseMessaging.instance;
|
||||
|
||||
final settings = await messaging.requestPermission();
|
||||
|
||||
if (settings.authorizationStatus == AuthorizationStatus.denied) {
|
||||
debugPrint('Permesso notifiche negato dall\'utente.');
|
||||
return;
|
||||
}
|
||||
|
||||
final deviceToken = await messaging.getToken();
|
||||
if (deviceToken == null) return;
|
||||
|
||||
_deviceToken = deviceToken;
|
||||
|
||||
await PushApi.registerDevice(
|
||||
token: authToken,
|
||||
deviceToken: deviceToken,
|
||||
platform: _platformName(),
|
||||
);
|
||||
|
||||
messaging.onTokenRefresh.listen((nuovo) async {
|
||||
_deviceToken = nuovo;
|
||||
try {
|
||||
await PushApi.registerDevice(
|
||||
token: authToken,
|
||||
deviceToken: nuovo,
|
||||
platform: _platformName(),
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('Aggiornamento token fallito: $e');
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
debugPrint('Registrazione push fallita: $e');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> unregisterOnLogout(String authToken) async {
|
||||
final deviceToken = _deviceToken;
|
||||
if (deviceToken == null) return;
|
||||
|
||||
try {
|
||||
await PushApi.unregisterDevice(
|
||||
token: authToken,
|
||||
deviceToken: deviceToken,
|
||||
);
|
||||
_deviceToken = null;
|
||||
} catch (e) {
|
||||
debugPrint('Disattivazione dispositivo fallita: $e');
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> enableForegroundNotifications() async {
|
||||
if (!_firebaseReady) return;
|
||||
|
||||
try {
|
||||
await FirebaseMessaging.instance
|
||||
.setForegroundNotificationPresentationOptions(
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true,
|
||||
);
|
||||
} catch (e) {
|
||||
debugPrint('Impostazione notifiche in foreground fallita: $e');
|
||||
}
|
||||
}
|
||||
|
||||
static String _platformName() {
|
||||
if (kIsWeb) return 'web';
|
||||
return Platform.isIOS ? 'ios' : 'android';
|
||||
}
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
Future<void> _backgroundHandler(RemoteMessage message) async {
|
||||
debugPrint('Notifica in background: ${message.messageId}');
|
||||
}
|
||||
@@ -8,6 +8,9 @@ import Foundation
|
||||
import audioplayers_darwin
|
||||
import file_picker
|
||||
import file_selector_macos
|
||||
import firebase_core
|
||||
import firebase_messaging
|
||||
import flutter_local_notifications
|
||||
import google_sign_in_ios
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
@@ -17,6 +20,9 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
|
||||
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
|
||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
|
||||
+142
-6
@@ -1,6 +1,22 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_flutterfire_internals:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _flutterfire_internals
|
||||
sha256: "6727cf2ced9b104abca9daa278380be2eca2b98ce33d4b46f11708e387dc6b4d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.76"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -121,6 +137,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.8"
|
||||
dbus:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dbus
|
||||
sha256: "792974a4007974fbc5c1b5433eb2330a9db3e368c3f906253af4c007d0f49a91"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.13"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -185,6 +209,54 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.3+5"
|
||||
firebase_core:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_core
|
||||
sha256: "9478ca6700c02d315c6aba37e206e612317f98bb4f335bb1cbd6e0ce67dcf764"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.13.0"
|
||||
firebase_core_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_platform_interface
|
||||
sha256: e28f9afdcb5b0f0a8ea74ea3b322f5a7592c81cb45dd9d189913bdae08a2089a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.1.0"
|
||||
firebase_core_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
sha256: f471a288b0101a45567548322ac4a5ad31e3ecbf87a576dcc0e424e6a11e04ea
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.10.0"
|
||||
firebase_messaging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_messaging
|
||||
sha256: "55cf1000dd72d229ebff3ce6a399bd35705a7675275478b31308afd90ac85751"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "16.5.0"
|
||||
firebase_messaging_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_platform_interface
|
||||
sha256: e5fbb62bd23a27c983825277877ac91fdfdb6bfb31c6e5399700963ae586e339
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.9.3"
|
||||
firebase_messaging_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_messaging_web
|
||||
sha256: "663d320e90a41fe57d651ec79df2bc831bf29e051bc0c2cd41faf3106eb412d9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.4"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -206,6 +278,46 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
flutter_local_notifications:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_local_notifications
|
||||
sha256: "1447ba911c60f2ba3f25dae1af151ec187162566b0f57e37771bf0b400f013ad"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "22.3.0"
|
||||
flutter_local_notifications_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_linux
|
||||
sha256: "9ca97e63776f29ab1b955725c09999fc2c150523269db150c39274f2a43c5a8b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.0.1"
|
||||
flutter_local_notifications_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_platform_interface
|
||||
sha256: "43c3761d916c9bd3d5c7ebbc44d82f4990329840c0c5d62ad5260cc1b5d399bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "12.2.0"
|
||||
flutter_local_notifications_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_web
|
||||
sha256: "516afaf97a2d1e67a036c6617321b00d205d72f7a67b6eccf936cd565f985878"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
flutter_local_notifications_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_local_notifications_windows
|
||||
sha256: "6f43bdd03b171b7a90f22647506fea33e2bb12294b7c7c7a3d690e960a382945"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
flutter_localizations:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -493,6 +605,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.2"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -630,10 +750,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
|
||||
sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.9"
|
||||
version: "0.7.12"
|
||||
timezone:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: timezone
|
||||
sha256: "981d1020d6ef8fe1e7b3de5054e5b25579ae7c403d7734adc508ffc47668e9cb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.11.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -718,10 +846,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
|
||||
sha256: f36f9f3be64c6198714492bb455c11056e33e2f85d9a0b676a48301e44fdcf47
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
version: "2.4.2"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -754,6 +882,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
sha256: "67f0aff7be013d107995e9b75bf4e7f2c3ef2dfdb2c8e68024bba0a7fd5756a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
sdks:
|
||||
dart: ">=3.10.4 <4.0.0"
|
||||
flutter: ">=3.35.0"
|
||||
dart: ">=3.11.0 <4.0.0"
|
||||
flutter: ">=3.38.1"
|
||||
|
||||
@@ -44,6 +44,9 @@ dependencies:
|
||||
mime: ^2.0.0
|
||||
provider: ^6.1.5+1
|
||||
shared_preferences: ^2.2.3
|
||||
firebase_core: ^4.13.0
|
||||
firebase_messaging: ^16.5.0
|
||||
flutter_local_notifications: ^22.3.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <audioplayers_windows/audioplayers_windows_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <firebase_core/firebase_core_plugin_c_api.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
@@ -15,6 +16,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
FirebaseCorePluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
audioplayers_windows
|
||||
file_selector_windows
|
||||
firebase_core
|
||||
url_launcher_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
flutter_local_notifications_windows
|
||||
)
|
||||
|
||||
set(PLUGIN_BUNDLED_LIBRARIES)
|
||||
|
||||
Reference in New Issue
Block a user