Commit 9c259642 by tanghuan

dev

1 parent 128403df
......@@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:appframe/config/constant.dart';
import 'package:appframe/config/locator.dart';
import 'package:appframe/config/routes.dart';
import 'package:appframe/data/models/message/h5_message.dart';
......@@ -510,6 +511,7 @@ class WebCubit extends Cubit<WebState> {
pickerConfig: CameraPickerConfig(
enableRecording: true,
onlyEnableRecording: true,
// enableTapRecording: true,
maximumRecordingDuration: Duration(seconds: maxDuration),
),
);
......@@ -704,7 +706,7 @@ class WebCubit extends Cubit<WebState> {
throw Exception("录音器未初始化");
}
if (state.recordState != 1) {
if (state.recordState != 1 && state.recordState != 2) {
throw Exception("录音器状态错误");
}
......@@ -730,7 +732,10 @@ class WebCubit extends Cubit<WebState> {
// var duration = await AudioUtil.getAudioDuration(mp3Path);
var duration = await AudioUtil.getAudioDuration(url);
return {'tempFilePath': mp3Path, 'duration': duration.inSeconds};
return {
'tempFilePath': 'http://127.0.0.1:${Constant.localServerPort}/temp$mp3Path',
'duration': duration.inSeconds,
};
}
/// 清空录音
......@@ -827,7 +832,7 @@ class WebCubit extends Cubit<WebState> {
throw Exception("播放器未初始化");
}
if (state.playState != 1) {
if (state.playState != 1 && state.playState != 2) {
throw Exception("播放器状态错误");
}
......
import 'package:appframe/config/constant.dart';
import 'package:appframe/config/locator.dart';
import 'package:appframe/config/routes.dart';
import 'package:appframe/data/repositories/wechat_auth_repository.dart';
......@@ -62,10 +63,7 @@ class WechatAuthCubit extends Cubit<WechatAuthState> {
_fluwx = getIt.get<Fluwx>();
_fluwx.addSubscriber(_responseListener);
// _textEditingController = TextEditingController()..text = '127.0.0.1';
// _textEditingController = TextEditingController()..text = 'appdev-th.banxiaoer.net';
_textEditingController = TextEditingController()..text = 'appdev-xj.banxiaoer.net';
// _textEditingController = TextEditingController()..text = '192.168.1.136';
_textEditingController = TextEditingController()..text = Constant.h5Server;
_wechatAuthRepository = getIt<WechatAuthRepository>();
}
......@@ -88,10 +86,8 @@ class WechatAuthCubit extends Cubit<WechatAuthState> {
sharedPreferences.setString('auth_userCode', userCode);
sharedPreferences.setString('auth_classCode', classCode);
sharedPreferences.setInt('auth_userType', userType);
sharedPreferences.setString('auth_stuId', stuId??'');
// sharedPreferences.setString('auth_ip', 'appdev-th.banxiaoer.net');
sharedPreferences.setString('auth_ip', 'appdev-xj.banxiaoer.net');
// sharedPreferences.setString('auth_ip', '192.168.1.136');
sharedPreferences.setString('auth_stuId', stuId ?? '');
sharedPreferences.setString('auth_ip', Constant.h5Server);
router.go(
'/web',
......
class Constant {
static const String localServerHost = '127.0.0.1';
static const int localServerPort = 35982;
static const String localServerUrl = 'http://$localServerHost:$localServerPort';
// static const String h5Server = 'appdev-xj.banxiaoer.net';
static const String h5Server = 'appdev-th.banxiaoer.net';
}
......@@ -6,6 +6,7 @@ import 'package:appframe/data/repositories/message/choose_image_handler.dart';
import 'package:appframe/data/repositories/message/choose_video_handler.dart';
import 'package:appframe/data/repositories/message/clipboard_data_handler.dart';
import 'package:appframe/data/repositories/message/compress_handler.dart';
import 'package:appframe/data/repositories/message/crop_image_handler.dart';
import 'package:appframe/data/repositories/message/device_info_handler.dart';
import 'package:appframe/data/repositories/message/download_file_handler.dart';
import 'package:appframe/data/repositories/message/go_login_handler.dart';
......@@ -57,13 +58,13 @@ Future<void> setupLocator() async {
/// 设备信息
getIt.registerLazySingleton<MessageHandler>(() => DeviceInfoHandler(), instanceName: 'getDeviceInfo');
// 位置信息
/// 位置信息
getIt.registerLazySingleton<MessageHandler>(() => LocationHandler(), instanceName: 'getLocation');
// 网络信息
/// 网络信息
getIt.registerLazySingleton<MessageHandler>(() => NetworkTypeHandler(), instanceName: 'getNetworkType');
// wifi信息
/// wifi信息
getIt.registerLazySingleton<MessageHandler>(() => WifiInfoHandler(), instanceName: 'getWifiInfo');
/// 设备方向
......@@ -140,6 +141,9 @@ Future<void> setupLocator() async {
getIt.registerLazySingleton<MessageHandler>(() => AudioStopHandler(), instanceName: 'audioStop');
getIt.registerLazySingleton<MessageHandler>(() => AudioClearHandler(), instanceName: 'audioClear');
/// 裁剪图片
getIt.registerLazySingleton<MessageHandler>(() => CropImageHandler(), instanceName: 'cropImage');
/// 震动
getIt.registerLazySingleton<MessageHandler>(() => VibrateShortHandler(), instanceName: 'vibrateShort');
......
final int serverPort = 35982;
import 'dart:io';
import 'package:appframe/config/constant.dart';
import 'package:appframe/services/dispatcher.dart';
import 'package:appframe/utils/file_type_util.dart';
import 'package:appframe/utils/thumbnail_util.dart';
import 'package:file_picker/file_picker.dart';
import 'package:image_size_getter/file_input.dart';
import 'package:image_size_getter/image_size_getter.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:video_player/video_player.dart';
class ChooseFileHandler extends MessageHandler {
@override
......@@ -16,7 +17,11 @@ class ChooseFileHandler extends MessageHandler {
throw Exception('参数错误');
}
final count = params['count'] as int;
var count = 1;
if (params.containsKey('count')) {
count = params['count'] as int;
}
final fileTypes = params['fileTypes'] as List<dynamic>;
FilePickerResult? filePickerResult = await FilePicker.platform.pickFiles(
......@@ -27,7 +32,7 @@ class ChooseFileHandler extends MessageHandler {
// 用户取消选择,返回空数组
if (filePickerResult == null) {
return [];
throw Exception('cancel');
}
// 限制最多count个文件
......@@ -40,21 +45,12 @@ class ChooseFileHandler extends MessageHandler {
result.add(await _handleFile(file));
}
return result;
return {'tempFiles': result};
}
Future<Map<String, dynamic>> _handleFile(PlatformFile file) async {
// 获取临时目录
final tempDir = await getTemporaryDirectory();
// 临时文件路径
// final uniqueFileName = '${DateTime.now().millisecondsSinceEpoch}_${file.name}';
// final tempFilePath = path.join(tempDir.path, uniqueFileName);
// 所选中的文件已经被插件复制到临时目录,所以不需要再复制
final originalFile = File(file.path!);
// final copiedFile = await originalFile.copy(tempFilePath);
bool isImage = await FileTypeUtil.isImage(originalFile);
bool isVideo = false;
......@@ -62,25 +58,43 @@ class ChooseFileHandler extends MessageHandler {
isVideo = await FileTypeUtil.isVideo(originalFile);
}
// 通过image_size_getter获取图片尺寸
SizeResult? sizeResult;
String? thumbTempFilePath;
int? imgWidth, imgHeight;
String? imgThumbFilePath;
if (isImage) {
sizeResult = ImageSizeGetter.getSizeResult(FileInput(originalFile));
thumbTempFilePath = await ThumbnailUtil.genTempThumbnail(originalFile, tempDir);
// 通过image_size_getter获取图片尺寸
var sizeResult = ImageSizeGetter.getSizeResult(FileInput(originalFile));
var size = sizeResult.size;
imgWidth = sizeResult.size.width;
imgHeight = sizeResult.size.height;
final tempDir = await getTemporaryDirectory();
imgThumbFilePath = await ThumbnailUtil.genTempThumbnail(originalFile, tempDir);
}
double? videoWidth, videoHeight;
String? videoThumbFilePath;
if (isVideo) {
thumbTempFilePath = await ThumbnailUtil.genVideoThumbnail(originalFile.path, tempDir);
// 获取视频尺寸
VideoPlayerController controller = VideoPlayerController.file(originalFile);
await controller.initialize();
var size = controller.value.size;
videoWidth = size.width;
videoHeight = size.height;
controller.dispose();
final tempDir = await getTemporaryDirectory();
videoThumbFilePath = await ThumbnailUtil.genVideoThumbnail(originalFile.path, tempDir);
}
// 返回临时文件信息
return {
'tempFilePath': '/temp${originalFile.path}',
'tempFilePath': 'http://127.0.0.1:${Constant.localServerPort}/temp${file.path}',
'size': file.size,
'width': sizeResult != null ? sizeResult.size.width : '',
'height': sizeResult != null ? sizeResult.size.height : '',
'thumbTempFilePath': thumbTempFilePath ?? '',
'fileType': originalFile.path.split('/').last.split('.').last,
'width': isImage ? imgWidth : (isVideo ? videoWidth : ''),
'height': isImage ? imgHeight : (isVideo ? videoHeight : ''),
'thumbTempFilePath': isImage
? 'http://127.0.0.1:${Constant.localServerPort}/temp$imgThumbFilePath'
: (isVideo ? 'http://127.0.0.1:${Constant.localServerPort}/temp$videoThumbFilePath' : ''),
'fileType': file.extension,
};
}
}
import 'dart:io';
import 'dart:typed_data';
import 'package:appframe/config/constant.dart';
import 'package:appframe/services/dispatcher.dart';
import 'package:dio/dio.dart';
import 'package:image/image.dart' as img;
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:uuid/uuid.dart';
class CropImageHandler extends MessageHandler {
@override
......@@ -6,11 +15,11 @@ class CropImageHandler extends MessageHandler {
if (params is! Map<String, dynamic>) {
throw Exception('参数错误');
}
var url = params['sourceType'] as String?;
var url = params['url'] as String?;
if (url == null || url.isEmpty) {
throw Exception('参数错误');
}
var cropScale = params['scale'] as String?;
var cropScale = params['cropScale'] as String?;
if (cropScale == null || cropScale.isEmpty) {
throw Exception('参数错误');
}
......@@ -19,7 +28,78 @@ class CropImageHandler extends MessageHandler {
throw Exception('参数错误');
}
return false;
try {
String outputPath = await _cropImageByRatio(url, cropScale);
return {'tempFilePath': 'http://127.0.0.1:${Constant.localServerPort}/temp$outputPath'};
} catch (e) {
throw Exception('裁剪出错');
}
}
Future<String> _cropImageByRatio(String url, String cropScale) async {
if (url.startsWith('http://127.0.0.1:${Constant.localServerPort}')) {
url = url.replaceFirst('http://127.0.0.1:${Constant.localServerPort}', '');
}
if (url.startsWith('/temp')) {
url = url.substring(5);
}
String extension = path.extension(url);
Directory cacheDirectory = await getApplicationCacheDirectory();
File imageFile;
// 对于远程图片,先下载到应用缓存目录,然后生成File
if (url.startsWith('https://') || url.startsWith('http://')) {
String tempFilePath = '${cacheDirectory.path}/${Uuid().v4()}$extension';
Dio dio = Dio();
Response resp = await dio.download(url, tempFilePath);
if (resp.statusCode != 200) {
throw Exception('下载图片失败');
}
dio.close(force: true);
imageFile = File(tempFilePath);
}
// 对于本地路径,直接生成File
else {
imageFile = File(url);
}
// 1. 读取图片文件并解码
Uint8List bytes = await imageFile.readAsBytes();
img.Image originalImage = img.decodeImage(bytes)!;
int originalWidth = originalImage.width;
int originalHeight = originalImage.height;
// 2. 计算目标裁剪区域
var targetRatio = cropScale.split(":");
double targetAspect = int.parse(targetRatio[0]) / int.parse(targetRatio[1]); // 例如 16/9
double currentAspect = originalWidth / originalHeight;
int cropWidth, cropHeight;
if (currentAspect > targetAspect) {
// 原图更宽,以高度为基准裁剪宽度
cropHeight = originalHeight;
cropWidth = (originalHeight * targetAspect).round();
} else {
// 原图更高,以宽度为基准裁剪高度
cropWidth = originalWidth;
cropHeight = (originalWidth / targetAspect).round();
}
// 3. 计算居中裁剪的起始点
int startX = (originalWidth - cropWidth) ~/ 2;
int startY = (originalHeight - cropHeight) ~/ 2;
// 4. 执行裁剪
img.Image croppedImage = img.copyCrop(originalImage, x: startX, y: startY, width: cropWidth, height: cropHeight);
// 5. 保存裁剪后的图片
String outputPath = '${cacheDirectory.path}/${Uuid().v4()}$extension';
await File(outputPath).writeAsBytes(img.encodeJpg(croppedImage));
return outputPath;
}
}
import 'package:appframe/config/constant.dart';
import 'package:appframe/services/dispatcher.dart';
import 'package:open_file/open_file.dart';
import 'package:url_launcher/url_launcher.dart';
class OpenDocumentHandler extends MessageHandler {
......@@ -7,12 +9,25 @@ class OpenDocumentHandler extends MessageHandler {
if (params is! Map<String, dynamic>) {
throw Exception('参数错误');
}
final url = params['url'] as String;
var url = params['url'] as String;
if (url.isEmpty) {
throw Exception('参数错误');
}
return await _launchInBrowser(Uri.parse(url));
if (url.startsWith('http://127.0.0.1:${Constant.localServerPort}')) {
url = url.replaceFirst('http://127.0.0.1:${Constant.localServerPort}', '');
}
if (url.startsWith('/temp')) {
url = url.substring(5);
}
if (url.startsWith('http')) {
return await _launchInBrowser(Uri.parse(url));
} else {
return await _open(url);
}
}
Future<bool> _launchInBrowser(Uri url) async {
......@@ -21,8 +36,11 @@ class OpenDocumentHandler extends MessageHandler {
} else {
throw Exception('Could not launch $url');
}
/*if (!await launchUrl(url, mode: LaunchMode.externalNonBrowserApplication)) {
throw Exception('Could not launch $url');
}*/
}
/// 暂时就简单打开一下,未做复杂调用
Future<bool> _open(String filePath) async {
var r = await OpenFile.open("filePath");
return r.type == ResultType.done;
}
}
import 'dart:io';
import 'package:appframe/config/constant.dart';
import 'package:appframe/services/api_service.dart';
import 'package:appframe/services/dispatcher.dart';
import 'package:appframe/utils/file_type_util.dart';
......@@ -19,7 +20,17 @@ class UploadFileHandler extends MessageHandler {
throw Exception('参数错误');
}
final result = await compute(_handleUpload, {'filePath': tempFilePath});
final String? busi = params['busi'] as String?;
if (busi == null || busi.isEmpty) {
throw Exception('参数错误');
}
final String? subBusi = params['subBusi'] as String?;
if (subBusi == null || subBusi.isEmpty) {
throw Exception('参数错误');
}
final result = await compute(_handleUpload, {'filePath': tempFilePath, 'busi': busi, 'subBusi': subBusi});
// final result = await _handleUpload({'filePath': tempFilePath});
return result;
......@@ -32,19 +43,27 @@ class UploadFileHandler extends MessageHandler {
/// 在Isolate中执行
static Future<Map<String, dynamic>> _handleUpload(Map<String, dynamic> fileParams) async {
var filePath = fileParams['filePath'] as String;
String filePath = fileParams['filePath'] as String;
String busi = fileParams['busi'] as String;
String subBusi = fileParams['subBusi'] as String;
if (filePath.startsWith('http://127.0.0.1:${Constant.localServerPort}')) {
filePath = filePath.replaceFirst('http://127.0.0.1:${Constant.localServerPort}', '');
}
if (filePath.startsWith('/temp')) {
filePath = filePath.substring(5);
}
String logicPrefix = _getLoginPrefix(busi, subBusi);
final bxeApiService = ApiService(baseUrl: _bxeBaseUrl);
// 由于服务端签名时未设置Content-Type,这里必须设置为空,否则会报签名错误
// 由于封装有默认值,所以不能不设置
final obsApiService = ApiService(defaultHeaders: {'Content-Type': '', 'Accept': ''});
//并行上传分段
final uploadResult = await _uploadInParallel(bxeApiService, obsApiService, filePath);
final uploadResult = await _uploadInParallel(bxeApiService, obsApiService, logicPrefix, filePath);
String objectKey = uploadResult['objectKey'] as String;
String bucket = uploadResult['bucket'] as String;
String uploadId = uploadResult['uploadId'] as String;
......@@ -57,15 +76,17 @@ class UploadFileHandler extends MessageHandler {
bxeApiService.close();
obsApiService.close();
return {'url': response.data['location']};
return {'url': _addPreUrl(response.data["location"])};
}
/// 并行上传
static Future<Map<String, dynamic>> _uploadInParallel(ApiService bxeApiService,
ApiService obsApiService,
String filePath, {
int maxConcurrency = 5,
}) async {
static Future<Map<String, dynamic>> _uploadInParallel(
ApiService bxeApiService,
ApiService obsApiService,
String logicPrefix,
String filePath, {
int maxConcurrency = 5,
}) async {
//判断文件
File file = File(filePath);
if (!file.existsSync()) {
......@@ -97,8 +118,7 @@ class UploadFileHandler extends MessageHandler {
//生成唯一文件名,
// String objectKey = 'd2/test/file.csv';
var uuid = Uuid();
// String objectKey = '${uuid.v5(Namespace.url.value, 'www.banxiaoer.com')}${path.extension(file.path)}';
String objectKey = '${uuid.v4()}${path.extension(file.path)}';
String objectKey = '$logicPrefix/${uuid.v4()}${path.extension(file.path)}';
String uploadId = '';
Map<int, String> tagsMap = {};
......@@ -149,24 +169,27 @@ class UploadFileHandler extends MessageHandler {
}
/// 每次上传前,请求后端获取签名信息
static Future<Map<String, dynamic>> _next(ApiService bxeApiService,
String objectKey,
String bucket,
String uploadId,
int partNum,) async {
static Future<Map<String, dynamic>> _next(
ApiService bxeApiService,
String objectKey,
String bucket,
String uploadId,
int partNum,
) async {
var endpoint = '$_signatureNextUrl?objectKey=$objectKey&bucket=$bucket&uploadId=$uploadId&partNum=$partNum';
final resp = await bxeApiService.get(endpoint);
return resp.data;
}
/// 上传段,按照最大重试次数进行上传重试
static Future<void> _uploadChunkWithRetry(ApiService obsApiService,
String signUrl,
int chunkIndex,
Uint8List chunk,
Map<int, String> tagsMap, {
int maxRetries = 3,
}) async {
static Future<void> _uploadChunkWithRetry(
ApiService obsApiService,
String signUrl,
int chunkIndex,
Uint8List chunk,
Map<int, String> tagsMap, {
int maxRetries = 3,
}) async {
for (int attempt = 0; attempt <= maxRetries; attempt++) {
try {
final resp = await _uploadChunk(obsApiService, signUrl, chunk);
......@@ -201,11 +224,13 @@ class UploadFileHandler extends MessageHandler {
}
/// 请求合并文件
static Future<Response> _merge(ApiService bxeApiService,
String objectKey,
String bucket,
String uploadId,
Map<int, String> tagsMap,) async {
static Future<Response> _merge(
ApiService bxeApiService,
String objectKey,
String bucket,
String uploadId,
Map<int, String> tagsMap,
) async {
final parts = [];
for (int i = 1; i <= tagsMap.length; i++) {
parts.add({'partNumber': i, 'etag': tagsMap[i]});
......@@ -224,4 +249,27 @@ class UploadFileHandler extends MessageHandler {
return response;
}
static String _getLoginPrefix(String busi, String subBusi) {
var now = DateTime.now();
var year = now.year;
var month = now.month;
var day = now.day;
return '/d2/pridel/user/$year$month$day/bxe/${busi}_$subBusi';
}
static String _addPreUrl(String location) {
// /bxe-pics//d2/pridel/user/20251017/bxe/bxe_homework/f4ea233d-9e1b-4a3f-bc8f-b64e776f42a6.jpg
// 多了一个斜杠,暂时多截取1位
if (location.startsWith('/bxe-files')) {
return 'https://files-obs.banxiaoer.com${location.substring(11)}';
} else if (location.startsWith('/bxe-pics')) {
return 'https://pics-obs.banxiaoer.com${location.substring(10)}';
} else if (location.startsWith('/bxe-videos')) {
return 'https://videos-obs.banxiaoer.com${location.substring(12)}';
} else {
return location;
}
}
}
import 'dart:io';
import 'package:appframe/config/constant.dart';
import 'package:archive/archive.dart';
import 'package:dio/dio.dart';
import 'package:flutter/services.dart';
......@@ -13,7 +14,7 @@ class LocalServerService {
// 测试情况下, 每次启动服务,先解压dist文件
_extractDist();
HttpServer server = await HttpServer.bind(InternetAddress.loopbackIPv4, 35982);
HttpServer server = await HttpServer.bind(InternetAddress.loopbackIPv4, Constant.localServerPort);
print('本地服务器启动在端口: ${server.port}');
server.listen((HttpRequest request) async {
......@@ -189,13 +190,19 @@ class LocalServerService {
var distUrl = "https://github.com/xinxin-wu/flutter_web_dist/releases/download/v1.0.0/dist.zip";
// Dio进行下载
var dio = Dio();
dio.download(distUrl, '$httpDirectory/dist.zip', onReceiveProgress: (received, total) {
if (total != -1) {
print((received / total * 100).toStringAsFixed(0) + "%");
}
}).then((_) {
_extractDist();
});
dio
.download(
distUrl,
'$httpDirectory/dist.zip',
onReceiveProgress: (received, total) {
if (total != -1) {
print((received / total * 100).toStringAsFixed(0) + "%");
}
},
)
.then((_) {
_extractDist();
});
dio.close();
}
}
......@@ -365,42 +365,10 @@ packages:
dependency: "direct main"
description:
name: file_picker
sha256: e7e16c9d15c36330b94ca0e2ad8cb61f93cd5282d0158c09805aed13b5452f22
sha256: f2d9f173c2c14635cc0e9b14c143c49ef30b4934e8d1d274d6206fcb0086a06f
url: "https://pub.flutter-io.cn"
source: hosted
version: "10.3.2"
file_selector_linux:
dependency: transitive
description:
name: file_selector_linux
sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.9.3+2"
file_selector_macos:
dependency: transitive
description:
name: file_selector_macos
sha256: "19124ff4a3d8864fdc62072b6a2ef6c222d55a3404fe14893a3c02744907b60c"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.9.4+4"
file_selector_platform_interface:
dependency: transitive
description:
name: file_selector_platform_interface
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.6.2"
file_selector_windows:
dependency: transitive
description:
name: file_selector_windows
sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.9.3+4"
version: "10.3.3"
fixnum:
dependency: transitive
description:
......@@ -709,70 +677,14 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "4.1.2"
image_picker:
image:
dependency: "direct main"
description:
name: image_picker
sha256: "736eb56a911cf24d1859315ad09ddec0b66104bc41a7f8c5b96b4e2620cf5041"
name: image
sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.2.0"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
sha256: dd7a61daaa5896cc34b7bc95f66c60225ae6bee0d167dde0e21a9d9016cac0dc
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.8.13+4"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
sha256: "40c2a6a0da15556dc0f8e38a3246064a971a9f512386c3339b89f76db87269b6"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.0"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
sha256: eb06fe30bab4c4497bad449b66448f50edcc695f1c59408e78aa3a8059eb8f0e
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.8.13"
image_picker_linux:
dependency: transitive
description:
name: image_picker_linux
sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4"
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.2"
image_picker_macos:
dependency: transitive
description:
name: image_picker_macos
sha256: d58cd9d67793d52beefd6585b12050af0a7663c0c2a6ece0fb110a35d6955e04
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.2"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
sha256: "9f143b0dba3e459553209e20cc425c9801af48e6dfa4f01a0fcf927be3f41665"
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.11.0"
image_picker_windows:
dependency: transitive
description:
name: image_picker_windows
sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.2.2"
version: "4.5.4"
image_size_getter:
dependency: "direct main"
description:
......@@ -941,6 +853,70 @@ packages:
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.5.0"
open_file:
dependency: "direct main"
description:
name: open_file
sha256: d17e2bddf5b278cb2ae18393d0496aa4f162142ba97d1a9e0c30d476adf99c0e
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.5.10"
open_file_android:
dependency: transitive
description:
name: open_file_android
sha256: "58141fcaece2f453a9684509a7275f231ac0e3d6ceb9a5e6de310a7dff9084aa"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.6"
open_file_ios:
dependency: transitive
description:
name: open_file_ios
sha256: "02996f01e5f6863832068e97f8f3a5ef9b613516db6897f373b43b79849e4d07"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.3"
open_file_linux:
dependency: transitive
description:
name: open_file_linux
sha256: d189f799eecbb139c97f8bc7d303f9e720954fa4e0fa1b0b7294767e5f2d7550
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.5"
open_file_mac:
dependency: transitive
description:
name: open_file_mac
sha256: "1440b1e37ceb0642208cfeb2c659c6cda27b25187a90635c9d1acb7d0584d324"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.3"
open_file_platform_interface:
dependency: transitive
description:
name: open_file_platform_interface
sha256: "101b424ca359632699a7e1213e83d025722ab668b9fd1412338221bf9b0e5757"
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.3"
open_file_web:
dependency: transitive
description:
name: open_file_web
sha256: e3dbc9584856283dcb30aef5720558b90f88036360bd078e494ab80a80130c4f
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.4"
open_file_windows:
dependency: transitive
description:
name: open_file_windows
sha256: d26c31ddf935a94a1a3aa43a23f4fff8a5ff4eea395fe7a8cb819cf55431c875
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.0.3"
package_config:
dependency: transitive
description:
......@@ -1451,7 +1427,7 @@ packages:
source: hosted
version: "3.1.4"
video_player:
dependency: transitive
dependency: "direct main"
description:
name: video_player
sha256: "0d55b1f1a31e5ad4c4967bfaa8ade0240b07d20ee4af1dfef5f531056512961a"
......
......@@ -47,12 +47,14 @@ dependencies:
get_it: ^8.2.0
geolocator: ^14.0.2
go_router: ^16.2.1
image_picker: ^1.2.0
# image_picker: ^1.2.0
image: ^4.5.4
image_size_getter: ^2.4.1
json_annotation: ^4.9.0
mime: ^2.0.0
mobile_scanner: ^7.0.1
network_info_plus: ^7.0.0
open_file: ^3.5.10
path: ^1.9.1
path_provider: ^2.1.5
permission_handler: ^12.0.1
......@@ -61,6 +63,7 @@ dependencies:
uuid: ^4.5.1
vibration: ^3.1.3
video_compress: ^3.1.4
video_player: ^2.10.0
webview_flutter: ^4.13.0
wechat_assets_picker: ^9.8.0
wechat_camera_picker: ^4.4.0
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!