From ca570272139f440ec51cdace3d061657d3fc7f2f Mon Sep 17 00:00:00 2001 From: luckyvermeil Date: Wed, 23 Feb 2022 00:40:28 +0800 Subject: [PATCH] add home widget --- android/app/build.gradle | 5 + android/app/src/main/AndroidManifest.xml | 19 +++ .../SingleCourseWidgetProvider.kt | 46 ++++++ .../main/res/drawable/widget_background.xml | 5 + .../main/res/layout/single_course_layout.xml | 29 ++++ .../src/main/res/xml/single_course_widget.xml | 9 ++ lib/Utils/HomeWidgetUtil.dart | 151 ++++++++++++++++++ lib/generated/intl/messages_en.dart | 2 +- lib/generated/intl/messages_zh_CN.dart | 2 +- lib/generated/l10n.dart | 4 +- lib/l10n/intl_en.arb | 2 +- lib/l10n/intl_zh_CN.arb | 2 +- lib/main.dart | 22 ++- pubspec.lock | 14 ++ pubspec.yaml | 6 +- 15 files changed, 309 insertions(+), 9 deletions(-) create mode 100644 android/app/src/main/kotlin/com/lilystudio/wheretosleepinnju/SingleCourseWidgetProvider.kt create mode 100644 android/app/src/main/res/drawable/widget_background.xml create mode 100644 android/app/src/main/res/layout/single_course_layout.xml create mode 100644 android/app/src/main/res/xml/single_course_widget.xml create mode 100644 lib/Utils/HomeWidgetUtil.dart diff --git a/android/app/build.gradle b/android/app/build.gradle index 5cb6f8a..c32e534 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -22,6 +22,7 @@ if (flutterVersionName == null) { } apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" def keystorePropertiesFile = rootProject.file("key.properties") @@ -43,6 +44,10 @@ android { versionName flutterVersionName } + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + signingConfigs { release { keyAlias keystoreProperties['keyAlias'] diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index f0a5b6a..2c19c6d 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -30,6 +30,25 @@ android:usesCleartextTraffic="true" android:extractNativeLibs="true"> + + + + + + + + + + + + + + + + val views = RemoteViews(context.packageName, R.layout.single_course_layout).apply { + // Open App on Widget Click + val pendingIntent = HomeWidgetLaunchIntent.getActivity( + context, + MainActivity::class.java) + setOnClickPendingIntent(R.id.widget_container, pendingIntent) + + // Swap Title Text by calling Dart Code in the Background + setTextViewText(R.id.widget_title, widgetData.getString("title", null) + ?: "") + val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast( + context, + Uri.parse("singleCourseWidget://titleClicked") + ) + setOnClickPendingIntent(R.id.widget_title, backgroundIntent) + + val content = widgetData.getString("content", null) + setTextViewText(R.id.widget_content, content + ?: "No Content") + // Detect App opened via Click inside Flutter + val pendingIntentWithData = HomeWidgetLaunchIntent.getActivity( + context, + MainActivity::class.java, + Uri.parse("singleCourseWidget://message?message=$content")) + setOnClickPendingIntent(R.id.widget_content, pendingIntentWithData) + } + + appWidgetManager.updateAppWidget(widgetId, views) + } + } +} \ No newline at end of file diff --git a/android/app/src/main/res/drawable/widget_background.xml b/android/app/src/main/res/drawable/widget_background.xml new file mode 100644 index 0000000..1969f25 --- /dev/null +++ b/android/app/src/main/res/drawable/widget_background.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/layout/single_course_layout.xml b/android/app/src/main/res/layout/single_course_layout.xml new file mode 100644 index 0000000..a714dd9 --- /dev/null +++ b/android/app/src/main/res/layout/single_course_layout.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/xml/single_course_widget.xml b/android/app/src/main/res/xml/single_course_widget.xml new file mode 100644 index 0000000..becb40e --- /dev/null +++ b/android/app/src/main/res/xml/single_course_widget.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/lib/Utils/HomeWidgetUtil.dart b/lib/Utils/HomeWidgetUtil.dart new file mode 100644 index 0000000..66beb11 --- /dev/null +++ b/lib/Utils/HomeWidgetUtil.dart @@ -0,0 +1,151 @@ +import 'dart:convert'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:home_widget/home_widget.dart'; +import 'package:path/path.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:sqflite/sqflite.dart'; +import 'package:wheretosleepinnju/Resources/Constant.dart'; +import '../Models/CourseModel.dart'; +import '../Models/Db/DbHelper.dart'; + +class HomeWidgetUtil { + final now = DateTime.now(); + + // final now = DateTime.parse("1970-01-01 17:00:00"); + + updateWidget() async { + int nowWeek = await _getWeekOrder(); + int tableId = await _getClassTableId(); + String title = ""; + String content = ""; + List tac = await _getNextCourse(tableId, nowWeek); + title = tac[0]; + content = tac[1]; + return Future.wait([ + HomeWidget.saveWidgetData( + 'title', + title, + ), + HomeWidget.saveWidgetData( + 'content', + content, + ), + HomeWidget.updateWidget( + name: 'SingleCourseWidgetProvider', + androidName: 'SingleCourseWidgetProvider', + iOSName: 'SingleCourseWidget', + ), + ]).then((value) { + return !value.contains(false); + }); + } + + _getCoursesToday(int tableId, nowWeek) async { + List coursesToday = []; + List allCourses = []; + List allCoursesMap = []; + dynamic dbbasePath = await getDatabasesPath(); + String path = join(dbbasePath, DbHelper.DATABASE_NAME); + Database db = await openDatabase(path, readOnly: true); + + List rst = await db.query(DbHelper.COURSE_TABLE_NAME, + where: '${DbHelper.COURSE_COLUMN_COURSETABLEID} = ?', + whereArgs: [tableId]); + allCoursesMap = rst.toList(); + // List allCoursesMap = await CourseProvider().getAllCourses(tableId); + + for (Map courseMap in allCoursesMap) { + allCourses.add(Course.fromMap(courseMap)); + } + for (Course course in allCourses) { + List weeks = json.decode(course.weeks!); + if (weeks.contains(nowWeek) && course.weekTime == 1) { + coursesToday.add(course); + } + } + return coursesToday; + } + + _getNextCourse(tableId, nowWeek) async { + String title = ""; + String content = ""; + List l = Constant.CLASS_TIME_LIST; + + List courses = await _getCoursesToday(tableId, nowWeek); + courses.sort((a, b) => _s2t(l[a.startTime! - 1]['start']) + .compareTo(_s2t(l[b.startTime! - 1]['start']))); + + if (courses.isEmpty) { + title = '${now.year}-${now.month}-${now.day}'; + content = '今天没有课哦╰(*°▽°*)╯'; + } else { + if (now.isBefore(_c2t(courses[0]))) { + // 如果在第一节课之前 + title = '${courses[0].name}'; + content = + '${l[courses[0].startTime! - 1]['start']}-${l[courses[0].startTime! + courses[0].timeCount! - 1]['end']} 第${courses[0].startTime}-${courses[0].startTime! + courses[0].timeCount!}节 @${courses[0].classroom}'; + } + if (now.isAfter(_c2t(courses[courses.length - 1])) && + now.isBefore(_c2t(courses[courses.length - 1], mode: 'end'))) { + //如果在最后一节课之中 + title = '${courses[courses.length - 1].name}'; + content = + '${l[courses[courses.length - 1].startTime! - 1]['start']}-${l[courses[courses.length - 1].startTime! + courses[courses.length - 1].timeCount! - 1]['end']} 第${courses[courses.length - 1].startTime}-${courses[courses.length - 1].startTime! + courses[courses.length - 1].timeCount!}节 @${courses[courses.length - 1].classroom}'; + } + if (now.isAfter(_c2t(courses[courses.length - 1], mode: 'end'))) { + //如果在最后一节课之后 + title = '${now.year}-${now.month}-${now.day}'; + content = '今天课上完了哦╰(*°▽°*)╯'; + } + for (int i = 1; i < courses.length; i++) { + if (now.isAfter(_c2t(courses[i - 1])) && + now.isBefore(_c2t(courses[i]))) { + //如果在上节课上课后且在下节课上课前 + title = '${courses[i].name}'; + content = + '${l[courses[i].startTime! - 1]['start']}-${l[courses[i].startTime! + courses[i].timeCount! - 1]['end']} 第${courses[i].startTime}-${courses[i].startTime! + courses[i].timeCount!}节 @${courses[i].classroom}'; + } + } + } + + if (kDebugMode) { + title = title + " " + DateTime.now().toString().split('-').last.split('.').first; + } + + return [title, content]; + } + + Future _getWeekOrder() async { + SharedPreferences sp = await SharedPreferences.getInstance(); + int? weekIndex = sp.getInt("weekIndex"); + if (weekIndex != null) { + return weekIndex; + } + return 1; + } + + Future _getClassTableId() async { + SharedPreferences sp = await SharedPreferences.getInstance(); + int? classTableIndex = sp.getInt("tableId"); + if (classTableIndex != null) { + return classTableIndex; + } + return 0; + } + + DateTime _c2t(Course course, {String mode = 'start'}) { + List l = Constant.CLASS_TIME_LIST; + if (mode == 'start') { + return _s2t(l[course.startTime! - 1]['start']); + } else { + return _s2t(l[course.startTime! + course.timeCount! - 1]['end']); + } + } + + DateTime _s2t(String? time24) { + // 22:00格式转换为今天22:00:00的DateTime + String yymmddhhmm = '${now.toString().split(" ").first} $time24:00'; + return DateTime.parse(yymmddhhmm); + } +} \ No newline at end of file diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index d507255..9e7461f 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -262,7 +262,7 @@ class MessageLookup extends MessageLookupByLibrary { "online_parse_error_toast": MessageLookupByLibrary.simpleMessage("导入课表失败,可能是 bug"), "open_source_library_content": MessageLookupByLibrary.simpleMessage( - "shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0"), + "shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0\nhome_widget: ^0.1.5\nworkmanager: ^0.4.1"), "open_source_library_title": MessageLookupByLibrary.simpleMessage("所使用到的开源库"), "password": MessageLookupByLibrary.simpleMessage("密码"), diff --git a/lib/generated/intl/messages_zh_CN.dart b/lib/generated/intl/messages_zh_CN.dart index 2a7c461..44f270e 100644 --- a/lib/generated/intl/messages_zh_CN.dart +++ b/lib/generated/intl/messages_zh_CN.dart @@ -262,7 +262,7 @@ class MessageLookup extends MessageLookupByLibrary { "online_parse_error_toast": MessageLookupByLibrary.simpleMessage("导入课表失败,可能是 bug"), "open_source_library_content": MessageLookupByLibrary.simpleMessage( - "shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0"), + "shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0\nhome_widget: ^0.1.5\nworkmanager: ^0.4.1"), "open_source_library_title": MessageLookupByLibrary.simpleMessage("所使用到的开源库"), "password": MessageLookupByLibrary.simpleMessage("密码"), diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart index e993b39..247984b 100644 --- a/lib/generated/l10n.dart +++ b/lib/generated/l10n.dart @@ -1820,10 +1820,10 @@ class S { ); } - /// `shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0` + /// `shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0\nhome_widget: ^0.1.5\nworkmanager: ^0.4.1` String get open_source_library_content { return Intl.message( - 'shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0', + 'shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0\nhome_widget: ^0.1.5\nworkmanager: ^0.4.1', name: 'open_source_library_content', desc: '', args: [], diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index b242506..d36d2cf 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -176,7 +176,7 @@ "developer": "开发者 idealclover", "introduction": "博客:https://idealclover.top\nEmail:idealclover@163.com", "open_source_library_title": "所使用到的开源库", - "open_source_library_content": "shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0", + "open_source_library_content": "shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0\nhome_widget: ^0.1.5\nworkmanager: ^0.4.1", "easter_egg": "感谢小百合工作室\n感谢 @ns @lgt @FengChendian 协助开发\n感谢 @ovoclover 制作图标\n感谢 @无忌 @子枨 提供配色方案\n特别感谢 1A335 三位室友的支持\n感谢各位提供反馈的 NJUers\n谨以此 APP 敬我的大学时光", "easter_egg": "感谢小百合工作室\n感谢 @ns @lgt @FengChendian 协助开发\n感谢 @ovoclover 制作图标\n感谢 @无忌 @子枨 提供配色方案\n特别感谢 1A335 三位室友的支持\n感谢各位提供反馈的 NJUers\n谨以此 APP 敬我的大学时光", "love_and_donate": "完美导入!投喂傻翠w", "bug_and_report": "似乎有bug,我要反馈", diff --git a/lib/l10n/intl_zh_CN.arb b/lib/l10n/intl_zh_CN.arb index 4c3f9de..4bb775f 100644 --- a/lib/l10n/intl_zh_CN.arb +++ b/lib/l10n/intl_zh_CN.arb @@ -176,7 +176,7 @@ "developer": "开发者 idealclover", "introduction": "博客:https://idealclover.top\nEmail:idealclover@163.com", "open_source_library_title": "所使用到的开源库", - "open_source_library_content": "shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0", + "open_source_library_content": "shared_preferences: ^2.0.7\nflutter_swiper_null_safety: ^1.0.2\nscoped_model: ^2.0.0-nullsafety.0\nazlistview: ^2.0.0-nullsafety.0\nwebview_flutter: ^2.0.13\nflutter_linkify: ^5.0.2\nimage_picker: ^0.8.4\npackage_info: ^2.0.2\npath_provider: ^2.0.3\nurl_launcher: ^6.0.10\nflutter_html: ^2.1.3\nfluttertoast: ^8.0.1\nsqflite: ^2.0.0+4\nhtml: ^0.15.0\ndio: ^4.0.0\nhome_widget: ^0.1.5\nworkmanager: ^0.4.1", "easter_egg": "感谢小百合工作室\n感谢 @ns @lgt @FengChendian 协助开发\n感谢 @ovoclover 制作图标\n感谢 @无忌 @子枨 提供配色方案\n特别感谢 1A335 三位室友的支持\n感谢各位提供反馈的 NJUers\n谨以此 APP 敬我的大学时光", "love_and_donate": "完美导入!投喂傻翠w", "bug_and_report": "似乎有bug,我要反馈", diff --git a/lib/main.dart b/lib/main.dart index aeac76d..1d3146d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,9 @@ import 'dart:io'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; - +import 'package:workmanager/workmanager.dart'; +import 'Utils/HomeWidgetUtil.dart'; import 'generated/l10n.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:umeng_common_sdk/umeng_common_sdk.dart'; @@ -15,7 +17,15 @@ import 'Resources/Constant.dart'; import 'Utils/States/MainState.dart'; import 'Utils/InitUtil.dart'; +void callbackDispatcher() { + Workmanager().executeTask((taskName, inputData) async { + return await HomeWidgetUtil().updateWidget(); + }); +} + void main() async { + bool isInDebugMode = true; + WidgetsFlutterBinding.ensureInitialized(); //Initialize the app config. List themeConf = await InitUtil.initialize(); @@ -24,11 +34,19 @@ void main() async { '5f8ef217fac90f1c19a7b0f3', '5f9e1efa1c520d30739d2737', 'Umeng'); UmengCommonSdk.setPageCollectionModeAuto(); // UmengCommonSdk.onEvent("privacy_accept", {"result":"accept"}); + Workmanager().initialize( + callbackDispatcher, // The top level function, aka callbackDispatcher + isInDebugMode: isInDebugMode & + kDebugMode // If enabled it will post a notification whenever the task is running. Handy for debugging tasks + ); - /// 原生安卓上去除状态栏遮罩 if (Platform.isAndroid) { + /// 原生安卓上去除状态栏遮罩 SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle(statusBarColor: Colors.transparent)); + Workmanager().registerPeriodicTask("1", "simplePeriodicTask", + frequency: const Duration(minutes: 15)); + Workmanager().registerOneOffTask("2", "simpleTask"); } runApp( MyApp(themeConf[0], Constant.themeModeList[themeConf[1]], themeConf[2])); diff --git a/pubspec.lock b/pubspec.lock index d34af40..08f416e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -196,6 +196,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "8.0.8" + home_widget: + dependency: "direct main" + description: + name: home_widget + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.5" html: dependency: "direct main" description: @@ -796,6 +803,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.4.1" + workmanager: + dependency: "direct main" + description: + name: workmanager + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.4.1" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b853123..7883410 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: flutter_localizations: sdk: flutter - shared_preferences: ^2.0.7 + shared_preferences: 2.0.7 # Android iOS Linux macOS web Windows flutter_swiper_null_safety: ^1.0.2 # Android iOS Linux macOS web Windows @@ -64,6 +64,10 @@ dependencies: # Android iOS Linux macOS web Windows dio: ^4.0.0 # Android iOS Linux macOS web Windows + home_widget: ^0.1.5 + # Android iOS + workmanager: ^0.4.1 + # Android iOS dev_dependencies: flutter_lints: ^1.0.4