improvements

ui_ux_rollout_merge
Sikander Saleem 2 weeks ago
parent a8667f31c9
commit 072f3da97e

@ -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,7 +333,7 @@ class OneTimeTaskPreviewScreen extends StatelessWidget {
SizedBox(
width: 100,
child: InfoTextLabelWidget(
label:'$label:',
label: '$label:',
),
),
Expanded(

@ -277,24 +277,7 @@ class _CleanerChecklistWidgetState extends State<CleanerChecklistWidget> {
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

@ -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(),
],
),
),
),
),
);
}
}

@ -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)),

@ -205,10 +205,7 @@ class _ServiceRequestDetailViewState extends State<ServiceRequestDetailView> {
],
),
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),

@ -24,7 +24,6 @@ class ChatFileViewer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FutureBuilder<File?>(
future: checkFileInLocalStorage(),
builder: (BuildContext context, AsyncSnapshot<File?> 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);
}

@ -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);
}

@ -200,21 +200,7 @@ class _CleanerChecklistWidgetState extends State<CleanerChecklistWidget> {
),
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<CleanerChecklistWidget> {
),
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<CleanerChecklistWidget> {
),
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(),
],

@ -80,7 +80,7 @@ class _AssetDetailPageState extends State<AssetDetailPage> 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<AssetDetailPage> with SingleTickerProv
))
.toList() ??
[];
// Start animation when data is loaded
if (!_animationController.isCompleted) {
_animationController.forward(from: 0.0);
}
// Image animation - fade in with scale
final imageAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(
@ -238,7 +240,7 @@ class _AssetDetailPageState extends State<AssetDetailPage> 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<AssetDetailPage> 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<AssetDetailPage> 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<AssetDetailPage> with SingleTickerProv
),
),
8.height,
// Details row with animation
FadeTransition(
opacity: detailsAnimation,
@ -294,41 +295,39 @@ class _AssetDetailPageState extends State<AssetDetailPage> 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<AssetDetailPage> 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<AssetDetailPage> 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<AssetDetailPage> 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(

@ -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<AssetImageUploadPage> {
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<AssetImageUploadPage> {
),
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<AssetImageUploadPage> {
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);

@ -129,13 +129,20 @@ class _MyAssetsPageState extends State<MyAssetsPage> with SingleTickerProviderSt
_searchableList.clear();
_searchableList.addAll(_devicesProvider.devices);
}).expanded,
16.width,
Icon(Icons.grid_view_outlined, color: AppColor.icon2Color(context)).onPress(() => setState(() {
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<MyAssetsPage> 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)));

@ -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) {

@ -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<File> files;
// final List<GenericAttachmentModel> attachment;
//
// final bool enabled, onlyImages;
// double? buttonHeight;
// Widget? buttonIcon;
// Color? buttonColor;
// final Function(List<File>)? onChange;
// final bool showAsGrid;
//
// MultiFilesPicker(
// {Key? key,
// this.files = const <File>[],
// this.attachment = const <GenericAttachmentModel>[],
// 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<MultiFilesPicker> createState() => _MultiFilesPickerState();
// }
//
// class _MultiFilesPickerState extends State<MultiFilesPicker> {
// @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: <Widget>[
// 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<ImageSource>(
// 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: <Widget>[
// 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: <Widget>[
// // 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<GenericAttachmentModel> attachment;
@ -322,7 +49,6 @@ class AttachmentPicker extends StatefulWidget {
Widget? buttonIcon;
Color? buttonColor;
final Function(List<GenericAttachmentModel>)? 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 <GenericAttachmentModel>[],
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<AttachmentPicker> createState() => _AttachmentPickerState();
}
class _AttachmentPickerState extends State<AttachmentPicker> {
class _AttachmentPickerState extends State<AttachmentPicker> 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<AttachmentPicker> {
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<AttachmentPicker> {
}
}
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: <Widget>[
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),
@ -521,6 +206,10 @@ class _AttachmentPickerState extends State<AttachmentPicker> {
}
onFilePicker(bool checkQuality) async {
// Reset and restart animation for bottom sheet
_animationController.reset();
_animationController.forward();
ImageSource? source = await showModalBottomSheet<ImageSource>(
context: context,
builder: (BuildContext context) {
@ -536,30 +225,14 @@ class _AttachmentPickerState extends State<AttachmentPicker> {
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);
}
return SafeArea(
top: false,
child: Container(
width: double.infinity,
color: AppColor.background(context),
child: 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: <Widget>[
List<Widget> listItems = [
listCard(
icon: 'camera_icon',
label: '${context.translation.open}\n${context.translation.camera}',
@ -582,70 +255,65 @@ class _AttachmentPickerState extends State<AttachmentPicker> {
Navigator.pop(context);
},
),
],
];
return SafeArea(
top: false,
child: Container(
width: double.infinity,
color: AppColor.bottomSheetColor(context),
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
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: 16, mainAxisSpacing: 16),
itemCount: listItems.length,
itemBuilder: (context, index) {
// Calculate staggered animation delay
final delay = index * 0.08;
final animation = Tween<double>(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<Offset>(
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: <Widget>[
// 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: <Widget>[
// 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) {

@ -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)
context.fullScreenImageViewer(_isLocalUrl(file.path)
? Image.file(file)
: ImageLoader(
url: URLs.getFileUrl(file.path),
boxFit: BoxFit.cover,
),
).center,
),
),
),
);
));
} 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)
context.fullScreenImageViewer(_isLocalUrl(file.path)
? Image.file(file)
: ImageLoader(
url: URLs.getFileUrl(file.path),
boxFit: BoxFit.cover,
),
).center,
),
),
),
);
));
} 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!();

@ -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;
}
}

@ -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:

Loading…
Cancel
Save