diff --git a/lib/providers/websocket.dart b/lib/providers/websocket.dart index 7758577..69418da 100644 --- a/lib/providers/websocket.dart +++ b/lib/providers/websocket.dart @@ -42,22 +42,22 @@ class WebSocketProvider extends ChangeNotifier { _connectCompleter = null; } - _connectCompleter = Completer(); - if (!_ua.isAuthorized) return; if (isConnected || conn != null) { disconnect(); } - final atk = await _sn.getFreshAtk(); - final uri = Uri.parse( - '${_sn.client.options.baseUrl.replaceFirst('http', 'ws')}/ws?tk=$atk', - ); - - isBusy = true; - notifyListeners(); - try { + _connectCompleter = Completer(); + + final atk = await _sn.getFreshAtk(); + final uri = Uri.parse( + '${_sn.client.options.baseUrl.replaceFirst('http', 'ws')}/ws?tk=$atk', + ); + + isBusy = true; + notifyListeners(); + conn = WebSocketChannel.connect(uri); await conn!.ready; _wsStream = conn!.stream.asBroadcastStream(); @@ -82,6 +82,7 @@ class WebSocketProvider extends ChangeNotifier { isBusy = false; notifyListeners(); _connectCompleter!.complete(); + _connectCompleter = null; } } diff --git a/lib/screens/post/post_editor.dart b/lib/screens/post/post_editor.dart index ca32033..fd55915 100644 --- a/lib/screens/post/post_editor.dart +++ b/lib/screens/post/post_editor.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_context_menu/flutter_context_menu.dart'; import 'package:gap/gap.dart'; +import 'package:go_router/go_router.dart'; import 'package:hotkey_manager/hotkey_manager.dart'; import 'package:material_symbols_icons/symbols.dart'; import 'package:pasteboard/pasteboard.dart'; @@ -90,8 +91,9 @@ class _PostEditorScreenState extends State { resp.data?.map((e) => SnPublisher.fromJson(e)) ?? [], ); final beforeId = config.prefs.getInt('int_last_publisher_id'); - _writeController - .setPublisher(_publishers?.where((ele) => ele.id == beforeId).firstOrNull ?? _publishers?.firstOrNull); + _writeController.setPublisher( + _publishers?.where((ele) => ele.id == beforeId).firstOrNull ?? + _publishers?.firstOrNull); } catch (err) { if (!mounted) return; context.showErrorDialog(err); @@ -110,7 +112,9 @@ class _PostEditorScreenState extends State { final HotKey _pasteHotKey = HotKey( key: PhysicalKeyboardKey.keyV, - modifiers: [Platform.isMacOS ? HotKeyModifier.meta : HotKeyModifier.control], + modifiers: [ + Platform.isMacOS ? HotKeyModifier.meta : HotKeyModifier.control + ], scope: HotKeyScope.inapp, ); @@ -160,7 +164,8 @@ class _PostEditorScreenState extends State { @override void dispose() { _writeController.dispose(); - if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) hotKeyManager.unregister(_pasteHotKey); + if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) + hotKeyManager.unregister(_pasteHotKey); super.dispose(); } @@ -184,7 +189,8 @@ class _PostEditorScreenState extends State { if (widget.extraProps != null) { _writeController.contentController.text = widget.extraProps!.text ?? ''; _writeController.titleController.text = widget.extraProps!.title ?? ''; - _writeController.descriptionController.text = widget.extraProps!.description ?? ''; + _writeController.descriptionController.text = + widget.extraProps!.description ?? ''; _writeController.addAttachments(widget.extraProps!.attachments ?? []); } } @@ -205,7 +211,9 @@ class _PostEditorScreenState extends State { textAlign: TextAlign.center, text: TextSpan(children: [ TextSpan( - text: _writeController.title.isNotEmpty ? _writeController.title : 'untitled'.tr(), + text: _writeController.title.isNotEmpty + ? _writeController.title + : 'untitled'.tr(), style: Theme.of(context).textTheme.titleLarge!.copyWith( color: Theme.of(context).appBarTheme.foregroundColor!, ), @@ -232,7 +240,8 @@ class _PostEditorScreenState extends State { children: [ if (_writeController.editingPost != null) Container( - padding: const EdgeInsets.only(top: 4, bottom: 4, left: 20, right: 20), + padding: const EdgeInsets.only( + top: 4, bottom: 4, left: 20, right: 20), decoration: BoxDecoration( border: Border( bottom: BorderSide( @@ -246,7 +255,9 @@ class _PostEditorScreenState extends State { children: [ const Icon(Icons.edit, size: 16), const Gap(10), - Text('postEditingNotice').tr(args: ['@${_writeController.editingPost!.publisher.name}']), + Text('postEditingNotice').tr(args: [ + '@${_writeController.editingPost!.publisher.name}' + ]), ], ), ), @@ -276,7 +287,8 @@ class _PostEditorScreenState extends State { }) .padding(top: 8), ), - if (_writeController.attachments.isNotEmpty || _writeController.thumbnail != null) + if (_writeController.attachments.isNotEmpty || + _writeController.thumbnail != null) Positioned( bottom: 0, left: 0, @@ -286,7 +298,8 @@ class _PostEditorScreenState extends State { attachments: _writeController.attachments, isBusy: _writeController.isBusy, onUpload: (int idx) async { - await _writeController.uploadSingleAttachment(context, idx); + await _writeController.uploadSingleAttachment( + context, idx); }, onPostSetThumbnail: (int? idx) { _writeController.setThumbnail(idx); @@ -295,10 +308,12 @@ class _PostEditorScreenState extends State { _writeController.contentController.text += '\n![](solink://attachments/${_writeController.attachments[idx].attachment!.rid})'; }, - onUpdate: (int idx, PostWriteMedia updatedMedia) async { + onUpdate: + (int idx, PostWriteMedia updatedMedia) async { _writeController.setIsBusy(true); try { - _writeController.setAttachmentAt(idx, updatedMedia); + _writeController.setAttachmentAt( + idx, updatedMedia); } finally { _writeController.setIsBusy(false); } @@ -311,7 +326,8 @@ class _PostEditorScreenState extends State { _writeController.setIsBusy(false); } }, - onUpdateBusy: (state) => _writeController.setIsBusy(state), + onUpdateBusy: (state) => + _writeController.setIsBusy(state), ).padding(bottom: 8), ), ], @@ -322,11 +338,13 @@ class _PostEditorScreenState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (_writeController.isBusy && _writeController.progress != null) + if (_writeController.isBusy && + _writeController.progress != null) TweenAnimationBuilder( tween: Tween(begin: 0, end: _writeController.progress), duration: Duration(milliseconds: 300), - builder: (context, value, _) => LinearProgressIndicator(value: value, minHeight: 2), + builder: (context, value, _) => + LinearProgressIndicator(value: value, minHeight: 2), ) else if (_writeController.isBusy) const LinearProgressIndicator(value: null, minHeight: 2), @@ -335,12 +353,14 @@ class _PostEditorScreenState extends State { Container( child: _writeController.temporaryRestored ? Container( - padding: const EdgeInsets.only(top: 4, bottom: 4, left: 28, right: 22), + padding: const EdgeInsets.only( + top: 4, bottom: 4, left: 28, right: 22), decoration: BoxDecoration( border: Border( bottom: BorderSide( color: Theme.of(context).dividerColor, - width: 1 / MediaQuery.of(context).devicePixelRatio, + width: 1 / + MediaQuery.of(context).devicePixelRatio, ), ), ), @@ -349,7 +369,9 @@ class _PostEditorScreenState extends State { children: [ const Icon(Icons.restore, size: 20), const Gap(8), - Expanded(child: Text('postLocalDraftRestored').tr()), + Expanded( + child: + Text('postLocalDraftRestored').tr()), InkWell( child: Text('dialogDismiss').tr(), onTap: () { @@ -360,8 +382,10 @@ class _PostEditorScreenState extends State { )) : const SizedBox.shrink(), ) - .height(_writeController.temporaryRestored ? 32 : 0, animate: true) - .animate(const Duration(milliseconds: 300), Curves.fastLinearToSlowEaseIn), + .height(_writeController.temporaryRestored ? 32 : 0, + animate: true) + .animate(const Duration(milliseconds: 300), + Curves.fastLinearToSlowEaseIn), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -381,11 +405,18 @@ class _PostEditorScreenState extends State { ), if (_writeController.mode == 'stories') IconButton( - icon: Icon(Symbols.poll, color: Theme.of(context).colorScheme.primary), + icon: Icon(Symbols.poll, + color: Theme.of(context) + .colorScheme + .primary), style: ButtonStyle( - backgroundColor: _writeController.poll == null - ? null - : WidgetStatePropertyAll(Theme.of(context).colorScheme.surfaceContainer), + backgroundColor: + _writeController.poll == null + ? null + : WidgetStatePropertyAll( + Theme.of(context) + .colorScheme + .surfaceContainer), ), onPressed: () { _showPollEditorDialog(); @@ -397,7 +428,8 @@ class _PostEditorScreenState extends State { ), ), TextButton.icon( - onPressed: (_writeController.isBusy || _writeController.publisher == null) + onPressed: (_writeController.isBusy || + _writeController.publisher == null) ? null : () { _writeController.sendPost(context).then((_) { @@ -447,9 +479,21 @@ class _PostPublisherPopup extends StatelessWidget { children: [ const Icon(Symbols.face, size: 24), const Gap(16), - Text('accountPublishers', style: Theme.of(context).textTheme.titleLarge).tr(), + Text('accountPublishers', + style: Theme.of(context).textTheme.titleLarge) + .tr(), ], ).padding(horizontal: 20, top: 16, bottom: 12), + ListTile( + leading: const Icon(Symbols.add), + title: Text('publishersNew').tr(), + subtitle: Text('publisherNewSubtitle').tr(), + contentPadding: const EdgeInsets.symmetric(horizontal: 24), + onTap: () { + GoRouter.of(context).pushNamed('accountPublisherNew'); + }, + ), + const Divider(height: 1), Expanded( child: ListView.builder( itemCount: publishers?.length ?? 0, @@ -509,7 +553,8 @@ class _PostStoryEditor extends StatelessWidget { border: InputBorder.none, ), style: Theme.of(context).textTheme.titleLarge, - onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), ).padding(horizontal: 16), const Gap(8), TextField( @@ -524,7 +569,8 @@ class _PostStoryEditor extends StatelessWidget { ), border: InputBorder.none, ), - onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), ), ], ), @@ -614,7 +660,8 @@ class _PostArticleEditor extends StatelessWidget { ), border: InputBorder.none, ), - onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), ), ), const Gap(8), @@ -693,7 +740,8 @@ class _PostQuestionEditor extends StatelessWidget { border: InputBorder.none, ), style: Theme.of(context).textTheme.titleLarge, - onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), ).padding(horizontal: 16), const Gap(8), TextField( @@ -704,7 +752,8 @@ class _PostQuestionEditor extends StatelessWidget { border: InputBorder.none, isCollapsed: true, ), - onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), ).padding(horizontal: 16), const Gap(8), TextField( @@ -719,7 +768,8 @@ class _PostQuestionEditor extends StatelessWidget { ), border: InputBorder.none, ), - onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), ), ], ), @@ -755,7 +805,8 @@ class _PostVideoEditor extends StatelessWidget { final result = await showDialog( context: context, - builder: (context) => PendingAttachmentAltDialog(media: PostWriteMedia(controller.videoAttachment)), + builder: (context) => PendingAttachmentAltDialog( + media: PostWriteMedia(controller.videoAttachment)), ); if (result == null) return; @@ -767,7 +818,8 @@ class _PostVideoEditor extends StatelessWidget { final result = await showDialog( context: context, - builder: (context) => PendingAttachmentBoostDialog(media: PostWriteMedia(controller.videoAttachment)), + builder: (context) => PendingAttachmentBoostDialog( + media: PostWriteMedia(controller.videoAttachment)), ); if (result == null) return; @@ -810,7 +862,8 @@ class _PostVideoEditor extends StatelessWidget { try { final sn = context.read(); - await sn.client.delete('/cgi/uc/attachments/${controller.videoAttachment!.id}'); + await sn.client + .delete('/cgi/uc/attachments/${controller.videoAttachment!.id}'); controller.setVideoAttachment(null); } catch (err) { if (!context.mounted) return; @@ -902,7 +955,8 @@ class _PostVideoEditor extends StatelessWidget { label: 'attachmentCopyRandomId'.tr(), icon: Symbols.content_copy, onSelected: () { - Clipboard.setData(ClipboardData(text: controller.videoAttachment!.rid)); + Clipboard.setData( + ClipboardData(text: controller.videoAttachment!.rid)); }, ), MenuItem( @@ -921,7 +975,9 @@ class _PostVideoEditor extends StatelessWidget { ), child: InkWell( borderRadius: BorderRadius.circular(16), - onTap: controller.videoAttachment == null ? () => _selectVideo(context) : null, + onTap: controller.videoAttachment == null + ? () => _selectVideo(context) + : null, child: AspectRatio( aspectRatio: 16 / 9, child: controller.videoAttachment == null diff --git a/pubspec.lock b/pubspec.lock index 569a582..06b6faa 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -498,10 +498,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "3d57312a53746ed4eb8c843dc50372454bbda37dd0c01a4d40fedc83e2ce4921" + sha256: ab13ae8ef5580a411c458d6207b6774a6c237d77ac37011b13994879f68a8810 url: "https://pub.dev" source: hosted - version: "8.3.5" + version: "8.3.7" file_saver: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 1bf4295..a44dea3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 2.3.2+67 +version: 2.3.2+68 environment: sdk: ^3.5.4