|
|
@@ -1,8 +1,14 @@
|
|
|
+import 'dart:io';
|
|
|
+
|
|
|
import 'package:clean/base/base_page.dart';
|
|
|
import 'package:clean/module/contact/backup/controller.dart';
|
|
|
import 'package:clean/resource/assets.gen.dart';
|
|
|
+import 'package:clean/utils/expand.dart';
|
|
|
+import 'package:clean/utils/file_utils.dart';
|
|
|
import 'package:flutter/Material.dart';
|
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
|
+import 'package:get/get.dart';
|
|
|
+import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart';
|
|
|
|
|
|
class ContactBackUpPage extends BasePage<ContactBackUpController> {
|
|
|
const ContactBackUpPage({super.key});
|
|
|
@@ -17,9 +23,10 @@ class ContactBackUpPage extends BasePage<ContactBackUpController> {
|
|
|
|
|
|
@override
|
|
|
Widget buildBody(BuildContext context) {
|
|
|
+ controller.init();
|
|
|
return Stack(
|
|
|
children: [
|
|
|
- // buildMain(context),
|
|
|
+ buildMain(context),
|
|
|
IgnorePointer(
|
|
|
child: Assets.images.bgHome.image(
|
|
|
width: 360.w,
|
|
|
@@ -28,4 +35,340 @@ class ContactBackUpPage extends BasePage<ContactBackUpController> {
|
|
|
],
|
|
|
);
|
|
|
}
|
|
|
-}
|
|
|
+
|
|
|
+ Widget buildMain(BuildContext context) {
|
|
|
+ return SafeArea(
|
|
|
+ child: Container(
|
|
|
+ padding: EdgeInsets.only(left: 16.w, top: 14.h, right: 16.w),
|
|
|
+ child: Obx(() {
|
|
|
+ return Column(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.start,
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ !controller.isEdit.value
|
|
|
+ ? Row(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
+ children: [
|
|
|
+ GestureDetector(
|
|
|
+ onTap: () {
|
|
|
+ Get.back();
|
|
|
+ },
|
|
|
+ child: Assets.images.iconCommonBack
|
|
|
+ .image(width: 28.w, height: 28.w),
|
|
|
+ ),
|
|
|
+ GestureDetector(
|
|
|
+ onTap: () {
|
|
|
+ controller.isEdit.value = true;
|
|
|
+ },
|
|
|
+ child: Container(
|
|
|
+ width: 71.w,
|
|
|
+ height: 30.h,
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: "#1F2D3F".color,
|
|
|
+ borderRadius: BorderRadius.all(
|
|
|
+ Radius.circular(15.h),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: Center(
|
|
|
+ child: Text(
|
|
|
+ "Select",
|
|
|
+ style: TextStyle(
|
|
|
+ color: Colors.white,
|
|
|
+ fontSize: 14.sp,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ )
|
|
|
+ : Row(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
+ children: [
|
|
|
+ GestureDetector(
|
|
|
+ onTap: () {
|
|
|
+ controller.isEdit.value = false;
|
|
|
+ },
|
|
|
+ child: Container(
|
|
|
+ width: 71.w,
|
|
|
+ height: 30.h,
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: "#1F2D3F".color,
|
|
|
+ borderRadius: BorderRadius.all(
|
|
|
+ Radius.circular(15.h),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: Center(
|
|
|
+ child: Text(
|
|
|
+ "Cancel",
|
|
|
+ style: TextStyle(
|
|
|
+ color: Colors.white,
|
|
|
+ fontSize: 14.sp,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ GestureDetector(
|
|
|
+ onTap: () {
|
|
|
+ // controller.toggleSelectAll();
|
|
|
+ },
|
|
|
+ child: Text(
|
|
|
+ controller.isAllSelected.value
|
|
|
+ ? "Deselect all"
|
|
|
+ : "Select All",
|
|
|
+ style: TextStyle(
|
|
|
+ color: Colors.white.withOpacity(0.65),
|
|
|
+ fontSize: 14.sp,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ SizedBox(
|
|
|
+ height: 12.h,
|
|
|
+ ),
|
|
|
+ Row(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ "Backup",
|
|
|
+ style: TextStyle(
|
|
|
+ color: Colors.white,
|
|
|
+ fontWeight: FontWeight.w700,
|
|
|
+ fontSize: 24.sp,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ SizedBox(
|
|
|
+ height: 26.h,
|
|
|
+ ),
|
|
|
+ Expanded(
|
|
|
+ child: Obx(() {
|
|
|
+ return ListView.builder(
|
|
|
+ itemCount: controller.backupFilesMap.length,
|
|
|
+ itemBuilder: (context, index) {
|
|
|
+ final date =
|
|
|
+ controller.backupFilesMap.keys.toList()[index];
|
|
|
+ final files = controller.backupFilesMap[date]!;
|
|
|
+ return Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ date,
|
|
|
+ style: TextStyle(
|
|
|
+ color: Colors.white.withOpacity(0.7),
|
|
|
+ fontSize: 14.sp,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ SizedBox(
|
|
|
+ height: 10.h,
|
|
|
+ ),
|
|
|
+ ...files.asMap().entries.map((entry) {
|
|
|
+ final file = entry.value;
|
|
|
+ final fileName = file.path
|
|
|
+ .split('/')
|
|
|
+ .last
|
|
|
+ .split('_')
|
|
|
+ .firstOrNull;
|
|
|
+ final timestamp = file.path
|
|
|
+ .split('/')
|
|
|
+ .last
|
|
|
+ .split('_')
|
|
|
+ .last
|
|
|
+ .split('.')
|
|
|
+ .first;
|
|
|
+ final dateTime =
|
|
|
+ DateTime.fromMillisecondsSinceEpoch(
|
|
|
+ int.parse(timestamp));
|
|
|
+ final time = _formatTime(dateTime);
|
|
|
+ // final size = _fileSize(file);
|
|
|
+ return FutureBuilder(
|
|
|
+ future: _fileSize(file),
|
|
|
+ builder: (context, snapshot) {
|
|
|
+ final size = snapshot.data ?? 0;
|
|
|
+ return GestureDetector(
|
|
|
+ onTap: () {
|
|
|
+ controller.restoreContacts(file);
|
|
|
+ },
|
|
|
+ child: Container(
|
|
|
+ margin: EdgeInsets.only(bottom: 10.h),
|
|
|
+ height: 60.h,
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: Colors.white.withOpacity(0.12),
|
|
|
+ borderRadius: BorderRadius.all(
|
|
|
+ Radius.circular(10.r)),
|
|
|
+ ),
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ SizedBox(
|
|
|
+ width: 10.w,
|
|
|
+ ),
|
|
|
+ Assets.images.iconContactsFile
|
|
|
+ .image(width: 28.w, height: 28.w),
|
|
|
+ SizedBox(
|
|
|
+ width: 9.w,
|
|
|
+ ),
|
|
|
+ Column(
|
|
|
+ mainAxisAlignment:
|
|
|
+ MainAxisAlignment.center,
|
|
|
+ crossAxisAlignment:
|
|
|
+ CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ fileName ?? "",
|
|
|
+ style: TextStyle(
|
|
|
+ color: Colors.white,
|
|
|
+ fontSize: 14.sp,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ Text(
|
|
|
+ "$size | $time",
|
|
|
+ style: TextStyle(
|
|
|
+ color: Colors.white
|
|
|
+ .withOpacity(0.8),
|
|
|
+ fontSize: 12.sp,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ Spacer(),
|
|
|
+ // 删除按钮
|
|
|
+ Obx(() {
|
|
|
+ return Visibility(
|
|
|
+ visible: controller.isEdit.value,
|
|
|
+ child: GestureDetector(
|
|
|
+ onTap: () {
|
|
|
+ controller
|
|
|
+ .toggleSelectFile(file);
|
|
|
+ // controller.toggleSelectContact(
|
|
|
+ // contact);
|
|
|
+ },
|
|
|
+ child: Container(
|
|
|
+ child: controller.selectedFiles
|
|
|
+ .contains(file.path)
|
|
|
+ ? Center(
|
|
|
+ child: Assets
|
|
|
+ .images.iconSelected
|
|
|
+ .image(
|
|
|
+ width: 16.w,
|
|
|
+ height: 16.h,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ : Center(
|
|
|
+ child: Assets.images
|
|
|
+ .iconUnselected
|
|
|
+ .image(
|
|
|
+ width: 16.w,
|
|
|
+ height: 16.h,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }),
|
|
|
+ SizedBox(width: 20.w,),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ }),
|
|
|
+ ),
|
|
|
+ controller.isEdit.value
|
|
|
+ ? GestureDetector(
|
|
|
+ onTap: () {
|
|
|
+ controller.deleteBtnClick();
|
|
|
+ },
|
|
|
+ child: Container(
|
|
|
+ width: 328.w,
|
|
|
+ height: 48.h,
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: "#0279FB".color,
|
|
|
+ borderRadius: BorderRadius.all(
|
|
|
+ Radius.circular(10.r),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: Center(
|
|
|
+ child: Row(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.center,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ "Delete",
|
|
|
+ style: TextStyle(
|
|
|
+ color: Colors.white,
|
|
|
+ fontSize: 16.sp,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ : GestureDetector(
|
|
|
+ onTap: () {
|
|
|
+ controller.backupContacts();
|
|
|
+ },
|
|
|
+ child: Container(
|
|
|
+ width: 328.w,
|
|
|
+ height: 48.h,
|
|
|
+ decoration: BoxDecoration(
|
|
|
+ color: "#0279FB".color,
|
|
|
+ borderRadius: BorderRadius.all(
|
|
|
+ Radius.circular(10.r),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ child: Center(
|
|
|
+ child: Row(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.center,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ "Backup Now",
|
|
|
+ style: TextStyle(
|
|
|
+ color: Colors.white,
|
|
|
+ fontSize: 16.sp,
|
|
|
+ fontWeight: FontWeight.w500,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ }),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Future<String> _fileSize(File file) async {
|
|
|
+ return _formatFileSize(await file.length());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 格式化文件大小
|
|
|
+ String _formatFileSize(int bytes) {
|
|
|
+ if (bytes < 1024) {
|
|
|
+ return '$bytes B';
|
|
|
+ } else if (bytes < 1024 * 1024) {
|
|
|
+ return '${(bytes / 1024).toStringAsFixed(1)} KB';
|
|
|
+ } else {
|
|
|
+ return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 格式化时间为 "HH:mm"
|
|
|
+ String _formatTime(DateTime dateTime) {
|
|
|
+ return '${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
|
|
|
+ }
|
|
|
+}
|