v2.40 — Issue #9: Progress-Notification für Download/Upload (flutter_local_notifications)
- flutter_local_notifications ^22.2.0 hinzugefügt - Notification-Channel 'de.baka.melo.downloads' in main() initialisiert - DownloadService._showProgress(): Fortschritts-Notification mit ProgressBar - DownloadService._completeNotification(): Abschluss-Notification (Erfolg/Fehler/Abbruch) - Integration in downloadBatch(): Fortschritt pro Song, Abschluss nach Batch - CloudScreen._upload(): Upload-Fortschritt + Abschluss-Notification
This commit is contained in:
@@ -4,6 +4,7 @@ import 'dart:io' show Platform;
|
|||||||
import 'package:audio_service/audio_service.dart';
|
import 'package:audio_service/audio_service.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'database/db_helper.dart';
|
import 'database/db_helper.dart';
|
||||||
import 'services/favoriten_service.dart';
|
import 'services/favoriten_service.dart';
|
||||||
import 'services/auth_service.dart';
|
import 'services/auth_service.dart';
|
||||||
@@ -15,12 +16,37 @@ import 'utils/farb_theme.dart';
|
|||||||
import 'screens/home_screen.dart';
|
import 'screens/home_screen.dart';
|
||||||
import 'screens/login_screen.dart';
|
import 'screens/login_screen.dart';
|
||||||
|
|
||||||
|
/// Globaler Notification-Plugin (wird in main() initialisiert)
|
||||||
|
final FlutterLocalNotificationsPlugin notificationsPlugin =
|
||||||
|
FlutterLocalNotificationsPlugin();
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
// Logger startet sofort – zeichnet ALLES auf
|
// Logger startet sofort – zeichnet ALLES auf
|
||||||
MeloLogger().init('2.35');
|
MeloLogger().init('2.35');
|
||||||
|
|
||||||
|
// ── Notifications initialisieren (Issue #9) ──
|
||||||
|
const androidInit = AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||||
|
const initSettings = InitializationSettings(android: androidInit);
|
||||||
|
await notificationsPlugin.initialize(
|
||||||
|
settings: initSettings,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Notification-Channel für Downloads (Fortschritt + Abschluss)
|
||||||
|
const downloadChannel = AndroidNotificationChannel(
|
||||||
|
'de.baka.melo.downloads',
|
||||||
|
'Melo Downloads',
|
||||||
|
description: 'Download-Fortschritt und Abschluss',
|
||||||
|
importance: Importance.low,
|
||||||
|
playSound: false,
|
||||||
|
enableVibration: false,
|
||||||
|
);
|
||||||
|
await notificationsPlugin
|
||||||
|
.resolvePlatformSpecificImplementation<
|
||||||
|
AndroidFlutterLocalNotificationsPlugin>()
|
||||||
|
?.createNotificationChannel(downloadChannel);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await DbHelper().db;
|
await DbHelper().db;
|
||||||
await FavoritenService().init();
|
await FavoritenService().init();
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ import 'dart:io';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import '../utils/farb_theme.dart';
|
import '../utils/farb_theme.dart';
|
||||||
import '../services/cloud_service.dart';
|
import '../services/cloud_service.dart';
|
||||||
import '../services/auth_service.dart';
|
import '../services/auth_service.dart';
|
||||||
import '../database/db_helper.dart';
|
import '../database/db_helper.dart';
|
||||||
import '../services/melo_logger.dart';
|
import '../services/melo_logger.dart';
|
||||||
|
import '../main.dart'; // notificationsPlugin
|
||||||
|
|
||||||
/// Melo Cloud Sync Screen v3 — vollständiges Sync-System
|
/// Melo Cloud Sync Screen v3 — vollständiges Sync-System
|
||||||
/// Playlisten, Favoriten, Auto-Sync, Persistent Login, Benutzerdefinierte Namen
|
/// Playlisten, Favoriten, Auto-Sync, Persistent Login, Benutzerdefinierte Namen
|
||||||
@@ -398,6 +400,9 @@ class _CloudScreenState extends State<CloudScreen> {
|
|||||||
|
|
||||||
// ─── Upload / Download ───
|
// ─── Upload / Download ───
|
||||||
|
|
||||||
|
static const String _cloudChannelId = 'de.baka.melo.downloads';
|
||||||
|
static const int _cloudNotifyId = 200;
|
||||||
|
|
||||||
Future<void> _upload() async {
|
Future<void> _upload() async {
|
||||||
setState(() => _ladt = true);
|
setState(() => _ladt = true);
|
||||||
_setzeStatus('Suche lokale Songs...');
|
_setzeStatus('Suche lokale Songs...');
|
||||||
@@ -413,12 +418,59 @@ class _CloudScreenState extends State<CloudScreen> {
|
|||||||
}
|
}
|
||||||
final files = dir.listSync().whereType<File>().where(
|
final files = dir.listSync().whereType<File>().where(
|
||||||
(f) => f.path.endsWith('.mp3') || f.path.endsWith('.m4a'));
|
(f) => f.path.endsWith('.mp3') || f.path.endsWith('.m4a'));
|
||||||
|
final fileList = files.toList();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (final f in files) {
|
for (int i = 0; i < fileList.length; i++) {
|
||||||
|
final f = fileList[i];
|
||||||
_setzeStatus('Upload: ${f.path.split('/').last}...');
|
_setzeStatus('Upload: ${f.path.split('/').last}...');
|
||||||
|
// Progress-Notification
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
notificationsPlugin.show(
|
||||||
|
id: _cloudNotifyId,
|
||||||
|
title: 'Melo Cloud Upload',
|
||||||
|
body: '${i + 1} / ${fileList.length}: ${f.path.split('/').last}',
|
||||||
|
notificationDetails: NotificationDetails(
|
||||||
|
android: AndroidNotificationDetails(
|
||||||
|
_cloudChannelId,
|
||||||
|
'Melo Downloads',
|
||||||
|
channelDescription: 'Cloud Upload-Fortschritt',
|
||||||
|
importance: Importance.low,
|
||||||
|
priority: Priority.low,
|
||||||
|
onlyAlertOnce: true,
|
||||||
|
showProgress: true,
|
||||||
|
maxProgress: fileList.length,
|
||||||
|
progress: i,
|
||||||
|
ongoing: true,
|
||||||
|
autoCancel: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
final sid = await widget.cloud.upload(f.path, f.path.split('/').last);
|
final sid = await widget.cloud.upload(f.path, f.path.split('/').last);
|
||||||
if (sid != null) count++;
|
if (sid != null) count++;
|
||||||
}
|
}
|
||||||
|
// Abschluss-Notification
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
notificationsPlugin.cancel(id: _cloudNotifyId);
|
||||||
|
final ok = count > 0;
|
||||||
|
notificationsPlugin.show(
|
||||||
|
id: _cloudNotifyId + 1,
|
||||||
|
title: ok ? 'Cloud Upload fertig' : 'Cloud Upload fehlgeschlagen',
|
||||||
|
body: ok
|
||||||
|
? '$count / ${fileList.length} Songs hochgeladen ✅'
|
||||||
|
: 'Kein Song konnte hochgeladen werden ❌',
|
||||||
|
notificationDetails: NotificationDetails(
|
||||||
|
android: AndroidNotificationDetails(
|
||||||
|
_cloudChannelId,
|
||||||
|
'Melo Downloads',
|
||||||
|
channelDescription: 'Cloud Upload-Abschluss',
|
||||||
|
importance: Importance.defaultImportance,
|
||||||
|
priority: Priority.defaultPriority,
|
||||||
|
autoCancel: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
await _ladeStatus();
|
await _ladeStatus();
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() => _ladt = false);
|
setState(() => _ladt = false);
|
||||||
@@ -427,6 +479,9 @@ class _CloudScreenState extends State<CloudScreen> {
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
MeloLogger().fehler('cloud_upload_path', e);
|
MeloLogger().fehler('cloud_upload_path', e);
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
notificationsPlugin.cancel(id: _cloudNotifyId);
|
||||||
|
}
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_ladt = false;
|
_ladt = false;
|
||||||
|
|||||||
@@ -4,14 +4,17 @@ import 'dart:io';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import '../models/song.dart';
|
import '../models/song.dart';
|
||||||
import '../database/db_helper.dart';
|
import '../database/db_helper.dart';
|
||||||
import '../utils/audio_validator.dart';
|
import '../utils/audio_validator.dart';
|
||||||
import 'melo_logger.dart';
|
import 'melo_logger.dart';
|
||||||
import '../config/app_config.dart';
|
import '../config/app_config.dart';
|
||||||
|
import '../main.dart'; // für notificationsPlugin
|
||||||
|
|
||||||
/// Download-Service: Lädt YouTube-Audio über den yt-proxy herunter.
|
/// Download-Service: Lädt YouTube-Audio über den yt-proxy herunter.
|
||||||
/// Nutzt ChangeNotifier für UI-Updates via ListenableBuilder.
|
/// Nutzt ChangeNotifier für UI-Updates via ListenableBuilder.
|
||||||
|
/// Issue #9: Fortschritt per System-Notification (ProgressBar).
|
||||||
class DownloadService extends ChangeNotifier {
|
class DownloadService extends ChangeNotifier {
|
||||||
static final http.Client _client = http.Client();
|
static final http.Client _client = http.Client();
|
||||||
|
|
||||||
@@ -23,6 +26,10 @@ class DownloadService extends ChangeNotifier {
|
|||||||
static String get _apiKey => AppConfig.ytProxyApiKey;
|
static String get _apiKey => AppConfig.ytProxyApiKey;
|
||||||
static Map<String, String> get _authHeader => {'X-API-Key': _apiKey};
|
static Map<String, String> get _authHeader => {'X-API-Key': _apiKey};
|
||||||
|
|
||||||
|
static const String _channelId = 'de.baka.melo.downloads';
|
||||||
|
static const int _notifyProgressId = 100;
|
||||||
|
static const int _notifyCompleteId = 101;
|
||||||
|
|
||||||
final DbHelper _db = DbHelper();
|
final DbHelper _db = DbHelper();
|
||||||
|
|
||||||
bool _ladt = false;
|
bool _ladt = false;
|
||||||
@@ -91,12 +98,14 @@ class DownloadService extends ChangeNotifier {
|
|||||||
int erfolgreich = 0;
|
int erfolgreich = 0;
|
||||||
_aktuellerTitel = '0/${urls.length} – Starte...';
|
_aktuellerTitel = '0/${urls.length} – Starte...';
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
_showProgress(0, urls.length);
|
||||||
|
|
||||||
for (int i = 0; i < urls.length; i++) {
|
for (int i = 0; i < urls.length; i++) {
|
||||||
if (sollAbbrechen) break;
|
if (sollAbbrechen) break;
|
||||||
|
|
||||||
_aktuellerTitel = '${i + 1}/${urls.length} – ${urls[i]._titelKurz()}';
|
_aktuellerTitel = '${i + 1}/${urls.length} – ${urls[i]._titelKurz()}';
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
_showProgress(i, urls.length, titel: urls[i]._titelKurz());
|
||||||
|
|
||||||
MeloLogger().zustand('download_einzeln_start', {
|
MeloLogger().zustand('download_einzeln_start', {
|
||||||
'index': i,
|
'index': i,
|
||||||
@@ -137,6 +146,7 @@ class DownloadService extends ChangeNotifier {
|
|||||||
_aktuellerTitel = '✅ $erfolgreich/${urls.length} Songs geladen';
|
_aktuellerTitel = '✅ $erfolgreich/${urls.length} Songs geladen';
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
_completeNotification(erfolgreich, urls.length, abgebrochen: sollAbbrechen);
|
||||||
MeloLogger().zustand('download_batch_ende', {
|
MeloLogger().zustand('download_batch_ende', {
|
||||||
'erfolgreich': erfolgreich,
|
'erfolgreich': erfolgreich,
|
||||||
'gesamt': urls.length,
|
'gesamt': urls.length,
|
||||||
@@ -458,6 +468,66 @@ class DownloadService extends ChangeNotifier {
|
|||||||
return _downloadEinzeln(song.ytUrl!);
|
return _downloadEinzeln(song.ytUrl!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── #9: Notification-Progress ─────────────────
|
||||||
|
|
||||||
|
/// Zeigt oder aktualisiert eine Fortschritts-Notification.
|
||||||
|
/// [current] = aktueller Index (1-basiert), [total] = Gesamtanzahl.
|
||||||
|
void _showProgress(int current, int total, {String? titel}) {
|
||||||
|
if (!Platform.isAndroid) return;
|
||||||
|
notificationsPlugin.show(
|
||||||
|
id: _notifyProgressId,
|
||||||
|
title: 'Melo lädt herunter',
|
||||||
|
body: titel ?? '$current / $total Songs',
|
||||||
|
notificationDetails: NotificationDetails(
|
||||||
|
android: AndroidNotificationDetails(
|
||||||
|
_channelId,
|
||||||
|
'Melo Downloads',
|
||||||
|
channelDescription: 'Download-Fortschritt',
|
||||||
|
importance: Importance.low,
|
||||||
|
priority: Priority.low,
|
||||||
|
onlyAlertOnce: true,
|
||||||
|
showProgress: true,
|
||||||
|
maxProgress: total,
|
||||||
|
progress: current,
|
||||||
|
ongoing: true,
|
||||||
|
autoCancel: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Zeigt Abschluss-Notification (Erfolg oder Fehler).
|
||||||
|
void _completeNotification(int erfolgreich, int gesamt, {bool abgebrochen = false}) {
|
||||||
|
if (!Platform.isAndroid) return;
|
||||||
|
// Fortschritts-Notification abbrechen
|
||||||
|
notificationsPlugin.cancel(id: _notifyProgressId);
|
||||||
|
|
||||||
|
final titel = abgebrochen
|
||||||
|
? 'Download abgebrochen'
|
||||||
|
: (erfolgreich > 0 ? 'Download fertig' : 'Download fehlgeschlagen');
|
||||||
|
final body = abgebrochen
|
||||||
|
? '$erfolgreich / $gesamt Songs geladen'
|
||||||
|
: (erfolgreich > 0
|
||||||
|
? '$erfolgreich / $gesamt Songs geladen ✅'
|
||||||
|
: 'Kein Song konnte geladen werden ❌');
|
||||||
|
|
||||||
|
notificationsPlugin.show(
|
||||||
|
id: _notifyCompleteId,
|
||||||
|
title: titel,
|
||||||
|
body: body,
|
||||||
|
notificationDetails: NotificationDetails(
|
||||||
|
android: AndroidNotificationDetails(
|
||||||
|
_channelId,
|
||||||
|
'Melo Downloads',
|
||||||
|
channelDescription: 'Download-Abschluss',
|
||||||
|
importance: Importance.defaultImportance,
|
||||||
|
priority: Priority.defaultPriority,
|
||||||
|
autoCancel: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
abbrechen();
|
abbrechen();
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import Foundation
|
|||||||
|
|
||||||
import audio_service
|
import audio_service
|
||||||
import audio_session
|
import audio_session
|
||||||
|
import flutter_local_notifications
|
||||||
import flutter_secure_storage_darwin
|
import flutter_secure_storage_darwin
|
||||||
import just_audio
|
import just_audio
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
@@ -15,6 +16,7 @@ import sqflite_darwin
|
|||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
|
AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin"))
|
||||||
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
|
||||||
|
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||||
FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin"))
|
FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin"))
|
||||||
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
|
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
|
|||||||
@@ -97,6 +97,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.7"
|
version: "3.0.7"
|
||||||
|
dbus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dbus
|
||||||
|
sha256: "792974a4007974fbc5c1b5433eb2330a9db3e368c3f906253af4c007d0f49a91"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.13"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -158,6 +166,46 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "5.0.0"
|
||||||
|
flutter_local_notifications:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications
|
||||||
|
sha256: "9375211fd7df9c070504ac4db7047c7fae857e238291433b770cfe696b5c357a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "22.2.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: "945a438a4779f3aca3a948718d8a4048cbe9f9c8c797492c00abd5d39112bf37"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "12.1.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_secure_storage:
|
flutter_secure_storage:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -472,6 +520,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.1"
|
version: "0.2.1"
|
||||||
|
petitparser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: petitparser
|
||||||
|
sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.2"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -669,6 +725,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.11"
|
version: "0.7.11"
|
||||||
|
timezone:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: timezone
|
||||||
|
sha256: "981d1020d6ef8fe1e7b3de5054e5b25579ae7c403d7734adc508ffc47668e9cb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.11.1"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -725,6 +789,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
xml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xml
|
||||||
|
sha256: "67f0aff7be013d107995e9b75bf4e7f2c3ef2dfdb2c8e68024bba0a7fd5756a4"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.1"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ dependencies:
|
|||||||
http: ^1.2.0
|
http: ^1.2.0
|
||||||
crypto: ^3.0.6
|
crypto: ^3.0.6
|
||||||
flutter_secure_storage: ^10.3.1
|
flutter_secure_storage: ^10.3.1
|
||||||
|
flutter_local_notifications: ^22.2.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
flutter_local_notifications_windows
|
||||||
jni
|
jni
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user