upgrade dependencies and gradle
parent
9d0a3eebf5
commit
ecd1e8d052
|
@ -1,3 +1,9 @@
|
|||
plugins {
|
||||
id "com.android.application"
|
||||
id "kotlin-android"
|
||||
id "dev.flutter.flutter-gradle-plugin"
|
||||
}
|
||||
|
||||
def localProperties = new Properties()
|
||||
def localPropertiesFile = rootProject.file('local.properties')
|
||||
if (localPropertiesFile.exists()) {
|
||||
|
@ -6,10 +12,10 @@ if (localPropertiesFile.exists()) {
|
|||
}
|
||||
}
|
||||
|
||||
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||
if (flutterRoot == null) {
|
||||
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||
}
|
||||
//def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||
//if (flutterRoot == null) {
|
||||
// throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||
//}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
|
@ -21,9 +27,9 @@ if (flutterVersionName == null) {
|
|||
flutterVersionName = '1.0'
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
//apply plugin: 'com.android.application'
|
||||
//apply plugin: 'kotlin-android'
|
||||
//apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
android {
|
||||
namespace "com.example.together_mobile"
|
||||
|
@ -31,7 +37,7 @@ android {
|
|||
// flutter_local_notifications needed:
|
||||
// The 33 (Android 13) is minimal version to display a prompt to ask
|
||||
// notification permission
|
||||
compileSdkVersion 33
|
||||
compileSdkVersion 34
|
||||
ndkVersion flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
|
@ -61,7 +67,7 @@ android {
|
|||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||
// minSdkVersion flutter.minSdkVersion
|
||||
// device_info_plugin requires a higher android sdk version
|
||||
minSdkVersion 19
|
||||
minSdkVersion 21
|
||||
targetSdkVersion flutter.targetSdkVersion
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
|
@ -83,8 +89,8 @@ flutter {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
// flutter_local_notifications: solve the problem that enabling desugaring
|
||||
// implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
// flutter_local_notifications: solve the problem that enabling desugaring
|
||||
// may result in a Flutter app crashing on Android 12L and above
|
||||
// Default but also flutter_local_notifications needs
|
||||
implementation 'androidx.window:window:1.0.0'
|
||||
|
|
|
@ -1,20 +1,30 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.7.10'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
// diminish warning of "Deprecated imperative apply of Flutter's Gradle plugins"
|
||||
// https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
// flutter_local_notifications
|
||||
// classpath 'com.android.tools.build:gradle:4.2.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
//buildscript {
|
||||
// ext.kotlin_version = '1.7.10'
|
||||
// repositories {
|
||||
// google()
|
||||
// mavenCentral()
|
||||
// }
|
||||
//
|
||||
// dependencies {
|
||||
// classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
// // flutter_local_notifications
|
||||
// // classpath 'com.android.tools.build:gradle:4.2.2'
|
||||
// classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
// }
|
||||
//}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
maven { url "https://jitpack.io" }
|
||||
maven { url 'https://maven.aliyun.com/repository/releases' }
|
||||
maven { url 'https://maven.aliyun.com/repository/jcenter' }
|
||||
maven { url 'https://maven.aliyun.com/repository/google' }
|
||||
maven { url 'https://maven.aliyun.com/repository/central' }
|
||||
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
|
||||
maven { url 'https://maven.aliyun.com/repository/public' }
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
systemProp.https.proxyHost=127.0.0.1
|
||||
systemProp.https.proxyPort=2340
|
||||
systemProp.http.proxyHost=127.0.0.1
|
||||
systemProp.http.proxyPort=2340
|
||||
|
|
|
@ -1,11 +1,35 @@
|
|||
include ':app'
|
||||
pluginManagement {
|
||||
def flutterSdkPath = {
|
||||
def properties = new Properties()
|
||||
file("local.properties").withInputStream { properties.load(it) }
|
||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||
return flutterSdkPath
|
||||
}()
|
||||
|
||||
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
||||
def properties = new Properties()
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
assert localPropertiesFile.exists()
|
||||
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
||||
repositories {
|
||||
maven { url "https://jitpack.io" }
|
||||
maven { url 'https://maven.aliyun.com/repository/releases' }
|
||||
maven { url 'https://maven.aliyun.com/repository/jcenter' }
|
||||
maven { url 'https://maven.aliyun.com/repository/google' }
|
||||
maven { url 'https://maven.aliyun.com/repository/central' }
|
||||
maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
|
||||
maven { url 'https://maven.aliyun.com/repository/public' }
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "7.4.2" apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.7.10" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
||||
// diminish warning of "Deprecated imperative apply of Flutter's Gradle plugins"
|
||||
// https://docs.flutter.dev/release/breaking-changes/flutter-gradle-plugin-apply
|
||||
|
|
|
@ -46,8 +46,8 @@ var request = Dio(baseOptions)
|
|||
}
|
||||
},
|
||||
onError: (DioException e, ErrorInterceptorHandler handler) {
|
||||
// print('错误信息:' + e.response?.data);
|
||||
// print('错误码: ${e.response?.statusCode}');
|
||||
print('错误信息:' + e.response?.data);
|
||||
print('错误码: ${e.response?.statusCode}');
|
||||
handler.reject(e);
|
||||
},
|
||||
),
|
||||
|
|
|
@ -21,14 +21,14 @@ final chatRoute = GoRoute(
|
|||
name: 'Message',
|
||||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
int type = int.parse(state.queryParameters['type']!);
|
||||
int type = int.parse(state.uri.queryParameters['type']!);
|
||||
if (type == 0) {
|
||||
return FriendMessageScreen(
|
||||
friendId: state.queryParameters['friendId']!,
|
||||
friendId: state.uri.queryParameters['friendId']!,
|
||||
);
|
||||
} else {
|
||||
return GroupChatMessageScreen(
|
||||
groupChatId: state.queryParameters['groupChatId']!,
|
||||
groupChatId: state.uri.queryParameters['groupChatId']!,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -28,8 +28,8 @@ final contactRoute = GoRoute(
|
|||
path: '/contact',
|
||||
name: 'Contact',
|
||||
builder: (context, state) {
|
||||
if (state.queryParameters.isNotEmpty) {
|
||||
var deletedFriendId = state.queryParameters['deletedFriendId'];
|
||||
if (state.uri.queryParameters.isNotEmpty) {
|
||||
var deletedFriendId = state.uri.queryParameters['deletedFriendId'];
|
||||
if (deletedFriendId != null) {
|
||||
getIt.get<Contact>().removeFriend(deletedFriendId);
|
||||
getIt.get<ContactAccountProfile>().removeFriend(deletedFriendId);
|
||||
|
@ -53,7 +53,7 @@ final contactRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return AddFriendScreen(
|
||||
accountProfile: state.queryParameters,
|
||||
accountProfile: state.uri.queryParameters,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -79,7 +79,7 @@ final contactRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return ApplicantProfileScreen(
|
||||
accountProfile: state.queryParameters,
|
||||
accountProfile: state.uri.queryParameters,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
|
@ -33,7 +33,7 @@ final myProfileRoute = GoRoute(
|
|||
return AvatarViewScreen(
|
||||
isMyself: true,
|
||||
avatarType: AvatarType.user,
|
||||
avatar: state.queryParameters['avatar']!,
|
||||
avatar: state.uri.queryParameters['avatar']!,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -70,7 +70,7 @@ final friendProfileRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return FriendProfileScreen(
|
||||
friendId: state.queryParameters['friendId']!,
|
||||
friendId: state.uri.queryParameters['friendId']!,
|
||||
);
|
||||
},
|
||||
routes: [
|
||||
|
@ -82,7 +82,7 @@ final friendProfileRoute = GoRoute(
|
|||
return AvatarViewScreen(
|
||||
isMyself: false,
|
||||
avatarType: AvatarType.user,
|
||||
avatar: state.queryParameters['avatar']!,
|
||||
avatar: state.uri.queryParameters['avatar']!,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -92,7 +92,7 @@ final friendProfileRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return FriendSettingScreen(
|
||||
friendId: state.queryParameters['friendId']!,
|
||||
friendId: state.uri.queryParameters['friendId']!,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -105,7 +105,7 @@ final groupChatProfileRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return GroupChatProfileScreen(
|
||||
groupChatId: state.queryParameters['groupChatId']!,
|
||||
groupChatId: state.uri.queryParameters['groupChatId']!,
|
||||
);
|
||||
},
|
||||
routes: [
|
||||
|
@ -115,7 +115,7 @@ final groupChatProfileRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return GroupChatOutlineScreen(
|
||||
groupChatId: state.queryParameters['groupChatId']!,
|
||||
groupChatId: state.uri.queryParameters['groupChatId']!,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -125,7 +125,7 @@ final groupChatProfileRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return InviteGroupChatMemberScreen(
|
||||
groupChatId: state.queryParameters['groupChatId']!,
|
||||
groupChatId: state.uri.queryParameters['groupChatId']!,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -135,7 +135,7 @@ final groupChatProfileRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return ChangeGroupChatAvatarScreen(
|
||||
groupChatId: state.queryParameters['groupChatId']!,
|
||||
groupChatId: state.uri.queryParameters['groupChatId']!,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -145,8 +145,8 @@ final groupChatProfileRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return ChangeGroupChatNameScreen(
|
||||
groupChatId: state.queryParameters['groupChatId']!,
|
||||
name: state.queryParameters['name']!,
|
||||
groupChatId: state.uri.queryParameters['groupChatId']!,
|
||||
name: state.uri.queryParameters['name']!,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -156,8 +156,8 @@ final groupChatProfileRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return ChangeGroupChatIntroScreen(
|
||||
groupChatId: state.queryParameters['groupChatId']!,
|
||||
intro: state.queryParameters['intro']!,
|
||||
groupChatId: state.uri.queryParameters['groupChatId']!,
|
||||
intro: state.uri.queryParameters['intro']!,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -167,8 +167,8 @@ final groupChatProfileRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return ChangeGroupChatRemarkScreen(
|
||||
groupChatId: state.queryParameters['groupChatId']!,
|
||||
nameRemark: state.queryParameters['groupChatRemark']!,
|
||||
groupChatId: state.uri.queryParameters['groupChatId']!,
|
||||
nameRemark: state.uri.queryParameters['groupChatRemark']!,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -178,8 +178,8 @@ final groupChatProfileRoute = GoRoute(
|
|||
parentNavigatorKey: rootNavigatorKey,
|
||||
builder: (context, state) {
|
||||
return ChangeMyRemarkScreen(
|
||||
groupChatId: state.queryParameters['groupChatId']!,
|
||||
myRemark: state.queryParameters['remarkInGroupChat']!,
|
||||
groupChatId: state.uri.queryParameters['groupChatId']!,
|
||||
myRemark: state.uri.queryParameters['remarkInGroupChat']!,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
|
@ -42,6 +42,8 @@ final GoRouter router = GoRouter(
|
|||
getIt.get<UserAccount>().init(res['data']);
|
||||
await HiveDatabase.init();
|
||||
return '/chat';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -5,10 +5,10 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:cherry_toast/cherry_toast.dart';
|
||||
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:image_editor_plus/image_editor_plus.dart';
|
||||
import 'package:image_editor_plus/utils.dart';
|
||||
import 'package:image_editor_plus/options.dart' as iepo;
|
||||
|
||||
import 'package:together_mobile/common/constants.dart';
|
||||
import 'package:together_mobile/models/contact_model.dart';
|
||||
import 'package:together_mobile/models/route_state_model.dart';
|
||||
|
@ -159,7 +159,7 @@ class _ChangeGroupChatAvatarScreenState
|
|||
MaterialPageRoute(
|
||||
builder: (context) => ImageCropper(
|
||||
availableRatios: const [
|
||||
AspectRatioOption(ratio: 1, title: '1:1')
|
||||
iepo.AspectRatio(ratio: 1, title: '1:1')
|
||||
],
|
||||
image: imageData,
|
||||
),
|
||||
|
|
|
@ -136,7 +136,7 @@ class _HomeScreenWithNavBarState extends State<HomeScreenWithNavBar>
|
|||
AndroidFlutterLocalNotificationsPlugin>();
|
||||
|
||||
final bool? grantedNotificationPermission =
|
||||
await androidImplementation?.requestPermission();
|
||||
await androidImplementation?.requestNotificationsPermission();
|
||||
setState(() {
|
||||
_notificationsEnabled = grantedNotificationPermission ?? false;
|
||||
});
|
||||
|
|
|
@ -5,10 +5,10 @@ import 'package:flutter/material.dart';
|
|||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:cherry_toast/cherry_toast.dart';
|
||||
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:image_editor_plus/image_editor_plus.dart';
|
||||
import 'package:image_editor_plus/utils.dart';
|
||||
import 'package:image_editor_plus/options.dart' as iepo;
|
||||
|
||||
import 'package:together_mobile/common/constants.dart';
|
||||
import 'package:together_mobile/models/route_state_model.dart';
|
||||
import 'package:together_mobile/request/server.dart';
|
||||
|
@ -139,7 +139,7 @@ class _ChangeMyAvatarScreenState extends State<ChangeMyAvatarScreen> {
|
|||
MaterialPageRoute(
|
||||
builder: (context) => ImageCropper(
|
||||
availableRatios: const [
|
||||
AspectRatioOption(ratio: 1, title: '1:1')
|
||||
iepo.AspectRatio(ratio: 1, title: '1:1')
|
||||
],
|
||||
image: imageData,
|
||||
),
|
||||
|
|
|
@ -1,514 +0,0 @@
|
|||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// ignore_for_file: public_member_api_docs
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const MaterialApp(
|
||||
title: 'Image Picker Demo',
|
||||
home: MyHomePage(title: 'Image Picker Example'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
const MyHomePage({super.key, this.title});
|
||||
|
||||
final String? title;
|
||||
|
||||
@override
|
||||
State<MyHomePage> createState() => _MyHomePageState();
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
List<XFile>? _imageFileList;
|
||||
|
||||
void _setImageFileListFromFile(XFile? value) {
|
||||
_imageFileList = value == null ? null : <XFile>[value];
|
||||
}
|
||||
|
||||
dynamic _pickImageError;
|
||||
bool _isVideo = false;
|
||||
|
||||
VideoPlayerController? _videoController;
|
||||
VideoPlayerController? _toBeDisposed;
|
||||
String? _retrieveDataError;
|
||||
|
||||
final ImagePicker _picker = ImagePicker();
|
||||
final TextEditingController _maxWidthController = TextEditingController();
|
||||
final TextEditingController _maxHeightController = TextEditingController();
|
||||
final TextEditingController _qualityController = TextEditingController();
|
||||
|
||||
Future<void> _playVideo(XFile? file) async {
|
||||
if (file != null && mounted) {
|
||||
await _disposeVideoController();
|
||||
late VideoPlayerController controller;
|
||||
if (kIsWeb) {
|
||||
controller = VideoPlayerController.network(file.path);
|
||||
} else {
|
||||
controller = VideoPlayerController.file(File(file.path));
|
||||
}
|
||||
_videoController = controller;
|
||||
// In web, most browsers won't honor a programmatic call to .play
|
||||
// if the video has a sound track (and is not muted).
|
||||
// Mute the video so it auto-plays in web!
|
||||
// This is not needed if the call to .play is the result of user
|
||||
// interaction (clicking on a "play" button, for example).
|
||||
const double volume = kIsWeb ? 0.0 : 1.0;
|
||||
await controller.setVolume(volume);
|
||||
await controller.initialize();
|
||||
await controller.setLooping(true);
|
||||
await controller.play();
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onImageButtonPressed(
|
||||
ImageSource source, {
|
||||
required BuildContext context,
|
||||
bool isMultiImage = false,
|
||||
}) async {
|
||||
if (_videoController != null) {
|
||||
await _videoController!.setVolume(0.0);
|
||||
}
|
||||
if (context.mounted) {
|
||||
if (_isVideo) {
|
||||
final XFile? file = await _picker.pickVideo(
|
||||
source: source,
|
||||
maxDuration: const Duration(seconds: 10),
|
||||
);
|
||||
await _playVideo(file);
|
||||
} else if (isMultiImage) {
|
||||
await _displayPickImageDialog(
|
||||
context,
|
||||
(double? maxWidth, double? maxHeight, int? quality) async {
|
||||
try {
|
||||
final List<XFile> pickedFileList = await _picker.pickMultiImage(
|
||||
maxWidth: maxWidth,
|
||||
maxHeight: maxHeight,
|
||||
imageQuality: quality,
|
||||
);
|
||||
setState(() {
|
||||
_imageFileList = pickedFileList;
|
||||
});
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
_pickImageError = e;
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
} else {
|
||||
await _displayPickImageDialog(
|
||||
context,
|
||||
(double? maxWidth, double? maxHeight, int? quality) async {
|
||||
try {
|
||||
// call to `pickImage` jump to the image pick page automatically
|
||||
final XFile? pickedFile = await _picker.pickImage(
|
||||
source: source,
|
||||
maxWidth: maxWidth,
|
||||
maxHeight: maxHeight,
|
||||
imageQuality: quality,
|
||||
);
|
||||
setState(() {
|
||||
_setImageFileListFromFile(pickedFile);
|
||||
});
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
_pickImageError = e;
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void deactivate() {
|
||||
if (_videoController != null) {
|
||||
_videoController!.setVolume(0.0);
|
||||
_videoController!.pause();
|
||||
}
|
||||
super.deactivate();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_disposeVideoController();
|
||||
_maxWidthController.dispose();
|
||||
_maxHeightController.dispose();
|
||||
_qualityController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _disposeVideoController() async {
|
||||
if (_toBeDisposed != null) {
|
||||
await _toBeDisposed!.dispose();
|
||||
}
|
||||
_toBeDisposed = _videoController;
|
||||
_videoController = null;
|
||||
}
|
||||
|
||||
Widget _previewVideo() {
|
||||
final Text? retrieveError = _getRetrieveErrorWidget();
|
||||
if (retrieveError != null) {
|
||||
return retrieveError;
|
||||
}
|
||||
if (_videoController == null) {
|
||||
return const Text(
|
||||
'You have not yet picked a video',
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: AspectRatioVideo(_videoController),
|
||||
);
|
||||
}
|
||||
|
||||
// Show the image(s) on the home page after the image(s) is(are) picked
|
||||
Widget _previewImages() {
|
||||
final Text? retrieveError = _getRetrieveErrorWidget();
|
||||
if (retrieveError != null) {
|
||||
return retrieveError;
|
||||
}
|
||||
if (_imageFileList != null) {
|
||||
return Semantics(
|
||||
label: 'image_picker_example_picked_images',
|
||||
child: ListView.builder(
|
||||
key: UniqueKey(),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
// Why network for web?
|
||||
// See https://pub.dev/packages/image_picker_for_web#limitations-on-the-web-platform
|
||||
return Semantics(
|
||||
label: 'image_picker_example_picked_image',
|
||||
child: kIsWeb
|
||||
? Image.network(_imageFileList![index].path)
|
||||
: Image.file(
|
||||
File(_imageFileList![index].path),
|
||||
errorBuilder: (
|
||||
BuildContext context,
|
||||
Object error,
|
||||
StackTrace? stackTrace,
|
||||
) =>
|
||||
const Center(
|
||||
child: Text('This image type is not supported'),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount: _imageFileList!.length,
|
||||
),
|
||||
);
|
||||
} else if (_pickImageError != null) {
|
||||
return Text(
|
||||
'Pick image error: $_pickImageError',
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
} else {
|
||||
return const Text(
|
||||
'You have not yet picked an image.',
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _handlePreview() {
|
||||
if (_isVideo) {
|
||||
return _previewVideo();
|
||||
} else {
|
||||
return _previewImages();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> retrieveLostData() async {
|
||||
final LostDataResponse response = await _picker.retrieveLostData();
|
||||
if (response.isEmpty) {
|
||||
return;
|
||||
}
|
||||
if (response.file != null) {
|
||||
if (response.type == RetrieveType.video) {
|
||||
_isVideo = true;
|
||||
await _playVideo(response.file);
|
||||
} else {
|
||||
_isVideo = false;
|
||||
setState(() {
|
||||
if (response.files == null) {
|
||||
_setImageFileListFromFile(response.file);
|
||||
} else {
|
||||
_imageFileList = response.files;
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
_retrieveDataError = response.exception!.code;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.title!),
|
||||
),
|
||||
body: Center(
|
||||
child: !kIsWeb && defaultTargetPlatform == TargetPlatform.android
|
||||
? FutureBuilder<void>(
|
||||
future: retrieveLostData(),
|
||||
builder: (
|
||||
BuildContext context,
|
||||
AsyncSnapshot<void> snapshot,
|
||||
) {
|
||||
switch (snapshot.connectionState) {
|
||||
case ConnectionState.none:
|
||||
case ConnectionState.waiting:
|
||||
return const Text(
|
||||
'You have not yet picked an image.',
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
case ConnectionState.done:
|
||||
// When finish picking image, which also means the future
|
||||
//is done, this hanle will be executed.
|
||||
return _handlePreview();
|
||||
case ConnectionState.active:
|
||||
if (snapshot.hasError) {
|
||||
return Text(
|
||||
'Pick image/video error: ${snapshot.error}}',
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
} else {
|
||||
return const Text(
|
||||
'You have not yet picked an image.',
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
: _handlePreview(),
|
||||
),
|
||||
floatingActionButton: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
Semantics(
|
||||
label: 'image_picker_example_from_gallery',
|
||||
child: FloatingActionButton(
|
||||
onPressed: () {
|
||||
_isVideo = false;
|
||||
_onImageButtonPressed(
|
||||
ImageSource.gallery,
|
||||
context: context,
|
||||
);
|
||||
},
|
||||
heroTag: 'image0',
|
||||
tooltip: 'Pick Image from gallery',
|
||||
child: const Icon(Icons.photo),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16.0),
|
||||
child: FloatingActionButton(
|
||||
onPressed: () {
|
||||
_isVideo = false;
|
||||
_onImageButtonPressed(
|
||||
ImageSource.gallery,
|
||||
context: context,
|
||||
isMultiImage: true,
|
||||
);
|
||||
},
|
||||
heroTag: 'image1',
|
||||
tooltip: 'Pick Multiple Image from gallery',
|
||||
child: const Icon(Icons.photo_library),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16.0),
|
||||
child: FloatingActionButton(
|
||||
onPressed: () {
|
||||
_isVideo = false;
|
||||
_onImageButtonPressed(ImageSource.camera, context: context);
|
||||
},
|
||||
heroTag: 'image2',
|
||||
tooltip: 'Take a Photo',
|
||||
child: const Icon(Icons.camera_alt),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16.0),
|
||||
child: FloatingActionButton(
|
||||
backgroundColor: Colors.red,
|
||||
onPressed: () {
|
||||
_isVideo = true;
|
||||
_onImageButtonPressed(ImageSource.gallery, context: context);
|
||||
},
|
||||
heroTag: 'video0',
|
||||
tooltip: 'Pick Video from gallery',
|
||||
child: const Icon(Icons.video_library),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16.0),
|
||||
child: FloatingActionButton(
|
||||
backgroundColor: Colors.red,
|
||||
onPressed: () {
|
||||
_isVideo = true;
|
||||
_onImageButtonPressed(ImageSource.camera, context: context);
|
||||
},
|
||||
heroTag: 'video1',
|
||||
tooltip: 'Take a Video',
|
||||
child: const Icon(Icons.videocam),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Text? _getRetrieveErrorWidget() {
|
||||
if (_retrieveDataError != null) {
|
||||
final Text result = Text(_retrieveDataError!);
|
||||
_retrieveDataError = null;
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<void> _displayPickImageDialog(
|
||||
BuildContext context,
|
||||
OnPickImageCallback onPick,
|
||||
) async {
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Add optional parameters'),
|
||||
content: Column(
|
||||
children: <Widget>[
|
||||
TextField(
|
||||
controller: _maxWidthController,
|
||||
keyboardType:
|
||||
const TextInputType.numberWithOptions(decimal: true),
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Enter maxWidth if desired'),
|
||||
),
|
||||
TextField(
|
||||
controller: _maxHeightController,
|
||||
keyboardType: const TextInputType.numberWithOptions(
|
||||
decimal: true,
|
||||
),
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Enter maxHeight if desired',
|
||||
),
|
||||
),
|
||||
TextField(
|
||||
controller: _qualityController,
|
||||
keyboardType: TextInputType.number,
|
||||
decoration: const InputDecoration(
|
||||
hintText: 'Enter quality if desired',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('CANCEL'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('PICK'),
|
||||
onPressed: () {
|
||||
final double? width = _maxWidthController.text.isNotEmpty
|
||||
? double.parse(_maxWidthController.text)
|
||||
: null;
|
||||
final double? height = _maxHeightController.text.isNotEmpty
|
||||
? double.parse(_maxHeightController.text)
|
||||
: null;
|
||||
final int? quality = _qualityController.text.isNotEmpty
|
||||
? int.parse(_qualityController.text)
|
||||
: null;
|
||||
onPick(width, height, quality);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
typedef OnPickImageCallback = void Function(
|
||||
double? maxWidth,
|
||||
double? maxHeight,
|
||||
int? quality,
|
||||
);
|
||||
|
||||
class AspectRatioVideo extends StatefulWidget {
|
||||
const AspectRatioVideo(this.controller, {super.key});
|
||||
|
||||
final VideoPlayerController? controller;
|
||||
|
||||
@override
|
||||
AspectRatioVideoState createState() => AspectRatioVideoState();
|
||||
}
|
||||
|
||||
class AspectRatioVideoState extends State<AspectRatioVideo> {
|
||||
VideoPlayerController? get controller => widget.controller;
|
||||
bool initialized = false;
|
||||
|
||||
void _onVideoControllerUpdate() {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
if (initialized != controller!.value.isInitialized) {
|
||||
initialized = controller!.value.isInitialized;
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
controller!.addListener(_onVideoControllerUpdate);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
controller!.removeListener(_onVideoControllerUpdate);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (initialized) {
|
||||
return Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: controller!.value.aspectRatio,
|
||||
child: VideoPlayer(controller!),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,25 +8,23 @@ import Foundation
|
|||
import device_info_plus
|
||||
import fast_rsa
|
||||
import file_selector_macos
|
||||
import flutter_image_compress_macos
|
||||
import flutter_local_notifications
|
||||
import flutter_secure_storage_macos
|
||||
import flutter_timezone
|
||||
import image_editor_common
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
import sqflite
|
||||
import video_player_avfoundation
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
|
||||
FastRsaPlugin.register(with: registry.registrar(forPlugin: "FastRsaPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin"))
|
||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin"))
|
||||
ImageEditorPlugin.register(with: registry.registrar(forPlugin: "ImageEditorPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
|
||||
}
|
||||
|
|
836
pubspec.lock
836
pubspec.lock
File diff suppressed because it is too large
Load Diff
15
pubspec.yaml
15
pubspec.yaml
|
@ -34,23 +34,23 @@ dependencies:
|
|||
cached_network_image: ^3.2.3
|
||||
cherry_toast: ^1.4.3
|
||||
custom_pop_up_menu: ^1.2.4
|
||||
device_info_plus: ^9.0.2
|
||||
device_info_plus: ^9.1.2
|
||||
dio: ^5.2.1+1
|
||||
fast_rsa: ^3.5.7
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_local_notifications: ^15.1.1
|
||||
flutter_local_notifications: ^17.0.0
|
||||
flutter_pickers: ^2.1.9
|
||||
flutter_secure_storage: ^8.0.0
|
||||
flutter_secure_storage: ^9.0.0
|
||||
flutter_slidable: ^3.0.0
|
||||
flutter_timezone: ^1.0.6
|
||||
get_it: ^7.6.0
|
||||
get_it_mixin: ^4.2.0
|
||||
go_router: ^7.1.1
|
||||
google_fonts: ^4.0.0
|
||||
go_router: ^13.2.1
|
||||
google_fonts: ^6.2.1
|
||||
hive: ^2.2.3
|
||||
hive_flutter: ^1.1.0
|
||||
image_editor_plus: ^0.2.4
|
||||
image_editor_plus: ^1.0.5
|
||||
image_picker: ^1.0.0
|
||||
logging: ^1.2.0
|
||||
path_provider: ^2.0.15
|
||||
|
@ -59,13 +59,12 @@ dependencies:
|
|||
reorderables: ^0.6.0
|
||||
shared_preferences: ^2.2.0
|
||||
timezone: ^0.9.2
|
||||
video_player: ^2.6.1
|
||||
web_socket_channel: ^2.4.0
|
||||
worker_manager: ^6.3.1
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.4.5
|
||||
flutter_lints: ^2.0.0
|
||||
flutter_lints: ^3.0.1
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <fast_rsa/fast_rsa_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FastRsaPluginRegisterWithRegistrar(
|
||||
|
@ -17,4 +18,6 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
|||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
|
|||
fast_rsa
|
||||
file_selector_windows
|
||||
flutter_secure_storage_windows
|
||||
permission_handler_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
|
Loading…
Reference in New Issue