下载新版本

This commit is contained in:
GYJ 2024-12-10 16:58:37 +08:00
parent 36a0e183ff
commit 8cae1ffd7d
9 changed files with 424 additions and 5 deletions

View File

@ -1,8 +1,12 @@
import 'package:cashier_reserve/common/print/print.dart';
import 'package:cashier_reserve/common/push/push.dart';
import 'package:cashier_reserve/data_model/login/login_result.dart';
import 'package:cashier_reserve/login/login_view.dart';
import 'package:cashier_reserve/model/reserve_model.dart';
import 'package:cashier_reserve/model/version_model.dart';
import 'package:cashier_reserve/update_version/update_version_view.dart';
import 'package:easy_refresh/easy_refresh.dart';
import 'package:package_info_plus/package_info_plus.dart';
import '../base/ui.dart';
import '../channel/channel_event.dart';
@ -62,6 +66,36 @@ class AppManager {
YJPush.presentWidget(globalContext!, const LoginView());
}
static void checkAppVersion() async {
final res = await VersionModel.requestNewVersionInfo();
yjPrint(res);
if (res == null || res.version == null) {
return;
}
PackageInfo packageInfo = await PackageInfo.fromPlatform();
yjPrint("version == ${packageInfo.version}");
List<String> serverList = res.version!.split(".");
List<String> localList = packageInfo.version.split(".");
if (serverList.length != 3 || localList.length != 3) {
return;
}
int serverVersion = int.parse(serverList[0]) * 10000 + int.parse(serverList[1]) * 100 + int.parse(serverList[2]);
int localVersion = int.parse(localList[0]) * 10000 + int.parse(localList[1]) * 100 + int.parse(localList[2]);
if (serverVersion <= localVersion) {
return;
}
yjPrint("serverVersion == $serverVersion, localVersion == $localVersion");
YJPush.presentWidget(globalContext!, UpdateVersionView(versionModel: res,));
}
static void disposeLoginWidget() {
_isAlertLogin = false;
}

View File

@ -0,0 +1,128 @@
import 'dart:convert';
/// createdAt : 1712455187626
/// id : 19
/// isUp : 0
/// message : "需要更新"
/// sel : 1
/// source : "PC"
/// type : "android"
/// updatedAt : 1725353572331
/// url : "https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/version/1.4.20.exe"
/// version : "1.4.21"
UpdateVersionModel updateVersionModelFromJson(String str) =>
UpdateVersionModel.fromJson(json.decode(str));
String updateVersionModelToJson(UpdateVersionModel data) =>
json.encode(data.toJson());
class UpdateVersionModel {
UpdateVersionModel({
num? createdAt,
num? id,
num? isUp,
String? message,
num? sel,
String? source,
String? type,
num? updatedAt,
String? url,
String? version,
}) {
_createdAt = createdAt;
_id = id;
_isUp = isUp;
_message = message;
_sel = sel;
_source = source;
_type = type;
_updatedAt = updatedAt;
_url = url;
_version = version;
}
UpdateVersionModel.fromJson(dynamic json) {
_createdAt = json['createdAt'];
_id = json['id'];
_isUp = json['isUp'];
_message = json['message'];
_sel = json['sel'];
_source = json['source'];
_type = json['type'];
_updatedAt = json['updatedAt'];
_url = json['url'];
_version = json['version'];
}
num? _createdAt;
num? _id;
num? _isUp;
String? _message;
num? _sel;
String? _source;
String? _type;
num? _updatedAt;
String? _url;
String? _version;
UpdateVersionModel copyWith({
num? createdAt,
num? id,
num? isUp,
String? message,
num? sel,
String? source,
String? type,
num? updatedAt,
String? url,
String? version,
}) =>
UpdateVersionModel(
createdAt: createdAt ?? _createdAt,
id: id ?? _id,
isUp: isUp ?? _isUp,
message: message ?? _message,
sel: sel ?? _sel,
source: source ?? _source,
type: type ?? _type,
updatedAt: updatedAt ?? _updatedAt,
url: url ?? _url,
version: version ?? _version,
);
num? get createdAt => _createdAt;
num? get id => _id;
num? get isUp => _isUp;
String? get message => _message;
num? get sel => _sel;
String? get source => _source;
String? get type => _type;
num? get updatedAt => _updatedAt;
String? get url => _url;
String? get version => _version;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['createdAt'] = _createdAt;
map['id'] = _id;
map['isUp'] = _isUp;
map['message'] = _message;
map['sel'] = _sel;
map['source'] = _source;
map['type'] = _type;
map['updatedAt'] = _updatedAt;
map['url'] = _url;
map['version'] = _version;
return map;
}
}

View File

@ -49,6 +49,8 @@ class HomeViewModel extends BaseUIModel {
Future.delayed(const Duration(milliseconds: 700), () {
_checkLogin();
_checkAppVersion();
});
EventManager.addListener<CallStatusChangeEvent>(this, (event) {
@ -88,6 +90,10 @@ class HomeViewModel extends BaseUIModel {
yjPrint("is login $flag");
}
_checkAppVersion() {
AppManager.checkAppVersion();
}
void setIndex(int index) {
if (_currentIndex == index) {
return;

View File

@ -7,10 +7,8 @@ import '../common/base/provider.dart';
class OrderView extends BaseUI {
@override
Widget buildBody(BuildContext context) {
return Container(
child: Center(
child: Text("Order"),
),
return const Center(
child: Text("Order"),
);
}

View File

@ -1,5 +1,4 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:cashier_reserve/common/encrypt/pwd.dart';
import 'package:cashier_reserve/common/manager/app_manager.dart';

View File

@ -0,0 +1,12 @@
import 'package:cashier_reserve/common/request/request_manager.dart';
import 'package:cashier_reserve/data_model/version/update_version_model.dart';
class VersionModel {
static Future<UpdateVersionModel?> requestNewVersionInfo() async {
final r = await RequestManager.get("/api/tbVersion/findBySource", params: {"source": "电话机"});
if (r is Map) {
return UpdateVersionModel.fromJson(r);
}
return null;
}
}

View File

@ -0,0 +1,217 @@
import 'package:cashier_reserve/common/print/print.dart';
import 'package:cashier_reserve/data_model/version/update_version_model.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:path_provider/path_provider.dart';
import 'package:percent_indicator/percent_indicator.dart';
class UpdateVersionView extends StatefulWidget {
final UpdateVersionModel versionModel;
const UpdateVersionView({super.key, required this.versionModel});
@override
State<StatefulWidget> createState() {
return _UpdateVersionViewState();
}
}
class _UpdateVersionViewState extends State<UpdateVersionView> {
DateTime? lastPopTime;
double progress = 0;
String progressText = "0%";
bool isDownload = false;
// CancelToken
CancelToken? _cancelToken;
@override
void dispose() {
_cancelToken?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return PopScope(
canPop: (widget.versionModel.isUp ?? 0) != 0,
onPopInvokedWithResult: (didPop, result) async {
//
if (lastPopTime == null ||
DateTime.now().difference(lastPopTime!) >
const Duration(seconds: 2)) {
lastPopTime = DateTime.now();
// Utils.toast('再按一次退出', context);
} else {
lastPopTime = DateTime.now();
// 退app
await SystemChannels.platform.invokeMethod('SystemNavigator.pop');
}
},
child: Scaffold(
backgroundColor: Colors.black.withOpacity(0.2),
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: const Color(0x55000000),
child: Center(
child: Container(
padding: const EdgeInsets.fromLTRB(30, 30, 30, 30),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
width: 400,
// height: 400,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
"发现新版本",
style:
TextStyle(fontSize: 22, color: Color(0xff333333)),
),
const SizedBox(
height: 20,
),
Text(
widget.versionModel.message ?? "",
style: const TextStyle(
fontSize: 16, color: Color(0xff666666)),
),
const SizedBox(
height: 20,
),
isDownload
? LinearPercentIndicator(
padding: EdgeInsets.zero,
animation: false,
lineHeight: 20.0,
// animationDuration: 2500,
percent: progress,
center: Text(progressText),
// linearStrokeCap: LinearStrokeCap.roundAll,
progressColor: Colors.green,
)
: Container(),
isDownload
? const SizedBox(
height: 20,
)
: Container(),
_buildActionViews(context),
],
),
),
),
),
),
),
),
);
}
Widget _buildActionViews(BuildContext context) {
bool isMustUpdate = widget.versionModel.isUp == 1;
return Row(mainAxisAlignment: MainAxisAlignment.center, children: [
isMustUpdate
? Container()
: ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
style: ButtonStyle(
backgroundColor: WidgetStateProperty.all(Colors.white),
foregroundColor:
WidgetStateProperty.all(const Color(0xff666666)),
minimumSize: WidgetStateProperty.all(const Size(100, 40)),
shape: WidgetStateProperty.all(const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
)),
),
child: const Text("跳过"),
),
isMustUpdate
? Container()
: const SizedBox(
width: 20,
),
ElevatedButton(
onPressed: () {
startDownload();
},
style: ButtonStyle(
backgroundColor: WidgetStateProperty.all(Colors.blue),
foregroundColor: WidgetStateProperty.all(Colors.white),
minimumSize:
WidgetStateProperty.all(Size(isMustUpdate ? 200 : 100, 40)),
shape: WidgetStateProperty.all(const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(20)),
)),
),
child: const Text("立即更新"),
),
]);
}
startDownload() async {
setState(() {
isDownload = true;
});
String fileUrl = widget.versionModel.url ?? "";
if (fileUrl.isEmpty) {
yjPrint("下载地址为空");
return;
}
_cancelToken?.cancel();
setState(() {
progress = 0.0;
progressText = "0.0%";
});
yjPrint("fileUrl: $fileUrl");
Dio dio = Dio();
try {
String savePath = await getPhoneLocalPath();
String appName = "file.apk";
_cancelToken = CancelToken(); // CancelToken对象
await dio.download(
fileUrl, "$savePath$appName", onReceiveProgress: (received, total) {
if (total != -1) {
///
double currentProgress = received / total;
setState(() {
progressText = "${(currentProgress * 100).toStringAsFixed(2)}%";
progress = double.parse(currentProgress.toStringAsFixed(2));
});
yjPrint(progress);
_cancelToken = null;
}
}, cancelToken: _cancelToken);
yjPrint("文件下载成功");
} catch (e) {
yjPrint("文件下载失败:$e");
}
}
Future<String> getPhoneLocalPath() async {
final directory = await getExternalStorageDirectory();
return directory?.path ?? '';
}
}

View File

@ -418,6 +418,22 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0"
package_info_plus:
dependency: "direct main"
description:
name: package_info_plus
sha256: da8d9ac8c4b1df253d1a328b7bf01ae77ef132833479ab40763334db13b91cce
url: "https://pub.flutter-io.cn"
source: hosted
version: "8.1.1"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
path:
dependency: transitive
description:
@ -783,6 +799,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
win32:
dependency: transitive
description:
name: win32
sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.9.0"
xdg_directories:
dependency: transitive
description:

View File

@ -50,6 +50,7 @@ dependencies:
pointycastle: ^3.9.1
url_launcher: ^6.3.1
easy_refresh: ^3.4.0
package_info_plus: ^8.1.1
dev_dependencies:
flutter_test: