feat:增加闪灵上传图片功能

This commit is contained in:
2025-11-11 18:27:41 +08:00
parent 4ac7b2a698
commit 703a5a6aeb
7 changed files with 212 additions and 14 deletions

View File

@@ -25,7 +25,7 @@ class FlispPageState extends State<FlispPage> {
late List<Flisp> _flisps;
FlispTab _currentTab = FlispTab.all;
// 获取过滤后的待办事项
// 获取过滤后的闪灵事项
List<Flisp> get _activeFlisps => getActiveFlisps(_currentTab, _flisps);
void showAddDialog() {

View File

@@ -0,0 +1,57 @@
import 'dart:io';
import 'package:crypto/crypto.dart';
import 'package:file_picker/file_picker.dart';
import 'package:minio/io.dart';
import 'package:minio/minio.dart';
class MinIOHelper {
static final MinIOHelper _instance = MinIOHelper._internal();
factory MinIOHelper() => _instance;
final String rustfsIp = '14.103.235.151';
final String rustfsFileUrl = 'http://14.103.235.151:9100';
final String bucketName = 'flisp';
MinIOHelper._internal() {
_minio = Minio(
endPoint: rustfsIp,
port: 9100,
accessKey: "tHSFfcDW8qpCzKa2Xg6Y",
secretKey: "oq79EeYJ4jdczRp2IHUMCnbKtSw58NgDlG3sOkvX",
useSSL: false,
);
}
late Minio _minio;
Future<String> uploadFile({
required PlatformFile file,
Function(double)? onProgress,
}) async {
try {
String hashName = await _generateMD5HashName(file.path!);
String fileName = '$hashName${_getFileExtension(file.name)}';
await _minio.fPutObject(bucketName, fileName, file.path!);
return fileName;
} catch (e) {
throw Exception('文件上传失败: $e');
}
}
String _getFileExtension(String fileName) {
if (fileName.contains('.')) {
return '.${fileName.split('.').last.toLowerCase()}';
}
return '';
}
Future<String> _generateMD5HashName(String filePath) async {
final file = File(filePath);
final bytes = await file.readAsBytes();
final hash = md5.convert(bytes);
return hash.toString();
}
}

View File

@@ -1,5 +1,7 @@
import 'package:file_picker/file_picker.dart';
import 'package:flisp_app/models/flisp.dart';
import 'package:flisp_app/provider/flisp_provider.dart';
import 'package:flisp_app/utils/minio_utils.dart';
import 'package:flisp_app/widgets/flisp_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
@@ -45,6 +47,21 @@ class _FlispFormState extends State<FlispForm> {
});
}
void _selectImage(String fileName) {
final provider = Provider.of<FlispProvider>(context, listen: false);
setState(() {
provider.formItem.imageUrl =
'${MinIOHelper().rustfsFileUrl}/${MinIOHelper().bucketName}/$fileName';
});
}
void _deleteImage() {
final provider = Provider.of<FlispProvider>(context, listen: false);
setState(() {
provider.formItem.imageUrl = '';
});
}
@override
Widget build(BuildContext context) {
final int maxContentCount = 100;
@@ -105,15 +122,35 @@ class _FlispFormState extends State<FlispForm> {
SizedBox(height: 8),
buildFlispTag(provider.formItem),
SizedBox(height: 12),
if (provider.formItem.imageUrl.isNotEmpty)
buildFlispImage(
flisp: provider.formItem,
showDelete: true,
onDelete: _deleteImage,
),
],
),
),
);
}
void selectImage() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'jpeg', 'png'],
allowMultiple: false,
);
if (result != null) {
PlatformFile file = result.files.first;
final fileName = await MinIOHelper().uploadFile(file: file);
_selectImage(fileName);
}
}
Widget buildSelectImageButton() {
return GestureDetector(
onTap: () {},
onTap: () => selectImage(),
child: Container(
width: 36,
height: 36,

View File

@@ -98,26 +98,64 @@ Widget _buildFlispContent(Flisp flisp) {
);
}
Widget _buildFlispImage(Flisp flisp) {
Widget _buildDeleteImage(VoidCallback? onDelete) {
return Positioned(
top: -8,
right: 0,
child: GestureDetector(
onTap: onDelete,
child: Container(
width: 24,
height: 24,
decoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(10),
blurRadius: 4,
offset: Offset(0, 2),
),
],
),
child: Icon(Icons.close, color: Colors.white, size: 16),
),
),
);
}
Widget buildFlispImage({
required Flisp flisp,
bool showDelete = false,
VoidCallback? onDelete,
}) {
return Container(
height: 150,
height: 200,
margin: const EdgeInsets.only(bottom: 8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
image: DecorationImage(
image: NetworkImage(flisp.imageUrl),
fit: BoxFit.cover,
fit: BoxFit.contain,
),
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.black.withOpacity(0.3),
color: Colors.black.withAlpha(10),
),
alignment: Alignment.topRight,
child: const Padding(
padding: EdgeInsets.all(6.0),
child: Icon(Icons.image, color: Colors.white, size: 20),
child: Stack(
clipBehavior: Clip.none,
children: [
Align(
alignment: Alignment.topRight,
child: const Padding(
padding: EdgeInsets.all(6.0),
child: Icon(Icons.image, color: Colors.white, size: 20),
),
),
if (showDelete) _buildDeleteImage(onDelete),
],
),
),
);
@@ -253,7 +291,7 @@ Widget _buildFlispItem({
children: [
_buildFlispContent(flisp),
const SizedBox(height: 8),
if (hasImage) _buildFlispImage(flisp),
if (hasImage) buildFlispImage(flisp: flisp, showDelete: false),
const SizedBox(height: 4),
if (hasVideo) _buildFlispVideo(flisp),
const SizedBox(height: 4),

View File

@@ -5,12 +5,14 @@
import FlutterMacOS
import Foundation
import file_picker
import flutter_local_notifications
import path_provider_foundation
import rive_native
import shared_preferences_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
RiveNativePlugin.register(with: registry.registrar(forPlugin: "RiveNativePlugin"))

View File

@@ -54,6 +54,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.2"
buffer:
dependency: transitive
description:
name: buffer
sha256: "389da2ec2c16283c8787e0adaede82b1842102f8c8aae2f49003a766c5c6b3d1"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.3"
build:
dependency: transitive
description:
@@ -166,8 +174,16 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.2"
crypto:
cross_file:
dependency: transitive
description:
name: cross_file
sha256: "942a4791cd385a68ccb3b32c71c427aba508a1bb949b86dff2adbe4049f16239"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.3.5"
crypto:
dependency: "direct main"
description:
name: crypto
sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf
@@ -222,6 +238,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "7.0.1"
file_picker:
dependency: "direct main"
description:
name: file_picker
sha256: f2d9f173c2c14635cc0e9b14c143c49ef30b4934e8d1d274d6206fcb0086a06f
url: "https://pub.flutter-io.cn"
source: hosted
version: "10.3.3"
fixnum:
dependency: transitive
description:
@@ -280,6 +304,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: c2fe1001710127dfa7da89977a08d591398370d099aacdaa6d44da7eb14b8476
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.31"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -490,6 +522,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.0"
minio:
dependency: "direct main"
description:
name: minio
sha256: ee2ce47766e46c7d164f960f2f5ed6a9a82844d877f6b82574f6876ec50c56d1
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.5.8"
nested:
dependency: transitive
description:
@@ -863,6 +903,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.3"
win32:
dependency: transitive
description:
name: win32
sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba"
url: "https://pub.flutter-io.cn"
source: hosted
version: "5.13.0"
xdg_directories:
dependency: transitive
description:

View File

@@ -35,19 +35,35 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.8
provider: ^6.1.1 # 状态管理
shared_preferences: ^2.2.2 # 本地存储
# 状态管理
provider: ^6.1.1
# 本地存储
shared_preferences: ^2.2.2
# 对话框组件
awesome_dialog: ^3.3.0
# 切换开关组件
toggle_switch: ^2.3.0
# 轻量级提示
fluttertoast: ^8.2.2
# 表单构建器
flutter_form_builder: ^10.0.0
# 表单验证器
form_builder_validators: ^10.0.0
# 国际化支持
intl: ^0.19.0
# 轻量级NoSQL数据库
hive: ^2.2.3
# Hive的Flutter集成
hive_flutter: ^1.1.0
# 路径提供器
path_provider: ^2.1.1
# 本地通知
flutter_local_notifications: ^18.0.0
# 时区支持
timezone: ^0.10.1
file_picker: ^10.3.3
minio: ^3.5.8
crypto: ^3.0.7
dev_dependencies:
flutter_test: