diff --git a/lib/modules/cleaner_module/pages/one_time_task_preview_screen.dart b/lib/modules/cleaner_module/pages/one_time_task_preview_screen.dart index 0e44bcda..6448aeeb 100644 --- a/lib/modules/cleaner_module/pages/one_time_task_preview_screen.dart +++ b/lib/modules/cleaner_module/pages/one_time_task_preview_screen.dart @@ -272,23 +272,7 @@ class OneTimeTaskPreviewScreen extends StatelessWidget { children: taskData.imageRooms!.map((imageString) { return GestureDetector( onTap: () { - // Show full screen image - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - backgroundColor: Colors.black, - appBar: AppBar( - backgroundColor: Colors.black, - iconTheme: const IconThemeData(color: Colors.white), - ), - body: Center( - child: InteractiveViewer( - child: _buildImage(imageString), - ), - ), - ), - ), - ); + context.fullScreenImageViewer(_buildImage(imageString)); }, child: Container( width: 100, @@ -349,12 +333,12 @@ class OneTimeTaskPreviewScreen extends StatelessWidget { SizedBox( width: 100, child: InfoTextLabelWidget( - label:'$label:', + label: '$label:', ), ), Expanded( child: InfoTextLabelWidget( - label: value, + label: value, ), ), ], diff --git a/lib/modules/cleaner_module/widgets/cleaner_checklist_widget.dart b/lib/modules/cleaner_module/widgets/cleaner_checklist_widget.dart index 3f69efa1..1525ad64 100644 --- a/lib/modules/cleaner_module/widgets/cleaner_checklist_widget.dart +++ b/lib/modules/cleaner_module/widgets/cleaner_checklist_widget.dart @@ -277,24 +277,7 @@ class _CleanerChecklistWidgetState extends State { maxImages: 2, // Enforce max 2 images onImageTap: (index, imageUrl) { - // Handle image tap - show in full screen - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - backgroundColor: Colors.black, - body: SafeArea( - child: Stack( - children: [ - InteractiveViewer( - child: _buildImageForViewing(imageUrl), - ).center, - const ABackButton(), - ], - ), - ), - ), - ), - ); + context.fullScreenImageViewer(_buildImageForViewing(imageUrl)); }, onDelete: (index) { // Handle image delete diff --git a/lib/modules/cleaner_module/widgets/multi_image_picker.dart b/lib/modules/cleaner_module/widgets/multi_image_picker.dart index 002acbe4..d970c2d3 100644 --- a/lib/modules/cleaner_module/widgets/multi_image_picker.dart +++ b/lib/modules/cleaner_module/widgets/multi_image_picker.dart @@ -48,8 +48,7 @@ class MultiImagePicker extends StatelessWidget { ), // Add image button (only show if under max limit) - if (enabled && imageUrls.length < maxImages) - _buildAddImageButton(context), + if (enabled && imageUrls.length < maxImages) _buildAddImageButton(context), ], ), ], @@ -77,7 +76,9 @@ class MultiImagePicker extends StatelessWidget { if (onImageTap != null) { onImageTap!(index, imageUrl); } else { - _showFullImage(context, imageUrl); + context.fullScreenImageViewer( + _getImageWidget(imageUrl), + ); } }), if (enabled) @@ -193,26 +194,4 @@ class MultiImagePicker extends StatelessWidget { } } } - - void _showFullImage(BuildContext context, String imageUrl) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - backgroundColor: Colors.black, - body: SafeArea( - child: Stack( - children: [ - Center( - child: InteractiveViewer( - child: _getImageWidget(imageUrl), - ), - ), - const ABackButton(), - ], - ), - ), - ), - ), - ); - } } diff --git a/lib/modules/cm_module/views/components/history_log_view.dart b/lib/modules/cm_module/views/components/history_log_view.dart index e549f02f..7b7b1b5f 100644 --- a/lib/modules/cm_module/views/components/history_log_view.dart +++ b/lib/modules/cm_module/views/components/history_log_view.dart @@ -120,20 +120,7 @@ class HistoryLogView extends StatelessWidget { padding: EdgeInsets.symmetric(vertical: 12.toScreenWidth), child: InteractiveViewer(child: Image.network(URLs.getFileUrl(object.photoVerfication ?? '')!, height: 143.toScreenHeight)), ).onPress(() async { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - body: SafeArea( - child: Stack( - children: [ - InteractiveViewer(child: Image.network(URLs.getFileUrl(object.photoVerfication ?? '')!)).center, - const ABackButton(), - ], - ), - ), - ), - ), - ); + context.fullScreenImageViewer(Image.network(URLs.getFileUrl(object.photoVerfication ?? '')!)); }), ], title.bodyText(context).custom(color: AppColor.textColor(context)), diff --git a/lib/modules/cm_module/views/components/service_request_detail_view.dart b/lib/modules/cm_module/views/components/service_request_detail_view.dart index bd9ecbe6..4d8cc3d0 100644 --- a/lib/modules/cm_module/views/components/service_request_detail_view.dart +++ b/lib/modules/cm_module/views/components/service_request_detail_view.dart @@ -205,10 +205,7 @@ class _ServiceRequestDetailViewState extends State { ], ), if (context.userProvider.isEngineer && !(workOrder.asset!.hasTrainingImageData ?? true)) ...[ - Text( - '*Images are required for the asset', - style: AppTextStyles.bodyText.copyWith(color: AppColor.red30), - ), + InfoTextLabelWidget(label: '*Images are required for the asset', color: AppColor.red30), 4.height, ], InfoTextWidget(label: context.translation.assetName, value: workOrder.assetNdModel!.name?.cleanupWhitespace.capitalizeFirstOfEach), diff --git a/lib/modules/cx_module/chat/helper/chat_file_viewer.dart b/lib/modules/cx_module/chat/helper/chat_file_viewer.dart index 9eee8c44..34653e1b 100644 --- a/lib/modules/cx_module/chat/helper/chat_file_viewer.dart +++ b/lib/modules/cx_module/chat/helper/chat_file_viewer.dart @@ -24,7 +24,6 @@ class ChatFileViewer extends StatelessWidget { @override Widget build(BuildContext context) { - return FutureBuilder( future: checkFileInLocalStorage(), builder: (BuildContext context, AsyncSnapshot snapshot) { @@ -80,16 +79,7 @@ class ChatFileViewer extends StatelessWidget { padding: EdgeInsets.zero, onPressed: () async { if (isImage) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - appBar: const DefaultAppBar(), - body: SafeArea( - child: InteractiveViewer(child: Image.file(file)).center, - ), - ), - ), - ); + context.fullScreenImageViewer(Image.file(file)); } else { OpenFile.open(file.path); } diff --git a/lib/modules/cx_module/chat/view_all_attachment_page.dart b/lib/modules/cx_module/chat/view_all_attachment_page.dart index 1e442591..8eb13b7d 100644 --- a/lib/modules/cx_module/chat/view_all_attachment_page.dart +++ b/lib/modules/cx_module/chat/view_all_attachment_page.dart @@ -182,16 +182,7 @@ class AttachmentFileViewer extends StatelessWidget { ), ).onPress(() { if (isImage) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - appBar: const DefaultAppBar(), - body: SafeArea( - child: InteractiveViewer(child: Image.file(snapshot.data!)).center, - ), - ), - ), - ); + context.fullScreenImageViewer(Image.file(snapshot.data!)); } else { OpenFile.open(snapshot.data!.path); } @@ -253,16 +244,7 @@ class AttachmentFileViewer extends StatelessWidget { padding: EdgeInsets.zero, onPressed: () async { if (isImage) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - appBar: const DefaultAppBar(), - body: SafeArea( - child: InteractiveViewer(child: Image.file(file)).center, - ), - ), - ), - ); + context.fullScreenImageViewer(Image.file(file)); } else { OpenFile.open(file.path); } diff --git a/lib/modules/export_module/widgets/cleaner_checklist_widget.dart b/lib/modules/export_module/widgets/cleaner_checklist_widget.dart index 12d22165..090de70b 100644 --- a/lib/modules/export_module/widgets/cleaner_checklist_widget.dart +++ b/lib/modules/export_module/widgets/cleaner_checklist_widget.dart @@ -200,21 +200,7 @@ class _CleanerChecklistWidgetState extends State { ), child: imageWidget) .onPress(() { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - body: SafeArea( - child: Stack( - children: [ - // InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center, - InteractiveViewer(child: imageWidget).center, - const ABackButton(), - ], - ), - ), - ), - ), - ); + context.fullScreenImageViewer(imageWidget); }), _delete(), ], @@ -241,21 +227,7 @@ class _CleanerChecklistWidgetState extends State { ), child: imageWidget) .onPress(() { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - body: SafeArea( - child: Stack( - children: [ - // InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center, - InteractiveViewer(child: imageWidget).center, - const ABackButton(), - ], - ), - ), - ), - ), - ); + context.fullScreenImageViewer(imageWidget); }), _delete(), ], @@ -300,21 +272,7 @@ class _CleanerChecklistWidgetState extends State { ), child: imageWidget) .onPress(() { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - body: SafeArea( - child: Stack( - children: [ - // InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center, - InteractiveViewer(child: imageWidget).center, - const ABackButton(), - ], - ), - ), - ), - ), - ); + context.fullScreenImageViewer(imageWidget); }), _delete(), ], diff --git a/lib/views/widgets/equipment/asset_detail_page.dart b/lib/views/widgets/equipment/asset_detail_page.dart index d81f8eff..a876ffeb 100644 --- a/lib/views/widgets/equipment/asset_detail_page.dart +++ b/lib/views/widgets/equipment/asset_detail_page.dart @@ -80,7 +80,7 @@ class _AssetDetailPageState extends State with SingleTickerProv return const Center(child: ALoading()); } else if (snapshot.hasData) {} if (snapshot.hasData) { - AssetByIdModel assetModel = snapshot.data!; + assetModel = snapshot.data!; attachments = assetModel?.assetAttachments ?.map((attachment) => GenericAttachmentModel( id: attachment.id, @@ -89,8 +89,10 @@ class _AssetDetailPageState extends State with SingleTickerProv )) .toList() ?? []; - // Start animation when data is loaded - _animationController.forward(from: 0.0); + + if (!_animationController.isCompleted) { + _animationController.forward(from: 0.0); + } // Image animation - fade in with scale final imageAnimation = Tween(begin: 0.0, end: 1.0).animate( @@ -238,7 +240,7 @@ class _AssetDetailPageState extends State with SingleTickerProv ), image: DecorationImage( fit: BoxFit.cover, - image: NetworkImage(assetModel.assetPhoto != null ? URLs.getFileUrl(assetModel.assetPhoto!)! : "https://www.lasteelcraft.com/images/no-image-available.png"), + image: NetworkImage(assetModel?.assetPhoto != null ? URLs.getFileUrl(assetModel!.assetPhoto!)! : "https://www.lasteelcraft.com/images/no-image-available.png"), )), ), ), @@ -251,19 +253,19 @@ class _AssetDetailPageState extends State with SingleTickerProv crossAxisAlignment: CrossAxisAlignment.start, children: [ // Status label with animation - if (assetModel.commissioningStatus != null) + if (assetModel?.commissioningStatus != null) FadeTransition( opacity: statusAnimation, child: SlideTransition( position: statusSlideAnimation, child: StatusLabel( - label: assetModel.commissioningStatus!.name, - textColor: AppColor.getRequestStatusTextColorByName(context, assetModel.commissioningStatus!.name!), - backgroundColor: AppColor.getRequestStatusColorByName(context, assetModel.commissioningStatus!.name!), + label: assetModel!.commissioningStatus!.name, + textColor: AppColor.getRequestStatusTextColorByName(context, assetModel!.commissioningStatus!.name!), + backgroundColor: AppColor.getRequestStatusColorByName(context, assetModel!.commissioningStatus!.name!), ), ), ), - if (assetModel.commissioningStatus != null) 8.height, + if (assetModel?.commissioningStatus != null) 8.height, // Header with animation FadeTransition( @@ -275,8 +277,8 @@ class _AssetDetailPageState extends State with SingleTickerProv crossAxisAlignment: CrossAxisAlignment.start, spacing: 2, children: [ - InfoHeader16Widget(assetModel.modelDefinition?.assetName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"), - if (context.userProvider.isEngineer && !(assetModel.hasTrainingImageData ?? true)) + InfoHeader16Widget(assetModel?.modelDefinition?.assetName?.cleanupWhitespace.capitalizeFirstOfEach ?? "-"), + if (context.userProvider.isEngineer && !(assetModel?.hasTrainingImageData ?? true)) Text( '*Upload Images for this asset', style: AppTextStyles.bodyText2.copyWith(color: AppColor.red30), @@ -286,7 +288,6 @@ class _AssetDetailPageState extends State with SingleTickerProv ), ), 8.height, - // Details row with animation FadeTransition( opacity: detailsAnimation, @@ -294,41 +295,39 @@ class _AssetDetailPageState extends State with SingleTickerProv position: detailsSlideAnimation, child: Row( crossAxisAlignment: CrossAxisAlignment.start, + spacing: 8, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - InfoTextWidget(label: context.translation.assetNo, value: assetModel.multiAssets!.first.assetNumber, showEmptyValue: true), - InfoTextWidget(label: context.translation.modelName, value: assetModel.modelDefinition!.modelName, showEmptyValue: true), - InfoTextWidget(label: context.translation.supplier, value: assetModel.supplier?.suppliername, showEmptyValue: true), - InfoTextWidget(label: context.translation.manufacture, value: assetModel.modelDefinition!.manufacturerName, showEmptyValue: true), + InfoTextWidget(label: context.translation.assetNo, value: assetModel!.multiAssets!.first.assetNumber, showEmptyValue: true), + InfoTextWidget(label: context.translation.modelName, value: assetModel!.modelDefinition!.modelName, showEmptyValue: true), + InfoTextWidget(label: context.translation.supplier, value: assetModel!.supplier?.suppliername, showEmptyValue: true), + InfoTextWidget(label: context.translation.manufacture, value: assetModel!.modelDefinition!.manufacturerName, showEmptyValue: true), ], ).expanded, - 8.width, Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - InfoTextWidget(label: context.translation.snNo, value: assetModel.multiAssets!.first.assetSerialNo, showEmptyValue: true), - InfoTextWidget(label: context.translation.site, value: assetModel.site?.custName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.building, value: assetModel.building?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.floor, value: assetModel.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.md, value: assetModel.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), - InfoTextWidget(label: context.translation.room, value: assetModel.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.snNo, value: assetModel!.multiAssets!.first.assetSerialNo, showEmptyValue: true), + InfoTextWidget(label: context.translation.site, value: assetModel!.site?.custName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.building, value: assetModel!.building?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.floor, value: assetModel!.floor?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.md, value: assetModel!.department?.departmentName?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), + InfoTextWidget(label: context.translation.room, value: assetModel!.room?.name?.cleanupWhitespace.capitalizeFirstOfEach, showEmptyValue: true), ], ).expanded, ], ), ), ), - 8.height, - + // 8.height, // Divider with animation FadeTransition( opacity: datesAnimation, - child: const Divider(color: AppColor.neutral30, height: 1, thickness: 1), + child: const Divider().defaultStyle(context), ), - 8.height, - + // 8.height, // Dates section with animation FadeTransition( opacity: datesAnimation, @@ -337,17 +336,17 @@ class _AssetDetailPageState extends State with SingleTickerProv child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - InfoTextWidget(label: context.translation.installationDate, value: assetModel.installationDate?.toAssetDetailsFormat, showEmptyValue: true), - InfoTextWidget(label: context.translation.nextPmDate, value: assetModel.nextPMDate?.toAssetDetailsFormat, showEmptyValue: true), - InfoTextWidget(label: context.translation.lastPmDate, value: assetModel.lastPMDate?.toAssetDetailsFormat, showEmptyValue: true), + InfoTextWidget(label: context.translation.installationDate, value: assetModel?.installationDate?.toAssetDetailsFormat, showEmptyValue: true), + InfoTextWidget(label: context.translation.nextPmDate, value: assetModel?.nextPMDate?.toAssetDetailsFormat, showEmptyValue: true), + InfoTextWidget(label: context.translation.lastPmDate, value: assetModel?.lastPMDate?.toAssetDetailsFormat, showEmptyValue: true), ], ), ), ), // Description with animation (if exists) - if ((assetModel.modelDefinition?.assetDescription ?? "").isNotEmpty) ...[ - 8.height, + if ((assetModel?.modelDefinition?.assetDescription ?? "").isNotEmpty) ...[ + // 8.height, FadeTransition( opacity: descAnimation, child: const Divider().defaultStyle(context), @@ -356,13 +355,13 @@ class _AssetDetailPageState extends State with SingleTickerProv opacity: descAnimation, child: SlideTransition( position: descSlideAnimation, - child: InfoTextWidget(label: assetModel.modelDefinition!.assetDescription!, showEmptyValue: true, isMsg: true), + child: InfoTextWidget(label: assetModel!.modelDefinition!.assetDescription!, showEmptyValue: true, isMsg: true), ), ), ], if (attachments.isNotEmpty) ...[ - 8.height, + // 8.height, FadeTransition( opacity: attachmentAnimation, child: const Divider().defaultStyle(context), @@ -380,7 +379,7 @@ class _AssetDetailPageState extends State with SingleTickerProv ], ).toShadowContainer(context), ).expanded, - if (context.userProvider.isEngineer && !(assetModel.hasTrainingImageData ?? true)) + if (context.userProvider.isEngineer && !(assetModel!.hasTrainingImageData ?? true)) FooterActionButton.footerContainer( context: context, child: AppFilledButton( diff --git a/lib/views/widgets/equipment/asset_image_upload_page.dart b/lib/views/widgets/equipment/asset_image_upload_page.dart index 7cf3aaa1..33d48a62 100644 --- a/lib/views/widgets/equipment/asset_image_upload_page.dart +++ b/lib/views/widgets/equipment/asset_image_upload_page.dart @@ -19,6 +19,8 @@ import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/views/full_screen_image_viewer.dart'; import 'package:test_sa/views/widgets/dialogs/dialog.dart'; import 'package:test_sa/views/widgets/images/multi_image_picker.dart'; +import 'package:test_sa/views/widgets/item_views/info_header_widget.dart'; +import 'package:test_sa/views/widgets/item_views/info_text_widget.dart'; class AssetImageUploadPage extends StatefulWidget { int assetId; @@ -55,14 +57,10 @@ class _AssetImageUploadPageState extends State { ListView( padding: const EdgeInsets.all(16), children: [ - Text( - "Instructions", - style: AppTextStyles.heading5.copyWith(color: context.isDark ? AppColor.neutral30 : AppColor.neutral50), - ), - Text( - '* Please upload all images of the sides of the asset as mentioned below.\n* Images should be clear and high quality.\n* Avoid uploading blurry, low-light or low-resolution images.', - style: AppTextStyles.bodyText2.copyWith(color: context.isDark ? AppColor.neutral10 : AppColor.neutral120), - ), + InfoHeader16Widget("Instructions"), + InfoTextLabelWidget( + label: + "* Please upload all images of the sides of the asset as mentioned below.\n* Images should be clear and high quality.\n* Avoid uploading blurry, low-light or low-resolution images."), GridView( padding: const EdgeInsets.only(top: 16, bottom: 16), shrinkWrap: true, @@ -110,11 +108,13 @@ class _AssetImageUploadPageState extends State { ), AttachmentPicker( label: "Additional Images", + pickerTitle: "Attach Images", attachment: trainingImageData.additionalImages!, buttonColor: AppColor.black10, onlyImages: true, pickMultiple: true, - buttonIcon: 'image-plus'.toSvgAsset(color: context.isDark ? AppColor.primary10 : AppColor.neutral120), + // showAsGrid: true, + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), onChange: (_attachments) { trainingImageData.additionalImages = _attachments; setState(() {}); @@ -163,11 +163,12 @@ class _AssetImageUploadPageState extends State { Positioned.fill( child: AttachmentPicker( label: "", + pickerTitle: title, onlyImages: true, checkQuality: true, enabled: attachment == null, attachment: attachment == null ? [] : [attachment], - buttonIcon: 'image-plus'.toSvgAsset(color: context.isDark ? AppColor.primary10 : AppColor.neutral120), + buttonIcon: 'image-plus'.toSvgAsset(color: AppColor.primary10), onChange: (_attachments) { if (_attachments.isNotEmpty) { onUpdate(_attachments.first); diff --git a/lib/views/widgets/equipment/my_assets_page.dart b/lib/views/widgets/equipment/my_assets_page.dart index 92a168a8..43fbbd6d 100644 --- a/lib/views/widgets/equipment/my_assets_page.dart +++ b/lib/views/widgets/equipment/my_assets_page.dart @@ -129,13 +129,20 @@ class _MyAssetsPageState extends State with SingleTickerProviderSt _searchableList.clear(); _searchableList.addAll(_devicesProvider.devices); }).expanded, - 16.width, - Icon(Icons.grid_view_outlined, color: AppColor.icon2Color(context)).onPress(() => setState(() { - showListView = !showListView; - })), + 12.width, + IconButton( + icon: Icon(!showListView ? Icons.view_list_sharp : Icons.grid_view_outlined, color: AppColor.icon2Color(context)), + padding: EdgeInsets.zero, + visualDensity: VisualDensity.compact, + tooltip: !showListView ? "View as List" : "View as Grid", + onPressed: () => setState(() { + showListView = !showListView; + }), + ), IconButton( icon: "download".toSvgAsset(height: 24, width: 24, color: AppColor.icon2Color(context)), padding: EdgeInsets.zero, + visualDensity: VisualDensity.compact, tooltip: "Export", onPressed: () async { await Navigator.push( @@ -154,6 +161,7 @@ class _MyAssetsPageState extends State with SingleTickerProviderSt IconButton( icon: "filter".toSvgAsset(height: 24, width: 24, color: AppColor.icon2Color(context)), padding: EdgeInsets.zero, + visualDensity: VisualDensity.compact, tooltip: "Filter", onPressed: () async { final result = await Navigator.push(context, CupertinoPageRoute(builder: (context) => DeviceFilterScreen(data: _searchAsset))); diff --git a/lib/views/widgets/images/files_list.dart b/lib/views/widgets/images/files_list.dart index 851a19f7..9ca23d8a 100644 --- a/lib/views/widgets/images/files_list.dart +++ b/lib/views/widgets/images/files_list.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:open_file/open_file.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; +import 'package:test_sa/extensions/context_extension.dart'; import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; @@ -84,21 +85,7 @@ class FilesList extends StatelessWidget { recognizer: TapGestureRecognizer() ..onTap = () async { if (isImage) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - body: SafeArea( - child: Stack( - children: [ - // InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center, - InteractiveViewer(child: getImageWidget(itemIndex)).center, - const ABackButton(), - ], - ), - ), - ), - ), - ); + context.fullScreenImageViewer(getImageWidget(itemIndex)); } else if (_isLocalUrl(images[itemIndex])) { OpenFile.open(images[itemIndex]); } else { @@ -162,21 +149,7 @@ class FilesList extends StatelessWidget { ), ).onPress(() async { if (isImage) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - body: SafeArea( - child: Stack( - children: [ - // InteractiveViewer(child: Image(image: getImageObject(itemIndex))).center, - InteractiveViewer(child: getImageWidget(itemIndex)).center, - const ABackButton(), - ], - ), - ), - ), - ), - ); + context.fullScreenImageViewer(getImageWidget(itemIndex)); } else if (_isLocalUrl(images[itemIndex])) { OpenFile.open(images[itemIndex]); } else { @@ -192,59 +165,6 @@ class FilesList extends StatelessWidget { }); }, ); - - // return ListView.separated( - // padding: padding ?? EdgeInsets.symmetric(horizontal: 32 * AppStyle.getScaleFactor(context)), - // scrollDirection: Axis.horizontal, - // itemCount: images?.length ?? 0, - // separatorBuilder: (context, itemIndex) => 8.width, - // itemBuilder: (context, itemIndex) { - // if (images[itemIndex] == null || !images[itemIndex].contains(".")) { - // return Text("Bad\nFile"); - // } - // var isImage = - // images[itemIndex].split(".").last.toLowerCase() == "png" || images[itemIndex].split(".").last.toLowerCase() == "jpg" || images[itemIndex].split(".").last.toLowerCase() == "jpeg"; - // var isPdf = images[itemIndex].split(".").last.toLowerCase() == "pdf"; - // var isExcel = images[itemIndex].split(".").last.toLowerCase() == "xlsx"; - // - // return (isImage - // ? (_isLocalUrl(images[itemIndex]) - // ? Image.file(File(images[itemIndex])) - // : ImageLoader( - // url: images[itemIndex], - // boxFit: BoxFit.cover, - // )) - // : Image.asset("assets/images/${isPdf ? "pdf" : isExcel ? "excel" : "doc"}.png")) - // .onPress(() async { - // if (isImage) { - // Navigator.of(context).push( - // MaterialPageRoute( - // builder: (_) => Scaffold( - // body: SafeArea( - // child: Stack( - // children: [ - // InteractiveViewer(child: Image(image: (_isLocalUrl(images[itemIndex]) ? FileImage(File(images[itemIndex])) : NetworkImage(images[itemIndex])))).center, - // const ABackButton(), - // ], - // ), - // ), - // ), - // ), - // ); - // } else if (_isLocalUrl(images[itemIndex])) { - // OpenFile.open(images[itemIndex]); - // } else { - // try { - // if (!await launchUrl(Uri.parse(images[itemIndex]), mode: LaunchMode.externalApplication)) { - // Fluttertoast.showToast(msg: "UnExpected Error with file."); - // throw Exception('Could not launch '); - // } - // } catch (ex) { - // Fluttertoast.showToast(msg: "No Viewer found."); - // } - // } - // }); - // }); } Widget getImageWidget(int itemIndex) { diff --git a/lib/views/widgets/images/multi_image_picker.dart b/lib/views/widgets/images/multi_image_picker.dart index 58165803..a38bc0d5 100644 --- a/lib/views/widgets/images/multi_image_picker.dart +++ b/lib/views/widgets/images/multi_image_picker.dart @@ -17,280 +17,6 @@ import 'package:test_sa/new_views/app_style/app_color.dart'; import '../../../new_views/common_widgets/app_dashed_button.dart'; import 'multi_image_picker_item.dart'; -// class MultiFilesPicker extends StatefulWidget { -// final String label; -// final bool error; -// final List files; -// final List attachment; -// -// final bool enabled, onlyImages; -// double? buttonHeight; -// Widget? buttonIcon; -// Color? buttonColor; -// final Function(List)? onChange; -// final bool showAsGrid; -// -// MultiFilesPicker( -// {Key? key, -// this.files = const [], -// this.attachment = const [], -// required this.label, -// this.error = false, -// this.buttonHeight, -// this.buttonIcon, -// this.enabled = true, -// this.onlyImages = false, -// this.onChange, -// this.showAsGrid = false, -// this.buttonColor}) -// : super(key: key); -// -// @override -// State createState() => _MultiFilesPickerState(); -// } -// -// class _MultiFilesPickerState extends State { -// @override -// Widget build(BuildContext context) { -// return Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// if (widget.enabled) ...[ -// AppDashedButton( -// title: widget.label, -// height: widget.buttonHeight, -// buttonColor: widget.buttonColor, -// icon: widget.buttonIcon, -// onPressed: (widget.enabled == false) -// ? () {} -// : widget.showAsGrid -// ? showFileSourceSheet -// : onFilePicker), -// 16.height, -// ], -// if (widget.files.isNotEmpty) -// Wrap( -// spacing: 8.toScreenWidth, -// children: List.generate( -// widget.files!.length, -// (index) { -// File image = widget.files![index]; -// return MultiFilesPickerItem( -// file: image, -// enabled: widget.enabled, -// onRemoveTap: (image) { -// if (!widget.enabled) { -// return; -// } -// widget.files.remove(image); -// if (widget.onChange != null) { -// widget.onChange!(widget.files); -// } -// setState(() {}); -// }, -// ); -// }, -// ), -// ), -// ], -// ); -// } -// -// fromFilePicker() async { -// FilePickerResult? result = await FilePicker.platform.pickFiles( -// type: FileType.custom, -// allowMultiple: true, -// allowedExtensions: widget.onlyImages ? ['jpg', 'jpeg', 'png'] : ['jpg', 'jpeg', 'png', 'pdf', 'doc', 'docx', 'xlsx', 'pptx'], -// ); -// if (result != null) { -// for (var path in result.paths) { -// widget.files.add(File(path!)); -// if (widget.onChange != null) { -// widget.onChange!(widget.files); -// } -// } -// setState(() {}); -// } -// } -// -// void showFileSourceSheet() async { -// if (widget.files.length >= 5) { -// Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); -// return; -// } -// -// ImageSource? source = (await showModalBottomSheet( -// context: context, -// shape: const RoundedRectangleBorder( -// borderRadius: BorderRadius.vertical( -// top: Radius.circular(20), -// ), -// ), -// clipBehavior: Clip.antiAliasWithSaveLayer, -// builder: (BuildContext context) => Column( -// mainAxisSize: MainAxisSize.min, -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// "Attach File".heading4(context), -// 12.height, -// GridView( -// padding: const EdgeInsets.all(0), -// shrinkWrap: true, -// physics: const NeverScrollableScrollPhysics(), -// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), -// children: [ -// gridItem(Icons.camera_enhance_rounded, context.translation.pickFromCamera).onPress(() => Navigator.of(context).pop(ImageSource.camera)), -// gridItem(Icons.image_rounded, context.translation.pickFromGallery).onPress(() => Navigator.of(context).pop(ImageSource.gallery)), -// gridItem(Icons.file_present_rounded, context.translation.pickFromFiles).onPress(() async { -// await fromFilePicker(); -// Navigator.pop(context); -// }), -// ], -// ), -// 12.height, -// ], -// ).paddingAll(21), -// )) as ImageSource?; -// if (source == null) return; -// final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); -// -// if (pickedFile != null) { -// File fileImage = File(pickedFile.path); -// widget.files.add(fileImage); -// if (widget.onChange != null) { -// widget.onChange!(widget.files); -// } -// setState(() {}); -// } -// } -// -// Widget gridItem(IconData iconData, String title) { -// return Container( -// padding: const EdgeInsets.all(12), -// decoration: BoxDecoration( -// color: Colors.white, -// borderRadius: BorderRadius.circular(12), -// border: Border.all(color: const Color(0xffF1F1F1), width: 1), -// ), -// child: Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// mainAxisAlignment: MainAxisAlignment.spaceBetween, -// children: [ -// Icon(iconData, color: const Color(0xff7D859A), size: 36), -// Text( -// title, -// style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w500), -// ), -// ], -// ), -// ); -// } -// -// onFilePicker() async { -// if (widget.files.length >= 5) { -// Fluttertoast.showToast(msg: context.translation.maxImagesNumberIs5); -// return; -// } -// ImageSource? source = await showModalBottomSheet( -// context: context, -// builder: (BuildContext context) { -// Widget listCard({required String icon, required String label, required VoidCallback onTap}) { -// return GestureDetector( -// onTap: onTap, -// child: Container( -// constraints: BoxConstraints(minWidth: 111.toScreenWidth, minHeight: 111.toScreenHeight), -// padding: EdgeInsets.symmetric(horizontal: 12.toScreenWidth, vertical: 12.toScreenHeight), -// decoration: BoxDecoration(borderRadius: BorderRadius.circular(12), border: Border.all(width: 1, color: AppColor.white70)), -// child: Column( -// mainAxisSize: MainAxisSize.min, -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// icon.toSvgAsset(), -// 24.height, -// label.bodyText2(context).custom(color: AppColor.black20), -// ], -// ), -// ), -// ); -// } -// -// return Container( -// padding: const EdgeInsets.all(16.0), -// child: Row( -// mainAxisAlignment: MainAxisAlignment.spaceBetween, -// children: [ -// listCard( -// icon: 'camera_icon', -// label: '${context.translation.open}\n${context.translation.camera}', -// onTap: () { -// Navigator.of(context).pop(ImageSource.camera); -// }, -// ), -// listCard( -// icon: 'gallery_icon', -// label: '${context.translation.open}\n${context.translation.gallery}', -// onTap: () { -// Navigator.of(context).pop(ImageSource.gallery); -// }, -// ), -// listCard( -// icon: 'file_icon', -// label: '${context.translation.open}\n${context.translation.files}', -// onTap: () async { -// await fromFilePicker(); -// Navigator.pop(context); -// }, -// ), -// ], -// ), -// ); -// }, -// ); -// // ImageSource source = await showDialog( -// // context: context, -// // builder: (dialogContext) => CupertinoAlertDialog( -// // actions: [ -// // TextButton( -// // child: Text(context.translation.pickFromCamera), -// // onPressed: () { -// // Navigator.of(dialogContext).pop(ImageSource.camera); -// // }, -// // ), -// // TextButton( -// // child: Text(context.translation.pickFromGallery), -// // onPressed: () { -// // Navigator.of(dialogContext).pop(ImageSource.gallery); -// // }, -// // ), -// // TextButton( -// // child: Text(context.translation.pickFromFiles), -// // onPressed: () async { -// // await fromFilePicker(); -// // Navigator.pop(context); -// // }, -// // ), -// // ], -// // ), -// // ); -// if (source == null) return; -// -// final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); -// -// if (pickedFile != null) { -// File fileImage = File(pickedFile.path); -// if (fileImage != null) { -// widget.files.add(fileImage); -// if (widget.onChange != null) { -// widget.onChange!(widget.files); -// } -// setState(() {}); -// } -// } -// -// setState(() {}); -// } -// } - class AttachmentModel { int id = 0; File? file; @@ -313,6 +39,7 @@ class AttachmentModel { } class AttachmentPicker extends StatefulWidget { + final String pickerTitle; final String label; final bool error; final List attachment; @@ -322,7 +49,6 @@ class AttachmentPicker extends StatefulWidget { Widget? buttonIcon; Color? buttonColor; final Function(List)? onChange; - final bool showAsGrid; final bool showAsListView; final bool pickMultiple; Lookup? documentType; @@ -333,6 +59,7 @@ class AttachmentPicker extends StatefulWidget { {Key? key, this.attachment = const [], required this.label, + this.pickerTitle = "Attach File", this.error = false, this.buttonHeight, this.buttonIcon, @@ -340,7 +67,6 @@ class AttachmentPicker extends StatefulWidget { this.onlyImages = false, this.onChange, this.documentType, - this.showAsGrid = false, this.showAsListView = false, this.pickMultiple = false, this.checkQuality = false, @@ -352,15 +78,29 @@ class AttachmentPicker extends StatefulWidget { State createState() => _AttachmentPickerState(); } -class _AttachmentPickerState extends State { +class _AttachmentPickerState extends State with SingleTickerProviderStateMixin { + late AnimationController _animationController; + + @override + void initState() { + super.initState(); + _animationController = AnimationController( + duration: const Duration(milliseconds: 1200), + vsync: this, + ); + _animationController.forward(); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return widget.child != null - ? widget.child!.onPress((widget.enabled == false) - ? () {} - : widget.showAsGrid - ? () => showFileSourceSheet() - : () => onFilePicker(widget.checkQuality)) + ? widget.child!.onPress((widget.enabled == false) ? () {} : () => onFilePicker(widget.checkQuality)) : Column( crossAxisAlignment: CrossAxisAlignment.start, spacing: 12, @@ -370,11 +110,7 @@ class _AttachmentPickerState extends State { height: widget.buttonHeight, buttonColor: widget.buttonColor, icon: widget.buttonIcon, - onPressed: (widget.enabled == false) - ? () {} - : widget.showAsGrid - ? () => showFileSourceSheet() - : () => onFilePicker(widget.checkQuality)), + onPressed: (widget.enabled == false) ? () {} : () => onFilePicker(widget.checkQuality)), if (widget.attachment.isNotEmpty) widget.showAsListView ? ListView.separated( @@ -446,57 +182,6 @@ class _AttachmentPickerState extends State { } } - void showFileSourceSheet() async { - ImageSource source = (await showModalBottomSheet( - context: context, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(20), - ), - ), - clipBehavior: Clip.antiAliasWithSaveLayer, - builder: (BuildContext context) => Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - "Attach File".heading4(context), - 12.height, - GridView( - padding: const EdgeInsets.all(0), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), - children: [ - gridItem(Icons.camera_enhance_rounded, context.translation.pickFromCamera).onPress(() => Navigator.of(context).pop(ImageSource.camera)), - gridItem(Icons.image_rounded, context.translation.pickFromGallery).onPress(() => Navigator.of(context).pop(ImageSource.gallery)), - gridItem(Icons.file_present_rounded, context.translation.pickFromFiles).onPress(() async { - await fromFilePicker(); - Navigator.pop(context); - }), - ], - ), - 12.height, - ], - ).paddingAll(21), - )) as ImageSource; - - // if(widget.pickMultiple) { - final pickedFile12 = await ImagePicker().pickMultiImage(imageQuality: 70, maxWidth: 800, maxHeight: 800); - - // // } - // - // final pickedFile = await ImagePicker().pickImage(source: source, imageQuality: 70, maxWidth: 800, maxHeight: 800); - // - // if (pickedFile != null) { - // File fileImage = File(pickedFile.path); - // widget.attachment.add(GenericAttachmentModel(id: 0, name: fileImage.path, documentTypeId: widget.documentType)); - // if (widget.onChange != null) { - // widget.onChange!(widget.attachment); - // } - // setState(() {}); - // } - } - Widget gridItem(IconData iconData, String title) { return Container( padding: const EdgeInsets.all(12), @@ -509,7 +194,7 @@ class _AttachmentPickerState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Icon(iconData, color: AppColor.icon2Color(context), size: 24), + Icon(iconData, color: AppColor.icon2Color(context), size: 24), title.bodyText2(context).custom(color: AppColor.labelTextStyleColor(context), fontSize: context.isTablet() ? 10.toScreenWidth : null), // Text( // title, @@ -521,6 +206,10 @@ class _AttachmentPickerState extends State { } onFilePicker(bool checkQuality) async { + // Reset and restart animation for bottom sheet + _animationController.reset(); + _animationController.forward(); + ImageSource? source = await showModalBottomSheet( context: context, builder: (BuildContext context) { @@ -536,116 +225,95 @@ class _AttachmentPickerState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - icon.toSvgAsset(color: AppColor.icon2Color(context), width: 36, height: 36), + icon.toSvgAsset(width: 24, height: 24, color: AppColor.icon2Color(context)), label.bodyText2(context).custom(color: AppColor.labelTextStyleColor(context), fontSize: context.isTablet() ? 10.toScreenWidth : null), ], ), ).onPress(onTap); } + List listItems = [ + listCard( + icon: 'camera_icon', + label: '${context.translation.open}\n${context.translation.camera}', + onTap: () { + Navigator.of(context).pop(ImageSource.camera); + }, + ), + listCard( + icon: 'gallery_icon', + label: '${context.translation.open}\n${context.translation.gallery}', + onTap: () { + Navigator.of(context).pop(ImageSource.gallery); + }, + ), + listCard( + icon: 'file_icon', + label: '${context.translation.open}\n${context.translation.files}', + onTap: () async { + await fromFilePicker(); + Navigator.pop(context); + }, + ), + ]; + return SafeArea( top: false, child: Container( width: double.infinity, - color: AppColor.background(context), + color: AppColor.bottomSheetColor(context), + padding: const EdgeInsets.all(16.0), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - "Attach File".heading4(context), - 12.height, - GridView( - padding: const EdgeInsets.all(0), + widget.pickerTitle.heading4(context), + GridView.builder( + padding: const EdgeInsets.only(top: 16, bottom: 0), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 12, mainAxisSpacing: 12), - children: [ - listCard( - icon: 'camera_icon', - label: '${context.translation.open}\n${context.translation.camera}', - onTap: () { - Navigator.of(context).pop(ImageSource.camera); - }, - ), - listCard( - icon: 'gallery_icon', - label: '${context.translation.open}\n${context.translation.gallery}', - onTap: () { - Navigator.of(context).pop(ImageSource.gallery); - }, - ), - listCard( - icon: 'file_icon', - label: '${context.translation.open}\n${context.translation.files}', - onTap: () async { - await fromFilePicker(); - Navigator.pop(context); - }, - ), - ], + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 1, crossAxisSpacing: 16, mainAxisSpacing: 16), + itemCount: listItems.length, + itemBuilder: (context, index) { + // Calculate staggered animation delay + final delay = index * 0.08; + final animation = Tween(begin: 0.0, end: 1.0).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.8), + (delay + 0.3).clamp(0.0, 1.0), + curve: Curves.easeOut, + ), + ), + ); + + final slideAnimation = Tween( + begin: const Offset(0.0, 0.3), + end: Offset.zero, + ).animate( + CurvedAnimation( + parent: _animationController, + curve: Interval( + delay.clamp(0.0, 0.8), + (delay + 0.3).clamp(0.0, 1.0), + curve: Curves.easeOutCubic, + ), + ), + ); + + return FadeTransition( + opacity: animation, + child: SlideTransition(position: slideAnimation, child: listItems[index]), + ); + }, ), - // Container( - // padding: const EdgeInsets.all(16.0), - // child: Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // listCard( - // icon: 'camera_icon', - // label: '${context.translation.open}\n${context.translation.camera}', - // onTap: () { - // Navigator.of(context).pop(ImageSource.camera); - // }, - // ), - // listCard( - // icon: 'gallery_icon', - // label: '${context.translation.open}\n${context.translation.gallery}', - // onTap: () { - // Navigator.of(context).pop(ImageSource.gallery); - // }, - // ), - // listCard( - // icon: 'file_icon', - // label: '${context.translation.open}\n${context.translation.files}', - // onTap: () async { - // await fromFilePicker(); - // Navigator.pop(context); - // }, - // ), - // ], - // ), - // ), ], - ).paddingAll(16), + ), ), ); }, ); - // ImageSource source = await showDialog( - // context: context, - // builder: (dialogContext) => CupertinoAlertDialog( - // actions: [ - // TextButton( - // child: Text(context.translation.pickFromCamera), - // onPressed: () { - // Navigator.of(dialogContext).pop(ImageSource.camera); - // }, - // ), - // TextButton( - // child: Text(context.translation.pickFromGallery), - // onPressed: () { - // Navigator.of(dialogContext).pop(ImageSource.gallery); - // }, - // ), - // TextButton( - // child: Text(context.translation.pickFromFiles), - // onPressed: () async { - // await fromFilePicker(); - // Navigator.pop(context); - // }, - // ), - // ], - // ), - // ); if (source == null) return; if (widget.pickMultiple && source == ImageSource.gallery) { diff --git a/lib/views/widgets/images/multi_image_picker_item.dart b/lib/views/widgets/images/multi_image_picker_item.dart index acd8a992..e555a9dd 100644 --- a/lib/views/widgets/images/multi_image_picker_item.dart +++ b/lib/views/widgets/images/multi_image_picker_item.dart @@ -70,15 +70,20 @@ class MultiFilesPickerItem extends StatelessWidget { ), 8.width, if (enabled) - InkWell( - child: "remove".toSvgAsset(width: 16,color: AppColor.red30), - onTap: () { + IconButton( + padding: EdgeInsets.zero, + icon: const Icon(Icons.clear), + iconSize: 18, + style: IconButton.styleFrom(elevation: 2, tapTargetSize: MaterialTapTargetSize.shrinkWrap, backgroundColor: AppColor.red30, foregroundColor: Colors.white), + visualDensity: VisualDensity.compact, + constraints: const BoxConstraints(), + onPressed: () { onRemoveTap(file); if (onRemove != null) { onRemove!(); } }, - ) + ), ], ), 4.height, @@ -92,23 +97,12 @@ class MultiFilesPickerItem extends StatelessWidget { recognizer: TapGestureRecognizer() ..onTap = () async { if (isImage) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - appBar: const DefaultAppBar(), - body: SafeArea( - child: InteractiveViewer( - child: _isLocalUrl(file.path) - ? Image.file(file) - : ImageLoader( - url: URLs.getFileUrl(file.path), - boxFit: BoxFit.cover, - ), - ).center, - ), - ), - ), - ); + context.fullScreenImageViewer(_isLocalUrl(file.path) + ? Image.file(file) + : ImageLoader( + url: URLs.getFileUrl(file.path), + boxFit: BoxFit.cover, + )); } else if (_isLocalUrl(file.path)) { OpenFile.open(file.path); } else { @@ -150,23 +144,12 @@ class MultiFilesPickerItem extends StatelessWidget { padding: EdgeInsets.zero, onPressed: () async { if (isImage) { - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => Scaffold( - appBar: const DefaultAppBar(), - body: SafeArea( - child: InteractiveViewer( - child: _isLocalUrl(file.path) - ? Image.file(file) - : ImageLoader( - url: URLs.getFileUrl(file.path), - boxFit: BoxFit.cover, - ), - ).center, - ), - ), - ), - ); + context.fullScreenImageViewer(_isLocalUrl(file.path) + ? Image.file(file) + : ImageLoader( + url: URLs.getFileUrl(file.path), + boxFit: BoxFit.cover, + )); } else if (_isLocalUrl(file.path)) { OpenFile.open(file.path); } else { @@ -179,9 +162,14 @@ class MultiFilesPickerItem extends StatelessWidget { ), ), if (enabled) - InkWell( - child: "remove".toSvgAsset(width: 16), - onTap: () { + IconButton( + padding: EdgeInsets.zero, + icon: const Icon(Icons.clear), + iconSize: 18, + style: IconButton.styleFrom(elevation: 2, tapTargetSize: MaterialTapTargetSize.shrinkWrap, backgroundColor: AppColor.red30, foregroundColor: Colors.white), + visualDensity: VisualDensity.compact, + constraints: const BoxConstraints(), + onPressed: () { onRemoveTap(file); if (onRemove != null) { onRemove!(); diff --git a/lib/views/widgets/item_views/info_text_widget.dart b/lib/views/widgets/item_views/info_text_widget.dart index 661e1ab5..b3a2b252 100644 --- a/lib/views/widgets/item_views/info_text_widget.dart +++ b/lib/views/widgets/item_views/info_text_widget.dart @@ -51,13 +51,14 @@ class InfoTextWidget extends StatelessWidget { class InfoTextLabelWidget extends StatelessWidget { final String label; + final Color? color; - InfoTextLabelWidget({required this.label, Key? key}) : super(key: key); + InfoTextLabelWidget({required this.label, this.color, Key? key}) : super(key: key); @override Widget build(BuildContext context) { Widget text; - text = Text(label, style: AppTextStyles.bodyText2.copyWith(color: AppColor.lightTextColor(context))); + text = Text(label, style: AppTextStyles.bodyText2.copyWith(color: color ?? AppColor.lightTextColor(context))); return text; } } diff --git a/pubspec.lock b/pubspec.lock index 937cec84..8fa3ed1c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -758,6 +758,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.8.0" + image_blur_detection: + dependency: "direct main" + description: + name: image_blur_detection + sha256: "0d1043422b90b97dea2aa282aa5cbb206e34bdc43acc0cb312b31f160f977333" + url: "https://pub.dev" + source: hosted + version: "1.0.1" image_cropper: dependency: "direct main" description: