@@ -3,12 +3,14 @@ import 'dart:io';
import ' package:flutter/material.dart ' ;
import ' package:flutter/services.dart ' ;
import ' package:flutter_pdfview/flutter_pdfview.dart ' ;
import ' package:getx_scaffold/getx_scaffold.dart ' as dio ;
import ' package:getx_scaffold/getx_scaffold.dart ' ;
import ' package:image_picker/image_picker.dart ' ;
import ' package:ln_jq_app/common/model/base_model.dart ' ;
import ' package:ln_jq_app/common/styles/theme.dart ' ;
import ' package:ln_jq_app/storage_service.dart ' ;
import ' package:path_provider/path_provider.dart ' ;
import ' package:photo_view/photo_view.dart ' ;
import ' package:photo_view/photo_view_gallery.dart ' ;
import ' package:pull_to_refresh/pull_to_refresh.dart ' ;
@@ -794,8 +796,9 @@ class SiteController extends GetxController with BaseControllerMixin {
}
/// 保存图片到相册
Future < void > saveImag eToLocal ( String url ) async {
// 1. 权限请求
Future < void > saveFil eToLocal ( String url ) async {
try {
// 权限请求
if ( Platform . isAndroid ) {
dio . PermissionStatus status ;
@@ -822,28 +825,56 @@ class SiteController extends GetxController with BaseControllerMixin {
showLoading ( " 正在保存... " ) ;
// 2. 下载图片
// 下载文件
var response = await Dio ( ) . get (
url ,
options: Options ( responseType: ResponseType . bytes ) ,
) ;
// 3. 保存到相册
final Uint8List bytes = Uint8List . fromList ( response . data ) ;
if ( url . toLowerCase ( ) . endsWith ( ' .pdf ' ) ) {
String ? savePath ;
if ( Platform . isAndroid ) {
final directory = Directory ( ' /storage/emulated/0/Download ' ) ;
if ( ! await directory . exists ( ) ) {
await directory . create ( recursive: true ) ;
}
final String fileName = " certificate_ ${ DateTime . now ( ) . millisecondsSinceEpoch } .pdf " ;
savePath = " ${ directory . path } / $ fileName " ;
} else {
// iOS: 保存到文档目录
final directory = await getApplicationDocumentsDirectory ( ) ;
final String fileName = " certificate_ ${ DateTime . now ( ) . millisecondsSinceEpoch } .pdf " ;
savePath = " ${ directory . path } / $ fileName " ;
}
final File file = File ( savePath ) ;
await file . writeAsBytes ( bytes ) ;
dismissLoading ( ) ;
showSuccessToast ( Platform . isAndroid ? " PDF已保存至系统下载目录 " : " PDF已保存, 请在'文件'App中查看 " ) ;
} else {
// 保存图片到相册
final result = await SaverGallery . saveImage (
Uint8List . fromList ( response . data ) ,
bytes ,
quality: 100 ,
fileName: " certificate_ ${ DateTime . now ( ) . millisecondsSinceEpoch } " ,
skipIfExists: false ,
) ;
dismissLoading ( ) ;
if ( result . isSuccess ) {
showSuccessToast ( " 图片已保存至相册 " ) ;
} else {
showErrorToast ( " 保存失败 " ) ;
}
}
} catch ( e ) {
dismissLoading ( ) ;
showErrorToast ( " 保存异常 " ) ;
}
}
Widget buildInfoTag ( String label , List < String > images ) {
return GestureDetector (
@@ -888,12 +919,30 @@ class SiteController extends GetxController with BaseControllerMixin {
child: PhotoViewGallery . builder (
scrollPhysics: const BouncingScrollPhysics ( ) ,
builder: ( BuildContext context , int index ) {
return PhotoViewGalleryPageOptions (
imageProvider: NetworkImage ( images [ i ndex ] ) ,
final String url = images [ index ] ;
final bool isPdf = url . toLowerCase ( ) . e ndsWith ( ' .pdf ' ) ;
if ( isPdf ) {
return PhotoViewGalleryPageOptions . customChild (
child: GestureDetector (
onTap: ( ) {
_showSaveMenu ( url ) ;
} ,
child: _buildPdfPreview ( url ) , ) ,
initialScale: PhotoViewComputedScale . contained ,
heroAttributes: PhotoViewHeroAttributes ( tag: images [ index ] ) ,
heroAttributes: PhotoViewHeroAttributes ( tag: url ) ,
onTapDown: ( context , details , controllerValue ) {
_showSaveImage Menu ( images [ index ] ) ;
_showSaveMenu ( url ) ;
} ,
) ;
}
return PhotoViewGalleryPageOptions (
imageProvider: NetworkImage ( url ) ,
initialScale: PhotoViewComputedScale . contained ,
heroAttributes: PhotoViewHeroAttributes ( tag: url ) ,
onTapDown: ( context , details , controllerValue ) {
_showSaveMenu ( url ) ;
} ,
) ;
} ,
@@ -939,7 +988,38 @@ class SiteController extends GetxController with BaseControllerMixin {
) ;
}
void _showSaveImageMenu ( String url ) {
/// PDF 预览小部件
Widget _buildPdfPreview ( String url ) {
return FutureBuilder < String > (
future: _downloadPdf ( url ) ,
builder: ( context , snapshot ) {
if ( snapshot . connectionState = = ConnectionState . waiting ) {
return const Center ( child: CircularProgressIndicator ( color: Colors . white ) ) ;
}
if ( snapshot . hasError | | snapshot . data = = null ) {
return const Center ( child: Text ( " PDF 加载失败 " , style: TextStyle ( color: Colors . white ) ) ) ;
}
return PDFView (
filePath: snapshot . data ! ,
enableSwipe: false ,
swipeHorizontal: false ,
autoSpacing: false ,
pageFling: false ,
) ;
} ,
) ;
}
Future < String > _downloadPdf ( String url ) async {
final file = File ( ' ${ ( await getTemporaryDirectory ( ) ) . path } / ${ url . hashCode } .pdf ' ) ;
if ( await file . exists ( ) ) return file . path ;
var response = await Dio ( ) . get ( url , options: Options ( responseType: ResponseType . bytes ) ) ;
await file . writeAsBytes ( response . data ) ;
return file . path ;
}
void _showSaveMenu ( String url ) {
final bool isPdf = url . toLowerCase ( ) . endsWith ( ' .pdf ' ) ;
Get . bottomSheet (
Container (
color: Colors . white ,
@@ -949,10 +1029,10 @@ class SiteController extends GetxController with BaseControllerMixin {
children: [
ListTile (
leading: const Icon ( Icons . download ) ,
title: const Text ( ' 保存图片到相册 ' ) ,
title: Text ( isPdf ? ' 保存 PDF 文件 ' : ' 保存图片到相册 ' ) ,
onTap: ( ) {
Get . back ( ) ;
saveImag eToLocal ( url ) ;
saveFil eToLocal ( url ) ;
} ,
) ,
const Divider ( height: 1 ) ,