From 72e6a6a1f62587dc26246e8420804492c7d204d9 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 2 Mar 2025 20:37:30 +0800 Subject: [PATCH] :sparkles: Enhanced profile edit --- assets/translations/en-US.json | 9 +- assets/translations/zh-CN.json | 9 +- assets/translations/zh-HK.json | 10 +- assets/translations/zh-TW.json | 10 +- ios/Podfile.lock | 12 + lib/main.dart | 26 +- lib/screens/account.dart | 27 +- lib/screens/account/profile_edit.dart | 181 +++++++++- lib/screens/account/profile_page.dart | 2 +- .../account/publishers/publisher_edit.dart | 2 +- .../account/publishers/publisher_new.dart | 2 +- lib/types/account.dart | 15 +- lib/types/account.freezed.dart | 340 ++++++++++++------ lib/types/account.g.dart | 37 +- lib/widgets/post/post_item.dart | 183 +++------- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 4 + pubspec.lock | 136 +++++++ pubspec.yaml | 3 + .../flutter/generated_plugin_registrant.cc | 6 + windows/flutter/generated_plugins.cmake | 2 + 22 files changed, 717 insertions(+), 304 deletions(-) diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json index ea3da23..3fac7ef 100644 --- a/assets/translations/en-US.json +++ b/assets/translations/en-US.json @@ -736,5 +736,12 @@ "cacheDelete": "Clean Cache", "cacheDeleteDescription": "Remove the cached images and other resources from your disk, the content will be downloaded from server again.", "cacheDeleted": "All cache has been cleaned up.", - "userNoDescription": "No description." + "userNoDescription": "No description.", + "fieldTimeZone": "Time Zone", + "fieldGender": "Gender", + "fieldPronouns": "Pronouns", + "fieldLocation": "Location", + "fieldLinks": "Links", + "fieldLinkName": "Name", + "fieldLinkUrl": "URL" } diff --git a/assets/translations/zh-CN.json b/assets/translations/zh-CN.json index f86479d..9ec3b9b 100644 --- a/assets/translations/zh-CN.json +++ b/assets/translations/zh-CN.json @@ -734,5 +734,12 @@ "cacheDelete": "清除缓存", "cacheDeleteDescription": "从磁盘中移除缓存的图片和其他资源,内容将从服务器重新下载。", "cacheDeleted": "所有缓存已被清除。", - "userNoDescription": "这个人很懒,没有留下什么……" + "userNoDescription": "这个人很懒,没有留下什么……", + "fieldTimeZone": "时区", + "fieldGender": "性别", + "fieldPronouns": "人称代词", + "fieldLocation": "位置", + "fieldLinks": "链接", + "fieldLinkName": "名称", + "fieldLinkUrl": "链接" } diff --git a/assets/translations/zh-HK.json b/assets/translations/zh-HK.json index f29b7b6..2ca7774 100644 --- a/assets/translations/zh-HK.json +++ b/assets/translations/zh-HK.json @@ -733,5 +733,13 @@ "cacheSize": "緩存資源大小", "cacheDelete": "清除緩存", "cacheDeleteDescription": "從磁盤中移除緩存的圖片和其他資源,內容將從服務器重新下載。", - "cacheDeleted": "所有緩存已被清除。" + "cacheDeleted": "所有緩存已被清除。", + "userNoDescription": "這個人很懶,沒有留下什麼……", + "fieldTimeZone": "時區", + "fieldGender": "性別", + "fieldPronouns": "人稱代詞", + "fieldLocation": "位置", + "fieldLinks": "鏈接", + "fieldLinkName": "名稱", + "fieldLinkUrl": "鏈接" } diff --git a/assets/translations/zh-TW.json b/assets/translations/zh-TW.json index 6dda408..9960502 100644 --- a/assets/translations/zh-TW.json +++ b/assets/translations/zh-TW.json @@ -733,5 +733,13 @@ "cacheSize": "緩存資源大小", "cacheDelete": "清除緩存", "cacheDeleteDescription": "從磁盤中移除緩存的圖片和其他資源,內容將從服務器重新下載。", - "cacheDeleted": "所有緩存已被清除。" + "cacheDeleted": "所有緩存已被清除。", + "userNoDescription": "這個人很懶,沒有留下什麼……", + "fieldTimeZone": "時區", + "fieldGender": "性別", + "fieldPronouns": "人稱代詞", + "fieldLocation": "位置", + "fieldLinks": "鏈接", + "fieldLinkName": "名稱", + "fieldLinkUrl": "鏈接" } diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f4cc8a1..6f3e21c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -113,6 +113,8 @@ PODS: - OrderedSet (~> 6.0.3) - flutter_native_splash (2.4.3): - Flutter + - flutter_timezone (0.0.1): + - Flutter - flutter_udid (0.0.1): - Flutter - SAMKeychain @@ -122,6 +124,8 @@ PODS: - gal (1.0.0): - Flutter - FlutterMacOS + - geolocator_apple (1.2.0): + - Flutter - GoogleAppMeasurement (11.8.0): - GoogleAppMeasurement/AdIdSupport (= 11.8.0) - GoogleUtilities/AppDelegateSwizzler (~> 8.0) @@ -267,9 +271,11 @@ DEPENDENCIES: - flutter_app_update (from `.symlinks/plugins/flutter_app_update/ios`) - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) + - flutter_timezone (from `.symlinks/plugins/flutter_timezone/ios`) - flutter_udid (from `.symlinks/plugins/flutter_udid/ios`) - flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`) - gal (from `.symlinks/plugins/gal/darwin`) + - geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`) - home_widget (from `.symlinks/plugins/home_widget/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - in_app_review (from `.symlinks/plugins/in_app_review/ios`) @@ -343,12 +349,16 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" flutter_native_splash: :path: ".symlinks/plugins/flutter_native_splash/ios" + flutter_timezone: + :path: ".symlinks/plugins/flutter_timezone/ios" flutter_udid: :path: ".symlinks/plugins/flutter_udid/ios" flutter_webrtc: :path: ".symlinks/plugins/flutter_webrtc/ios" gal: :path: ".symlinks/plugins/gal/darwin" + geolocator_apple: + :path: ".symlinks/plugins/geolocator_apple/ios" home_widget: :path: ".symlinks/plugins/home_widget/ios" image_picker_ios: @@ -416,9 +426,11 @@ SPEC CHECKSUMS: flutter_app_update: 65f61da626cb111d1b24674abc4b01728d7723bc flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 flutter_native_splash: df59bb2e1421aa0282cb2e95618af4dcb0c56c29 + flutter_timezone: ac3da59ac941ff1c98a2e1f0293420e020120282 flutter_udid: b2417673f287ee62817a1de3d1643f47b9f508ab flutter_webrtc: 90260f83024b1b96d239a575ea4e3708e79344d1 gal: 6a522c75909f1244732d4596d11d6a2f86ff37a5 + geolocator_apple: 9bcea1918ff7f0062d98345d238ae12718acfbc1 GoogleAppMeasurement: fc0817122bd4d4189164f85374e06773b9561896 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d diff --git a/lib/main.dart b/lib/main.dart index 3fd49ed..1ad95aa 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -108,8 +108,7 @@ void main() async { } if (!kIsWeb && Platform.isAndroid) { - final ImagePickerPlatform imagePickerImplementation = - ImagePickerPlatform.instance; + final ImagePickerPlatform imagePickerImplementation = ImagePickerPlatform.instance; if (imagePickerImplementation is ImagePickerAndroid) { imagePickerImplementation.useAndroidPhotoPicker = true; } @@ -228,8 +227,7 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener { if (prefs.containsKey('first_boot_time')) { final rawTime = prefs.getString('first_boot_time'); final time = DateTime.tryParse(rawTime ?? ''); - if (time != null && - time.isBefore(DateTime.now().subtract(const Duration(days: 3)))) { + if (time != null && time.isBefore(DateTime.now().subtract(const Duration(days: 3)))) { final inAppReview = InAppReview.instance; if (prefs.getBool('rating_requested') == true) return; if (await inAppReview.isAvailable()) { @@ -260,18 +258,12 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener { final remoteVersionString = resp.data?['tag_name'] ?? '0.0.0+0'; final remoteVersion = Version.parse(remoteVersionString.split('+').first); final localVersion = Version.parse(localVersionString.split('+').first); - final remoteBuildNumber = - int.tryParse(remoteVersionString.split('+').last) ?? 0; - final localBuildNumber = - int.tryParse(localVersionString.split('+').last) ?? 0; - logging.info( - "[Update] Local: $localVersionString, Remote: $remoteVersionString"); - if ((remoteVersion > localVersion || - remoteBuildNumber > localBuildNumber) && - mounted) { + final remoteBuildNumber = int.tryParse(remoteVersionString.split('+').last) ?? 0; + final localBuildNumber = int.tryParse(localVersionString.split('+').last) ?? 0; + logging.info("[Update] Local: $localVersionString, Remote: $remoteVersionString"); + if ((remoteVersion > localVersion || remoteBuildNumber > localBuildNumber) && mounted) { final config = context.read(); - config.setUpdate( - remoteVersionString, resp.data?['body'] ?? 'No changelog'); + config.setUpdate(remoteVersionString, resp.data?['body'] ?? 'No changelog'); logging.info("[Update] Update available: $remoteVersionString"); } } catch (e) { @@ -363,9 +355,7 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener { Future _trayInitialization() async { if (kIsWeb || Platform.isAndroid || Platform.isIOS) return; - final icon = Platform.isWindows - ? 'assets/icon/tray-icon.ico' - : 'assets/icon/tray-icon.png'; + final icon = Platform.isWindows ? 'assets/icon/tray-icon.ico' : 'assets/icon/tray-icon.png'; final appVersion = await PackageInfo.fromPlatform(); trayManager.addListener(this); diff --git a/lib/screens/account.dart b/lib/screens/account.dart index c267b4e..592fbb6 100644 --- a/lib/screens/account.dart +++ b/lib/screens/account.dart @@ -45,8 +45,7 @@ class AccountScreen extends StatelessWidget { ? Stack( fit: StackFit.expand, children: [ - AutoResizeUniversalImage(sn.getAttachmentUrl(ua.user!.banner), - fit: BoxFit.cover), + AutoResizeUniversalImage(sn.getAttachmentUrl(ua.user!.banner), fit: BoxFit.cover), Positioned( top: 0, left: 0, @@ -80,9 +79,7 @@ class AccountScreen extends StatelessWidget { ], ), body: SingleChildScrollView( - child: ua.isAuthorized - ? _AuthorizedAccountScreen() - : _UnauthorizedAccountScreen(), + child: ua.isAuthorized ? _AuthorizedAccountScreen() : _UnauthorizedAccountScreen(), ), ); } @@ -118,15 +115,19 @@ class _AuthorizedAccountScreen extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic, children: [ - Text(ua.user!.nick) - .textStyle(Theme.of(context).textTheme.titleLarge!), + Text(ua.user!.nick).textStyle(Theme.of(context).textTheme.titleLarge!), const Gap(4), - Text('@${ua.user!.name}') - .textStyle(Theme.of(context).textTheme.bodySmall!), + Text('@${ua.user!.name}').textStyle(Theme.of(context).textTheme.bodySmall!), ], ), - Text(ua.user!.description) - .textStyle(Theme.of(context).textTheme.bodyMedium!), + Text( + (ua.user!.profile?.description.isNotEmpty ?? false) + ? ua.user!.profile!.description + : 'userNoDescription'.tr(), + style: (ua.user!.profile?.description.isEmpty ?? true) + ? TextStyle(fontStyle: FontStyle.italic) + : null, + ).textStyle(Theme.of(context).textTheme.bodyMedium!), ], ), ); @@ -225,9 +226,7 @@ class _UnauthorizedAccountScreen extends StatelessWidget { child: Icon(Symbols.waving_hand, size: 28), ), const Gap(8), - Text('accountIntroTitle') - .tr() - .textStyle(Theme.of(context).textTheme.titleLarge!), + Text('accountIntroTitle').tr().textStyle(Theme.of(context).textTheme.titleLarge!), Text('accountIntroSubtitle').tr(), ], ).padding(all: 20), diff --git a/lib/screens/account/profile_edit.dart b/lib/screens/account/profile_edit.dart index df1a477..23e6f7c 100644 --- a/lib/screens/account/profile_edit.dart +++ b/lib/screens/account/profile_edit.dart @@ -6,6 +6,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_timezone/flutter_timezone.dart'; import 'package:gap/gap.dart'; import 'package:image_picker/image_picker.dart'; import 'package:material_symbols_icons/symbols.dart'; @@ -36,11 +37,16 @@ class _ProfileEditScreenState extends State { final _firstNameController = TextEditingController(); final _lastNameController = TextEditingController(); final _descriptionController = TextEditingController(); + final _timezoneController = TextEditingController(); + final _genderController = TextEditingController(); + final _pronounsController = TextEditingController(); + final _locationController = TextEditingController(); final _birthdayController = TextEditingController(); String? _avatar; String? _banner; DateTime? _birthday; + List<(String, String)>? _links; bool _isBusy = false; @@ -51,15 +57,21 @@ class _ProfileEditScreenState extends State { final prof = ua.user!; _usernameController.text = prof.name; _nicknameController.text = prof.nick; - _descriptionController.text = prof.description; + _descriptionController.text = prof.profile!.description; _firstNameController.text = prof.profile!.firstName; _lastNameController.text = prof.profile!.lastName; + _timezoneController.text = prof.profile!.timeZone; + _genderController.text = prof.profile!.gender; + _pronounsController.text = prof.profile!.pronouns; + _locationController.text = prof.profile!.location; _avatar = prof.avatar; _banner = prof.banner; - if (prof.profile!.birthday != null) { + _links = prof.profile!.links.entries.map((ele) => (ele.key, ele.value)).toList(); + _birthday = prof.profile!.birthday?.toLocal(); + if(_birthday != null) { _birthdayController.text = DateFormat(_kDateFormat).format( - prof.profile!.birthday!.toLocal(), - ); + prof.profile!.birthday!.toLocal(), + ); } } @@ -166,7 +178,14 @@ class _ProfileEditScreenState extends State { 'description': _descriptionController.value.text, 'first_name': _firstNameController.value.text, 'last_name': _lastNameController.value.text, + 'time_zone': _timezoneController.value.text, + 'gender': _genderController.value.text, + 'pronouns': _pronounsController.value.text, + 'location': _locationController.value.text, 'birthday': _birthday?.toUtc().toIso8601String(), + 'links': { + for (final link in _links!.where((ele) => ele.$1.isNotEmpty && ele.$2.isNotEmpty)) link.$1: link.$2 + }, }, ); @@ -197,6 +216,10 @@ class _ProfileEditScreenState extends State { _firstNameController.dispose(); _lastNameController.dispose(); _descriptionController.dispose(); + _timezoneController.dispose(); + _genderController.dispose(); + _pronounsController.dispose(); + _locationController.dispose(); _birthdayController.dispose(); super.dispose(); } @@ -262,6 +285,7 @@ class _ProfileEditScreenState extends State { ).padding(horizontal: padding), const Gap(8 + 28), Column( + spacing: 4, children: [ TextField( readOnly: true, @@ -271,16 +295,16 @@ class _ProfileEditScreenState extends State { labelText: 'fieldUsername'.tr(), helperText: 'fieldUsernameCannotEditHint'.tr(), ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), ), - const Gap(4), TextField( controller: _nicknameController, decoration: InputDecoration( border: const UnderlineInputBorder(), labelText: 'fieldNickname'.tr(), ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), ), - const Gap(4), Row( children: [ Flexible( @@ -291,6 +315,7 @@ class _ProfileEditScreenState extends State { border: const UnderlineInputBorder(), labelText: 'fieldFirstName'.tr(), ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), ), ), const Gap(8), @@ -302,11 +327,38 @@ class _ProfileEditScreenState extends State { border: const UnderlineInputBorder(), labelText: 'fieldLastName'.tr(), ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + ), + ), + ], + ), + Row( + children: [ + Flexible( + flex: 1, + child: TextField( + controller: _genderController, + decoration: InputDecoration( + border: const UnderlineInputBorder(), + labelText: 'fieldGender'.tr(), + ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + ), + ), + const Gap(4), + Flexible( + flex: 1, + child: TextField( + controller: _pronounsController, + decoration: InputDecoration( + border: const UnderlineInputBorder(), + labelText: 'fieldPronouns'.tr(), + ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), ), ), ], ), - const Gap(4), TextField( controller: _descriptionController, keyboardType: TextInputType.multiline, @@ -316,8 +368,51 @@ class _ProfileEditScreenState extends State { border: const UnderlineInputBorder(), labelText: 'fieldDescription'.tr(), ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: TextField( + controller: _timezoneController, + decoration: InputDecoration( + border: const UnderlineInputBorder(), + labelText: 'fieldTimeZone'.tr(), + ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + ), + ), + const Gap(4), + StyledWidget(IconButton( + icon: const Icon(Symbols.calendar_month), + visualDensity: VisualDensity(horizontal: -4, vertical: -4), + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + onPressed: () async { + _timezoneController.text = await FlutterTimezone.getLocalTimezone(); + }, + )).padding(top: 6), + const Gap(4), + StyledWidget(IconButton( + icon: const Icon(Symbols.clear), + visualDensity: VisualDensity(horizontal: -4, vertical: -4), + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + onPressed: () { + _timezoneController.clear(); + }, + )).padding(top: 6), + ], + ), + TextField( + controller: _locationController, + decoration: InputDecoration( + border: const UnderlineInputBorder(), + labelText: 'fieldLocation'.tr(), + ), + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), ), - const Gap(4), TextField( controller: _birthdayController, readOnly: true, @@ -327,6 +422,75 @@ class _ProfileEditScreenState extends State { ), onTap: () => _selectBirthday(), ), + if (_links != null) + Card( + margin: const EdgeInsets.only(top: 16, bottom: 4), + child: Container( + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text( + 'fieldLinks'.tr(), + style: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 17), + ), + ), + IconButton( + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + visualDensity: VisualDensity(horizontal: -4, vertical: -4), + icon: const Icon(Symbols.add), + onPressed: () { + setState(() => _links!.add(('', ''))); + }, + ), + ], + ), + const Gap(8), + for (var idx = 0; idx < _links!.length; idx++) + Row( + children: [ + Flexible( + flex: 1, + child: TextFormField( + initialValue: _links![idx].$1, + decoration: InputDecoration( + isDense: true, + border: const OutlineInputBorder(), + labelText: 'fieldLinkName'.tr(), + ), + onChanged: (value) { + _links![idx] = (value, _links![idx].$2); + }, + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + ), + ), + const Gap(8), + Flexible( + flex: 1, + child: TextFormField( + initialValue: _links![idx].$2, + decoration: InputDecoration( + isDense: true, + border: const OutlineInputBorder(), + labelText: 'fieldLinkUrl'.tr(), + ), + onChanged: (value) { + _links![idx] = (_links![idx].$1, value); + }, + onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + ), + ), + ], + ), + ], + ), + ), + ), ], ).padding(horizontal: padding + 8), const Gap(12), @@ -340,6 +504,7 @@ class _ProfileEditScreenState extends State { ), ], ).padding(horizontal: padding), + Gap(MediaQuery.of(context).padding.bottom), ], ), ), diff --git a/lib/screens/account/profile_page.dart b/lib/screens/account/profile_page.dart index bc000ba..58bf2b8 100644 --- a/lib/screens/account/profile_page.dart +++ b/lib/screens/account/profile_page.dart @@ -406,7 +406,7 @@ class _UserScreenState extends State ], ).padding(right: 8), const Gap(12), - Text(_account!.description).padding(horizontal: 8), + Text(_account!.profile!.description).padding(horizontal: 8), const Gap(4), Card( child: Row( diff --git a/lib/screens/account/publishers/publisher_edit.dart b/lib/screens/account/publishers/publisher_edit.dart index 0b6dde6..147ec8e 100644 --- a/lib/screens/account/publishers/publisher_edit.dart +++ b/lib/screens/account/publishers/publisher_edit.dart @@ -97,7 +97,7 @@ class _AccountPublisherEditScreenState extends State _banner = ua.user!.banner; _nickController.text = ua.user!.nick; _nameController.text = ua.user!.name; - _descriptionController.text = ua.user!.description; + _descriptionController.text = ua.user!.profile!.description; setState(() {}); } diff --git a/lib/screens/account/publishers/publisher_new.dart b/lib/screens/account/publishers/publisher_new.dart index febe118..9a59eec 100644 --- a/lib/screens/account/publishers/publisher_new.dart +++ b/lib/screens/account/publishers/publisher_new.dart @@ -109,7 +109,7 @@ class _PublisherNewPersonalState extends State<_PublisherNewPersonal> { _nameController.text = ua.user!.name; _nickController.text = ua.user!.nick; - _descriptionController.text = ua.user!.description; + _descriptionController.text = ua.user!.profile!.description; } @override diff --git a/lib/types/account.dart b/lib/types/account.dart index cfea640..39eab2c 100644 --- a/lib/types/account.dart +++ b/lib/types/account.dart @@ -16,7 +16,6 @@ abstract class SnAccount with _$SnAccount { required List? contacts, @Default("") String avatar, @Default("") String banner, - required String description, required String name, required String nick, @Default({}) Map permNodes, @@ -57,15 +56,21 @@ abstract class SnAccountContact with _$SnAccountContact { abstract class SnAccountProfile with _$SnAccountProfile { const factory SnAccountProfile({ required int id, - required int accountId, - required DateTime? birthday, required DateTime createdAt, + required DateTime updatedAt, required DateTime? deletedAt, - required int experience, required String firstName, required String lastName, + required String description, + required String timeZone, + required String location, + required String pronouns, + required String gender, + @Default({}) Map links, + required int experience, required DateTime? lastSeenAt, - required DateTime updatedAt, + required DateTime? birthday, + required int accountId, }) = _SnAccountProfile; factory SnAccountProfile.fromJson(Map json) => diff --git a/lib/types/account.freezed.dart b/lib/types/account.freezed.dart index 48f74c1..95d3642 100644 --- a/lib/types/account.freezed.dart +++ b/lib/types/account.freezed.dart @@ -23,7 +23,6 @@ mixin _$SnAccount { List? get contacts; String get avatar; String get banner; - String get description; String get name; String get nick; Map get permNodes; @@ -63,8 +62,6 @@ mixin _$SnAccount { const DeepCollectionEquality().equals(other.contacts, contacts) && (identical(other.avatar, avatar) || other.avatar == avatar) && (identical(other.banner, banner) || other.banner == banner) && - (identical(other.description, description) || - other.description == description) && (identical(other.name, name) || other.name == name) && (identical(other.nick, nick) || other.nick == nick) && const DeepCollectionEquality().equals(other.permNodes, permNodes) && @@ -96,7 +93,6 @@ mixin _$SnAccount { const DeepCollectionEquality().hash(contacts), avatar, banner, - description, name, nick, const DeepCollectionEquality().hash(permNodes), @@ -112,7 +108,7 @@ mixin _$SnAccount { @override String toString() { - return 'SnAccount(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, confirmedAt: $confirmedAt, contacts: $contacts, avatar: $avatar, banner: $banner, description: $description, name: $name, nick: $nick, permNodes: $permNodes, language: $language, profile: $profile, badges: $badges, suspendedAt: $suspendedAt, affiliatedId: $affiliatedId, affiliatedTo: $affiliatedTo, automatedBy: $automatedBy, automatedId: $automatedId)'; + return 'SnAccount(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, confirmedAt: $confirmedAt, contacts: $contacts, avatar: $avatar, banner: $banner, name: $name, nick: $nick, permNodes: $permNodes, language: $language, profile: $profile, badges: $badges, suspendedAt: $suspendedAt, affiliatedId: $affiliatedId, affiliatedTo: $affiliatedTo, automatedBy: $automatedBy, automatedId: $automatedId)'; } } @@ -130,7 +126,6 @@ abstract mixin class $SnAccountCopyWith<$Res> { List? contacts, String avatar, String banner, - String description, String name, String nick, Map permNodes, @@ -166,7 +161,6 @@ class _$SnAccountCopyWithImpl<$Res> implements $SnAccountCopyWith<$Res> { Object? contacts = freezed, Object? avatar = null, Object? banner = null, - Object? description = null, Object? name = null, Object? nick = null, Object? permNodes = null, @@ -212,10 +206,6 @@ class _$SnAccountCopyWithImpl<$Res> implements $SnAccountCopyWith<$Res> { ? _self.banner : banner // ignore: cast_nullable_to_non_nullable as String, - description: null == description - ? _self.description - : description // ignore: cast_nullable_to_non_nullable - as String, name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable @@ -290,7 +280,6 @@ class _SnAccount extends SnAccount { required final List? contacts, this.avatar = "", this.banner = "", - required this.description, required this.name, required this.nick, final Map permNodes = const {}, @@ -336,8 +325,6 @@ class _SnAccount extends SnAccount { @JsonKey() final String banner; @override - final String description; - @override final String name; @override final String nick; @@ -406,8 +393,6 @@ class _SnAccount extends SnAccount { const DeepCollectionEquality().equals(other._contacts, _contacts) && (identical(other.avatar, avatar) || other.avatar == avatar) && (identical(other.banner, banner) || other.banner == banner) && - (identical(other.description, description) || - other.description == description) && (identical(other.name, name) || other.name == name) && (identical(other.nick, nick) || other.nick == nick) && const DeepCollectionEquality() @@ -440,7 +425,6 @@ class _SnAccount extends SnAccount { const DeepCollectionEquality().hash(_contacts), avatar, banner, - description, name, nick, const DeepCollectionEquality().hash(_permNodes), @@ -456,7 +440,7 @@ class _SnAccount extends SnAccount { @override String toString() { - return 'SnAccount(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, confirmedAt: $confirmedAt, contacts: $contacts, avatar: $avatar, banner: $banner, description: $description, name: $name, nick: $nick, permNodes: $permNodes, language: $language, profile: $profile, badges: $badges, suspendedAt: $suspendedAt, affiliatedId: $affiliatedId, affiliatedTo: $affiliatedTo, automatedBy: $automatedBy, automatedId: $automatedId)'; + return 'SnAccount(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, confirmedAt: $confirmedAt, contacts: $contacts, avatar: $avatar, banner: $banner, name: $name, nick: $nick, permNodes: $permNodes, language: $language, profile: $profile, badges: $badges, suspendedAt: $suspendedAt, affiliatedId: $affiliatedId, affiliatedTo: $affiliatedTo, automatedBy: $automatedBy, automatedId: $automatedId)'; } } @@ -477,7 +461,6 @@ abstract mixin class _$SnAccountCopyWith<$Res> List? contacts, String avatar, String banner, - String description, String name, String nick, Map permNodes, @@ -514,7 +497,6 @@ class __$SnAccountCopyWithImpl<$Res> implements _$SnAccountCopyWith<$Res> { Object? contacts = freezed, Object? avatar = null, Object? banner = null, - Object? description = null, Object? name = null, Object? nick = null, Object? permNodes = null, @@ -560,10 +542,6 @@ class __$SnAccountCopyWithImpl<$Res> implements _$SnAccountCopyWith<$Res> { ? _self.banner : banner // ignore: cast_nullable_to_non_nullable as String, - description: null == description - ? _self.description - : description // ignore: cast_nullable_to_non_nullable - as String, name: null == name ? _self.name : name // ignore: cast_nullable_to_non_nullable @@ -954,15 +932,21 @@ class __$SnAccountContactCopyWithImpl<$Res> /// @nodoc mixin _$SnAccountProfile { int get id; - int get accountId; - DateTime? get birthday; DateTime get createdAt; + DateTime get updatedAt; DateTime? get deletedAt; - int get experience; String get firstName; String get lastName; + String get description; + String get timeZone; + String get location; + String get pronouns; + String get gender; + Map get links; + int get experience; DateTime? get lastSeenAt; - DateTime get updatedAt; + DateTime? get birthday; + int get accountId; /// Create a copy of SnAccountProfile /// with the given fields replaced by the non-null parameter values. @@ -981,24 +965,34 @@ mixin _$SnAccountProfile { (other.runtimeType == runtimeType && other is SnAccountProfile && (identical(other.id, id) || other.id == id) && - (identical(other.accountId, accountId) || - other.accountId == accountId) && - (identical(other.birthday, birthday) || - other.birthday == birthday) && (identical(other.createdAt, createdAt) || other.createdAt == createdAt) && + (identical(other.updatedAt, updatedAt) || + other.updatedAt == updatedAt) && (identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt) && - (identical(other.experience, experience) || - other.experience == experience) && (identical(other.firstName, firstName) || other.firstName == firstName) && (identical(other.lastName, lastName) || other.lastName == lastName) && + (identical(other.description, description) || + other.description == description) && + (identical(other.timeZone, timeZone) || + other.timeZone == timeZone) && + (identical(other.location, location) || + other.location == location) && + (identical(other.pronouns, pronouns) || + other.pronouns == pronouns) && + (identical(other.gender, gender) || other.gender == gender) && + const DeepCollectionEquality().equals(other.links, links) && + (identical(other.experience, experience) || + other.experience == experience) && (identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt) && - (identical(other.updatedAt, updatedAt) || - other.updatedAt == updatedAt)); + (identical(other.birthday, birthday) || + other.birthday == birthday) && + (identical(other.accountId, accountId) || + other.accountId == accountId)); } @JsonKey(includeFromJson: false, includeToJson: false) @@ -1006,19 +1000,25 @@ mixin _$SnAccountProfile { int get hashCode => Object.hash( runtimeType, id, - accountId, - birthday, createdAt, + updatedAt, deletedAt, - experience, firstName, lastName, + description, + timeZone, + location, + pronouns, + gender, + const DeepCollectionEquality().hash(links), + experience, lastSeenAt, - updatedAt); + birthday, + accountId); @override String toString() { - return 'SnAccountProfile(id: $id, accountId: $accountId, birthday: $birthday, createdAt: $createdAt, deletedAt: $deletedAt, experience: $experience, firstName: $firstName, lastName: $lastName, lastSeenAt: $lastSeenAt, updatedAt: $updatedAt)'; + return 'SnAccountProfile(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, firstName: $firstName, lastName: $lastName, description: $description, timeZone: $timeZone, location: $location, pronouns: $pronouns, gender: $gender, links: $links, experience: $experience, lastSeenAt: $lastSeenAt, birthday: $birthday, accountId: $accountId)'; } } @@ -1030,15 +1030,21 @@ abstract mixin class $SnAccountProfileCopyWith<$Res> { @useResult $Res call( {int id, - int accountId, - DateTime? birthday, DateTime createdAt, + DateTime updatedAt, DateTime? deletedAt, - int experience, String firstName, String lastName, + String description, + String timeZone, + String location, + String pronouns, + String gender, + Map links, + int experience, DateTime? lastSeenAt, - DateTime updatedAt}); + DateTime? birthday, + int accountId}); } /// @nodoc @@ -1055,41 +1061,39 @@ class _$SnAccountProfileCopyWithImpl<$Res> @override $Res call({ Object? id = null, - Object? accountId = null, - Object? birthday = freezed, Object? createdAt = null, + Object? updatedAt = null, Object? deletedAt = freezed, - Object? experience = null, Object? firstName = null, Object? lastName = null, + Object? description = null, + Object? timeZone = null, + Object? location = null, + Object? pronouns = null, + Object? gender = null, + Object? links = null, + Object? experience = null, Object? lastSeenAt = freezed, - Object? updatedAt = null, + Object? birthday = freezed, + Object? accountId = null, }) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as int, - accountId: null == accountId - ? _self.accountId - : accountId // ignore: cast_nullable_to_non_nullable - as int, - birthday: freezed == birthday - ? _self.birthday - : birthday // ignore: cast_nullable_to_non_nullable - as DateTime?, createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime, + updatedAt: null == updatedAt + ? _self.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as DateTime, deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable as DateTime?, - experience: null == experience - ? _self.experience - : experience // ignore: cast_nullable_to_non_nullable - as int, firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable @@ -1098,14 +1102,46 @@ class _$SnAccountProfileCopyWithImpl<$Res> ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable as String, + description: null == description + ? _self.description + : description // ignore: cast_nullable_to_non_nullable + as String, + timeZone: null == timeZone + ? _self.timeZone + : timeZone // ignore: cast_nullable_to_non_nullable + as String, + location: null == location + ? _self.location + : location // ignore: cast_nullable_to_non_nullable + as String, + pronouns: null == pronouns + ? _self.pronouns + : pronouns // ignore: cast_nullable_to_non_nullable + as String, + gender: null == gender + ? _self.gender + : gender // ignore: cast_nullable_to_non_nullable + as String, + links: null == links + ? _self.links + : links // ignore: cast_nullable_to_non_nullable + as Map, + experience: null == experience + ? _self.experience + : experience // ignore: cast_nullable_to_non_nullable + as int, lastSeenAt: freezed == lastSeenAt ? _self.lastSeenAt : lastSeenAt // ignore: cast_nullable_to_non_nullable as DateTime?, - updatedAt: null == updatedAt - ? _self.updatedAt - : updatedAt // ignore: cast_nullable_to_non_nullable - as DateTime, + birthday: freezed == birthday + ? _self.birthday + : birthday // ignore: cast_nullable_to_non_nullable + as DateTime?, + accountId: null == accountId + ? _self.accountId + : accountId // ignore: cast_nullable_to_non_nullable + as int, )); } } @@ -1115,38 +1151,64 @@ class _$SnAccountProfileCopyWithImpl<$Res> class _SnAccountProfile implements SnAccountProfile { const _SnAccountProfile( {required this.id, - required this.accountId, - required this.birthday, required this.createdAt, + required this.updatedAt, required this.deletedAt, - required this.experience, required this.firstName, required this.lastName, + required this.description, + required this.timeZone, + required this.location, + required this.pronouns, + required this.gender, + final Map links = const {}, + required this.experience, required this.lastSeenAt, - required this.updatedAt}); + required this.birthday, + required this.accountId}) + : _links = links; factory _SnAccountProfile.fromJson(Map json) => _$SnAccountProfileFromJson(json); @override final int id; @override - final int accountId; - @override - final DateTime? birthday; - @override final DateTime createdAt; @override - final DateTime? deletedAt; + final DateTime updatedAt; @override - final int experience; + final DateTime? deletedAt; @override final String firstName; @override final String lastName; @override + final String description; + @override + final String timeZone; + @override + final String location; + @override + final String pronouns; + @override + final String gender; + final Map _links; + @override + @JsonKey() + Map get links { + if (_links is EqualUnmodifiableMapView) return _links; + // ignore: implicit_dynamic_type + return EqualUnmodifiableMapView(_links); + } + + @override + final int experience; + @override final DateTime? lastSeenAt; @override - final DateTime updatedAt; + final DateTime? birthday; + @override + final int accountId; /// Create a copy of SnAccountProfile /// with the given fields replaced by the non-null parameter values. @@ -1169,24 +1231,34 @@ class _SnAccountProfile implements SnAccountProfile { (other.runtimeType == runtimeType && other is _SnAccountProfile && (identical(other.id, id) || other.id == id) && - (identical(other.accountId, accountId) || - other.accountId == accountId) && - (identical(other.birthday, birthday) || - other.birthday == birthday) && (identical(other.createdAt, createdAt) || other.createdAt == createdAt) && + (identical(other.updatedAt, updatedAt) || + other.updatedAt == updatedAt) && (identical(other.deletedAt, deletedAt) || other.deletedAt == deletedAt) && - (identical(other.experience, experience) || - other.experience == experience) && (identical(other.firstName, firstName) || other.firstName == firstName) && (identical(other.lastName, lastName) || other.lastName == lastName) && + (identical(other.description, description) || + other.description == description) && + (identical(other.timeZone, timeZone) || + other.timeZone == timeZone) && + (identical(other.location, location) || + other.location == location) && + (identical(other.pronouns, pronouns) || + other.pronouns == pronouns) && + (identical(other.gender, gender) || other.gender == gender) && + const DeepCollectionEquality().equals(other._links, _links) && + (identical(other.experience, experience) || + other.experience == experience) && (identical(other.lastSeenAt, lastSeenAt) || other.lastSeenAt == lastSeenAt) && - (identical(other.updatedAt, updatedAt) || - other.updatedAt == updatedAt)); + (identical(other.birthday, birthday) || + other.birthday == birthday) && + (identical(other.accountId, accountId) || + other.accountId == accountId)); } @JsonKey(includeFromJson: false, includeToJson: false) @@ -1194,19 +1266,25 @@ class _SnAccountProfile implements SnAccountProfile { int get hashCode => Object.hash( runtimeType, id, - accountId, - birthday, createdAt, + updatedAt, deletedAt, - experience, firstName, lastName, + description, + timeZone, + location, + pronouns, + gender, + const DeepCollectionEquality().hash(_links), + experience, lastSeenAt, - updatedAt); + birthday, + accountId); @override String toString() { - return 'SnAccountProfile(id: $id, accountId: $accountId, birthday: $birthday, createdAt: $createdAt, deletedAt: $deletedAt, experience: $experience, firstName: $firstName, lastName: $lastName, lastSeenAt: $lastSeenAt, updatedAt: $updatedAt)'; + return 'SnAccountProfile(id: $id, createdAt: $createdAt, updatedAt: $updatedAt, deletedAt: $deletedAt, firstName: $firstName, lastName: $lastName, description: $description, timeZone: $timeZone, location: $location, pronouns: $pronouns, gender: $gender, links: $links, experience: $experience, lastSeenAt: $lastSeenAt, birthday: $birthday, accountId: $accountId)'; } } @@ -1220,15 +1298,21 @@ abstract mixin class _$SnAccountProfileCopyWith<$Res> @useResult $Res call( {int id, - int accountId, - DateTime? birthday, DateTime createdAt, + DateTime updatedAt, DateTime? deletedAt, - int experience, String firstName, String lastName, + String description, + String timeZone, + String location, + String pronouns, + String gender, + Map links, + int experience, DateTime? lastSeenAt, - DateTime updatedAt}); + DateTime? birthday, + int accountId}); } /// @nodoc @@ -1245,41 +1329,39 @@ class __$SnAccountProfileCopyWithImpl<$Res> @pragma('vm:prefer-inline') $Res call({ Object? id = null, - Object? accountId = null, - Object? birthday = freezed, Object? createdAt = null, + Object? updatedAt = null, Object? deletedAt = freezed, - Object? experience = null, Object? firstName = null, Object? lastName = null, + Object? description = null, + Object? timeZone = null, + Object? location = null, + Object? pronouns = null, + Object? gender = null, + Object? links = null, + Object? experience = null, Object? lastSeenAt = freezed, - Object? updatedAt = null, + Object? birthday = freezed, + Object? accountId = null, }) { return _then(_SnAccountProfile( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as int, - accountId: null == accountId - ? _self.accountId - : accountId // ignore: cast_nullable_to_non_nullable - as int, - birthday: freezed == birthday - ? _self.birthday - : birthday // ignore: cast_nullable_to_non_nullable - as DateTime?, createdAt: null == createdAt ? _self.createdAt : createdAt // ignore: cast_nullable_to_non_nullable as DateTime, + updatedAt: null == updatedAt + ? _self.updatedAt + : updatedAt // ignore: cast_nullable_to_non_nullable + as DateTime, deletedAt: freezed == deletedAt ? _self.deletedAt : deletedAt // ignore: cast_nullable_to_non_nullable as DateTime?, - experience: null == experience - ? _self.experience - : experience // ignore: cast_nullable_to_non_nullable - as int, firstName: null == firstName ? _self.firstName : firstName // ignore: cast_nullable_to_non_nullable @@ -1288,14 +1370,46 @@ class __$SnAccountProfileCopyWithImpl<$Res> ? _self.lastName : lastName // ignore: cast_nullable_to_non_nullable as String, + description: null == description + ? _self.description + : description // ignore: cast_nullable_to_non_nullable + as String, + timeZone: null == timeZone + ? _self.timeZone + : timeZone // ignore: cast_nullable_to_non_nullable + as String, + location: null == location + ? _self.location + : location // ignore: cast_nullable_to_non_nullable + as String, + pronouns: null == pronouns + ? _self.pronouns + : pronouns // ignore: cast_nullable_to_non_nullable + as String, + gender: null == gender + ? _self.gender + : gender // ignore: cast_nullable_to_non_nullable + as String, + links: null == links + ? _self._links + : links // ignore: cast_nullable_to_non_nullable + as Map, + experience: null == experience + ? _self.experience + : experience // ignore: cast_nullable_to_non_nullable + as int, lastSeenAt: freezed == lastSeenAt ? _self.lastSeenAt : lastSeenAt // ignore: cast_nullable_to_non_nullable as DateTime?, - updatedAt: null == updatedAt - ? _self.updatedAt - : updatedAt // ignore: cast_nullable_to_non_nullable - as DateTime, + birthday: freezed == birthday + ? _self.birthday + : birthday // ignore: cast_nullable_to_non_nullable + as DateTime?, + accountId: null == accountId + ? _self.accountId + : accountId // ignore: cast_nullable_to_non_nullable + as int, )); } } diff --git a/lib/types/account.g.dart b/lib/types/account.g.dart index 9ca1d53..2e15e82 100644 --- a/lib/types/account.g.dart +++ b/lib/types/account.g.dart @@ -21,7 +21,6 @@ _SnAccount _$SnAccountFromJson(Map json) => _SnAccount( .toList(), avatar: json['avatar'] as String? ?? "", banner: json['banner'] as String? ?? "", - description: json['description'] as String, name: json['name'] as String, nick: json['nick'] as String, permNodes: json['perm_nodes'] as Map? ?? const {}, @@ -52,7 +51,6 @@ Map _$SnAccountToJson(_SnAccount instance) => 'contacts': instance.contacts?.map((e) => e.toJson()).toList(), 'avatar': instance.avatar, 'banner': instance.banner, - 'description': instance.description, 'name': instance.name, 'nick': instance.nick, 'perm_nodes': instance.permNodes, @@ -101,35 +99,50 @@ Map _$SnAccountContactToJson(_SnAccountContact instance) => _SnAccountProfile _$SnAccountProfileFromJson(Map json) => _SnAccountProfile( id: (json['id'] as num).toInt(), - accountId: (json['account_id'] as num).toInt(), - birthday: json['birthday'] == null - ? null - : DateTime.parse(json['birthday'] as String), createdAt: DateTime.parse(json['created_at'] as String), + updatedAt: DateTime.parse(json['updated_at'] as String), deletedAt: json['deleted_at'] == null ? null : DateTime.parse(json['deleted_at'] as String), - experience: (json['experience'] as num).toInt(), firstName: json['first_name'] as String, lastName: json['last_name'] as String, + description: json['description'] as String, + timeZone: json['time_zone'] as String, + location: json['location'] as String, + pronouns: json['pronouns'] as String, + gender: json['gender'] as String, + links: (json['links'] as Map?)?.map( + (k, e) => MapEntry(k, e as String), + ) ?? + const {}, + experience: (json['experience'] as num).toInt(), lastSeenAt: json['last_seen_at'] == null ? null : DateTime.parse(json['last_seen_at'] as String), - updatedAt: DateTime.parse(json['updated_at'] as String), + birthday: json['birthday'] == null + ? null + : DateTime.parse(json['birthday'] as String), + accountId: (json['account_id'] as num).toInt(), ); Map _$SnAccountProfileToJson(_SnAccountProfile instance) => { 'id': instance.id, - 'account_id': instance.accountId, - 'birthday': instance.birthday?.toIso8601String(), 'created_at': instance.createdAt.toIso8601String(), + 'updated_at': instance.updatedAt.toIso8601String(), 'deleted_at': instance.deletedAt?.toIso8601String(), - 'experience': instance.experience, 'first_name': instance.firstName, 'last_name': instance.lastName, + 'description': instance.description, + 'time_zone': instance.timeZone, + 'location': instance.location, + 'pronouns': instance.pronouns, + 'gender': instance.gender, + 'links': instance.links, + 'experience': instance.experience, 'last_seen_at': instance.lastSeenAt?.toIso8601String(), - 'updated_at': instance.updatedAt.toIso8601String(), + 'birthday': instance.birthday?.toIso8601String(), + 'account_id': instance.accountId, }; _SnRelationship _$SnRelationshipFromJson(Map json) => diff --git a/lib/widgets/post/post_item.dart b/lib/widgets/post/post_item.dart index 981933d..4981d53 100644 --- a/lib/widgets/post/post_item.dart +++ b/lib/widgets/post/post_item.dart @@ -92,10 +92,9 @@ class OpenablePostItem extends StatelessWidget { openColor: Colors.transparent, openElevation: 0, transitionType: ContainerTransitionType.fade, - closedColor: - Theme.of(context).colorScheme.surfaceContainerLow.withOpacity( - cfg.prefs.getBool(kAppBackgroundStoreKey) == true ? 0.75 : 1, - ), + closedColor: Theme.of(context).colorScheme.surfaceContainerLow.withOpacity( + cfg.prefs.getBool(kAppBackgroundStoreKey) == true ? 0.75 : 1, + ), closedShape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16)), ), @@ -136,11 +135,9 @@ class PostItem extends StatelessWidget { final box = context.findRenderObject() as RenderBox?; final url = 'https://solsynth.dev/posts/${data.id}'; if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) { - Share.shareUri(Uri.parse(url), - sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size); + Share.shareUri(Uri.parse(url), sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size); } else { - Share.share(url, - sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size); + Share.share(url, sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size); } } @@ -158,8 +155,7 @@ class PostItem extends StatelessWidget { child: MultiProvider( providers: [ Provider(create: (_) => context.read()), - ChangeNotifierProvider( - create: (_) => context.read()), + ChangeNotifierProvider(create: (_) => context.read()), ], child: ResponsiveBreakpoints.builder( breakpoints: ResponsiveBreakpoints.of(context).breakpoints, @@ -187,8 +183,7 @@ class PostItem extends StatelessWidget { sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size, ); } else { - await FileSaver.instance.saveFile( - name: 'Solar Network Post #${data.id}.png', file: imageFile); + await FileSaver.instance.saveFile(name: 'Solar Network Post #${data.id}.png', file: imageFile); } await imageFile.delete(); @@ -202,9 +197,7 @@ class PostItem extends StatelessWidget { final isAuthor = ua.isAuthorized && data.publisher.accountId == ua.user?.id; // Video full view - if (showFullPost && - data.type == 'video' && - ResponsiveBreakpoints.of(context).largerThan(TABLET)) { + if (showFullPost && data.type == 'video' && ResponsiveBreakpoints.of(context).largerThan(TABLET)) { return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -224,8 +217,7 @@ class PostItem extends StatelessWidget { if (onDeleted != null) {} }, ).padding(bottom: 8), - if (data.preload?.video != null) - _PostVideoPlayer(data: data).padding(bottom: 8), + if (data.preload?.video != null) _PostVideoPlayer(data: data).padding(bottom: 8), _PostHeadline(data: data).padding(horizontal: 4, bottom: 8), _PostFeaturedComment(data: data), _PostBottomAction( @@ -273,8 +265,7 @@ class PostItem extends StatelessWidget { if (onDeleted != null) {} }, ).padding(horizontal: 12, top: 8, bottom: 8), - if (data.preload?.video != null) - _PostVideoPlayer(data: data).padding(horizontal: 12, bottom: 8), + if (data.preload?.video != null) _PostVideoPlayer(data: data).padding(horizontal: 12, bottom: 8), Container( width: double.infinity, margin: const EdgeInsets.only(bottom: 4, left: 12, right: 12), @@ -317,13 +308,8 @@ class PostItem extends StatelessWidget { ], ), ), - Text('postArticle') - .tr() - .fontSize(13) - .opacity(0.75) - .padding(horizontal: 24, bottom: 8), - _PostFeaturedComment(data: data, maxWidth: maxWidth) - .padding(horizontal: 12), + Text('postArticle').tr().fontSize(13).opacity(0.75).padding(horizontal: 24, bottom: 8), + _PostFeaturedComment(data: data, maxWidth: maxWidth).padding(horizontal: 12), _PostBottomAction( data: data, showComments: showComments, @@ -338,8 +324,7 @@ class PostItem extends StatelessWidget { } final displayableAttachments = data.preload?.attachments - ?.where((ele) => - ele?.mediaType != SnMediaType.image || data.type != 'article') + ?.where((ele) => ele?.mediaType != SnMediaType.image || data.type != 'article') .toList(); final cfg = context.read(); @@ -364,13 +349,9 @@ class PostItem extends StatelessWidget { if (onDeleted != null) onDeleted!(); }, ).padding(horizontal: 12, vertical: 8), - if (data.preload?.video != null) - _PostVideoPlayer(data: data).padding(horizontal: 12, bottom: 8), - if (data.type == 'question') - _PostQuestionHint(data: data) - .padding(horizontal: 16, bottom: 8), - if (data.body['title'] != null || - data.body['description'] != null) + if (data.preload?.video != null) _PostVideoPlayer(data: data).padding(horizontal: 12, bottom: 8), + if (data.type == 'question') _PostQuestionHint(data: data).padding(horizontal: 16, bottom: 8), + if (data.body['title'] != null || data.body['description'] != null) _PostHeadline( data: data, isEnlarge: data.type == 'article' && showFullPost, @@ -384,8 +365,7 @@ class PostItem extends StatelessWidget { if (data.repostTo != null) _PostQuoteContent(child: data.repostTo!).padding( horizontal: 12, - bottom: - data.preload?.attachments?.isNotEmpty ?? false ? 12 : 0, + bottom: data.preload?.attachments?.isNotEmpty ?? false ? 12 : 0, ), if (data.visibility > 0) _PostVisibilityHint(data: data).padding( @@ -397,9 +377,7 @@ class PostItem extends StatelessWidget { horizontal: 16, vertical: 4, ), - if (data.tags.isNotEmpty) - _PostTagsList(data: data) - .padding(horizontal: 16, top: 4, bottom: 6), + if (data.tags.isNotEmpty) _PostTagsList(data: data).padding(horizontal: 16, top: 4, bottom: 6), ], ), ), @@ -412,16 +390,12 @@ class PostItem extends StatelessWidget { fit: showFullPost ? BoxFit.cover : BoxFit.contain, padding: const EdgeInsets.symmetric(horizontal: 12), ), - if (data.preload?.poll != null) - PostPoll(poll: data.preload!.poll!) - .padding(horizontal: 12, vertical: 4), - if (data.body['content'] != null && - (cfg.prefs.getBool(kAppExpandPostLink) ?? true)) + if (data.preload?.poll != null) PostPoll(poll: data.preload!.poll!).padding(horizontal: 12, vertical: 4), + if (data.body['content'] != null && (cfg.prefs.getBool(kAppExpandPostLink) ?? true)) LinkPreviewWidget( text: data.body['content'], ).padding(horizontal: 4), - _PostFeaturedComment(data: data, maxWidth: maxWidth) - .padding(horizontal: 12), + _PostFeaturedComment(data: data, maxWidth: maxWidth).padding(horizontal: 12), Container( constraints: BoxConstraints(maxWidth: maxWidth ?? double.infinity), child: Column( @@ -483,8 +457,7 @@ class PostShareImageWidget extends StatelessWidget { showMenu: false, isRelativeDate: false, ).padding(horizontal: 16, bottom: 8), - if (data.type == 'question') - _PostQuestionHint(data: data).padding(horizontal: 16, bottom: 8), + if (data.type == 'question') _PostQuestionHint(data: data).padding(horizontal: 16, bottom: 8), _PostHeadline( data: data, isEnlarge: data.type == 'article', @@ -499,8 +472,7 @@ class PostShareImageWidget extends StatelessWidget { child: data.repostTo!, isRelativeDate: false, ).padding(horizontal: 16, bottom: 8), - if (data.type != 'article' && - (data.preload?.attachments?.isNotEmpty ?? false)) + if (data.type != 'article' && (data.preload?.attachments?.isNotEmpty ?? false)) StyledWidget(AttachmentList( data: data.preload!.attachments!, columned: true, @@ -509,8 +481,7 @@ class PostShareImageWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (data.visibility > 0) _PostVisibilityHint(data: data), - if (data.body['content_truncated'] == true) - _PostTruncatedHint(data: data), + if (data.body['content_truncated'] == true) _PostTruncatedHint(data: data), ], ).padding(horizontal: 16), _PostBottomAction( @@ -570,8 +541,7 @@ class PostShareImageWidget extends StatelessWidget { version: QrVersions.auto, size: 100, gapless: true, - embeddedImage: - AssetImage('assets/icon/icon-light-radius.png'), + embeddedImage: AssetImage('assets/icon/icon-light-radius.png'), embeddedImageStyle: QrEmbeddedImageStyle( size: Size(28, 28), ), @@ -602,11 +572,9 @@ class _PostQuestionHint extends StatelessWidget { Widget build(BuildContext context) { return Row( children: [ - Icon(data.body['answer'] == null ? Symbols.help : Symbols.check_circle, - size: 20), + Icon(data.body['answer'] == null ? Symbols.help : Symbols.check_circle, size: 20), const Gap(4), - if (data.body['answer'] == null && - data.body['reward']?.toDouble() != null) + if (data.body['answer'] == null && data.body['reward']?.toDouble() != null) Text('postQuestionUnansweredWithReward'.tr(args: [ '${data.body['reward']}', ])).opacity(0.75) @@ -642,9 +610,7 @@ class _PostBottomAction extends StatelessWidget { ); final String? mostTypicalReaction = data.metric.reactionList.isNotEmpty - ? data.metric.reactionList.entries - .reduce((a, b) => a.value > b.value ? a : b) - .key + ? data.metric.reactionList.entries.reduce((a, b) => a.value > b.value ? a : b).key : null; return Row( @@ -658,8 +624,7 @@ class _PostBottomAction extends StatelessWidget { InkWell( child: Row( children: [ - if (mostTypicalReaction == null || - kTemplateReactions[mostTypicalReaction] == null) + if (mostTypicalReaction == null || kTemplateReactions[mostTypicalReaction] == null) Icon(Symbols.add_reaction, size: 20, color: iconColor) else Text( @@ -671,8 +636,7 @@ class _PostBottomAction extends StatelessWidget { ), ), const Gap(8), - if (data.totalUpvote > 0 && - data.totalUpvote >= data.totalDownvote) + if (data.totalUpvote > 0 && data.totalUpvote >= data.totalDownvote) Text('postReactionUpvote').plural( data.totalUpvote, ) @@ -691,12 +655,8 @@ class _PostBottomAction extends StatelessWidget { data: data, onChanged: (value, attr, delta) { onChanged(data.copyWith( - totalUpvote: attr == 1 - ? data.totalUpvote + delta - : data.totalUpvote, - totalDownvote: attr == 2 - ? data.totalDownvote + delta - : data.totalDownvote, + totalUpvote: attr == 1 ? data.totalUpvote + delta : data.totalUpvote, + totalDownvote: attr == 2 ? data.totalDownvote + delta : data.totalDownvote, metric: data.metric.copyWith(reactionList: value), )); }, @@ -803,7 +763,7 @@ class _PostHeadline extends StatelessWidget { children: [ Text( 'articleWrittenAt'.tr( - args: [DateFormat('y/M/d HH:mm').format(data.createdAt)], + args: [DateFormat('y/M/d HH:mm').format(data.createdAt.toLocal())], ), style: TextStyle(fontSize: 13), ), @@ -811,7 +771,7 @@ class _PostHeadline extends StatelessWidget { if (data.editedAt != null) Text( 'articleEditedAt'.tr( - args: [DateFormat('y/M/d HH:mm').format(data.editedAt!)], + args: [DateFormat('y/M/d HH:mm').format(data.editedAt!.toLocal())], ), style: TextStyle(fontSize: 13), ), @@ -944,10 +904,8 @@ class _PostContentHeader extends StatelessWidget { const Gap(4), Text( isRelativeDate - ? RelativeTime(context) - .format(data.publishedAt ?? data.createdAt) - : DateFormat('y/M/d HH:mm') - .format(data.publishedAt ?? data.createdAt), + ? RelativeTime(context).format((data.publishedAt ?? data.createdAt).toLocal()) + : DateFormat('y/M/d HH:mm').format((data.publishedAt ?? data.createdAt).toLocal()), ).fontSize(13), ], ).opacity(0.8), @@ -965,10 +923,8 @@ class _PostContentHeader extends StatelessWidget { const Gap(4), Text( isRelativeDate - ? RelativeTime(context) - .format(data.publishedAt ?? data.createdAt) - : DateFormat('y/M/d HH:mm') - .format(data.publishedAt ?? data.createdAt), + ? RelativeTime(context).format((data.publishedAt ?? data.createdAt).toLocal()) + : DateFormat('y/M/d HH:mm').format((data.publishedAt ?? data.createdAt).toLocal()), ).fontSize(13), ], ).opacity(0.8), @@ -1151,8 +1107,7 @@ class _PostContentBody extends StatelessWidget { if (data.body['content'] == null) return const SizedBox.shrink(); final content = MarkdownTextContent( isAutoWarp: data.type == 'story', - isEnlargeSticker: - RegExp(r"^:([-\w]+):$").hasMatch(data.body['content'] ?? ''), + isEnlargeSticker: RegExp(r"^:([-\w]+):$").hasMatch(data.body['content'] ?? ''), textScaler: isEnlarge ? TextScaler.linear(1.1) : null, content: data.body['content'], attachments: data.preload?.attachments, @@ -1201,12 +1156,10 @@ class _PostQuoteContent extends StatelessWidget { onDeleted: () {}, ).padding(bottom: 4), _PostContentBody(data: child), - if (child.visibility > 0) - _PostVisibilityHint(data: child).padding(top: 4), + if (child.visibility > 0) _PostVisibilityHint(data: child).padding(top: 4), ], ).padding(horizontal: 16), - if (child.type != 'article' && - (child.preload?.attachments?.isNotEmpty ?? false)) + if (child.type != 'article' && (child.preload?.attachments?.isNotEmpty ?? false)) ClipRRect( borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(8), @@ -1357,9 +1310,7 @@ class _PostTruncatedHint extends StatelessWidget { const Gap(4), Text('postReadEstimate').tr(args: [ '${Duration( - seconds: (data.body['content_length'] as num).toDouble() * - 60 ~/ - kHumanReadSpeed, + seconds: (data.body['content_length'] as num).toDouble() * 60 ~/ kHumanReadSpeed, ).inSeconds}s', ]), ], @@ -1398,8 +1349,7 @@ class _PostFeaturedCommentState extends State<_PostFeaturedComment> { // If this is a answered question, fetch the answer instead if (widget.data.type == 'question' && widget.data.body['answer'] != null) { final sn = context.read(); - final resp = - await sn.client.get('/cgi/co/posts/${widget.data.body['answer']}'); + final resp = await sn.client.get('/cgi/co/posts/${widget.data.body['answer']}'); _isAnswer = true; setState(() => _featuredComment = SnPost.fromJson(resp.data)); return; @@ -1407,11 +1357,9 @@ class _PostFeaturedCommentState extends State<_PostFeaturedComment> { try { final sn = context.read(); - final resp = await sn.client.get( - '/cgi/co/posts/${widget.data.id}/replies/featured', - queryParameters: { - 'take': 1, - }); + final resp = await sn.client.get('/cgi/co/posts/${widget.data.id}/replies/featured', queryParameters: { + 'take': 1, + }); setState(() => _featuredComment = SnPost.fromJson(resp.data[0])); } catch (err) { if (!mounted) return; @@ -1440,9 +1388,7 @@ class _PostFeaturedCommentState extends State<_PostFeaturedComment> { width: double.infinity, child: Material( borderRadius: const BorderRadius.all(Radius.circular(8)), - color: _isAnswer - ? Colors.green.withOpacity(0.5) - : Theme.of(context).colorScheme.surfaceContainerHigh, + color: _isAnswer ? Colors.green.withOpacity(0.5) : Theme.of(context).colorScheme.surfaceContainerHigh, child: InkWell( borderRadius: const BorderRadius.all(Radius.circular(8)), onTap: () { @@ -1462,17 +1408,11 @@ class _PostFeaturedCommentState extends State<_PostFeaturedComment> { crossAxisAlignment: CrossAxisAlignment.center, children: [ const Gap(2), - Icon(_isAnswer ? Symbols.task_alt : Symbols.prompt_suggestion, - size: 20), + Icon(_isAnswer ? Symbols.task_alt : Symbols.prompt_suggestion, size: 20), const Gap(10), Text( - _isAnswer - ? 'postQuestionAnswerTitle' - : 'postFeaturedComment', - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(fontSize: 15), + _isAnswer ? 'postQuestionAnswerTitle' : 'postFeaturedComment', + style: Theme.of(context).textTheme.titleMedium!.copyWith(fontSize: 15), ).tr(), ], ), @@ -1610,8 +1550,7 @@ class _PostGetInsightPopupState extends State<_PostGetInsightPopup> { } RegExp cleanThinkingRegExp = RegExp(r'[\s\S]*?'); - setState( - () => _response = out.replaceAll(cleanThinkingRegExp, '').trim()); + setState(() => _response = out.replaceAll(cleanThinkingRegExp, '').trim()); } catch (err) { if (!mounted) return; context.showErrorDialog(err); @@ -1634,16 +1573,11 @@ class _PostGetInsightPopupState extends State<_PostGetInsightPopup> { children: [ const Icon(Symbols.book_4_spark, size: 24), const Gap(16), - Text('postGetInsightTitle', - style: Theme.of(context).textTheme.titleLarge) - .tr(), + Text('postGetInsightTitle', style: Theme.of(context).textTheme.titleLarge).tr(), ], ).padding(horizontal: 20, top: 16, bottom: 12), const Gap(4), - Text('postGetInsightDescription', - style: Theme.of(context).textTheme.bodySmall) - .tr() - .padding(horizontal: 20), + Text('postGetInsightDescription', style: Theme.of(context).textTheme.bodySmall).tr().padding(horizontal: 20), const Gap(4), if (_response == null) Expanded( @@ -1661,16 +1595,12 @@ class _PostGetInsightPopupState extends State<_PostGetInsightPopup> { leading: const Icon(Symbols.info), title: Text('aiThinkingProcess'.tr()), tilePadding: const EdgeInsets.symmetric(horizontal: 20), - collapsedBackgroundColor: - Theme.of(context).colorScheme.surfaceContainerHigh, + collapsedBackgroundColor: Theme.of(context).colorScheme.surfaceContainerHigh, minTileHeight: 32, children: [ SelectableText( _thinkingProcess!, - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(fontStyle: FontStyle.italic), + style: Theme.of(context).textTheme.bodyMedium!.copyWith(fontStyle: FontStyle.italic), ).padding(horizontal: 20, vertical: 8), ], ).padding(vertical: 8), @@ -1707,8 +1637,7 @@ class _PostVideoPlayer extends StatelessWidget { aspectRatio: 16 / 9, child: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(8)), - child: AttachmentItem( - data: data.preload!.video!, heroTag: 'post-video-${data.id}'), + child: AttachmentItem(data: data.preload!.video!, heroTag: 'post-video-${data.id}'), ), ), ); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 829bb26..ca76b95 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,9 @@ 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_timezone_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterTimezonePlugin"); + flutter_timezone_plugin_register_with_registrar(flutter_timezone_registrar); g_autoptr(FlPluginRegistrar) flutter_udid_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterUdidPlugin"); flutter_udid_plugin_register_with_registrar(flutter_udid_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 02e94ea..8908477 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST bitsdojo_window_linux file_saver file_selector_linux + flutter_timezone flutter_udid flutter_webrtc hotkey_manager_linux diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 965bc4c..66c7b43 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -15,9 +15,11 @@ import firebase_analytics import firebase_core import firebase_messaging import flutter_inappwebview_macos +import flutter_timezone import flutter_udid import flutter_webrtc import gal +import geolocator_apple import hotkey_manager_macos import in_app_review import livekit_client @@ -48,9 +50,11 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) + FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin")) FlutterUdidPlugin.register(with: registry.registrar(forPlugin: "FlutterUdidPlugin")) FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin")) GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin")) + GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) HotkeyManagerMacosPlugin.register(with: registry.registrar(forPlugin: "HotkeyManagerMacosPlugin")) InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin")) LiveKitPlugin.register(with: registry.registrar(forPlugin: "LiveKitPlugin")) diff --git a/pubspec.lock b/pubspec.lock index ad4c980..2a53880 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -345,6 +345,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dart_earcut: + dependency: transitive + description: + name: dart_earcut + sha256: e485001bfc05dcbc437d7bfb666316182e3522d4c3f9668048e004d0eb2ce43b + url: "https://pub.dev" + source: hosted + version: "1.2.0" dart_style: dependency: transitive description: @@ -803,6 +811,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_map: + dependency: "direct main" + description: + name: flutter_map + sha256: bbf145e8220531f2f727608c431871c7457f3b134e513543913afd00fdc1cd47 + url: "https://pub.dev" + source: hosted + version: "8.1.0" flutter_markdown: dependency: "direct main" description: @@ -872,6 +888,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_timezone: + dependency: "direct main" + description: + name: flutter_timezone + sha256: bc286cecb0366d88e6c4644e3962ebd1ce1d233abc658eb1e0cd803389f84b64 + url: "https://pub.dev" + source: hosted + version: "4.1.0" flutter_udid: dependency: "direct main" description: @@ -933,6 +957,54 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: d2ec66329cab29cb297d51d96c067d457ca519dca8589665fa0b82ebacb7dbe4 + url: "https://pub.dev" + source: hosted + version: "13.0.2" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: "7aefc530db47d90d0580b552df3242440a10fe60814496a979aa67aa98b1fd47" + url: "https://pub.dev" + source: hosted + version: "4.6.1" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: c4ecead17985ede9634f21500072edfcb3dba0ef7b97f8d7bc556d2d722b3ba3 + url: "https://pub.dev" + source: hosted + version: "2.3.9" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "386ce3d9cce47838355000070b1d0b13efb5bc430f8ecda7e9238c8409ace012" + url: "https://pub.dev" + source: hosted + version: "4.2.4" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: "2ed69328e05cd94e7eb48bb0535f5fc0c0c44d1c4fa1e9737267484d05c29b5e" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "53da08937d07c24b0d9952eb57a3b474e29aae2abf9dd717f7e1230995f13f0e" + url: "https://pub.dev" + source: hosted + version: "0.2.3" glob: dependency: transitive description: @@ -1197,6 +1269,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.9.4" + latlong2: + dependency: transitive + description: + name: latlong2 + sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe" + url: "https://pub.dev" + source: hosted + version: "0.9.1" leak_tracker: dependency: transitive description: @@ -1237,6 +1317,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.1.1" + lists: + dependency: transitive + description: + name: lists + sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" + url: "https://pub.dev" + source: hosted + version: "1.0.1" livekit_client: dependency: "direct main" description: @@ -1253,6 +1341,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.6" + logger: + dependency: transitive + description: + name: logger + sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1 + url: "https://pub.dev" + source: hosted + version: "2.5.0" logging: dependency: transitive description: @@ -1389,6 +1485,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.16.0" + mgrs_dart: + dependency: transitive + description: + name: mgrs_dart + sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 + url: "https://pub.dev" + source: hosted + version: "2.0.0" mime: dependency: "direct main" description: @@ -1605,6 +1709,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" + polylabel: + dependency: transitive + description: + name: polylabel + sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b" + url: "https://pub.dev" + source: hosted + version: "1.0.1" pool: dependency: transitive description: @@ -1629,6 +1741,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.0.1" + proj4dart: + dependency: transitive + description: + name: proj4dart + sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e + url: "https://pub.dev" + source: hosted + version: "2.1.0" protobuf: dependency: transitive description: @@ -2146,6 +2266,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.3" + unicode: + dependency: transitive + description: + name: unicode + sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" + url: "https://pub.dev" + source: hosted + version: "0.3.1" universal_io: dependency: transitive description: @@ -2386,6 +2514,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + wkt_parser: + dependency: transitive + description: + name: wkt_parser + sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" + url: "https://pub.dev" + source: hosted + version: "2.0.0" workmanager: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 2647432..7addab9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -134,6 +134,9 @@ dependencies: talker_dio_logger: ^4.6.14 talker: ^4.6.14 flutter_cache_manager: ^3.4.1 + flutter_timezone: ^4.1.0 + flutter_map: ^8.1.0 + geolocator: ^13.0.2 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 91d44ed..4ec2695 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -12,9 +12,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -41,12 +43,16 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); + FlutterTimezonePluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterTimezonePluginCApi")); FlutterUdidPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterUdidPluginCApi")); FlutterWebRTCPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterWebRTCPlugin")); GalPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("GalPluginCApi")); + GeolocatorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GeolocatorWindows")); HotkeyManagerWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("HotkeyManagerWindowsPluginCApi")); LiveKitPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 4b751c1..fa1c0b0 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -9,9 +9,11 @@ list(APPEND FLUTTER_PLUGIN_LIST file_selector_windows firebase_core flutter_inappwebview_windows + flutter_timezone flutter_udid flutter_webrtc gal + geolocator_windows hotkey_manager_windows livekit_client local_notifier