✨ Edit profile
This commit is contained in:
parent
ed2e44cc54
commit
abc1d5a9d7
@ -11,6 +11,7 @@
|
||||
"screenAccountPublishers": "Publishers",
|
||||
"screenAccountPublisherNew": "New Publisher",
|
||||
"screenAccountPublisherEdit": "Edit Publisher",
|
||||
"screenAccountProfileEdit": "Edit Profile",
|
||||
"dialogOkay": "Okay",
|
||||
"dialogCancel": "Cancel",
|
||||
"dialogConfirm": "Confirm",
|
||||
@ -36,6 +37,10 @@
|
||||
"fieldDescription": "Description",
|
||||
"fieldUsernameCannotEditHint": "Username cannot be edited after created",
|
||||
"fieldUsernameLookupHint": "You can use username, phone number or email to login",
|
||||
"fieldFirstName": "First name",
|
||||
"fieldLastName": "Last name",
|
||||
"fieldBirthday": "Birthday",
|
||||
"fieldImageHint": "You can click those profile pictures to edit them.",
|
||||
"forgotPassword": "Forgot password",
|
||||
"loginPickFactor": "Pick a factor",
|
||||
"loginMultiFactor": {
|
||||
@ -54,6 +59,9 @@
|
||||
"accountLogoutConfirm": "You will need to re-enter your account password, even if you have already done so. This is required to login again.",
|
||||
"accountPublishers": "Your publishers",
|
||||
"accountPublishersSubtitle": "Manage your publish identities.",
|
||||
"accountProfileEdit": "Edit your profile",
|
||||
"accountProfileEditSubtitle": "Make your Solarpass account more looks like you.",
|
||||
"accountProfileEditApplied": "Profile modification applied.",
|
||||
"publishersNew": "New Publisher",
|
||||
"publisherNewSubtitle": "Create a new publisher identity.",
|
||||
"publisherSyncWithAccount": "Sync with account"
|
||||
|
@ -11,6 +11,7 @@
|
||||
"screenAccountPublishers": "发布者",
|
||||
"screenAccountPublisherNew": "新建发布者",
|
||||
"screenAccountPublisherEdit": "编辑发布者",
|
||||
"screenAccountProfileEdit": "编辑资料",
|
||||
"dialogOkay": "好的",
|
||||
"dialogCancel": "取消",
|
||||
"dialogConfirm": "确认",
|
||||
@ -35,6 +36,10 @@
|
||||
"fieldPassword": "密码",
|
||||
"fieldUsernameCannotEditHint": "用户名在创建后无法修改",
|
||||
"fieldUsernameLookupHint": "支持用户名、电话号码或邮箱地址",
|
||||
"fieldFirstName": "名",
|
||||
"fieldLastName": "姓",
|
||||
"fieldBirthday": "生日",
|
||||
"fieldImageHint": "你可以点击这些个人头像来编辑它们。",
|
||||
"fieldDescription": "简介",
|
||||
"forgotPassword": "忘记密码",
|
||||
"loginPickFactor": "选择方式验证",
|
||||
@ -54,6 +59,9 @@
|
||||
"accountLogoutConfirm": "您需要重新输入账号密码,甚至可能需要多步验证来再次登陆。",
|
||||
"accountPublishers": "你的发布者",
|
||||
"accountPublishersSubtitle": "管理你的公共形象。",
|
||||
"accountProfileEdit": "编辑资料",
|
||||
"accountProfileEditSubtitle": "使你的 Solarpass 账户更像你。",
|
||||
"accountProfileEditApplied": "个人资料修改已被应用。",
|
||||
"publishersNew": "新发布者",
|
||||
"publisherNewSubtitle": "创建一个新的公共身份。",
|
||||
"publisherSyncWithAccount": "同步账户信息"
|
||||
|
@ -2,47 +2,134 @@ PODS:
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- croppy (0.0.1):
|
||||
- Flutter
|
||||
- cupertino_http (0.0.1):
|
||||
- Flutter
|
||||
- DKImagePickerController/Core (4.3.9):
|
||||
- DKImagePickerController/ImageDataManager
|
||||
- DKImagePickerController/Resource
|
||||
- DKImagePickerController/ImageDataManager (4.3.9)
|
||||
- DKImagePickerController/PhotoGallery (4.3.9):
|
||||
- DKImagePickerController/Core
|
||||
- DKPhotoGallery
|
||||
- DKImagePickerController/Resource (4.3.9)
|
||||
- DKPhotoGallery (0.0.19):
|
||||
- DKPhotoGallery/Core (= 0.0.19)
|
||||
- DKPhotoGallery/Model (= 0.0.19)
|
||||
- DKPhotoGallery/Preview (= 0.0.19)
|
||||
- DKPhotoGallery/Resource (= 0.0.19)
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Core (0.0.19):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Preview
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Model (0.0.19):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Preview (0.0.19):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Resource
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Resource (0.0.19):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- file_picker (0.0.1):
|
||||
- DKImagePickerController/PhotoGallery
|
||||
- Flutter
|
||||
- Flutter (1.0.0)
|
||||
- flutter_image_compress_common (1.0.0):
|
||||
- Flutter
|
||||
- Mantle
|
||||
- SDWebImage
|
||||
- SDWebImageWebPCoder
|
||||
- flutter_native_splash (0.0.1):
|
||||
- Flutter
|
||||
- flutter_secure_storage (3.3.1):
|
||||
- Flutter
|
||||
- image_picker_ios (0.0.1):
|
||||
- Flutter
|
||||
- libwebp (1.3.2):
|
||||
- libwebp/demux (= 1.3.2)
|
||||
- libwebp/mux (= 1.3.2)
|
||||
- libwebp/sharpyuv (= 1.3.2)
|
||||
- libwebp/webp (= 1.3.2)
|
||||
- libwebp/demux (1.3.2):
|
||||
- libwebp/webp
|
||||
- libwebp/mux (1.3.2):
|
||||
- libwebp/demux
|
||||
- libwebp/sharpyuv (1.3.2)
|
||||
- libwebp/webp (1.3.2):
|
||||
- libwebp/sharpyuv
|
||||
- Mantle (2.2.0):
|
||||
- Mantle/extobjc (= 2.2.0)
|
||||
- Mantle/extobjc (2.2.0)
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- SDWebImage (5.19.7):
|
||||
- SDWebImage/Core (= 5.19.7)
|
||||
- SDWebImage/Core (5.19.7)
|
||||
- SDWebImageWebPCoder (0.14.6):
|
||||
- libwebp (~> 1.0)
|
||||
- SDWebImage/Core (~> 5.17)
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- sqflite_darwin (0.0.4):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- SwiftyGif (5.4.5)
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
|
||||
- croppy (from `.symlinks/plugins/croppy/ios`)
|
||||
- cupertino_http (from `.symlinks/plugins/cupertino_http/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_image_compress_common (from `.symlinks/plugins/flutter_image_compress_common/ios`)
|
||||
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
|
||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- libwebp
|
||||
- Mantle
|
||||
- SDWebImage
|
||||
- SDWebImageWebPCoder
|
||||
- SwiftyGif
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
connectivity_plus:
|
||||
:path: ".symlinks/plugins/connectivity_plus/darwin"
|
||||
croppy:
|
||||
:path: ".symlinks/plugins/croppy/ios"
|
||||
cupertino_http:
|
||||
:path: ".symlinks/plugins/cupertino_http/ios"
|
||||
file_picker:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_image_compress_common:
|
||||
:path: ".symlinks/plugins/flutter_image_compress_common/ios"
|
||||
flutter_native_splash:
|
||||
:path: ".symlinks/plugins/flutter_native_splash/ios"
|
||||
flutter_secure_storage:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||
image_picker_ios:
|
||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
shared_preferences_foundation:
|
||||
@ -54,13 +141,24 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
connectivity_plus: 4c41c08fc6d7c91f63bc7aec70ffe3730b04f563
|
||||
croppy: b6199bc8d56bd2e03cc11609d1c47ad9875c1321
|
||||
cupertino_http: 1a3a0f163c1b26e7f1a293b33d476e0fde7a64ec
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e
|
||||
flutter_native_splash: edf599c81f74d093a4daf8e17bd7a018854bc778
|
||||
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
|
||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||
libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009
|
||||
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
|
||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3
|
||||
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
|
||||
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
|
||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||
|
||||
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
@ -50,7 +50,15 @@
|
||||
<string>en</string>
|
||||
<string>zh_CN</string>
|
||||
</array>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Grant access to Photo Library will allow Solian upload photo or video for your post.</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Grant access to Photo Library will allow Solian take photo or video for your post.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Grant access to Photo Library will allow Solian record audio for your post.</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:croppy/croppy.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:easy_localization_loader/easy_localization_loader.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -48,6 +49,7 @@ class SolianApp extends StatelessWidget {
|
||||
locale: context.locale,
|
||||
supportedLocales: context.supportedLocales,
|
||||
localizationsDelegates: [
|
||||
CroppyLocalizations.delegate,
|
||||
RelativeTimeLocalizations.delegate,
|
||||
...context.localizationDelegates,
|
||||
],
|
||||
|
@ -1,8 +1,15 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:cross_file/cross_file.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:surface/providers/sn_network.dart';
|
||||
import 'package:surface/types/attachment.dart';
|
||||
|
||||
const kConcurrentUploadChunks = 5;
|
||||
|
||||
class SnAttachmentProvider {
|
||||
late final SnNetworkProvider _sn;
|
||||
final Map<String, SnAttachment> _cache = {};
|
||||
@ -43,4 +50,157 @@ class SnAttachmentProvider {
|
||||
}
|
||||
return rids.map((rid) => _cache[rid]!).toList();
|
||||
}
|
||||
|
||||
static Map<String, String> mimetypeOverrides = {
|
||||
'mov': 'video/quicktime',
|
||||
'mp4': 'video/mp4'
|
||||
};
|
||||
|
||||
Future<SnAttachment> directUploadOne(
|
||||
Uint8List data,
|
||||
String filename,
|
||||
String pool,
|
||||
Map<String, dynamic>? metadata, {
|
||||
String? mimetype,
|
||||
Function(double progress)? onProgress,
|
||||
}) async {
|
||||
final filePayload = MultipartFile.fromBytes(data, filename: filename);
|
||||
final fileAlt = filename.contains('.')
|
||||
? filename.substring(0, filename.lastIndexOf('.'))
|
||||
: filename;
|
||||
final fileExt =
|
||||
filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
|
||||
|
||||
String? mimetypeOverride;
|
||||
if (mimetype != null) {
|
||||
mimetypeOverride = mimetype;
|
||||
} else if (mimetypeOverrides.keys.contains(fileExt)) {
|
||||
mimetypeOverride = mimetypeOverrides[fileExt];
|
||||
}
|
||||
|
||||
final formData = FormData.fromMap({
|
||||
'alt': fileAlt,
|
||||
'file': filePayload,
|
||||
'pool': pool,
|
||||
'metadata': metadata,
|
||||
if (mimetypeOverride != null) 'mimetype': mimetypeOverride,
|
||||
});
|
||||
final resp = await _sn.client.post(
|
||||
'/cgi/uc/attachments',
|
||||
data: formData,
|
||||
onSendProgress: (count, total) {
|
||||
if (onProgress != null) {
|
||||
onProgress(count / total);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return SnAttachment.fromJson(resp.data);
|
||||
}
|
||||
|
||||
Future<(SnAttachment, int)> chunkedUploadInitialize(
|
||||
int size,
|
||||
String filename,
|
||||
String pool,
|
||||
Map<String, dynamic>? metadata,
|
||||
) async {
|
||||
final fileAlt = filename.contains('.')
|
||||
? filename.substring(0, filename.lastIndexOf('.'))
|
||||
: filename;
|
||||
final fileExt =
|
||||
filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
|
||||
|
||||
String? mimetypeOverride;
|
||||
if (mimetypeOverrides.keys.contains(fileExt)) {
|
||||
mimetypeOverride = mimetypeOverrides[fileExt];
|
||||
}
|
||||
|
||||
final resp = await _sn.client.post('/cgi/uc/attachments/multipart', data: {
|
||||
'alt': fileAlt,
|
||||
'name': filename,
|
||||
'pool': pool,
|
||||
'metadata': metadata,
|
||||
'size': size,
|
||||
if (mimetypeOverride != null) 'mimetype': mimetypeOverride,
|
||||
});
|
||||
|
||||
return (
|
||||
SnAttachment.fromJson(resp.data['meta']),
|
||||
resp.data['chunk_size'] as int
|
||||
);
|
||||
}
|
||||
|
||||
Future<SnAttachment> _chunkedUploadOnePart(
|
||||
Uint8List data,
|
||||
String rid,
|
||||
String cid, {
|
||||
Function(double progress)? onProgress,
|
||||
}) async {
|
||||
final resp = await _sn.client.post(
|
||||
'/cgi/uc/attachments/multipart/$rid/$cid',
|
||||
data: data,
|
||||
options: Options(headers: {'Content-Type': 'application/octet-stream'}),
|
||||
onSendProgress: (count, total) {
|
||||
if (onProgress != null) {
|
||||
onProgress(count / total);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return SnAttachment.fromJson(resp.data);
|
||||
}
|
||||
|
||||
Future<SnAttachment> chunkedUploadParts(
|
||||
XFile file,
|
||||
SnAttachment place,
|
||||
int chunkSize, {
|
||||
Function(double progress)? onProgress,
|
||||
}) async {
|
||||
final Map<String, dynamic> chunks = place.fileChunks ?? {};
|
||||
var currentTask = 0;
|
||||
|
||||
final queue = Queue<Future<void>>();
|
||||
final activeTasks = <Future<void>>[];
|
||||
|
||||
for (final entry in chunks.entries) {
|
||||
queue.add(() async {
|
||||
final beginCursor = entry.value * chunkSize;
|
||||
final endCursor = (entry.value + 1) * chunkSize;
|
||||
final data = Uint8List.fromList(await file
|
||||
.openRead(beginCursor, endCursor)
|
||||
.expand((chunk) => chunk)
|
||||
.toList());
|
||||
|
||||
place = await _chunkedUploadOnePart(
|
||||
data,
|
||||
place.rid,
|
||||
entry.key,
|
||||
onProgress: (chunkProgress) {
|
||||
final overallProgress =
|
||||
(currentTask + chunkProgress) / chunks.length;
|
||||
if (onProgress != null) {
|
||||
onProgress(overallProgress);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
currentTask++;
|
||||
}());
|
||||
}
|
||||
|
||||
while (queue.isNotEmpty || activeTasks.isNotEmpty) {
|
||||
while (activeTasks.length < kConcurrentUploadChunks && queue.isNotEmpty) {
|
||||
final task = queue.removeFirst();
|
||||
activeTasks.add(task);
|
||||
|
||||
task.then((_) => activeTasks.remove(task));
|
||||
}
|
||||
|
||||
if (activeTasks.isNotEmpty) {
|
||||
await Future.any(activeTasks);
|
||||
}
|
||||
}
|
||||
|
||||
return place;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:surface/screens/account.dart';
|
||||
import 'package:surface/screens/account/publisher_edit.dart';
|
||||
import 'package:surface/screens/account/publisher_new.dart';
|
||||
import 'package:surface/screens/account/publishers.dart';
|
||||
import 'package:surface/screens/account/profile_edit.dart';
|
||||
import 'package:surface/screens/account/publishers/publisher_edit.dart';
|
||||
import 'package:surface/screens/account/publishers/publisher_new.dart';
|
||||
import 'package:surface/screens/account/publishers/publishers.dart';
|
||||
import 'package:surface/screens/auth/login.dart';
|
||||
import 'package:surface/screens/auth/register.dart';
|
||||
import 'package:surface/screens/explore.dart';
|
||||
@ -50,6 +51,11 @@ final appRouter = GoRouter(
|
||||
name: 'authRegister',
|
||||
builder: (context, state) => const RegisterScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/account/profile/edit',
|
||||
name: 'accountProfileEdit',
|
||||
builder: (context, state) => const ProfileEditScreen(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/account/publishers',
|
||||
name: 'accountPublishers',
|
||||
|
@ -74,6 +74,16 @@ class _AuthorizedAccountScreen extends StatelessWidget {
|
||||
);
|
||||
}).padding(all: 20),
|
||||
).padding(horizontal: 8, top: 16, bottom: 4),
|
||||
ListTile(
|
||||
title: Text('accountProfileEdit').tr(),
|
||||
subtitle: Text('accountProfileEditSubtitle').tr(),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
leading: const Icon(Symbols.contact_page),
|
||||
trailing: const Icon(Icons.chevron_right),
|
||||
onTap: () {
|
||||
GoRouter.of(context).pushNamed('accountProfileEdit');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Text('accountPublishers').tr(),
|
||||
subtitle: Text('accountPublishersSubtitle').tr(),
|
||||
|
348
lib/screens/account/profile_edit.dart
Normal file
348
lib/screens/account/profile_edit.dart
Normal file
@ -0,0 +1,348 @@
|
||||
import 'dart:io';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:croppy/croppy.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:path/path.dart' show basename;
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:surface/providers/sn_attachment.dart';
|
||||
import 'package:surface/providers/sn_network.dart';
|
||||
import 'package:surface/providers/userinfo.dart';
|
||||
import 'package:surface/widgets/account/account_image.dart';
|
||||
import 'package:surface/widgets/dialog.dart';
|
||||
import 'package:surface/widgets/loading_indicator.dart';
|
||||
import 'package:surface/widgets/universal_image.dart';
|
||||
|
||||
class ProfileEditScreen extends StatefulWidget {
|
||||
const ProfileEditScreen({super.key});
|
||||
|
||||
@override
|
||||
State<ProfileEditScreen> createState() => _ProfileEditScreenState();
|
||||
}
|
||||
|
||||
class _ProfileEditScreenState extends State<ProfileEditScreen> {
|
||||
final _imagePicker = ImagePicker();
|
||||
|
||||
final _usernameController = TextEditingController();
|
||||
final _nicknameController = TextEditingController();
|
||||
final _firstNameController = TextEditingController();
|
||||
final _lastNameController = TextEditingController();
|
||||
final _descriptionController = TextEditingController();
|
||||
final _birthdayController = TextEditingController();
|
||||
|
||||
String? _avatar;
|
||||
String? _banner;
|
||||
DateTime? _birthday;
|
||||
|
||||
bool _isBusy = false;
|
||||
|
||||
static const _kDateFormat = 'y/M/d';
|
||||
|
||||
void _syncWidget() async {
|
||||
final ua = context.read<UserProvider>();
|
||||
final prof = ua.user!;
|
||||
_usernameController.text = prof.name;
|
||||
_nicknameController.text = prof.nick;
|
||||
_descriptionController.text = prof.description;
|
||||
_firstNameController.text = prof.profile!.firstName;
|
||||
_lastNameController.text = prof.profile!.lastName;
|
||||
_avatar = prof.avatar;
|
||||
_banner = prof.banner;
|
||||
if (prof.profile!.birthday != null) {
|
||||
_birthdayController.text = DateFormat(_kDateFormat).format(
|
||||
prof.profile!.birthday!.toLocal(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _selectBirthday() async {
|
||||
await showCupertinoModalPopup<DateTime?>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => Container(
|
||||
height: 216,
|
||||
padding: const EdgeInsets.only(top: 6.0),
|
||||
margin: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: CupertinoDatePicker(
|
||||
initialDateTime: _birthday?.toLocal(),
|
||||
mode: CupertinoDatePickerMode.date,
|
||||
use24hFormat: true,
|
||||
onDateTimeChanged: (DateTime newDate) {
|
||||
setState(() {
|
||||
_birthday = newDate;
|
||||
_birthdayController.text =
|
||||
DateFormat(_kDateFormat).format(_birthday!);
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _updateImage(String place) async {
|
||||
final image = await _imagePicker.pickImage(source: ImageSource.gallery);
|
||||
if (image == null) return;
|
||||
if (!mounted) return;
|
||||
|
||||
final ImageProvider imageProvider =
|
||||
kIsWeb ? NetworkImage(image.path) : FileImage(File(image.path));
|
||||
final aspectRatios = place == 'banner'
|
||||
? [CropAspectRatio(width: 16, height: 7)]
|
||||
: [CropAspectRatio(width: 1, height: 1)];
|
||||
final result = (!kIsWeb && (Platform.isIOS || Platform.isMacOS))
|
||||
? await showCupertinoImageCropper(
|
||||
// ignore: use_build_context_synchronously
|
||||
context,
|
||||
allowedAspectRatios: aspectRatios,
|
||||
imageProvider: imageProvider,
|
||||
)
|
||||
: await showMaterialImageCropper(
|
||||
// ignore: use_build_context_synchronously
|
||||
context,
|
||||
allowedAspectRatios: aspectRatios,
|
||||
imageProvider: imageProvider,
|
||||
);
|
||||
|
||||
if (result == null) return;
|
||||
|
||||
if (!mounted) return;
|
||||
final attach = context.read<SnAttachmentProvider>();
|
||||
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final rawBytes =
|
||||
(await result.uiImage.toByteData(format: ImageByteFormat.png))!
|
||||
.buffer
|
||||
.asUint8List();
|
||||
|
||||
try {
|
||||
final attachment = await attach.directUploadOne(
|
||||
rawBytes,
|
||||
basename(image.path),
|
||||
'avatar',
|
||||
null,
|
||||
mimetype: 'image/png',
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
final sn = context.read<SnNetworkProvider>();
|
||||
await sn.client.put(
|
||||
'/cgi/id/users/me/$place',
|
||||
data: {'attachment': attachment.rid},
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
final ua = context.read<UserProvider>();
|
||||
await ua.refreshUser();
|
||||
|
||||
if (!mounted) return;
|
||||
context.showSnackbar('accountProfileEditApplied'.tr());
|
||||
_syncWidget();
|
||||
} catch (err) {
|
||||
if (!mounted) return;
|
||||
context.showErrorDialog(err);
|
||||
} finally {
|
||||
setState(() => _isBusy = false);
|
||||
}
|
||||
}
|
||||
|
||||
void _updateUserInfo() async {
|
||||
setState(() => _isBusy = true);
|
||||
|
||||
final sn = context.read<SnNetworkProvider>();
|
||||
|
||||
try {
|
||||
await sn.client.put(
|
||||
'/cgi/id/users/me',
|
||||
data: {
|
||||
'nick': _nicknameController.value.text,
|
||||
'description': _descriptionController.value.text,
|
||||
'first_name': _firstNameController.value.text,
|
||||
'last_name': _lastNameController.value.text,
|
||||
'birthday': _birthday?.toUtc().toIso8601String(),
|
||||
},
|
||||
);
|
||||
|
||||
if (!mounted) return;
|
||||
final ua = context.read<UserProvider>();
|
||||
await ua.refreshUser();
|
||||
|
||||
if (!mounted) return;
|
||||
context.showSnackbar('accountProfileEditApplied'.tr());
|
||||
_syncWidget();
|
||||
} catch (err) {
|
||||
context.showErrorDialog(err);
|
||||
} finally {
|
||||
setState(() => _isBusy = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_syncWidget();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_usernameController.dispose();
|
||||
_nicknameController.dispose();
|
||||
_firstNameController.dispose();
|
||||
_lastNameController.dispose();
|
||||
_descriptionController.dispose();
|
||||
_birthdayController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const double padding = 24;
|
||||
|
||||
final sn = context.read<SnNetworkProvider>();
|
||||
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
LoadingIndicator(isActive: _isBusy),
|
||||
const Gap(24),
|
||||
Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Material(
|
||||
elevation: 0,
|
||||
child: InkWell(
|
||||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 16 / 9,
|
||||
child: Container(
|
||||
color:
|
||||
Theme.of(context).colorScheme.surfaceContainerHigh,
|
||||
child: _banner != null
|
||||
? UniversalImage(
|
||||
sn.getAttachmentUrl(_banner!),
|
||||
fit: BoxFit.cover,
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
_updateImage('banner');
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
bottom: -28,
|
||||
left: 16,
|
||||
child: Material(
|
||||
elevation: 2,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(40)),
|
||||
child: InkWell(
|
||||
child: AccountImage(content: _avatar, radius: 40),
|
||||
onTap: () {
|
||||
_updateImage('avatar');
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: padding),
|
||||
const Gap(8 + 28),
|
||||
Column(
|
||||
children: [
|
||||
TextField(
|
||||
readOnly: true,
|
||||
controller: _usernameController,
|
||||
decoration: InputDecoration(
|
||||
border: const UnderlineInputBorder(),
|
||||
labelText: 'fieldUsername'.tr(),
|
||||
helperText: 'fieldUsernameCannotEditHint'.tr(),
|
||||
),
|
||||
),
|
||||
const Gap(4),
|
||||
TextField(
|
||||
controller: _nicknameController,
|
||||
decoration: InputDecoration(
|
||||
border: const UnderlineInputBorder(),
|
||||
labelText: 'fieldNickname'.tr(),
|
||||
),
|
||||
),
|
||||
const Gap(4),
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: TextField(
|
||||
controller: _firstNameController,
|
||||
decoration: InputDecoration(
|
||||
border: const UnderlineInputBorder(),
|
||||
labelText: 'fieldFirstName'.tr(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Gap(8),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: TextField(
|
||||
controller: _lastNameController,
|
||||
decoration: InputDecoration(
|
||||
border: const UnderlineInputBorder(),
|
||||
labelText: 'fieldLastName'.tr(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Gap(4),
|
||||
TextField(
|
||||
controller: _descriptionController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
minLines: 3,
|
||||
decoration: InputDecoration(
|
||||
border: const UnderlineInputBorder(),
|
||||
labelText: 'fieldDescription'.tr(),
|
||||
),
|
||||
),
|
||||
const Gap(4),
|
||||
TextField(
|
||||
controller: _birthdayController,
|
||||
readOnly: true,
|
||||
decoration: InputDecoration(
|
||||
border: const UnderlineInputBorder(),
|
||||
labelText: 'fieldBirthday'.tr(),
|
||||
),
|
||||
onTap: () => _selectBirthday(),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: padding + 8),
|
||||
const Gap(12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
ElevatedButton.icon(
|
||||
onPressed: _isBusy ? null : _updateUserInfo,
|
||||
icon: const Icon(Symbols.save),
|
||||
label: Text('apply').tr(),
|
||||
),
|
||||
],
|
||||
).padding(horizontal: padding),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -134,7 +134,7 @@ class _AccountPublisherEditScreenState
|
||||
const Gap(4),
|
||||
TextField(
|
||||
controller: _descriptionController,
|
||||
maxLines: 3,
|
||||
maxLines: null,
|
||||
minLines: 3,
|
||||
decoration: InputDecoration(
|
||||
labelText: 'fieldDescription'.tr(),
|
@ -4,7 +4,7 @@ import 'package:surface/providers/sn_network.dart';
|
||||
import 'package:surface/widgets/universal_image.dart';
|
||||
|
||||
class AccountImage extends StatelessWidget {
|
||||
final String content;
|
||||
final String? content;
|
||||
final Color? backgroundColor;
|
||||
final Color? foregroundColor;
|
||||
final double? radius;
|
||||
@ -22,21 +22,21 @@ class AccountImage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sn = context.read<SnNetworkProvider>();
|
||||
final url = sn.getAttachmentUrl(content);
|
||||
final url = sn.getAttachmentUrl(content ?? '');
|
||||
|
||||
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
||||
return CircleAvatar(
|
||||
key: Key('attachment-${content.hashCode}'),
|
||||
radius: radius,
|
||||
backgroundColor: backgroundColor,
|
||||
backgroundImage: content.isNotEmpty
|
||||
backgroundImage: (content?.isNotEmpty ?? false)
|
||||
? ResizeImage(
|
||||
UniversalImage.provider(url),
|
||||
width: ((radius ?? 20) * devicePixelRatio * 2).round(),
|
||||
height: ((radius ?? 20) * devicePixelRatio * 2).round(),
|
||||
)
|
||||
: null,
|
||||
child: content.isEmpty
|
||||
child: (content?.isEmpty ?? true)
|
||||
? (fallbackWidget ??
|
||||
Icon(
|
||||
Icons.account_circle,
|
||||
|
@ -6,10 +6,14 @@
|
||||
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <file_selector_linux/file_selector_plugin.h>
|
||||
#include <flutter_secure_storage/flutter_secure_storage_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
|
||||
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) flutter_secure_storage_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStoragePlugin");
|
||||
flutter_secure_storage_plugin_register_with_registrar(flutter_secure_storage_registrar);
|
||||
|
@ -3,11 +3,13 @@
|
||||
#
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
file_selector_linux
|
||||
flutter_secure_storage
|
||||
url_launcher_linux
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
croppy
|
||||
jni
|
||||
)
|
||||
|
||||
|
@ -6,6 +6,8 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import connectivity_plus
|
||||
import file_selector_macos
|
||||
import flutter_image_compress_macos
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
import sqflite_darwin
|
||||
@ -13,6 +15,8 @@ import url_launcher_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||
FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||
|
200
pubspec.lock
200
pubspec.lock
@ -158,6 +158,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
cassowary:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cassowary
|
||||
sha256: f304452beaf93b9349daaeeda23f853578c9dd8674c06c6100fda0319c46b967
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.3"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -230,6 +238,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
croppy:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: croppy
|
||||
sha256: "14bb40fd6c1771b093a907ddbf24df9aa49a4e6e379dd630602eb446e30ec629"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
cross_file:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cross_file
|
||||
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.4+2"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -334,6 +358,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.2"
|
||||
equatable:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: equatable
|
||||
sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -358,6 +390,46 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
file_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: file_picker
|
||||
sha256: aac85f20436608e01a6ffd1fdd4e746a7f33c93a2c83752e626bdfaea139b877
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.1.3"
|
||||
file_selector_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_linux
|
||||
sha256: "712ce7fab537ba532c8febdb1a8f167b32441e74acd68c3ccb2e36dcb52c4ab2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.3"
|
||||
file_selector_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_macos
|
||||
sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.4+2"
|
||||
file_selector_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_platform_interface
|
||||
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.2"
|
||||
file_selector_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_windows
|
||||
sha256: "8f5d2f6590d51ecd9179ba39c64f722edc15226cc93dcc8698466ad36a4a85a4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.3+3"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -387,6 +459,54 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.1"
|
||||
flutter_image_compress:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_image_compress
|
||||
sha256: "45a3071868092a61b11044c70422b04d39d4d9f2ef536f3c5b11fb65a1e7dd90"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
flutter_image_compress_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_image_compress_common
|
||||
sha256: "7f79bc6c8a363063620b4e372fa86bc691e1cb28e58048cd38e030692fbd99ee"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
flutter_image_compress_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_image_compress_macos
|
||||
sha256: "26df6385512e92b3789dc76b613b54b55c457a7f1532e59078b04bf189782d47"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
flutter_image_compress_ohos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_image_compress_ohos
|
||||
sha256: e76b92bbc830ee08f5b05962fc78a532011fcd2041f620b5400a593e96da3f51
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.0.3"
|
||||
flutter_image_compress_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_image_compress_platform_interface
|
||||
sha256: "579cb3947fd4309103afe6442a01ca01e1e6f93dc53bb4cbd090e8ce34a41889"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
flutter_image_compress_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_image_compress_web
|
||||
sha256: f02fe352b17f82b72f481de45add240db062a2585850bea1667e82cc4cd6c311
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.4+1"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -416,6 +536,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.23"
|
||||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -562,6 +690,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.3.0"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_picker
|
||||
sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
image_picker_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_android
|
||||
sha256: "8faba09ba361d4b246dc0a17cb4289b3324c2b9f6db7b3d457ee69106a86bd32"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.12+17"
|
||||
image_picker_for_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_for_web
|
||||
sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.6"
|
||||
image_picker_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_ios
|
||||
sha256: "4f0568120c6fcc0aaa04511cb9f9f4d29fc3d0139884b1d06be88dcec7641d6b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.12+1"
|
||||
image_picker_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_linux
|
||||
sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+1"
|
||||
image_picker_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_macos
|
||||
sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+1"
|
||||
image_picker_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_platform_interface
|
||||
sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.10.0"
|
||||
image_picker_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_windows
|
||||
sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+1"
|
||||
intl:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -1263,6 +1455,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.8.0"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -59,6 +59,11 @@ dependencies:
|
||||
path: ^1.9.0
|
||||
relative_time: ^5.0.0
|
||||
flutter_secure_storage: ^4.2.1
|
||||
image_picker: ^1.1.2
|
||||
cross_file: ^0.3.4+2
|
||||
file_picker: ^8.1.3
|
||||
flutter_image_compress: ^2.3.0
|
||||
croppy: ^1.3.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -7,11 +7,14 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
}
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
connectivity_plus
|
||||
file_selector_windows
|
||||
url_launcher_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
croppy
|
||||
jni
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user