view.dart 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. import 'dart:io';
  2. import 'package:clean/base/base_page.dart';
  3. import 'package:clean/module/contact/backup/controller.dart';
  4. import 'package:clean/resource/assets.gen.dart';
  5. import 'package:clean/utils/expand.dart';
  6. import 'package:clean/utils/file_utils.dart';
  7. import 'package:flutter/Material.dart';
  8. import 'package:flutter_screenutil/flutter_screenutil.dart';
  9. import 'package:get/get.dart';
  10. import 'package:get/get_state_manager/src/rx_flutter/rx_obx_widget.dart';
  11. class ContactBackUpPage extends BasePage<ContactBackUpController> {
  12. const ContactBackUpPage({super.key});
  13. @override
  14. bool immersive() {
  15. return true;
  16. }
  17. @override
  18. bool statusBarDarkFont() => false;
  19. @override
  20. Widget buildBody(BuildContext context) {
  21. controller.init();
  22. return Stack(
  23. children: [
  24. buildMain(context),
  25. IgnorePointer(
  26. child: Assets.images.bgHome.image(
  27. width: 360.w,
  28. ),
  29. ),
  30. ],
  31. );
  32. }
  33. Widget buildMain(BuildContext context) {
  34. return SafeArea(
  35. child: Container(
  36. padding: EdgeInsets.only(left: 16.w, top: 14.h, right: 16.w),
  37. child: Obx(() {
  38. return Column(
  39. mainAxisAlignment: MainAxisAlignment.start,
  40. crossAxisAlignment: CrossAxisAlignment.start,
  41. children: [
  42. !controller.isEdit.value
  43. ? Row(
  44. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  45. children: [
  46. GestureDetector(
  47. onTap: () {
  48. Get.back();
  49. },
  50. child: Assets.images.iconCommonBack
  51. .image(width: 28.w, height: 28.w),
  52. ),
  53. GestureDetector(
  54. onTap: () {
  55. controller.isEdit.value = true;
  56. },
  57. child: Container(
  58. width: 71.w,
  59. height: 30.h,
  60. decoration: BoxDecoration(
  61. color: "#1F2D3F".color,
  62. borderRadius: BorderRadius.all(
  63. Radius.circular(15.h),
  64. ),
  65. ),
  66. child: Center(
  67. child: Text(
  68. "Select",
  69. style: TextStyle(
  70. color: Colors.white,
  71. fontSize: 14.sp,
  72. ),
  73. ),
  74. ),
  75. ),
  76. ),
  77. ],
  78. )
  79. : Row(
  80. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  81. children: [
  82. GestureDetector(
  83. onTap: () {
  84. controller.isEdit.value = false;
  85. },
  86. child: Container(
  87. width: 71.w,
  88. height: 30.h,
  89. decoration: BoxDecoration(
  90. color: "#1F2D3F".color,
  91. borderRadius: BorderRadius.all(
  92. Radius.circular(15.h),
  93. ),
  94. ),
  95. child: Center(
  96. child: Text(
  97. "Cancel",
  98. style: TextStyle(
  99. color: Colors.white,
  100. fontSize: 14.sp,
  101. ),
  102. ),
  103. ),
  104. ),
  105. ),
  106. GestureDetector(
  107. onTap: () {
  108. // controller.toggleSelectAll();
  109. },
  110. child: Text(
  111. controller.isAllSelected.value
  112. ? "Deselect all"
  113. : "Select All",
  114. style: TextStyle(
  115. color: Colors.white.withOpacity(0.65),
  116. fontSize: 14.sp,
  117. ),
  118. ),
  119. ),
  120. ],
  121. ),
  122. SizedBox(
  123. height: 12.h,
  124. ),
  125. Row(
  126. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  127. children: [
  128. Text(
  129. "Backup",
  130. style: TextStyle(
  131. color: Colors.white,
  132. fontWeight: FontWeight.w700,
  133. fontSize: 24.sp,
  134. ),
  135. ),
  136. ],
  137. ),
  138. SizedBox(
  139. height: 26.h,
  140. ),
  141. Expanded(
  142. child: Obx(() {
  143. return ListView.builder(
  144. itemCount: controller.backupFilesMap.length,
  145. itemBuilder: (context, index) {
  146. final date =
  147. controller.backupFilesMap.keys.toList()[index];
  148. final files = controller.backupFilesMap[date]!;
  149. return Column(
  150. crossAxisAlignment: CrossAxisAlignment.start,
  151. children: [
  152. Text(
  153. date,
  154. style: TextStyle(
  155. color: Colors.white.withOpacity(0.7),
  156. fontSize: 14.sp,
  157. fontWeight: FontWeight.w500,
  158. ),
  159. ),
  160. SizedBox(
  161. height: 10.h,
  162. ),
  163. ...files.asMap().entries.map((entry) {
  164. final file = entry.value;
  165. final fileName = file.path
  166. .split('/')
  167. .last
  168. .split('_')
  169. .firstOrNull;
  170. final timestamp = file.path
  171. .split('/')
  172. .last
  173. .split('_')
  174. .last
  175. .split('.')
  176. .first;
  177. final dateTime =
  178. DateTime.fromMillisecondsSinceEpoch(
  179. int.parse(timestamp));
  180. final time = _formatTime(dateTime);
  181. // final size = _fileSize(file);
  182. return FutureBuilder(
  183. future: _fileSize(file),
  184. builder: (context, snapshot) {
  185. final size = snapshot.data ?? 0;
  186. return GestureDetector(
  187. onTap: () {
  188. controller.restoreContacts(file);
  189. },
  190. child: Container(
  191. margin: EdgeInsets.only(bottom: 10.h),
  192. height: 60.h,
  193. decoration: BoxDecoration(
  194. color: Colors.white.withOpacity(0.12),
  195. borderRadius: BorderRadius.all(
  196. Radius.circular(10.r)),
  197. ),
  198. child: Row(
  199. children: [
  200. SizedBox(
  201. width: 10.w,
  202. ),
  203. Assets.images.iconContactsFile
  204. .image(width: 28.w, height: 28.w),
  205. SizedBox(
  206. width: 9.w,
  207. ),
  208. Column(
  209. mainAxisAlignment:
  210. MainAxisAlignment.center,
  211. crossAxisAlignment:
  212. CrossAxisAlignment.start,
  213. children: [
  214. Text(
  215. fileName ?? "",
  216. style: TextStyle(
  217. color: Colors.white,
  218. fontSize: 14.sp,
  219. fontWeight: FontWeight.w500,
  220. ),
  221. ),
  222. Text(
  223. "$size | $time",
  224. style: TextStyle(
  225. color: Colors.white
  226. .withOpacity(0.8),
  227. fontSize: 12.sp,
  228. ),
  229. ),
  230. ],
  231. ),
  232. Spacer(),
  233. // 删除按钮
  234. Obx(() {
  235. return Visibility(
  236. visible: controller.isEdit.value,
  237. child: GestureDetector(
  238. onTap: () {
  239. controller
  240. .toggleSelectFile(file);
  241. // controller.toggleSelectContact(
  242. // contact);
  243. },
  244. child: Container(
  245. child: controller.selectedFiles
  246. .contains(file.path)
  247. ? Center(
  248. child: Assets
  249. .images.iconSelected
  250. .image(
  251. width: 16.w,
  252. height: 16.h,
  253. ),
  254. )
  255. : Center(
  256. child: Assets.images
  257. .iconUnselected
  258. .image(
  259. width: 16.w,
  260. height: 16.h,
  261. ),
  262. ),
  263. ),
  264. ),
  265. );
  266. }),
  267. SizedBox(width: 20.w,),
  268. ],
  269. ),
  270. ),
  271. );
  272. },
  273. );
  274. }),
  275. ],
  276. );
  277. },
  278. );
  279. }),
  280. ),
  281. controller.isEdit.value
  282. ? GestureDetector(
  283. onTap: () {
  284. controller.deleteBtnClick();
  285. },
  286. child: Container(
  287. width: 328.w,
  288. height: 48.h,
  289. decoration: BoxDecoration(
  290. color: "#0279FB".color,
  291. borderRadius: BorderRadius.all(
  292. Radius.circular(10.r),
  293. ),
  294. ),
  295. child: Center(
  296. child: Row(
  297. mainAxisAlignment: MainAxisAlignment.center,
  298. children: [
  299. Text(
  300. "Delete",
  301. style: TextStyle(
  302. color: Colors.white,
  303. fontSize: 16.sp,
  304. fontWeight: FontWeight.w500,
  305. ),
  306. ),
  307. ],
  308. ),
  309. ),
  310. ),
  311. )
  312. : GestureDetector(
  313. onTap: () {
  314. controller.backupContacts();
  315. },
  316. child: Container(
  317. width: 328.w,
  318. height: 48.h,
  319. decoration: BoxDecoration(
  320. color: "#0279FB".color,
  321. borderRadius: BorderRadius.all(
  322. Radius.circular(10.r),
  323. ),
  324. ),
  325. child: Center(
  326. child: Row(
  327. mainAxisAlignment: MainAxisAlignment.center,
  328. children: [
  329. Text(
  330. "Backup Now",
  331. style: TextStyle(
  332. color: Colors.white,
  333. fontSize: 16.sp,
  334. fontWeight: FontWeight.w500,
  335. ),
  336. ),
  337. ],
  338. ),
  339. ),
  340. ),
  341. ),
  342. ],
  343. );
  344. }),
  345. ),
  346. );
  347. }
  348. Future<String> _fileSize(File file) async {
  349. return _formatFileSize(await file.length());
  350. }
  351. // 格式化文件大小
  352. String _formatFileSize(int bytes) {
  353. if (bytes < 1024) {
  354. return '$bytes B';
  355. } else if (bytes < 1024 * 1024) {
  356. return '${(bytes / 1024).toStringAsFixed(1)} KB';
  357. } else {
  358. return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB';
  359. }
  360. }
  361. // 格式化时间为 "HH:mm"
  362. String _formatTime(DateTime dateTime) {
  363. return '${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}';
  364. }
  365. }