265 lines
7.5 KiB
Dart
265 lines
7.5 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:rasadyar_app/data/model/app_info_model.dart';
|
|
import 'package:rasadyar_app/infrastructure/utils/local_storage_utils.dart';
|
|
import 'package:rasadyar_core/core.dart';
|
|
|
|
class SplashLogic extends GetxController with GetTickerProviderStateMixin {
|
|
late final AnimationController scaleController;
|
|
late final AnimationController rotateController;
|
|
Rxn<Animation<double>> scaleAnimation = Rxn();
|
|
Rxn<Animation<double>> rotationAnimation = Rxn();
|
|
RxBool hasUpdated = false.obs;
|
|
RxBool onUpdateDownload = false.obs;
|
|
RxDouble percent = 0.0.obs;
|
|
RxString strVersion = ''.obs;
|
|
final RxnString _updateFilePath = RxnString();
|
|
final platform = MethodChannel('apk_installer');
|
|
final Dio _dio = Dio();
|
|
var gService = Get.find<GService>();
|
|
var tokenService = Get.find<TokenStorageService>();
|
|
|
|
AppInfoModel? appInfoModel;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
scaleController = AnimationController(
|
|
vsync: this,
|
|
duration: const Duration(milliseconds: 1500),
|
|
);
|
|
|
|
rotateController = AnimationController(
|
|
vsync: this,
|
|
duration: const Duration(milliseconds: 8000),
|
|
);
|
|
|
|
scaleAnimation.value = Tween<double>(
|
|
begin: 0.8,
|
|
end: 1.2,
|
|
).animate(scaleController);
|
|
|
|
rotationAnimation.value = Tween<double>(
|
|
begin: 0.0,
|
|
end: 1,
|
|
).animate(rotateController);
|
|
|
|
rotateController.forward();
|
|
rotateController.addStatusListener((status) {
|
|
if (status == AnimationStatus.completed) {
|
|
rotateController.repeat();
|
|
} else if (status == AnimationStatus.dismissed) {
|
|
rotateController.forward();
|
|
}
|
|
});
|
|
|
|
scaleController.forward();
|
|
scaleController.addStatusListener((status) {
|
|
if (status == AnimationStatus.completed) {
|
|
scaleController.reverse();
|
|
} else if (status == AnimationStatus.dismissed) {
|
|
scaleController.forward();
|
|
}
|
|
});
|
|
|
|
hasUpdated.listen((data) {
|
|
if (data) {
|
|
requiredUpdateDialog(
|
|
onConfirm: () async {
|
|
await fileDownload();
|
|
},
|
|
changes: appInfoModel?.info?.changes,
|
|
);
|
|
} else if (!data && Get.isDialogOpen == true) {
|
|
Get.back();
|
|
}
|
|
});
|
|
onUpdateDownload.listen((data) {
|
|
hasUpdated.value = false;
|
|
if (data) {
|
|
Get.bottomSheet(
|
|
isDismissible: false,
|
|
isScrollControlled: true,
|
|
backgroundColor: Colors.transparent,
|
|
Container(
|
|
height: 170,
|
|
decoration: const BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.vertical(top: Radius.circular(16.0)),
|
|
),
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
spacing: 8,
|
|
children: [
|
|
const Text('در حال دانلود بروزرسانی برنامه...'),
|
|
Obx(
|
|
() => Row(
|
|
spacing: 8,
|
|
children: [
|
|
Expanded(
|
|
child: LinearProgressIndicator(
|
|
value: percent.value,
|
|
color: AppColor.greenNormal,
|
|
minHeight: 4,
|
|
),
|
|
),
|
|
SizedBox(
|
|
width: 55.w,
|
|
child: Text(
|
|
'${(percent.value * 100).toStringAsFixed(2)}%',
|
|
textAlign: TextAlign.center,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
Row(
|
|
spacing: 8,
|
|
children: [
|
|
Expanded(
|
|
child: ObxValue((data) {
|
|
return RElevated(
|
|
backgroundColor: AppColor.greenNormal,
|
|
height: 40.h,
|
|
onPressed: data.value != null
|
|
? () {
|
|
installApk();
|
|
Get.back();
|
|
}
|
|
: null,
|
|
text: 'نصب',
|
|
);
|
|
}, _updateFilePath),
|
|
),
|
|
Expanded(
|
|
child: ROutlinedElevated(
|
|
borderColor: AppColor.error,
|
|
text: 'خروج',
|
|
onPressed: () async {
|
|
exit(0);
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
void onReady() {
|
|
super.onReady();
|
|
|
|
Future.delayed(const Duration(milliseconds: 250), () async {
|
|
try {
|
|
final isUpdateNeeded = await checkVersion();
|
|
if (isUpdateNeeded) return;
|
|
|
|
final module = gService.getSelectedModule();
|
|
final target = gService.getTargetPage(module);
|
|
if (module != null) {
|
|
tokenService.setGlobalTokenAndRefToken(module);
|
|
}
|
|
|
|
if (target != null) {
|
|
var mFuns = getFunctionsList(target.functions);
|
|
await Future.wait(mFuns ?? []);
|
|
Get.offAndToNamed(target.route!);
|
|
}
|
|
} catch (e, st) {
|
|
eLog("onReady error: $e\n$st");
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
rotateController.dispose();
|
|
scaleController.dispose();
|
|
super.onClose();
|
|
}
|
|
|
|
Future<bool> checkVersion() async {
|
|
try {
|
|
final info = await PackageInfo.fromPlatform();
|
|
strVersion.value = info.version;
|
|
int version = strVersion.value.versionNumber;
|
|
|
|
var res = await _dio.get(
|
|
"https://rsibackend.rasadyar.com/app/rasadyar-app-info/",
|
|
);
|
|
|
|
appInfoModel = AppInfoModel.fromJson(res.data);
|
|
|
|
if ((appInfoModel?.info?.version?.versionNumber ?? 0) > version) {
|
|
hasUpdated.value = !hasUpdated.value;
|
|
return true;
|
|
}
|
|
return false;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Future<void> fileDownload() async {
|
|
onUpdateDownload.value = true;
|
|
final dir = await getApplicationDocumentsDirectory();
|
|
final filePath = "${dir.path}/rasadyar.apk";
|
|
final file = File(filePath);
|
|
if (await file.exists()) {
|
|
await file.delete();
|
|
}
|
|
int attempts = 0;
|
|
int retryCount = 4;
|
|
bool success = false;
|
|
|
|
while (attempts < retryCount && !success) {
|
|
try {
|
|
await _dio.download(
|
|
appInfoModel?.file ?? '',
|
|
filePath,
|
|
onReceiveProgress: (count, total) {
|
|
if (total != -1 && total > 0) {
|
|
percent.value = count / total;
|
|
}
|
|
},
|
|
);
|
|
success = true;
|
|
} on DioException catch (e) {
|
|
attempts++;
|
|
percent.value = 0.0;
|
|
if (attempts >= retryCount) {
|
|
eLog("Download failed after $attempts attempts: ${e.message}");
|
|
} else {
|
|
await Future.delayed(const Duration(milliseconds: 1200));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (success) {
|
|
_updateFilePath.value = filePath;
|
|
}
|
|
|
|
onUpdateDownload.value = false;
|
|
}
|
|
|
|
Future<void> installApk() async {
|
|
try {
|
|
eLog(_updateFilePath.value);
|
|
await platform.invokeMethod('apk_installer', {
|
|
'appPath': _updateFilePath.value,
|
|
});
|
|
} catch (e) {
|
|
eLog(e);
|
|
}
|
|
}
|
|
}
|