From 1f0ff2353c49ebe13482b2f8926338b088397568 Mon Sep 17 00:00:00 2001 From: toly <1981462002@qq.com> Date: Tue, 20 Jul 2021 08:14:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BA=94=E7=94=A8=E5=86=85=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/src/main/AndroidManifest.xml | 1 + lib/app/api/app_info.dart | 40 ++++ lib/app/res/path_unit.dart | 1 + lib/app/utils/Toast.dart | 16 ++ lib/app/utils/convert.dart | 14 ++ lib/painter_system/particle/out/clock_fx.dart | 197 ++++++++++++++++++ .../particle/out/clock_widget.dart | 88 ++++++++ lib/painter_system/particle/out/particle.dart | 40 ++++ lib/painter_system/particle/out/rnd.dart | 48 +++++ .../about/version/app_version_checker.dart | 166 +++++++++++++++ .../pages/about/version/version_shower.dart | 32 +++ lib/views/pages/about/version_info.dart | 19 +- lib/views/pages/widget_home/toly_app_bar.dart | 4 +- pubspec.lock | 14 ++ pubspec.yaml | 3 +- 15 files changed, 669 insertions(+), 14 deletions(-) create mode 100644 lib/app/api/app_info.dart create mode 100644 lib/painter_system/particle/out/clock_fx.dart create mode 100644 lib/painter_system/particle/out/clock_widget.dart create mode 100644 lib/painter_system/particle/out/particle.dart create mode 100644 lib/painter_system/particle/out/rnd.dart create mode 100644 lib/views/pages/about/version/app_version_checker.dart create mode 100644 lib/views/pages/about/version/version_shower.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 66f7a92..1d5b54c 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -9,6 +9,7 @@ + > getAppVersion() async { + String errorMsg = ""; + var result = await HttpUtil.getInstance() + .client + .get(PathUnit.appInfo) + .catchError((err) { + errorMsg = err.toString(); + }); + + // 获取的数据非空且 status = true + if (result.data != null && result.data['status']) { + // 说明有数据 + if (result.data['data'] != null) { + return ResultBean.ok( + AppInfo( + appName: result.data['data']['appName'], + appVersion: result.data['data']['appVersion'], + appUrl: result.data['data']['appUrl'], + )); + } else { + return ResultBean.ok(null); + } + } + return ResultBean.error('请求错误: $errorMsg'); + } +} + +class AppInfo{ + final String appName; + final String appVersion; + final String appUrl; + + AppInfo({this.appName, this.appVersion, this.appUrl}); +} \ No newline at end of file diff --git a/lib/app/res/path_unit.dart b/lib/app/res/path_unit.dart index b28b691..75cdce2 100644 --- a/lib/app/res/path_unit.dart +++ b/lib/app/res/path_unit.dart @@ -12,6 +12,7 @@ class PathUnit{ static const categoryDataSync = '/categoryData/sync'; static const categoryData = '/categoryData'; + static const appInfo = '/appInfo/name/FlutterUnit'; static const login = '/login'; diff --git a/lib/app/utils/Toast.dart b/lib/app/utils/Toast.dart index f431d62..c353721 100644 --- a/lib/app/utils/Toast.dart +++ b/lib/app/utils/Toast.dart @@ -14,4 +14,20 @@ class Toast { backgroundColor: color??Theme.of(context).primaryColor, )); } + + static void error(BuildContext context,String msg){ + toast(context,msg, color:Colors.red, ); + } + + static void warning(BuildContext context,String msg){ + toast(context,msg, color:Colors.orange, ); + } + + static void success(BuildContext context,String msg){ + toast(context,msg, color:Theme.of(context).primaryColor, ); + } + + static void green(BuildContext context,String msg){ + toast(context,msg, color:Colors.green, ); + } } diff --git a/lib/app/utils/convert.dart b/lib/app/utils/convert.dart index ebf939c..2bfff69 100644 --- a/lib/app/utils/convert.dart +++ b/lib/app/utils/convert.dart @@ -34,4 +34,18 @@ class Convert { GalleryType.anim: "动画手势", GalleryType.art: "艺术画廊", }; + + static String convertFileSize(int size){ + if(size==null) return '0 kb'; + double result = size / 1024.0; + if(result<1024){ + return "${result.toStringAsFixed(2)}Kb"; + }else if(result>1024&&result<1024*1024){ + return "${(result/1024).toStringAsFixed(2)}Mb"; + }else{ + return "${(result/1024/1024).toStringAsFixed(2)}Gb"; + } + } + + } diff --git a/lib/painter_system/particle/out/clock_fx.dart b/lib/painter_system/particle/out/clock_fx.dart new file mode 100644 index 0000000..0a09c56 --- /dev/null +++ b/lib/painter_system/particle/out/clock_fx.dart @@ -0,0 +1,197 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'rnd.dart'; + +import 'particle.dart'; + + +final easingDelayDuration = Duration(seconds: 10); + +/// Probabilities of Hour, Minute, Noise. +// final particleDistributions = [2, 4, 100]; + +/// Number of "arms" to emit noise particles from center. +final int noiseAngles = 2000; + +/// Threshold for particles to go rouge. Lower = more particles. +final rougeDistributionLmt = 85; + +/// Threshold for particles to go jelly. Lower = more particles. +final jellyDistributionLmt = 97; + + +class ClockFx with ChangeNotifier { + + double width; //宽 + double height;//高 + double sizeMin; // 宽高最小值 + Offset center; //画布中心 + Rect spawnArea; // 粒子活动区域 + + List particles; // 所有粒子 + + int numParticles;// 最大粒子数 + + DateTime time; //时间 + + ClockFx({ + @required Size size, + @required DateTime time, + this.numParticles = 5000, + }) { + this.time = time; + particles = List.filled(numParticles, null); + setSize(size); + } + + void init() { + for (int i = 0; i < numParticles; i++) { + particles[i] = Particle(color:Colors.black ); + resetParticle(i); + } + } + + void setTime(DateTime time) { + this.time = time; + } + + void setSize(Size size) { + width = size.width; + height = size.height; + sizeMin = min(width, height); + center = Offset(width / 2, height / 2); + spawnArea = Rect.fromLTRB( + center.dx - sizeMin / 100, + center.dy - sizeMin / 100, + center.dx + sizeMin / 100, + center.dy + sizeMin / 100, + ); + init(); + } + + /// Resets a particle's values. + Particle resetParticle(int i) { + Particle p = particles[i]; + p.size = p.a = p.vx = p.vy = p.life = p.lifeLeft = 0; + p.x = center.dx; + p.y = center.dy; + return p; + } + + void tick(Duration duration) { + updateParticles(duration); // 更新粒子 + notifyListeners();// 通知监听者(画板)更新 + } + + void updateParticles(Duration duration){ + var secFrac = DateTime.now().millisecond / 1000; + + var vecSpeed = duration.compareTo(easingDelayDuration) > 0 + ? max(.2, Curves.easeInOutSine.transform(1 - secFrac)) + : 1; + + var vecSpeedInv = Curves.easeInSine.transform(secFrac); + + var maxSpawnPerTick = 10; + + particles.asMap().forEach((i, p) { + p.x -= p.vx * vecSpeed; + p.y -= p.vy * vecSpeed; + + p.dist = _getDistanceFromCenter(p); + p.distFrac = p.dist / (sizeMin / 2); + + p.lifeLeft = p.life - p.distFrac; + + p.vx -= p.lifeLeft * p.vx * .001; + p.vy -= p.lifeLeft * p.vy * .001; + + if (p.lifeLeft < .3) { + p.size -= p.size * .0015; + } + + if (p.distribution > rougeDistributionLmt && p.distribution < jellyDistributionLmt) { + var r = Rnd.getDouble(.2, 2.5) * vecSpeedInv * p.distFrac; + p.x -= p.vx * r + (p.distFrac * Rnd.getDouble(-.4, .4)); + p.y -= p.vy * r + (p.distFrac * Rnd.getDouble(-.4, .4)); + } + + if (p.distribution >= jellyDistributionLmt) { + var r = Rnd.getDouble(.1, .9) * vecSpeedInv * (1 - p.lifeLeft); + p.x += p.vx * r; + p.y += p.vy * r; + } + + if (p.lifeLeft <= 0 || p.size <= .5) { + resetParticle(i); + if (maxSpawnPerTick > 0) { + _activateParticle(p); + maxSpawnPerTick--; + } + } + + }); + } + + void _activateParticle(Particle p) { + p.x = Rnd.getDouble(spawnArea.left, spawnArea.right); + p.y = Rnd.getDouble(spawnArea.top, spawnArea.bottom); + p.isFilled = Rnd.getBool(); + p.size = Rnd.getDouble(3, 8); + p.distFrac = 0; + p.distribution = Rnd.getInt(1, 2); + + double angle = Rnd.ratio * pi * 2; + + + var am = _getMinuteRadians(); + var ah = _getHourRadians() % (pi * 2); + var d = pi / 18; + // + // Probably not the most efficient solution right here. + do { + angle = Rnd.ratio * pi * 2; + } while (_isBetween(angle, am - d, am + d) || + _isBetween(angle, ah - d, ah + d) ); + + p.life = Rnd.getDouble(0.75, .8); + + p.size = sizeMin * + (Rnd.ratio > .8 + ? Rnd.getDouble(.0015, .003) + : Rnd.getDouble(.002, .006)); + + p.vx = sin(-angle); + p.vy = cos(-angle); + + p.a = atan2(p.vy, p.vx) + pi; + + double v = Rnd.getDouble(.5, 1); + + p.vx *= v; + p.vy *= v; + } + + double _getDistanceFromCenter(Particle p) { + var a = pow(center.dx - p.x, 2); + var b = pow(center.dy - p.y, 2); + return sqrt(a + b); + } + + /// Gets the radians of the hour hand. + double _getHourRadians() => + (time.hour * pi / 6) + + (time.minute * pi / (6 * 60)) + + (time.second * pi / (360 * 60)); + + /// Gets the radians of the minute hand. + double _getMinuteRadians() => + (time.minute * (2 * pi) / 60) + (time.second * pi / (30 * 60)); + + /// Checks if a value is between two other values. + bool _isBetween(double value, double min, double max) { + return value >= min && value <= max; + } + +} diff --git a/lib/painter_system/particle/out/clock_widget.dart b/lib/painter_system/particle/out/clock_widget.dart new file mode 100644 index 0000000..6cd5039 --- /dev/null +++ b/lib/painter_system/particle/out/clock_widget.dart @@ -0,0 +1,88 @@ +import 'dart:math'; +import 'dart:ui'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; + +import 'clock_fx.dart'; + +/// create by 张风捷特烈 on 2021/2/7 +/// contact me by email 1981462002@qq.com +/// 说明: + +class ClockWidget extends StatefulWidget { + final double radius; + + const ClockWidget({Key key, this.radius = 100}) : super(key: key); + + @override + _ClockWidgetState createState() => _ClockWidgetState(); +} + +class _ClockWidgetState extends State + with SingleTickerProviderStateMixin { + Ticker _ticker; + ClockFx _fx; + + @override + void initState() { + super.initState(); + _ticker = createTicker(_tick)..start(); + _fx = ClockFx( + size: Size(widget.radius * 2, widget.radius * 2), + time: DateTime.now(), + ); + } + + @override + void dispose() { + _ticker.dispose(); + _fx.dispose(); + super.dispose(); + } + + void _tick(Duration duration) { + _fx.tick(duration); + if (_fx.time.second != DateTime.now().second) { + _fx.setTime(DateTime.now()); + } + } + + @override + Widget build(BuildContext context) { + return CustomPaint( + size: Size(widget.radius * 2, widget.radius * 2), + painter: ClockFxPainter(fx: _fx), + ); + } +} + +/// Alpha value for noise particles. +const double noiseAlpha = 160; + +class ClockFxPainter extends CustomPainter { + final ClockFx fx; + + ClockFxPainter({@required this.fx}) : super(repaint: fx); + + @override + void paint(Canvas canvas, Size size) { + fx.particles.forEach((p) { + double a; + a = max(0.0, (p.distFrac - .13) / p.distFrac) * 255; + a = min(a, min(noiseAlpha, p.lifeLeft * 3 * 255)); + int alpha = a.floor(); + + Paint circlePaint = Paint() + ..style = PaintingStyle.fill + ..color = p.color.withAlpha(alpha); + + canvas.drawCircle(Offset(p.x, p.y), p.size, circlePaint); + }); + } + + @override + bool shouldRepaint(covariant ClockFxPainter oldDelegate) => + oldDelegate.fx != fx; +} diff --git a/lib/painter_system/particle/out/particle.dart b/lib/painter_system/particle/out/particle.dart new file mode 100644 index 0000000..e106040 --- /dev/null +++ b/lib/painter_system/particle/out/particle.dart @@ -0,0 +1,40 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +class Particle { + + double x; // x 坐标 + double y; // y 坐标 + double vx; // x 速度 + double vy; // y 速度 + double a; // 发射弧度 + double dist; // 距离画布中心的长度 + double distFrac;// 距离画布中心的百分比 + double size;// 粒子大小 + double life; // 粒子寿命 + double lifeLeft; // 粒子剩余寿命 + bool isFilled; // 是否填充 + Color color; // 颜色 + int distribution; // 分配情况 + + + Particle({ + this.x = 0, + this.y = 0, + this.a = 0, + this.vx = 0, + this.vy = 0, + this.dist = 0, + this.distFrac = 0, + this.size = 0, + this.life = 0, + this.lifeLeft = 0, + this.isFilled = false, + this.color = Colors.blueAccent, + this.distribution = 0, + }); +} + + diff --git a/lib/painter_system/particle/out/rnd.dart b/lib/painter_system/particle/out/rnd.dart new file mode 100644 index 0000000..ede4b0c --- /dev/null +++ b/lib/painter_system/particle/out/rnd.dart @@ -0,0 +1,48 @@ +import 'dart:math'; + + +class Rnd { + static int _seed = DateTime.now().millisecondsSinceEpoch; + static Random random = Random(_seed); + + static set seed(int val) => random = Random(_seed = val); + static int get seed => _seed; + + /// Gets the next double. + static get ratio => random.nextDouble(); + + /// Gets a random int between [min] and [max]. + static int getInt(int min, int max) { + return min + random.nextInt(max - min); + } + + /// Gets a random double between [min] and [max]. + static double getDouble(double min, double max) { + return min + random.nextDouble() * (max - min); + } + + /// Gets a random boolean with chance [chance]. + static bool getBool([double chance = 0.5]) { + return random.nextDouble() < chance; + } + + /// Randomize the positions of items in a list. + static List shuffle(List list) { + for (int i = 0, l = list.length; i < l; i++) { + int j = random.nextInt(l); + if (j == i) { + continue; + } + dynamic item = list[j]; + list[j] = list[i]; + list[i] = item; + } + return list; + } + + /// Randomly selects an item from a list. + static dynamic getItem(List list) { + return list[random.nextInt(list.length)]; + } + +} diff --git a/lib/views/pages/about/version/app_version_checker.dart b/lib/views/pages/about/version/app_version_checker.dart new file mode 100644 index 0000000..fb62260 --- /dev/null +++ b/lib/views/pages/about/version/app_version_checker.dart @@ -0,0 +1,166 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/api/app_info.dart'; +import 'package:flutter_unit/app/utils/Toast.dart'; +import 'package:flutter_unit/app/utils/convert.dart'; +import 'package:flutter_unit/app/utils/http_utils/http_util.dart'; +import 'package:flutter_unit/app/utils/http_utils/result_bean.dart'; +import 'package:install_plugin/install_plugin.dart'; +import 'package:package_info/package_info.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart'; + +class AppVersionChecker extends StatefulWidget { + const AppVersionChecker({Key key}) : super(key: key); + + @override + _AppVersionCheckerState createState() => _AppVersionCheckerState(); +} + +enum VersionState { none, loading, shouldUpdate, downloading } + +class _AppVersionCheckerState extends State { + final TextStyle labelStyle = TextStyle(fontSize: 13); + String oldVersion = ''; + String newVersion = ''; + int totalSize =0; + String url = 'http://toly1994.com/file/FlutterUnit.apk'; + ValueNotifier versionState = + ValueNotifier(VersionState.none); + + ValueNotifier progress = ValueNotifier(0); + + _doDownload() async { + Directory dir = await getExternalStorageDirectory(); + String dstPath = path.join(dir.path, 'FlutterUnit.apk'); + + if(File(dstPath).existsSync()){ + InstallPlugin.installApk(dstPath, 'com.toly1994.flutter_unit'); + return; + } + + versionState.value = VersionState.downloading; + + await HttpUtil.getInstance().client.download(url, dstPath, + onReceiveProgress: _onReceiveProgress, + options: Options(receiveTimeout: 24 * 60 * 60 * 1000)); + versionState.value = VersionState.none; + InstallPlugin.installApk(dstPath, 'com.toly1994.flutter_unit'); + } + + void _onReceiveProgress(int count, int total) { + totalSize = total; + progress.value = count / total; + } + + @override + Widget build(BuildContext context) { + return ListTile( + title: Text('检查新版本', style: labelStyle), + trailing: ValueListenableBuilder( + valueListenable: versionState, + builder: _buildTrailByState, + ), + onTap: () async { + if (versionState.value == VersionState.shouldUpdate && + Platform.isAndroid) { + _doDownload(); + return; + } + + if (versionState.value == VersionState.downloading) { + return; + } + + versionState.value = VersionState.loading; + ResultBean result = await AppInfoApi.getAppVersion(); + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + + if (result.status) { + print('${result.data.appName}:${result.data.appVersion}'); + if (packageInfo.version == result.data.appVersion) { + Toast.success(context, '当前应用已是最新版本!'); + versionState.value = VersionState.none; + } else { + oldVersion = packageInfo.version; + newVersion = result.data.appVersion; + Toast.green(context, '检测到新版本【${result.data.appVersion}】,可点击更新!'); + versionState.value = VersionState.shouldUpdate; + } + } else { + print('${result.msg}'); + versionState.value = VersionState.none; + } + }, + ); + } + + Widget _buildTrailByState( + BuildContext context, VersionState value, Widget child) { + switch (value) { + case VersionState.none: + return const SizedBox(); + case VersionState.loading: + return const CupertinoActivityIndicator(); + case VersionState.shouldUpdate: + return Wrap( + alignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Text( + '$oldVersion --> $newVersion ', + style: TextStyle(height: 1, fontSize: 12, color: Colors.grey), + ), + const SizedBox( + width: 5, + ), + const Icon( + Icons.update, + color: Colors.green, + ) + ]); + case VersionState.downloading: + return ValueListenableBuilder( + valueListenable: progress, builder: _buildProgress); + } + return const SizedBox(); + } + + Widget _buildProgress(BuildContext context, double value, Widget child) { + return Wrap( + alignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + Column( + children: [ + Text( + '${(value * 100).toStringAsFixed(2)} %', + style: TextStyle(height: 1, fontSize: 12, color: Colors.grey), + ), + const SizedBox( + height: 5, + ), + Text( + '${Convert.convertFileSize((totalSize * value).floor())}/${Convert.convertFileSize(totalSize)}', + style: TextStyle(height: 1, fontSize: 10, color: Colors.grey), + ), + ], + ), + const SizedBox( + width: 15, + ), + SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + backgroundColor: Colors.grey, + value: value, + ), + ) + ]); + } +} diff --git a/lib/views/pages/about/version/version_shower.dart b/lib/views/pages/about/version/version_shower.dart new file mode 100644 index 0000000..2a81a6d --- /dev/null +++ b/lib/views/pages/about/version/version_shower.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'package:package_info/package_info.dart'; + +class VersionShower extends StatefulWidget { + const VersionShower({Key key}) : super(key: key); + + @override + _VersionShowerState createState() => _VersionShowerState(); +} + +class _VersionShowerState extends State { + String version = '1.0.0'; + + @override + void initState() { + super.initState(); + _fetchVersion(); + } + + @override + Widget build(BuildContext context) { + return Text('Version $version'); + } + + void _fetchVersion() async{ + PackageInfo packageInfo = await PackageInfo.fromPlatform(); + if(mounted) + setState(() { + version= packageInfo.version; + }); + } +} diff --git a/lib/views/pages/about/version_info.dart b/lib/views/pages/about/version_info.dart index 5bb905d..552a6ce 100644 --- a/lib/views/pages/about/version_info.dart +++ b/lib/views/pages/about/version_info.dart @@ -1,12 +1,17 @@ import 'package:flutter/material.dart'; +import 'package:flutter_unit/app/api/app_info.dart'; import 'package:flutter_unit/app/res/str_unit.dart'; -import 'package:flutter_unit/app/router/unit_router.dart'; import 'package:flutter_unit/app/res/style/behavior/no_scroll_behavior.dart'; +import 'package:flutter_unit/app/router/unit_router.dart'; +import 'package:flutter_unit/app/utils/http_utils/result_bean.dart'; import 'package:flutter_unit/views/components/permanent/circle_image.dart'; import 'package:flutter_unit/views/components/permanent/feedback_widget.dart'; import 'package:url_launcher/url_launcher.dart'; +import 'version/app_version_checker.dart'; +import 'version/version_shower.dart'; + /// create by 张风捷特烈 on 2020/6/16 /// contact me by email 1981462002@qq.com /// 说明: @@ -54,13 +59,11 @@ class VersionInfo extends StatelessWidget { children: [ CircleImage(image: AssetImage("assets/images/icon_head.webp"),size: 80,), Text('Flutter Unit',style: TextStyle(fontSize: 20,fontWeight: FontWeight.bold),), - Text('Version ${StrUnit.version}'), + const VersionShower(), ], ); } - - Widget _buildCenter(BuildContext context) { final labelStyle= TextStyle(fontSize: 13); return Padding( @@ -77,13 +80,7 @@ class VersionInfo extends StatelessWidget { onTap: () => Navigator.of(context).pushNamed(UnitRouter.about_app), ), Divider(height: 1,indent: 10), - ListTile( - title: Text('检查新版本',style: labelStyle), - trailing: _nextIcon(context), - onTap: () { - - }, - ), + const AppVersionChecker(), Divider(height: 1,indent: 10), ListTile( title: Text('检查数据库新版本',style: labelStyle), diff --git a/lib/views/pages/widget_home/toly_app_bar.dart b/lib/views/pages/widget_home/toly_app_bar.dart index fc13079..0c5f8ed 100644 --- a/lib/views/pages/widget_home/toly_app_bar.dart +++ b/lib/views/pages/widget_home/toly_app_bar.dart @@ -19,8 +19,8 @@ const BorderRadius _kBorderRadius = BorderRadius.only( bottomRight: Radius.circular(15), ); -const _kTabTextStyle = TextStyle(color: Colors.white, shadows: [ - const Shadow(color: Colors.black, offset: Offset(0.5, 0.5), blurRadius: 0.5) +const TextStyle _kTabTextStyle = TextStyle(color: Colors.white, shadows: [ + Shadow(color: Colors.black, offset: Offset(0.5, 0.5), blurRadius: 0.5) ]); class _TolyAppBarState extends State diff --git a/pubspec.lock b/pubspec.lock index 48332e0..4a26443 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -149,6 +149,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.1.4" + install_plugin: + dependency: "direct main" + description: + name: install_plugin + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" intl: dependency: "direct main" description: @@ -205,6 +212,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.0.0" + package_info: + dependency: "direct main" + description: + name: package_info + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.2" path: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d3d4041..6e42aa6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,11 +15,12 @@ dependencies: flutter_bloc: ^7.0.0 # 状态管理 equatable: ^2.0.0 # 相等辅助 - + package_info: ^2.0.2 # 应用包信息 sqflite: ^2.0.0+3 # 数据库 shared_preferences: ^2.0.5 # xml 固化 jwt_decoder: ^2.0.1 # jwt 解析 toggle_rotate: ^0.0.5 + install_plugin: ^2.0.1 flutter_star: ^0.1.2 # 星星组件 url_launcher: ^6.0.3 # url share: ^2.0.1 # 文字分享