file_info_dialog.dart 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. import "dart:io";
  2. import "package:exif/exif.dart";
  3. import "package:flutter/cupertino.dart";
  4. import "package:flutter/material.dart";
  5. import "package:photos/core/configuration.dart";
  6. import "package:photos/ente_theme_data.dart";
  7. import "package:photos/models/file.dart";
  8. import "package:photos/models/file_type.dart";
  9. import "package:photos/services/collections_service.dart";
  10. import "package:photos/ui/viewer/file/exif_info_dialog.dart";
  11. import "package:photos/utils/date_time_util.dart";
  12. import "package:photos/utils/exif_util.dart";
  13. import "package:photos/utils/file_util.dart";
  14. import "package:photos/utils/magic_util.dart";
  15. import "package:photos/utils/toast_util.dart";
  16. class FileInfoWidget extends StatefulWidget {
  17. final File file;
  18. const FileInfoWidget(
  19. this.file, {
  20. Key key,
  21. }) : super(key: key);
  22. @override
  23. State<FileInfoWidget> createState() => _FileInfoWidgetState();
  24. }
  25. class _FileInfoWidgetState extends State<FileInfoWidget> {
  26. Map<String, IfdTag> _exif;
  27. final Map<String, dynamic> _exifData = {
  28. "focalLength": null,
  29. "fNumber": null,
  30. "resolution": null,
  31. "takenOnDevice": null,
  32. "exposureTime": null,
  33. "ISO": null,
  34. "megaPixels": null
  35. };
  36. bool _isImage = false;
  37. Color infoColor;
  38. @override
  39. void initState() {
  40. debugPrint('file_info_dialog initState');
  41. _isImage = widget.file.fileType == FileType.image ||
  42. widget.file.fileType == FileType.livePhoto;
  43. if (_isImage) {
  44. getExif(widget.file).then((exif) {
  45. setState(() {
  46. _exif = exif;
  47. });
  48. });
  49. }
  50. super.initState();
  51. }
  52. @override
  53. Widget build(BuildContext context) {
  54. final file = widget.file;
  55. final dateTime = DateTime.fromMicrosecondsSinceEpoch(file.creationTime);
  56. final dateTimeForUpdationTime =
  57. DateTime.fromMicrosecondsSinceEpoch(file.updationTime);
  58. infoColor =
  59. Theme.of(context).colorScheme.onSurface.withOpacity(0.85); //remove
  60. if (_isImage && _exif != null) {
  61. // items.add(_getExifWidgets(_exif));
  62. print("_isImage");
  63. print(_isImage);
  64. _generateExifForDetails(_exif);
  65. }
  66. final bool showExifListTile = _exifData["focalLength"] != null ||
  67. _exifData["fNumber"] != null ||
  68. _exifData["takenOnDevice"] != null ||
  69. _exifData["exposureTime"] != null ||
  70. _exifData["ISO"] != null;
  71. var listTiles = <Widget>[
  72. ListTile(
  73. leading: const Padding(
  74. padding: EdgeInsets.only(top: 8, left: 6),
  75. child: Icon(Icons.calendar_today_rounded),
  76. ),
  77. title: Text(
  78. getFullDate(
  79. DateTime.fromMicrosecondsSinceEpoch(file.creationTime),
  80. ),
  81. ),
  82. subtitle: Text(
  83. getTimeIn12hrFormat(dateTime) + " " + dateTime.timeZoneName,
  84. style: Theme.of(context)
  85. .textTheme
  86. .bodyText2
  87. .copyWith(color: Colors.black.withOpacity(0.5)),
  88. ),
  89. trailing: (widget.file.ownerID == null ||
  90. widget.file.ownerID ==
  91. Configuration.instance.getUserID()) &&
  92. widget.file.uploadedFileID != null
  93. ? IconButton(
  94. onPressed: () {
  95. PopupMenuItem(
  96. value: 2,
  97. child: Row(
  98. children: [
  99. Icon(
  100. Platform.isAndroid
  101. ? Icons.access_time_rounded
  102. : CupertinoIcons.time,
  103. color: Theme.of(context).iconTheme.color,
  104. ),
  105. const Padding(
  106. padding: EdgeInsets.all(8),
  107. ),
  108. const Text("Edit time"),
  109. ],
  110. ),
  111. );
  112. },
  113. icon: const Icon(Icons.edit),
  114. )
  115. : const SizedBox.shrink(),
  116. ),
  117. const DividerWithPadding(),
  118. ListTile(
  119. leading: const Padding(
  120. padding: EdgeInsets.only(top: 8, left: 6),
  121. child: Icon(
  122. Icons.image,
  123. ),
  124. ),
  125. title: Text(
  126. file.getDisplayName(),
  127. ),
  128. subtitle: Row(
  129. children: [
  130. Padding(
  131. padding: const EdgeInsets.only(right: 10),
  132. child: _getFileSize(),
  133. ),
  134. file.localID != null && !_isImage
  135. ? _getVideoDuration()
  136. : const SizedBox.shrink(),
  137. ],
  138. ),
  139. trailing: file.uploadedFileID == null ||
  140. file.ownerID != Configuration.instance.getUserID()
  141. ? const SizedBox.shrink()
  142. : IconButton(
  143. onPressed: () async {
  144. await editFilename(context, file);
  145. setState(() {});
  146. },
  147. icon: const Icon(Icons.edit),
  148. ),
  149. ),
  150. const DividerWithPadding(),
  151. ListTile(
  152. leading: const Padding(
  153. padding: EdgeInsets.only(left: 6),
  154. child: Icon(Icons.folder_outlined),
  155. ),
  156. title: Text(
  157. file.deviceFolder ??
  158. CollectionsService.instance
  159. .getCollectionByID(file.collectionID)
  160. .name,
  161. ),
  162. ),
  163. const DividerWithPadding(),
  164. showExifListTile
  165. ? ListTile(
  166. leading: const Padding(
  167. padding: EdgeInsets.only(left: 6),
  168. child: Icon(Icons.camera_rounded),
  169. ),
  170. title: Text(_exifData["takenOnDevice"] ?? "--"),
  171. subtitle: Row(
  172. children: [
  173. _exifData["fNumber"] != null
  174. ? Padding(
  175. padding: const EdgeInsets.only(right: 10),
  176. child: Text('ƒ/' + _exifData["fNumber"].toString()),
  177. )
  178. : const SizedBox.shrink(),
  179. _exifData["exposureTime"] != null
  180. ? Padding(
  181. padding: const EdgeInsets.only(right: 10),
  182. child: Text(_exifData["exposureTime"]),
  183. )
  184. : const SizedBox.shrink(),
  185. _exifData["focalLength"] != null
  186. ? Padding(
  187. padding: const EdgeInsets.only(right: 10),
  188. child:
  189. Text(_exifData["focalLength"].toString() + "mm"),
  190. )
  191. : const SizedBox.shrink(),
  192. _exifData["ISO"] != null
  193. ? Padding(
  194. padding: const EdgeInsets.only(right: 10),
  195. child: Text("ISO" + _exifData["ISO"].toString()),
  196. )
  197. : const SizedBox.shrink(),
  198. ],
  199. ),
  200. )
  201. : const SizedBox.shrink(),
  202. showExifListTile ? const DividerWithPadding() : const SizedBox.shrink(),
  203. (file.uploadedFileID != null && file.updationTime != null)
  204. ? ListTile(
  205. leading: const Padding(
  206. padding: EdgeInsets.only(top: 8, left: 6),
  207. child: Icon(Icons.cloud_upload_outlined),
  208. ),
  209. title: Text(
  210. getFullDate(
  211. DateTime.fromMicrosecondsSinceEpoch(file.updationTime),
  212. ),
  213. ),
  214. subtitle: Text(
  215. getTimeIn12hrFormat(dateTimeForUpdationTime) +
  216. " " +
  217. dateTimeForUpdationTime.timeZoneName,
  218. style: Theme.of(context)
  219. .textTheme
  220. .bodyText2
  221. .copyWith(color: Colors.black.withOpacity(0.5)),
  222. ),
  223. )
  224. : const SizedBox.shrink(),
  225. ];
  226. var items = <Widget>[
  227. Row(
  228. children: [
  229. Icon(Icons.calendar_today_outlined, color: infoColor),
  230. const SizedBox(height: 8),
  231. Text(
  232. getFormattedTime(
  233. DateTime.fromMicrosecondsSinceEpoch(file.creationTime),
  234. ),
  235. style: TextStyle(color: infoColor),
  236. ),
  237. ],
  238. ),
  239. const SizedBox(height: 12),
  240. Row(
  241. children: [
  242. Icon(Icons.folder_outlined, color: infoColor),
  243. const Padding(padding: EdgeInsets.all(4)),
  244. Text(
  245. file.deviceFolder ??
  246. CollectionsService.instance
  247. .getCollectionByID(file.collectionID)
  248. .name,
  249. style: TextStyle(color: infoColor),
  250. ),
  251. ],
  252. ),
  253. const SizedBox(height: 12),
  254. ];
  255. items.addAll(
  256. [
  257. Row(
  258. children: [
  259. Icon(Icons.sd_storage_outlined, color: infoColor),
  260. const Padding(padding: EdgeInsets.all(4)),
  261. _getFileSize(),
  262. ],
  263. ),
  264. const SizedBox(height: 12),
  265. ],
  266. );
  267. if (file.localID != null && !_isImage) {
  268. //remove
  269. items.addAll(
  270. [
  271. Row(
  272. children: [
  273. Icon(Icons.timer_outlined, color: infoColor),
  274. const Padding(padding: EdgeInsets.all(4)),
  275. FutureBuilder(
  276. future: file.getAsset(),
  277. builder: (context, snapshot) {
  278. if (snapshot.hasData) {
  279. return Text(
  280. snapshot.data.videoDuration.toString().split(".")[0],
  281. style: TextStyle(color: infoColor),
  282. );
  283. } else {
  284. return Center(
  285. child: SizedBox.fromSize(
  286. size: const Size.square(24),
  287. child: const CupertinoActivityIndicator(
  288. radius: 8,
  289. ),
  290. ),
  291. );
  292. }
  293. },
  294. ),
  295. ],
  296. ),
  297. const SizedBox(height: 12),
  298. ],
  299. );
  300. }
  301. if (_isImage && _exif != null) {
  302. //remove
  303. // items.add(_getExifWidgets(_exif));
  304. _generateExifForDetails(_exif);
  305. }
  306. if (file.uploadedFileID != null && file.updationTime != null) {
  307. items.addAll(
  308. [
  309. Row(
  310. children: [
  311. Icon(Icons.cloud_upload_outlined, color: infoColor),
  312. const Padding(padding: EdgeInsets.all(4)),
  313. Text(
  314. getFormattedTime(
  315. DateTime.fromMicrosecondsSinceEpoch(file.updationTime),
  316. ),
  317. style: TextStyle(color: infoColor),
  318. ),
  319. ],
  320. ),
  321. ],
  322. );
  323. }
  324. items.add(
  325. const SizedBox(height: 12),
  326. );
  327. items.add(
  328. Row(
  329. mainAxisAlignment:
  330. _isImage ? MainAxisAlignment.spaceBetween : MainAxisAlignment.end,
  331. children: _getActions(),
  332. ),
  333. );
  334. Widget titleContent;
  335. if (file.uploadedFileID == null ||
  336. file.ownerID != Configuration.instance.getUserID()) {
  337. titleContent = Text(file.getDisplayName());
  338. } else {
  339. titleContent = InkWell(
  340. child: Row(
  341. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  342. children: [
  343. Flexible(
  344. child: Text(
  345. file.getDisplayName(),
  346. style: Theme.of(context).textTheme.headline5,
  347. ),
  348. ),
  349. const SizedBox(width: 16),
  350. Icon(Icons.edit, color: infoColor),
  351. ],
  352. ),
  353. onTap: () async {
  354. await editFilename(context, file);
  355. setState(() {});
  356. },
  357. );
  358. }
  359. // return AlertDialog(
  360. // title: titleContent,
  361. // content: SingleChildScrollView(
  362. // child: ListBody(
  363. // children: items,
  364. // ),
  365. // ),
  366. // );
  367. return Column(
  368. mainAxisSize: MainAxisSize.min,
  369. children: [
  370. Padding(
  371. padding: const EdgeInsets.all(10),
  372. child: Row(
  373. crossAxisAlignment: CrossAxisAlignment.center,
  374. children: [
  375. IconButton(
  376. onPressed: () {
  377. Navigator.pop(context);
  378. },
  379. icon: const Icon(
  380. Icons.close,
  381. ),
  382. ),
  383. const SizedBox(width: 6),
  384. Padding(
  385. padding: const EdgeInsets.only(bottom: 2),
  386. child: Text(
  387. "Details",
  388. style: Theme.of(context).textTheme.bodyText1,
  389. ),
  390. ),
  391. ],
  392. ),
  393. ),
  394. ...listTiles
  395. ],
  396. );
  397. }
  398. List<Widget> _getActions() {
  399. final List<Widget> actions = [];
  400. if (_isImage) {
  401. if (_exif == null) {
  402. actions.add(
  403. TextButton(
  404. child: Row(
  405. mainAxisAlignment: MainAxisAlignment.spaceAround,
  406. children: [
  407. Center(
  408. child: SizedBox.fromSize(
  409. size: const Size.square(24),
  410. child: const CupertinoActivityIndicator(
  411. radius: 8,
  412. ),
  413. ),
  414. ),
  415. const Padding(padding: EdgeInsets.all(4)),
  416. Text(
  417. "EXIF",
  418. style: TextStyle(color: infoColor),
  419. ),
  420. ],
  421. ),
  422. onPressed: () {
  423. showDialog(
  424. context: context,
  425. builder: (BuildContext context) {
  426. return ExifInfoDialog(widget.file);
  427. },
  428. barrierColor: Colors.black87,
  429. );
  430. },
  431. ),
  432. );
  433. } else if (_exif.isNotEmpty) {
  434. actions.add(
  435. TextButton(
  436. child: Row(
  437. mainAxisAlignment: MainAxisAlignment.spaceAround,
  438. children: [
  439. Icon(Icons.feed_outlined, color: infoColor),
  440. const Padding(padding: EdgeInsets.all(4)),
  441. Text(
  442. "View raw EXIF",
  443. style: TextStyle(color: infoColor),
  444. ),
  445. ],
  446. ),
  447. onPressed: () {
  448. showDialog(
  449. context: context,
  450. builder: (BuildContext context) {
  451. return ExifInfoDialog(widget.file);
  452. },
  453. barrierColor: Colors.black87,
  454. );
  455. },
  456. ),
  457. );
  458. } else {
  459. actions.add(
  460. TextButton(
  461. child: Row(
  462. mainAxisAlignment: MainAxisAlignment.spaceAround,
  463. children: [
  464. Icon(
  465. Icons.feed_outlined,
  466. color: Theme.of(context)
  467. .colorScheme
  468. .defaultTextColor
  469. .withOpacity(0.5),
  470. ),
  471. const Padding(padding: EdgeInsets.all(4)),
  472. Text(
  473. "No exif",
  474. style: TextStyle(
  475. color: Theme.of(context)
  476. .colorScheme
  477. .defaultTextColor
  478. .withOpacity(0.5),
  479. ),
  480. ),
  481. ],
  482. ),
  483. onPressed: () {
  484. showShortToast(context, "This image has no exif data");
  485. },
  486. ),
  487. );
  488. }
  489. }
  490. actions.add(
  491. TextButton(
  492. child: Text(
  493. "Close",
  494. style: TextStyle(
  495. color: infoColor,
  496. ),
  497. ),
  498. onPressed: () {
  499. Navigator.of(context, rootNavigator: true).pop("dialog");
  500. },
  501. ),
  502. );
  503. return actions;
  504. }
  505. _generateExifForDetails(Map<String, IfdTag> exif) {
  506. if (exif["EXIF FocalLength"] != null) {
  507. _exifData["focalLength"] =
  508. (exif["EXIF FocalLength"].values.toList()[0] as Ratio).numerator /
  509. (exif["EXIF FocalLength"].values.toList()[0] as Ratio)
  510. .denominator;
  511. }
  512. if (exif["EXIF FNumber"] != null) {
  513. _exifData["fNumber"] =
  514. (exif["EXIF FNumber"].values.toList()[0] as Ratio).numerator /
  515. (exif["EXIF FNumber"].values.toList()[0] as Ratio).denominator;
  516. }
  517. if (exif["EXIF ExifImageWidth"] != null &&
  518. exif["EXIF ExifImageLength"] != null) {
  519. _exifData["resolution"] = exif["EXIF ExifImageWidth"].toString() +
  520. " x " +
  521. exif["EXIF ExifImageLength"].toString();
  522. _exifData['megaPixels'] = ((exif["Image ImageWidth"].values.firstAsInt() *
  523. exif["Image ImageLength"].values.firstAsInt()) /
  524. 1000000)
  525. .toStringAsFixed(1);
  526. } else if (exif["Image ImageWidth"] != null &&
  527. exif["Image ImageLength"] != null) {
  528. _exifData["resolution"] = exif["Image ImageWidth"].toString() +
  529. " x " +
  530. exif["Image ImageLength"].toString();
  531. }
  532. if (exif["Image Make"] != null && exif["Image Model"] != null) {
  533. _exifData["takenOnDevice"] =
  534. exif["Image Make"].toString() + " " + exif["Image Model"].toString();
  535. }
  536. if (exif["EXIF ExposureTime"] != null) {
  537. _exifData["exposureTime"] = exif["EXIF ExposureTime"].toString();
  538. }
  539. if (exif["EXIF ISOSpeedRatings"] != null) {
  540. _exifData['ISO'] = exif["EXIF ISOSpeedRatings"].toString();
  541. }
  542. }
  543. Widget _getExifWidgets(Map<String, IfdTag> exif) {
  544. final focalLength = exif["EXIF FocalLength"] != null
  545. ? (exif["EXIF FocalLength"].values.toList()[0] as Ratio).numerator /
  546. (exif["EXIF FocalLength"].values.toList()[0] as Ratio)
  547. .denominator //to remove
  548. : null;
  549. final fNumber = exif["EXIF FNumber"] != null
  550. ? (exif["EXIF FNumber"].values.toList()[0] as Ratio).numerator /
  551. (exif["EXIF FNumber"].values.toList()[0] as Ratio)
  552. .denominator //to remove
  553. : null;
  554. final List<Widget> children = [];
  555. if (exif["EXIF ExifImageWidth"] != null &&
  556. exif["EXIF ExifImageLength"] != null) {
  557. children.addAll([
  558. Row(
  559. children: [
  560. Icon(Icons.photo_size_select_actual_outlined, color: infoColor),
  561. const Padding(padding: EdgeInsets.all(4)),
  562. Text(
  563. exif["EXIF ExifImageWidth"].toString() +
  564. " x " +
  565. exif["EXIF ExifImageLength"].toString(),
  566. style: TextStyle(color: infoColor),
  567. ),
  568. ],
  569. ),
  570. const Padding(padding: EdgeInsets.all(6)),
  571. ]);
  572. } else if (exif["Image ImageWidth"] != null &&
  573. exif["Image ImageLength"] != null) {
  574. children.addAll([
  575. Row(
  576. children: [
  577. Icon(Icons.photo_size_select_actual_outlined, color: infoColor),
  578. const Padding(padding: EdgeInsets.all(4)),
  579. Text(
  580. exif["Image ImageWidth"].toString() +
  581. " x " +
  582. exif["Image ImageLength"].toString(),
  583. style: TextStyle(color: infoColor),
  584. ),
  585. ],
  586. ),
  587. const Padding(padding: EdgeInsets.all(6)),
  588. ]);
  589. }
  590. if (exif["Image Make"] != null && exif["Image Model"] != null) {
  591. children.addAll(
  592. [
  593. Row(
  594. children: [
  595. Icon(Icons.camera_outlined, color: infoColor),
  596. const Padding(padding: EdgeInsets.all(4)),
  597. Flexible(
  598. child: Text(
  599. exif["Image Make"].toString() +
  600. " " +
  601. exif["Image Model"].toString(),
  602. style: TextStyle(color: infoColor),
  603. overflow: TextOverflow.clip,
  604. ),
  605. ),
  606. ],
  607. ),
  608. const Padding(padding: EdgeInsets.all(6)),
  609. ],
  610. );
  611. }
  612. if (fNumber != null) {
  613. children.addAll([
  614. Row(
  615. children: [
  616. Icon(CupertinoIcons.f_cursive, color: infoColor),
  617. const Padding(padding: EdgeInsets.all(4)),
  618. Text(
  619. fNumber.toString(),
  620. style: TextStyle(color: infoColor),
  621. ),
  622. ],
  623. ),
  624. const Padding(padding: EdgeInsets.all(6)),
  625. ]);
  626. }
  627. if (focalLength != null) {
  628. children.addAll([
  629. Row(
  630. children: [
  631. Icon(Icons.center_focus_strong_outlined, color: infoColor),
  632. const Padding(padding: EdgeInsets.all(4)),
  633. Text(
  634. focalLength.toString() + " mm",
  635. style: TextStyle(color: infoColor),
  636. ),
  637. ],
  638. ),
  639. const Padding(padding: EdgeInsets.all(6)),
  640. ]);
  641. }
  642. if (exif["EXIF ExposureTime"] != null) {
  643. children.addAll([
  644. Row(
  645. children: [
  646. Icon(Icons.shutter_speed, color: infoColor),
  647. const Padding(padding: EdgeInsets.all(4)),
  648. Text(
  649. exif["EXIF ExposureTime"].toString(),
  650. style: TextStyle(color: infoColor),
  651. ),
  652. ],
  653. ),
  654. const Padding(padding: EdgeInsets.all(6)),
  655. ]);
  656. }
  657. return Column(
  658. children: children,
  659. );
  660. }
  661. Widget _getFileSize() {
  662. return FutureBuilder(
  663. future: getFile(widget.file).then((f) => f.length()),
  664. builder: (context, snapshot) {
  665. if (snapshot.hasData) {
  666. return Text(
  667. (snapshot.data / (1024 * 1024)).toStringAsFixed(2) + " MB",
  668. );
  669. } else {
  670. return Center(
  671. child: SizedBox.fromSize(
  672. size: const Size.square(24),
  673. child: const CupertinoActivityIndicator(
  674. radius: 8,
  675. ),
  676. ),
  677. );
  678. }
  679. },
  680. );
  681. }
  682. Widget _getVideoDuration() {
  683. return FutureBuilder(
  684. future: widget.file.getAsset(),
  685. builder: (context, snapshot) {
  686. if (snapshot.hasData) {
  687. return Text(
  688. snapshot.data.videoDuration.toString().split(".")[0],
  689. );
  690. } else {
  691. return Center(
  692. child: SizedBox.fromSize(
  693. size: const Size.square(24),
  694. child: const CupertinoActivityIndicator(
  695. radius: 8,
  696. ),
  697. ),
  698. );
  699. }
  700. },
  701. );
  702. }
  703. }
  704. class DividerWithPadding extends StatelessWidget {
  705. const DividerWithPadding({Key key}) : super(key: key);
  706. @override
  707. Widget build(BuildContext context) {
  708. return const Padding(
  709. padding: EdgeInsets.fromLTRB(70, 0, 20, 0),
  710. child: Divider(
  711. thickness: 0.5,
  712. ),
  713. );
  714. }
  715. }