From f2ebadf1b77e5cb18130fba82e7097065d1da4f8 Mon Sep 17 00:00:00 2001 From: Sikander Saleem Date: Wed, 10 Dec 2025 10:53:40 +0300 Subject: [PATCH] attachment list view added in files list widget. --- .../loan_module/provider/loan_provider.dart | 6 +- lib/views/widgets/images/files_list.dart | 235 +++++++++++++----- .../widgets/images/multi_image_picker.dart | 1 + .../images/multi_image_picker_item.dart | 8 +- pubspec.lock | 8 + pubspec.yaml | 1 + 6 files changed, 189 insertions(+), 70 deletions(-) diff --git a/lib/modules/loan_module/provider/loan_provider.dart b/lib/modules/loan_module/provider/loan_provider.dart index b5cb0093..b2a3a5e3 100644 --- a/lib/modules/loan_module/provider/loan_provider.dart +++ b/lib/modules/loan_module/provider/loan_provider.dart @@ -1,4 +1,5 @@ import 'package:flutter/cupertino.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:http/http.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/urls.dart'; @@ -8,9 +9,10 @@ import 'dart:convert'; class LoanProvider extends ChangeNotifier { Future addLoanRequest(Map body) async { try { - Response response = await ApiManager.instance.post(URLs.addLoan, body: body); + Response response = await ApiManager.instance.post(URLs.addLoan, body: body, showToast: false); if (response.statusCode >= 200 && response.statusCode < 300) { - // trafRequestDataModel = TrafRequestDataModel.fromJson(json.decode(response.body)["data"]); + String message = (jsonDecode(response.body)["data"] ?? "") + " " + (jsonDecode(response.body)["message"] ?? ""); + Fluttertoast.showToast(msg: message ?? "", toastLength: Toast.LENGTH_LONG); return true; } return false; diff --git a/lib/views/widgets/images/files_list.dart b/lib/views/widgets/images/files_list.dart index 9a24e097..3c3a120c 100644 --- a/lib/views/widgets/images/files_list.dart +++ b/lib/views/widgets/images/files_list.dart @@ -1,10 +1,15 @@ import 'dart:io'; +import 'package:ellipsized_text/ellipsized_text.dart'; +import 'package:flutter/gestures.dart'; 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/int_extensions.dart'; +import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart'; +import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/views/widgets/buttons/app_back_button.dart'; import 'package:test_sa/views/widgets/loaders/image_loader.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -12,78 +17,180 @@ import 'package:url_launcher/url_launcher.dart'; class FilesList extends StatelessWidget { final List images; final EdgeInsets? padding; + final bool showAsListView; - const FilesList({Key? key, this.images = const [], this.padding}) : super(key: key); + const FilesList({Key? key, this.images = const [], this.padding, this.showAsListView = false}) : super(key: key); @override Widget build(BuildContext context) { - return GridView.builder( - padding: const EdgeInsets.only(top: 8, bottom: 8), - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 6, mainAxisSpacing: 8, crossAxisSpacing: 8), - itemCount: images.length, - itemBuilder: (context, itemIndex) { - if (!images[itemIndex].contains(".")) { - return const 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 showAsListView + ? ListView.separated( + shrinkWrap: true, + padding: const EdgeInsets.only(top: 8), + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (cxt, itemIndex) { + if (!images[itemIndex].contains(".")) { + return const 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 Container( - decoration: ShapeDecoration( - color: Colors.white, - shape: RoundedRectangleBorder( - side: const BorderSide(width: 1, color: Color(0xFFEAF1F4)), - borderRadius: BorderRadius.circular(8), - ), - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(8), - child: (isImage - ? (_isLocalUrl(images[itemIndex]) - ? Image.file(File(images[itemIndex])) - : ImageLoader( - url: images[itemIndex], - boxFit: BoxFit.cover, - height: 48, - width: 48, - )) - : 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: getImageObject(itemIndex))).center, - InteractiveViewer(child: getImageWidget(itemIndex)).center, - const ABackButton(), - ], + return Row( + children: [ + Container( + width: 48.toScreenWidth, + height: 48.toScreenWidth, + decoration: ShapeDecoration( + color: Colors.white, + shape: RoundedRectangleBorder( + side: const BorderSide(width: 1, color: Color(0xFFEAF1F4)), + borderRadius: BorderRadius.circular(8), + ), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: (isImage + ? (_isLocalUrl(images[itemIndex]) + ? Image.file(File(images[itemIndex])) + : ImageLoader( + url: images[itemIndex], + boxFit: BoxFit.cover, + height: 48, + width: 48, + )) + : Image.asset("assets/images/${isPdf ? "pdf" : isExcel ? "excel" : "doc"}.png")), ), ), - ), - ), - ); - } 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 '); + 8.width, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + EllipsizedText( + images[itemIndex].split("/").last, + style: AppTextStyles.heading6.copyWith(color: AppColor.black10), + type: EllipsisType.start, // or EllipsisType.middle + ), + 4.height, + RichText( + text: TextSpan( + text: 'Asset Guide | ', + style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral120), + children: [ + TextSpan( + text: 'View', + 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(), + ], + ), + ), + ), + ), + ); + } 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."); + } + } + }, + style: AppTextStyles.bodyText.copyWith(color: AppColor.primary10, decoration: TextDecoration.underline), + ), + ], + ), + ), + ], + ).expanded + ], + ); + }, + separatorBuilder: (cxt, index) => 8.height, + itemCount: images.length) + : GridView.builder( + padding: const EdgeInsets.only(top: 8, bottom: 8), + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 6, mainAxisSpacing: 8, crossAxisSpacing: 8), + itemCount: images.length, + itemBuilder: (context, itemIndex) { + if (!images[itemIndex].contains(".")) { + return const Text("Bad\nFile"); } - } catch (ex) { - Fluttertoast.showToast(msg: "No Viewer found."); - } - } - }); - }, - ); + 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 Container( + decoration: ShapeDecoration( + color: Colors.white, + shape: RoundedRectangleBorder( + side: const BorderSide(width: 1, color: Color(0xFFEAF1F4)), + borderRadius: BorderRadius.circular(8), + ), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: (isImage + ? (_isLocalUrl(images[itemIndex]) + ? Image.file(File(images[itemIndex])) + : ImageLoader( + url: images[itemIndex], + boxFit: BoxFit.cover, + height: 48, + width: 48, + )) + : 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: getImageObject(itemIndex))).center, + InteractiveViewer(child: getImageWidget(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."); + } + } + }); + }, + ); // return ListView.separated( // padding: padding ?? EdgeInsets.symmetric(horizontal: 32 * AppStyle.getScaleFactor(context)), diff --git a/lib/views/widgets/images/multi_image_picker.dart b/lib/views/widgets/images/multi_image_picker.dart index 7105721e..e2973118 100644 --- a/lib/views/widgets/images/multi_image_picker.dart +++ b/lib/views/widgets/images/multi_image_picker.dart @@ -363,6 +363,7 @@ class _AttachmentPickerState extends State { ? ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), + padding: EdgeInsets.zero, itemBuilder: (cxt, index) { File image = File(widget.attachment[index].name!); return MultiFilesPickerItem( diff --git a/lib/views/widgets/images/multi_image_picker_item.dart b/lib/views/widgets/images/multi_image_picker_item.dart index 2a794125..662e7e4e 100644 --- a/lib/views/widgets/images/multi_image_picker_item.dart +++ b/lib/views/widgets/images/multi_image_picker_item.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:ellipsized_text/ellipsized_text.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; @@ -59,11 +60,10 @@ class MultiFilesPickerItem extends StatelessWidget { Row( children: [ Flexible( - child: Text( + child: EllipsizedText( file.path.split("/").last, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: AppTextStyles.heading6.copyWith(color: AppColor.black10), + style: AppTextStyles.bodyText.copyWith(color: AppColor.black10), + type: EllipsisType.start, // or EllipsisType.middle ), ), 8.width, diff --git a/pubspec.lock b/pubspec.lock index 44813421..f09bc410 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -265,6 +265,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + ellipsized_text: + dependency: "direct main" + description: + name: ellipsized_text + sha256: d4d372c2baf8d4adfb2ca3728c1e5955d1683e75fae774b311d557ad13317105 + url: "https://pub.dev" + source: hosted + version: "1.2.0" fake_async: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a7689979..35ecdeaa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -98,6 +98,7 @@ dependencies: tree_view_flutter: ^1.0.2 audio_waveforms: ^1.3.0 signalr_netcore: ^1.4.4 + ellipsized_text: ^1.2.0 local_auth_darwin: any dev_dependencies: