Notification is added
This commit is contained in:
1 parent
afe7fb578a
commit
a80a23e008
7 files changed
+153
-2
No files matched your search
@@ -12,6 +12,7 @@ android {
|
|||||||
ndkVersion = flutter.ndkVersion
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
isCoreLibraryDesugaringEnabled = true
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
@@ -59,3 +60,7 @@ kotlin {
|
|||||||
flutter {
|
flutter {
|
||||||
source = "../.."
|
source = "../.."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
|
||||||
|
}
|
||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
|
||||||
<!-- Required by url_launcher on Android 11+ to open external browser -->
|
<!-- Required by url_launcher on Android 11+ to open external browser -->
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 144 KiB |
@@ -0,0 +1,69 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
|
|
||||||
|
class VpnNotificationManager {
|
||||||
|
static final FlutterLocalNotificationsPlugin _plugin =
|
||||||
|
FlutterLocalNotificationsPlugin();
|
||||||
|
static bool _initialized = false;
|
||||||
|
|
||||||
|
static Future<void> init() async {
|
||||||
|
if (_initialized) return;
|
||||||
|
|
||||||
|
const androidSettings =
|
||||||
|
AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||||
|
const initSettings = InitializationSettings(android: androidSettings);
|
||||||
|
|
||||||
|
await _plugin.initialize(initSettings);
|
||||||
|
|
||||||
|
// Request POST_NOTIFICATIONS permission on Android 13+
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
final androidPlugin = _plugin
|
||||||
|
.resolvePlatformSpecificImplementation<
|
||||||
|
AndroidFlutterLocalNotificationsPlugin>();
|
||||||
|
await androidPlugin?.requestNotificationsPermission();
|
||||||
|
}
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> showOrUpdateStatus({
|
||||||
|
required String timeLeft,
|
||||||
|
required String speedKbps,
|
||||||
|
}) async {
|
||||||
|
if (!_initialized) await init();
|
||||||
|
|
||||||
|
const androidDetails = AndroidNotificationDetails(
|
||||||
|
'paladin_vpn_status',
|
||||||
|
'VPN Status',
|
||||||
|
channelDescription: 'Persistent notification shown while VPN is active',
|
||||||
|
importance: Importance.low,
|
||||||
|
priority: Priority.low,
|
||||||
|
// Non-dismissable while VPN is running
|
||||||
|
ongoing: true,
|
||||||
|
autoCancel: false,
|
||||||
|
// Silent updates — no sound or vibration each time stats refresh
|
||||||
|
playSound: false,
|
||||||
|
enableVibration: false,
|
||||||
|
onlyAlertOnce: true,
|
||||||
|
// Hide the auto-generated timestamp
|
||||||
|
showWhen: false,
|
||||||
|
// Show on lock screen
|
||||||
|
visibility: NotificationVisibility.public,
|
||||||
|
);
|
||||||
|
|
||||||
|
const notificationDetails = NotificationDetails(android: androidDetails);
|
||||||
|
|
||||||
|
await _plugin.show(
|
||||||
|
888, // Fixed ID — always updates the same notification
|
||||||
|
'Paladin VPN Active',
|
||||||
|
'Time: $timeLeft • $speedKbps',
|
||||||
|
notificationDetails,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<void> cancel() async {
|
||||||
|
if (!_initialized) return;
|
||||||
|
await _plugin.cancel(888);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -5,6 +5,7 @@ import 'package:http/http.dart' as http;
|
|||||||
import 'package:paladinvpn/logic/app_config.dart';
|
import 'package:paladinvpn/logic/app_config.dart';
|
||||||
import 'package:paladinvpn/logic/vpn_connection.dart';
|
import 'package:paladinvpn/logic/vpn_connection.dart';
|
||||||
import 'package:paladinvpn/logic/crypto_service.dart';
|
import 'package:paladinvpn/logic/crypto_service.dart';
|
||||||
|
import 'package:paladinvpn/components/notification.dart';
|
||||||
|
|
||||||
/// SessionTimer acts as the client-side session authority for the VPN tunnel.
|
/// SessionTimer acts as the client-side session authority for the VPN tunnel.
|
||||||
///
|
///
|
||||||
@@ -51,6 +52,16 @@ class SessionTimer extends ChangeNotifier {
|
|||||||
return '${gb.toStringAsFixed(2)} GB';
|
return '${gb.toStringAsFixed(2)} GB';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get formattedDataUsed {
|
||||||
|
if (_usedBytes == 0) return '0.00 MB';
|
||||||
|
if (_usedBytes > 1024 * 1024 * 1024) {
|
||||||
|
final gb = _usedBytes / (1024 * 1024 * 1024);
|
||||||
|
return '${gb.toStringAsFixed(2)} GB';
|
||||||
|
}
|
||||||
|
final mb = _usedBytes / (1024 * 1024);
|
||||||
|
return '${mb.toStringAsFixed(2)} MB';
|
||||||
|
}
|
||||||
|
|
||||||
double get progress {
|
double get progress {
|
||||||
// Max duration is generally 60 or 90 minutes. We'll base the ring purely on data usage or just standard time
|
// Max duration is generally 60 or 90 minutes. We'll base the ring purely on data usage or just standard time
|
||||||
// For UI simplicity, we'll return data progress:
|
// For UI simplicity, we'll return data progress:
|
||||||
@@ -119,6 +130,11 @@ class SessionTimer extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
_lastUsedBytes = _usedBytes;
|
_lastUsedBytes = _usedBytes;
|
||||||
|
|
||||||
|
VpnNotificationManager.showOrUpdateStatus(
|
||||||
|
timeLeft: formatted,
|
||||||
|
speedKbps: '${_currentSpeedKbps.toStringAsFixed(2)} KB/s',
|
||||||
|
);
|
||||||
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
} else if (response.statusCode == 404) {
|
} else if (response.statusCode == 404) {
|
||||||
// Peer not found on server (expired/deleted natively)
|
// Peer not found on server (expired/deleted natively)
|
||||||
@@ -159,6 +175,7 @@ class SessionTimer extends ChangeNotifier {
|
|||||||
_timer = null;
|
_timer = null;
|
||||||
_remainingSeconds = 0;
|
_remainingSeconds = 0;
|
||||||
_currentSpeedKbps = 0.0;
|
_currentSpeedKbps = 0.0;
|
||||||
|
VpnNotificationManager.cancel();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+57
-1
@@ -81,6 +81,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.9"
|
version: "1.0.9"
|
||||||
|
dbus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dbus
|
||||||
|
sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.12"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -134,6 +142,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.2"
|
||||||
|
flutter_local_notifications:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications
|
||||||
|
sha256: "674173fd3c9eda9d4c8528da2ce0ea69f161577495a9cc835a2a4ecd7eadeb35"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "17.2.4"
|
||||||
|
flutter_local_notifications_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications_linux
|
||||||
|
sha256: c49bd06165cad9beeb79090b18cd1eb0296f4bf4b23b84426e37dd7c027fc3af
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.1"
|
||||||
|
flutter_local_notifications_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications_platform_interface
|
||||||
|
sha256: "85f8d07fe708c1bdcf45037f2c0109753b26ae077e9d9e899d55971711a4ea66"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.2.0"
|
||||||
flutter_secure_storage:
|
flutter_secure_storage:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -345,7 +377,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.9.1"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
|
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
|
||||||
@@ -392,6 +424,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
|
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:
|
||||||
@@ -557,6 +597,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: "2236ec079a174ce07434e89fcd3fcda430025eb7692244139a9cf54fdcf1fc7d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.4"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -716,6 +764,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: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.6.1"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ dependencies:
|
|||||||
url_launcher: ^6.3.2
|
url_launcher: ^6.3.2
|
||||||
flutter_secure_storage: ^10.3.1
|
flutter_secure_storage: ^10.3.1
|
||||||
uuid: ^4.5.3
|
uuid: ^4.5.3
|
||||||
|
flutter_local_notifications: ^17.0.0
|
||||||
|
path_provider: ^2.1.5
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in new issue
Block a user