New Feature:

- Push notification!
This commit is contained in:
Linloir 2022-10-23 22:44:02 +08:00
parent 5834bcaa58
commit acc5f493af
No known key found for this signature in database
GPG Key ID: 58EEB209A0F2C366
14 changed files with 225 additions and 23 deletions

View File

@ -30,6 +30,7 @@ android {
ndkVersion flutter.ndkVersion ndkVersion flutter.ndkVersion
compileOptions { compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
@ -51,6 +52,7 @@ android {
targetSdkVersion flutter.targetSdkVersion targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
multiDexEnabled true
} }
buildTypes { buildTypes {
@ -68,4 +70,10 @@ flutter {
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
} }

27
android/app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,27 @@
## Gson rules
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken

View File

@ -11,7 +11,9 @@
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" 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 <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues while the Flutter UI initializes. After that, this theme continues
@ -30,6 +32,11 @@
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<service
android:name="com.dexterous.flutterlocalnotifications.ForegroundService"
android:exported="false"
android:stopWithTask="false"/>
</application> </application>
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
</manifest> </manifest>

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@drawable/*" />

View File

@ -7,7 +7,17 @@ import Flutter
_ application: UIApplication, _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
// This is required to make any communication available in the action isolate.
FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (registry) in
GeneratedPluginRegistrant.register(with: registry)
}
GeneratedPluginRegistrant.register(with: self) GeneratedPluginRegistrant.register(with: self)
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* @Author : Linloir * @Author : Linloir
* @Date : 2022-10-13 14:02:28 * @Date : 2022-10-13 14:02:28
* @LastEditTime : 2022-10-22 21:08:39 * @LastEditTime : 2022-10-23 22:37:55
* @Description : * @Description :
*/ */
@ -9,18 +9,22 @@ import 'dart:async';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:tcp_client/home/cubit/home_state.dart'; import 'package:tcp_client/home/cubit/home_state.dart';
import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart'; import 'package:tcp_client/repositories/local_service_repository/local_service_repository.dart';
import 'package:tcp_client/repositories/tcp_repository/models/tcp_request.dart'; import 'package:tcp_client/repositories/tcp_repository/models/tcp_request.dart';
import 'package:tcp_client/repositories/tcp_repository/models/tcp_response.dart'; import 'package:tcp_client/repositories/tcp_repository/models/tcp_response.dart';
import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart'; import 'package:tcp_client/repositories/tcp_repository/tcp_repository.dart';
import 'package:tcp_client/repositories/user_repository/user_repository.dart';
class HomeCubit extends Cubit<HomeState> { class HomeCubit extends Cubit<HomeState> {
HomeCubit({ HomeCubit({
required this.localServiceRepository, required this.localServiceRepository,
required this.tcpRepository, required this.tcpRepository,
required this.pageController required this.pageController,
required this.localNotificationsPlugin,
required this.userRepository
}): super(const HomeState(page: HomePagePosition.message, status: HomePageStatus.initializing)) { }): super(const HomeState(page: HomePagePosition.message, status: HomePageStatus.initializing)) {
pageController.addListener(() { pageController.addListener(() {
emit(state.copyWith(page: HomePagePosition.fromValue((pageController.page ?? 0).round()))); emit(state.copyWith(page: HomePagePosition.fromValue((pageController.page ?? 0).round())));
@ -59,7 +63,9 @@ class HomeCubit extends Cubit<HomeState> {
final LocalServiceRepository localServiceRepository; final LocalServiceRepository localServiceRepository;
final TCPRepository tcpRepository; final TCPRepository tcpRepository;
final PageController pageController; final PageController pageController;
final UserRepository userRepository;
late final StreamSubscription subscription; late final StreamSubscription subscription;
final FlutterLocalNotificationsPlugin localNotificationsPlugin;
void switchPage(HomePagePosition newPage) { void switchPage(HomePagePosition newPage) {
pageController.animateToPage( pageController.animateToPage(
@ -77,6 +83,36 @@ class HomeCubit extends Cubit<HomeState> {
case TCPResponseType.forwardMessage: { case TCPResponseType.forwardMessage: {
response as ForwardMessageResponse; response as ForwardMessageResponse;
await localServiceRepository.storeMessages([response.message]); await localServiceRepository.storeMessages([response.message]);
var curUser = (await SharedPreferences.getInstance()).getInt('userid');
if(response.message.senderID != curUser) {
//Push notification via flutter local notification
const androidNotificationDetails = AndroidNotificationDetails(
'0',
'New Messages',
channelDescription: 'New messages',
importance: Importance.max,
priority: Priority.max,
enableVibration: true,
enableLights: true,
visibility: NotificationVisibility.private
);
const iosNotificationDetails = DarwinNotificationDetails();
const linuxNotificationDetails = LinuxNotificationDetails();
const notificationDetails = NotificationDetails(
android: androidNotificationDetails,
iOS: iosNotificationDetails,
macOS: iosNotificationDetails,
linux: linuxNotificationDetails
);
var userName = userRepository.getUserInfo(userid: response.message.senderID).userName;
await localNotificationsPlugin.show(
response.message.contentmd5.hashCode,
'New Message',
'$userName: ${response.message.contentDecoded}',
notificationDetails,
payload: response.message.contentmd5
);
}
break; break;
} }
case TCPResponseType.fetchMessage: { case TCPResponseType.fetchMessage: {

View File

@ -1,12 +1,13 @@
/* /*
* @Author : Linloir * @Author : Linloir
* @Date : 2022-10-11 11:05:08 * @Date : 2022-10-11 11:05:08
* @LastEditTime : 2022-10-23 12:14:36 * @LastEditTime : 2022-10-23 22:37:02
* @Description : * @Description :
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:tcp_client/home/cubit/home_cubit.dart'; import 'package:tcp_client/home/cubit/home_cubit.dart';
import 'package:tcp_client/home/cubit/home_state.dart'; import 'package:tcp_client/home/cubit/home_state.dart';
@ -27,6 +28,7 @@ class HomePage extends StatelessWidget with WindowListener {
required this.userID, required this.userID,
required this.localServiceRepository, required this.localServiceRepository,
required this.tcpRepository, required this.tcpRepository,
required this.localNotificationsPlugin,
super.key super.key
}); });
//TODO: listen to file storage //TODO: listen to file storage
@ -34,15 +36,18 @@ class HomePage extends StatelessWidget with WindowListener {
final int userID; final int userID;
final LocalServiceRepository localServiceRepository; final LocalServiceRepository localServiceRepository;
final TCPRepository tcpRepository; final TCPRepository tcpRepository;
final FlutterLocalNotificationsPlugin localNotificationsPlugin;
static Route<void> route({ static Route<void> route({
required int userID, required int userID,
required LocalServiceRepository localServiceRepository, required LocalServiceRepository localServiceRepository,
required TCPRepository tcpRepository required TCPRepository tcpRepository,
required FlutterLocalNotificationsPlugin localNotificationsPlugin,
}) => MaterialPageRoute<void>(builder: (context) => HomePage( }) => MaterialPageRoute<void>(builder: (context) => HomePage(
userID: userID, userID: userID,
localServiceRepository: localServiceRepository, localServiceRepository: localServiceRepository,
tcpRepository: tcpRepository, tcpRepository: tcpRepository,
localNotificationsPlugin: localNotificationsPlugin,
)); ));
@override @override
@ -76,7 +81,9 @@ class HomePage extends StatelessWidget with WindowListener {
create: (context) => HomeCubit( create: (context) => HomeCubit(
localServiceRepository: localServiceRepository, localServiceRepository: localServiceRepository,
tcpRepository: tcpRepository, tcpRepository: tcpRepository,
pageController: PageController() pageController: PageController(),
localNotificationsPlugin: localNotificationsPlugin,
userRepository: context.read<UserRepository>()
), ),
) )
], ],

View File

@ -1,7 +1,7 @@
/* /*
* @Author : Linloir * @Author : Linloir
* @Date : 2022-10-12 23:36:12 * @Date : 2022-10-12 23:36:12
* @LastEditTime : 2022-10-20 11:45:15 * @LastEditTime : 2022-10-23 22:10:44
* @Description : * @Description :
*/ */
@ -57,7 +57,8 @@ class MyProfilePage extends StatelessWidget {
Future.delayed(const Duration(seconds: 1)).then((_) { Future.delayed(const Duration(seconds: 1)).then((_) {
Navigator.of(context).pushAndRemoveUntil(LoginPage.route( Navigator.of(context).pushAndRemoveUntil(LoginPage.route(
localServiceRepository: context.read<LocalServiceRepository>(), localServiceRepository: context.read<LocalServiceRepository>(),
tcpRepository: context.read<TCPRepository>() tcpRepository: context.read<TCPRepository>(),
localNotificationsPlugin: context.read<HomeCubit>().localNotificationsPlugin
), (route) => false); ), (route) => false);
}); });
} }

View File

@ -1,12 +1,13 @@
/* /*
* @Author : Linloir * @Author : Linloir
* @Date : 2022-10-12 15:06:30 * @Date : 2022-10-12 15:06:30
* @LastEditTime : 2022-10-23 10:15:11 * @LastEditTime : 2022-10-23 22:12:07
* @Description : * @Description :
*/ */
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:formz/formz.dart'; import 'package:formz/formz.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:tcp_client/home/home_page.dart'; import 'package:tcp_client/home/home_page.dart';
@ -21,19 +22,23 @@ class LoginPage extends StatelessWidget {
const LoginPage({ const LoginPage({
required this.localServiceRepository, required this.localServiceRepository,
required this.tcpRepository, required this.tcpRepository,
required this.localNotificationsPlugin,
super.key super.key
}); });
static Route<void> route({ static Route<void> route({
required LocalServiceRepository localServiceRepository, required LocalServiceRepository localServiceRepository,
required TCPRepository tcpRepository required TCPRepository tcpRepository,
required FlutterLocalNotificationsPlugin localNotificationsPlugin,
}) => MaterialPageRoute<void>(builder: (context) => LoginPage( }) => MaterialPageRoute<void>(builder: (context) => LoginPage(
localServiceRepository: localServiceRepository, localServiceRepository: localServiceRepository,
tcpRepository: tcpRepository tcpRepository: tcpRepository,
localNotificationsPlugin: localNotificationsPlugin,
)); ));
final LocalServiceRepository localServiceRepository; final LocalServiceRepository localServiceRepository;
final TCPRepository tcpRepository; final TCPRepository tcpRepository;
final FlutterLocalNotificationsPlugin localNotificationsPlugin;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -64,7 +69,8 @@ class LoginPage extends StatelessWidget {
Navigator.of(context).pushReplacement(HomePage.route( Navigator.of(context).pushReplacement(HomePage.route(
userID: userID, userID: userID,
localServiceRepository: localServiceRepository, localServiceRepository: localServiceRepository,
tcpRepository: tcpRepository tcpRepository: tcpRepository,
localNotificationsPlugin: localNotificationsPlugin
)); ));
}); });
} }
@ -96,7 +102,11 @@ class LoginPage extends StatelessWidget {
const Text('Does not have an account?'), const Text('Does not have an account?'),
const SizedBox(width: 8,), const SizedBox(width: 8,),
TextButton( TextButton(
onPressed: () => Navigator.of(context).push(RegisterPage.route(localServiceRepository: localServiceRepository, tcpRepository: tcpRepository)), onPressed: () => Navigator.of(context).push(RegisterPage.route(
localServiceRepository: localServiceRepository,
tcpRepository: tcpRepository,
localNotificationsPlugin: localNotificationsPlugin
)),
style: ButtonStyle( style: ButtonStyle(
overlayColor: MaterialStateProperty.all(Colors.transparent), overlayColor: MaterialStateProperty.all(Colors.transparent),
foregroundColor: MaterialStateProperty.all(Colors.blue[800]) foregroundColor: MaterialStateProperty.all(Colors.blue[800])

View File

@ -1,7 +1,7 @@
/* /*
* @Author : Linloir * @Author : Linloir
* @Date : 2022-10-10 08:04:53 * @Date : 2022-10-10 08:04:53
* @LastEditTime : 2022-10-23 12:18:17 * @LastEditTime : 2022-10-23 22:26:44
* @Description : * @Description :
*/ */
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
@ -13,8 +13,33 @@ import 'package:tcp_client/initialization/cubit/initialization_cubit.dart';
import 'package:tcp_client/initialization/cubit/initialization_state.dart'; import 'package:tcp_client/initialization/cubit/initialization_state.dart';
import 'package:tcp_client/initialization/initialization_page.dart'; import 'package:tcp_client/initialization/initialization_page.dart';
import 'package:tcp_client/login/login_page.dart'; import 'package:tcp_client/login/login_page.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
void main() async { void main() async {
// needed if you intend to initialize in the `main` function
WidgetsFlutterBinding.ensureInitialized();
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
const DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings();
const LinuxInitializationSettings initializationSettingsLinux =
LinuxInitializationSettings(
defaultActionName: 'Open notification'
);
const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
macOS: initializationSettingsDarwin,
linux: initializationSettingsLinux
);
await flutterLocalNotificationsPlugin.initialize(
initializationSettings
);
runApp(const MyApp()); runApp(const MyApp());
} }
@ -29,7 +54,7 @@ class MyAppState extends State<MyApp> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
title: 'Flutter Demo', title: 'LChatClient',
theme: ThemeData( theme: ThemeData(
primarySwatch: Colors.blue, primarySwatch: Colors.blue,
), ),
@ -49,7 +74,7 @@ class SplashPage extends StatelessWidget {
return BlocProvider<InitializationCubit>( return BlocProvider<InitializationCubit>(
create: (context) { create: (context) {
return InitializationCubit( return InitializationCubit(
serverAddress: '127.0.0.1', serverAddress: 'chat.linloir.cn',
serverPort: 20706 serverPort: 20706
); );
}, },
@ -65,13 +90,15 @@ class SplashPage extends StatelessWidget {
Navigator.of(context).pushReplacement(HomePage.route( Navigator.of(context).pushReplacement(HomePage.route(
userID: userID, userID: userID,
localServiceRepository: state.localServiceRepository!, localServiceRepository: state.localServiceRepository!,
tcpRepository: state.tcpRepository! tcpRepository: state.tcpRepository!,
localNotificationsPlugin: flutterLocalNotificationsPlugin
)); ));
} }
else { else {
Navigator.of(context).pushReplacement(LoginPage.route( Navigator.of(context).pushReplacement(LoginPage.route(
localServiceRepository: state.localServiceRepository!, localServiceRepository: state.localServiceRepository!,
tcpRepository: state.tcpRepository! tcpRepository: state.tcpRepository!,
localNotificationsPlugin: flutterLocalNotificationsPlugin
)); ));
} }
}); });

View File

@ -1,7 +1,7 @@
/* /*
* @Author : Linloir * @Author : Linloir
* @Date : 2022-10-12 17:36:38 * @Date : 2022-10-12 17:36:38
* @LastEditTime : 2022-10-23 10:15:31 * @LastEditTime : 2022-10-23 22:12:12
* @Description : * @Description :
*/ */
/* /*
@ -13,6 +13,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:formz/formz.dart'; import 'package:formz/formz.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:tcp_client/home/home_page.dart'; import 'package:tcp_client/home/home_page.dart';
@ -26,19 +27,24 @@ class RegisterPage extends StatelessWidget {
const RegisterPage({ const RegisterPage({
required this.localServiceRepository, required this.localServiceRepository,
required this.tcpRepository, required this.tcpRepository,
required this.localNotificationsPlugin,
super.key super.key
}); });
static Route<void> route({ static Route<void> route({
required LocalServiceRepository localServiceRepository, required LocalServiceRepository localServiceRepository,
required TCPRepository tcpRepository required TCPRepository tcpRepository,
required FlutterLocalNotificationsPlugin localNotificationsPlugin,
}) => MaterialPageRoute<void>(builder: (context) => RegisterPage( }) => MaterialPageRoute<void>(builder: (context) => RegisterPage(
localServiceRepository: localServiceRepository, localServiceRepository: localServiceRepository,
tcpRepository: tcpRepository tcpRepository: tcpRepository,
localNotificationsPlugin: localNotificationsPlugin,
)); ));
final LocalServiceRepository localServiceRepository; final LocalServiceRepository localServiceRepository;
final TCPRepository tcpRepository; final TCPRepository tcpRepository;
final FlutterLocalNotificationsPlugin localNotificationsPlugin;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -74,7 +80,8 @@ class RegisterPage extends StatelessWidget {
Navigator.of(context).pushAndRemoveUntil(HomePage.route( Navigator.of(context).pushAndRemoveUntil(HomePage.route(
userID: userID, userID: userID,
localServiceRepository: localServiceRepository, localServiceRepository: localServiceRepository,
tcpRepository: tcpRepository tcpRepository: tcpRepository,
localNotificationsPlugin: localNotificationsPlugin
), (route) => false); ), (route) => false);
}); });
} }

View File

@ -5,6 +5,7 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import flutter_local_notifications
import path_provider_macos import path_provider_macos
import screen_retriever import screen_retriever
import shared_preferences_macos import shared_preferences_macos
@ -12,6 +13,7 @@ import sqflite
import window_manager import window_manager
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))

View File

@ -1,6 +1,13 @@
# Generated by pub # Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile # See https://dart.dev/tools/pub/glossary#lockfile
packages: packages:
args:
dependency: transitive
description:
name: args
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.3.1"
async: async:
dependency: "direct main" dependency: "direct main"
description: description:
@ -71,6 +78,13 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.5" version: "1.0.5"
dbus:
dependency: transitive
description:
name: dbus
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.7.8"
easy_debounce: easy_debounce:
dependency: "direct main" dependency: "direct main"
description: description:
@ -132,6 +146,27 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
url: "https://pub.flutter-io.cn"
source: hosted
version: "12.0.2"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.0.0"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: transitive
description: description:
@ -284,6 +319,13 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.1.3" version: "2.1.3"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.0.0"
photo_view: photo_view:
dependency: "direct main" dependency: "direct main"
description: description:
@ -485,6 +527,13 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.4.12" version: "0.4.12"
timezone:
dependency: transitive
description:
name: timezone
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.9.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -520,6 +569,13 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.2.0+2" version: "0.2.0+2"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.flutter-io.cn"
source: hosted
version: "6.1.0"
sdks: sdks:
dart: ">=2.18.2 <3.0.0" dart: ">=2.18.2 <3.0.0"
flutter: ">=3.3.0-0" flutter: ">=3.3.0-0"

View File

@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 2.2.0 version: 3.0.0
environment: environment:
sdk: '>=2.18.2 <3.0.0' sdk: '>=2.18.2 <3.0.0'
@ -60,6 +60,7 @@ dependencies:
window_manager: ^0.2.7 window_manager: ^0.2.7
# easy_image_viewer: ^1.1.0 # easy_image_viewer: ^1.1.0
photo_view: ^0.14.0 photo_view: ^0.14.0
flutter_local_notifications: ^12.0.2
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.