chatapp3-flutter/lib/modules/user/crop/crop_image_page.dart
2026-04-09 21:32:23 +08:00

207 lines
6.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:yumi/app_localizations.dart';
import 'package:yumi/ui_kit/components/sc_tts.dart';
import 'package:yumi/shared/tools/sc_loading_manager.dart';
import 'package:yumi/app/constants/sc_global_config.dart';
import 'package:yumi/app/constants/sc_screen.dart';
import 'package:yumi/app/routes/sc_fluro_navigator.dart';
import 'package:yumi/shared/data_sources/sources/repositories/sc_general_repository_imp.dart';
typedef OnUpLoadCallBack = void Function(bool success, String url);
class CropImagePage extends StatefulWidget {
final double? aspectRatio; // 需要锁定的宽高比,例如 1 表示 1:1
final bool? backOriginalFile;
final OnUpLoadCallBack? onUpLoadCallBack;
final File image; // 原始图片文件
final bool needUpload;
const CropImagePage(this.image, {
Key? key,
this.onUpLoadCallBack,
this.aspectRatio,
this.backOriginalFile = true,
this.needUpload = true,
}) : super(key: key);
@override
_CropImageRouteState createState() => _CropImageRouteState();
}
class _CropImageRouteState extends State<CropImagePage> {
late Image imageView;
@override
void initState() {
super.initState();
imageView = Image.file(widget.image, fit: BoxFit.contain);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xff333333),
body: SafeArea(
top: false,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
// 预览原图
Align(
alignment: Alignment.center,
child: Container(
width: double.infinity,
height:
SCScreen.designHeight -
(kToolbarHeight * 2) -
ScreenUtil().bottomBarHeight -
ScreenUtil().statusBarHeight,
child: imageView,
),
),
// 顶部栏
Align(
alignment: Alignment.topCenter,
child: Container(
height: kToolbarHeight + ScreenUtil().statusBarHeight,
width: double.infinity,
padding: EdgeInsets.only(
left: width(15),
right: width(15),
top: ScreenUtil().statusBarHeight,
),
color: Colors.transparent,
child: Stack(
alignment: Alignment.centerLeft,
children: <Widget>[
GestureDetector(
onTap: () => SCNavigatorUtils.goBackWithParams(context, ''),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
SCGlobalConfig.lang == "ar"
? Icons.keyboard_arrow_right
: Icons.keyboard_arrow_left,
color: Colors.white,
),
),
),
Align(
alignment: Alignment.center,
child: Text(
SCAppLocalizations.of(context)!.crop,
style: TextStyle(fontSize: 18.sp, color: Colors.white),
),
),
],
),
),
),
// 底部完成按钮
Align(
alignment: Alignment.bottomCenter,
child: Container(
width: double.infinity,
height: kToolbarHeight + ScreenUtil().bottomBarHeight,
color: const Color(0xff666666),
alignment: Alignment.centerRight,
child: GestureDetector(
onTap: () =>
_cropAndUpload(context, widget.image, needUpload:widget.needUpload),
child: Padding(
padding: const EdgeInsets.all(8.0).copyWith(right: 18),
child: Text(
SCAppLocalizations.of(context)!.finish,
style: TextStyle(color: Colors.white, fontSize: 16.sp),
),
),
),
),
),
],
),
),
);
}
/// 使用 image_cropper 进行裁剪并上传
Future<void> _cropAndUpload(BuildContext context,
File originalFile, {
bool needUpload = true,
}) async {
// 调用系统裁剪界面
CroppedFile? cropped = await ImageCropper().cropImage(
sourcePath: originalFile.path,
aspectRatio:
widget.aspectRatio != null
? CropAspectRatio(ratioX: widget.aspectRatio!, ratioY: 1)
: null,
uiSettings: [
AndroidUiSettings(
toolbarTitle: SCAppLocalizations.of(context)!.crop,
toolbarColor: Colors.black,
toolbarWidgetColor: Colors.white,
hideBottomControls: true,
lockAspectRatio: widget.aspectRatio != null,
),
IOSUiSettings(
title: SCAppLocalizations.of(context)!.crop,
resetButtonHidden: true,
rotateButtonsHidden: true,
aspectRatioPickerButtonHidden: true,
rotateClockwiseButtonHidden: true,
aspectRatioLockEnabled: widget.aspectRatio != null,
),
],
);
// 用户可能直接点“取消”,此时 cropped 为 null
File fileToUpload;
if (cropped == null) {
if (widget.backOriginalFile ?? true) {
fileToUpload = originalFile;
} else {
widget.onUpLoadCallBack?.call(false, "");
return;
}
} else {
fileToUpload = File(cropped.path);
}
if (needUpload) {
// 弹出上传中的 loading
SCLoadingManager.show(context: context);
await upload(fileToUpload);
} else {
widget.onUpLoadCallBack?.call(true, fileToUpload.path);
SCNavigatorUtils.goBack(context);
}
}
/// 上传文件至oss
Future<void> upload(File file) async {
try {
String fileUrl = await SCGeneralRepositoryImp().upload(file);
SCLoadingManager.hide();
SCNavigatorUtils.goBack(context);
await Future.delayed(const Duration(milliseconds: 100));
widget.onUpLoadCallBack?.call(true, fileUrl);
} catch (e) {
SCTts.show("upload fail $e");
SCLoadingManager.hide();
}
}
/*
* 获取 OssToken如果依然需要可保留
*/
Future<void> _getOssToken() async {}
}