diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml index b1c258956b..44265f6071 100644 --- a/.github/workflows/dart.yml +++ b/.github/workflows/dart.yml @@ -20,7 +20,7 @@ jobs: - uses: subosito/flutter-action@v2 with: - channel: 'stable' # 'master', 'beta', 'dev' or 'stable' + channel: 'master' # 'master', 'beta', 'dev' or 'stable' # flutter build need ninja. # https://github.com/subosito/flutter-action/issues/49 diff --git a/.github/workflows/manual-build.yml b/.github/workflows/manual-build.yml index 758a25494b..98f55302e9 100644 --- a/.github/workflows/manual-build.yml +++ b/.github/workflows/manual-build.yml @@ -8,7 +8,7 @@ on: flutter_channel: description: "run with flutter channel, eg: master, beta, stable" required: true - default: "stable" + default: "master" jobs: build-linux: diff --git a/analysis_options.yaml b/analysis_options.yaml index 82d4d462bf..57804e4c67 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,4 +1,4 @@ -include: package:very_good_analysis/analysis_options.3.0.1.yaml +include: package:very_good_analysis/analysis_options.3.1.0.yaml analyzer: plugins: @@ -19,7 +19,7 @@ analyzer: implicit_dynamic_variable: ignore implicit_dynamic_function: ignore avoid_setters_without_getters: ignore -# experimental lint + # experimental lint use_build_context_synchronously: ignore body_might_complete_normally_nullable: ignore exclude: @@ -31,7 +31,7 @@ analyzer: # custom - 'lib/generated/**' - '**.g.dart' -# - 'editable/**' + # - 'editable/**' - 'third_party/**' linter: @@ -71,22 +71,26 @@ linter: prefer_asserts_with_message: false avoid_positional_boolean_parameters: false + depend_on_referenced_packages: false + no_leading_underscores_for_local_identifiers: false + use_if_null_to_convert_nulls_to_bools: false + dart_code_metrics: rules: - avoid-banned-imports - avoid-collection-methods-with-unrelated-types - avoid-duplicate-exports -# - avoid-dynamic -# - avoid-global-state -# - avoid-ignoring-return-values -# - avoid-late-keyword + # - avoid-dynamic + # - avoid-global-state + # - avoid-ignoring-return-values + # - avoid-late-keyword - avoid-missing-enum-constant-in-map - avoid-nested-conditional-expressions: acceptable-level: 2 - avoid-non-ascii-symbols: exclude: - test/** -# - avoid-non-null-assertion + # - avoid-non-null-assertion - avoid-throw-in-catch-block - avoid-unnecessary-type-assertions - avoid-unrelated-type-assertions @@ -96,48 +100,48 @@ dart_code_metrics: - ban-name - binary-expression-operand-order - double-literal-format -# - format-comment -# - member-ordering: -# alphabetize: true -# - member-ordering-extended -# do not use this -# - newline-before-return + # - format-comment + # - member-ordering: + # alphabetize: true + # - member-ordering-extended + # do not use this + # - newline-before-return - no-boolean-literal-compare -# - no-empty-block -# todo use -# - no-equal-arguments + # - no-empty-block + # todo use + # - no-equal-arguments - no-equal-then-else -# todo use -# - no-magic-number -# - no-object-declaration -# - prefer-async-await -# todo use -# - prefer-commenting-analyzer-ignores -# - prefer-conditional-expressions -# todo use -# - prefer-correct-identifier-length + # todo use + # - no-magic-number + # - no-object-declaration + # - prefer-async-await + # todo use + # - prefer-commenting-analyzer-ignores + # - prefer-conditional-expressions + # todo use + # - prefer-correct-identifier-length - prefer-correct-type-name - prefer-enums-by-name - prefer-first - prefer-immediate-return - prefer-last -# todo maybe use -# - prefer-match-file-name -# todo maybe use -# - prefer-trailing-comma: -# break-on: 3 + # todo maybe use + # - prefer-match-file-name + # todo maybe use + # - prefer-trailing-comma: + # break-on: 3 - tag-name -# Flutter specific + # Flutter specific - always-remove-listener -# - avoid-border-all -# - avoid-returning-widgets + # - avoid-border-all + # - avoid-returning-widgets - avoid-unnecessary-setstate -# - avoid-wrapping-in-padding + # - avoid-wrapping-in-padding - avoid-use-expanded-as-spacer - prefer-const-border-radius -# - prefer-extracting-callbacks -# - prefer-single-widget-per-file -# Intl specific + # - prefer-extracting-callbacks + # - prefer-single-widget-per-file + # Intl specific - prefer-intl-name - provide-correct-intl-args diff --git a/lib/ui/home/bloc/blink_cubit.dart b/lib/ui/home/bloc/blink_cubit.dart index f96a44c3c6..42c2702469 100644 --- a/lib/ui/home/bloc/blink_cubit.dart +++ b/lib/ui/home/bloc/blink_cubit.dart @@ -20,8 +20,8 @@ class BlinkState extends Equatable { ]; BlinkState copyWith({ - final Color? color, - final String? messageId, + Color? color, + String? messageId, }) => BlinkState( color: color ?? this.color, diff --git a/lib/ui/home/bloc/mention_cubit.dart b/lib/ui/home/bloc/mention_cubit.dart index 9e0e266454..1bf6ee875d 100644 --- a/lib/ui/home/bloc/mention_cubit.dart +++ b/lib/ui/home/bloc/mention_cubit.dart @@ -32,9 +32,9 @@ class MentionState extends Equatable { List get props => [text, users, index]; MentionState copyWith({ - final String? text, - final List? users, - final int? index, + String? text, + List? users, + int? index, }) => MentionState( text: text ?? this.text, diff --git a/lib/ui/home/bloc/message_bloc.dart b/lib/ui/home/bloc/message_bloc.dart index 3a4c3d1bff..e3fa880172 100644 --- a/lib/ui/home/bloc/message_bloc.dart +++ b/lib/ui/home/bloc/message_bloc.dart @@ -126,14 +126,14 @@ class MessageState extends Equatable { ]; MessageState copyWith({ - final String? conversationId, - final List? top, - final MessageItem? center, - final List? bottom, - final bool? isLatest, - final bool? isOldest, - final String? lastReadMessageId, - final Object? refreshKey, + String? conversationId, + List? top, + MessageItem? center, + List? bottom, + bool? isLatest, + bool? isOldest, + String? lastReadMessageId, + Object? refreshKey, }) => MessageState( conversationId: conversationId ?? this.conversationId, @@ -315,8 +315,8 @@ class MessageBloc extends Bloc<_MessageEvent, MessageState> }); final isOldest = list.length < limit; - return state.copyWith( - top: [...list.reversed.toList(), ...state.top], isOldest: isOldest); + return state + .copyWith(top: [...list.reversed, ...state.top], isOldest: isOldest); } Future _after(String conversationId) async { diff --git a/lib/ui/home/bloc/slide_category_state.dart b/lib/ui/home/bloc/slide_category_state.dart index 331a5a8107..c4605f7488 100644 --- a/lib/ui/home/bloc/slide_category_state.dart +++ b/lib/ui/home/bloc/slide_category_state.dart @@ -23,8 +23,8 @@ class SlideCategoryState extends Equatable { List get props => [type, id]; SlideCategoryState copyWith({ - final SlideCategoryType? type, - final String? id, + SlideCategoryType? type, + String? id, }) => SlideCategoryState( type: type ?? this.type, diff --git a/lib/ui/home/chat/chat_bar.dart b/lib/ui/home/chat/chat_bar.dart index f434944e2b..85467bcde0 100644 --- a/lib/ui/home/chat/chat_bar.dart +++ b/lib/ui/home/chat/chat_bar.dart @@ -61,102 +61,100 @@ class ChatBar extends HookWidget { ), ); - return Padding( - padding: const EdgeInsets.only(right: 16, top: 14, bottom: 14), - child: Row( - children: [ - Builder( - builder: (context) => routeMode - ? MoveWindowBarrier( - child: MixinBackButton( - color: actionColor, - onTap: () => - context.read().unselected(), - ), - ) - : const SizedBox(width: 16), + return Row( + children: [ + Builder( + builder: (context) => routeMode + ? MoveWindowBarrier( + child: MixinBackButton( + color: actionColor, + onTap: () => context.read().unselected(), + ), + ) + : const SizedBox(width: 16), + ), + toggleInfoPageWrapper( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + ConversationAvatar( + conversationState: conversation, + ), + const SizedBox(width: 10), + ], ), - toggleInfoPageWrapper( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - ConversationAvatar( + ), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + IgnorePointer( + child: ConversationName( conversationState: conversation, ), - const SizedBox(width: 10), - ], - ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - IgnorePointer( - child: ConversationName( - conversationState: conversation, - ), - ), - const SizedBox(height: 4), - IgnorePointer( - child: ConversationIDOrCount( - conversationState: conversation, - ), + ), + const SizedBox(height: 4), + IgnorePointer( + child: ConversationIDOrCount( + conversationState: conversation, ), - ] - .map((e) => toggleInfoPageWrapper( - child: e, - behavior: HitTestBehavior.deferToChild, - )) - .toList(), + ), + ] + .map((e) => toggleInfoPageWrapper( + child: e, + behavior: HitTestBehavior.deferToChild, + )) + .toList(), + ), + ), + AnimatedSize( + duration: const Duration(milliseconds: 200), + alignment: Alignment.centerLeft, + child: MoveWindowBarrier( + child: _BotIcon(conversation: conversation), + ), + ), + if (inMultiSelectMode) + MoveWindowBarrier( + child: TextButton( + onPressed: () { + context.read().clearSelection(); + }, + child: Text(context.l10n.cancel), + ), + ) + else ...[ + MoveWindowBarrier( + child: ActionButton( + name: Resources.assetsImagesIcSearchSvg, + color: actionColor, + onTap: () { + final cubit = context.read(); + if (cubit.state.pages.lastOrNull?.name == + ChatSideCubit.searchMessageHistory) { + return cubit.pop(); + } + cubit.replace(ChatSideCubit.searchMessageHistory); + }, ), ), AnimatedSize( duration: const Duration(milliseconds: 200), alignment: Alignment.centerLeft, child: MoveWindowBarrier( - child: _BotIcon(conversation: conversation), + child: chatSideRouteMode + ? const SizedBox() + : ActionButton( + name: Resources.assetsImagesIcScreenSvg, + color: actionColor, + onTap: chatSideCubit.toggleInfoPage, + ), ), ), - if (inMultiSelectMode) - MoveWindowBarrier( - child: TextButton( - onPressed: () { - context.read().clearSelection(); - }, - child: Text(context.l10n.cancel), - ), - ) - else ...[ - MoveWindowBarrier( - child: ActionButton( - name: Resources.assetsImagesIcSearchSvg, - color: actionColor, - onTap: () { - final cubit = context.read(); - if (cubit.state.pages.lastOrNull?.name == - ChatSideCubit.searchMessageHistory) { - return cubit.pop(); - } - cubit.replace(ChatSideCubit.searchMessageHistory); - }, - ), - ), - AnimatedSize( - duration: const Duration(milliseconds: 200), - alignment: Alignment.centerLeft, - child: MoveWindowBarrier( - child: chatSideRouteMode - ? const SizedBox() - : ActionButton( - name: Resources.assetsImagesIcScreenSvg, - color: actionColor, - onTap: chatSideCubit.toggleInfoPage, - ), - ), - ), - ], + const SizedBox(width: 16), ], - ), + ], ); } } diff --git a/lib/ui/home/chat/input_container.dart b/lib/ui/home/chat/input_container.dart index cbc2a846e4..88aa838b83 100644 --- a/lib/ui/home/chat/input_container.dart +++ b/lib/ui/home/chat/input_container.dart @@ -711,7 +711,7 @@ class _StickerButton extends HookWidget { padding: const EdgeInsets.all(8), child: Builder( builder: (context) => StickerPage( - tabController: DefaultTabController.of(context)!, + tabController: DefaultTabController.of(context), tabLength: tabLength, presetStickerGroups: presetStickerGroups, ), diff --git a/lib/ui/home/chat/voice_recorder_bottom_bar.dart b/lib/ui/home/chat/voice_recorder_bottom_bar.dart index 64231ff4d3..65dc192a05 100644 --- a/lib/ui/home/chat/voice_recorder_bottom_bar.dart +++ b/lib/ui/home/chat/voice_recorder_bottom_bar.dart @@ -185,8 +185,6 @@ class VoiceRecorderBarOverlayComposition extends HookWidget { final link = useMemoized(LayerLink.new); final overlay = Overlay.of(context, rootOverlay: true); - assert(overlay != null, 'overlay is null'); - final recorderBottomBarEntry = useRef(null); final voiceRecorderCubit = context.read(); @@ -231,7 +229,7 @@ class VoiceRecorderBarOverlayComposition extends HookWidget { ); recorderBottomBarEntry.value = entry; WidgetsBinding.instance.scheduleFrameCallback((timeStamp) { - overlay!.insert(entry); + overlay.insert(entry); }); }, [isRecorderMode, layoutWidth], @@ -276,10 +274,7 @@ void _showDiscardRecordingWarningAlertOverlay( required VoidCallback onDiscard, }) { final overlay = Overlay.of(context, rootOverlay: true); - if (overlay == null) { - e('_showDiscardRecordingWarningAlertOverlay: overlay is null'); - return; - } + OverlayEntry? entry; void dimiss() { diff --git a/lib/ui/home/chat_slide_page/circle_manager_page.dart b/lib/ui/home/chat_slide_page/circle_manager_page.dart index b8e5c280a1..1b94fc6bb2 100644 --- a/lib/ui/home/chat_slide_page/circle_manager_page.dart +++ b/lib/ui/home/chat_slide_page/circle_manager_page.dart @@ -82,29 +82,25 @@ class CircleManagerPage extends HookWidget { body: ListView( children: [ if (circles.isNotEmpty) - ...circles - .map( - (e) => _CircleManagerItem( - name: e.name, - count: e.count, - circleId: e.circleId, - selected: true, - ), - ) - .toList(), + ...circles.map( + (e) => _CircleManagerItem( + name: e.name, + count: e.count, + circleId: e.circleId, + selected: true, + ), + ), if (circles.isNotEmpty && otherCircles.isNotEmpty) const SizedBox(height: 10), if (otherCircles.isNotEmpty) - ...otherCircles - .map( - (e) => _CircleManagerItem( - name: e.name, - count: e.count, - circleId: e.circleId, - selected: false, - ), - ) - .toList(), + ...otherCircles.map( + (e) => _CircleManagerItem( + name: e.name, + count: e.count, + circleId: e.circleId, + selected: false, + ), + ), ], ), ); diff --git a/lib/ui/home/chat_slide_page/group_invite/group_invite_dialog.dart b/lib/ui/home/chat_slide_page/group_invite/group_invite_dialog.dart index 7db68ea14c..4c64319d97 100644 --- a/lib/ui/home/chat_slide_page/group_invite/group_invite_dialog.dart +++ b/lib/ui/home/chat_slide_page/group_invite/group_invite_dialog.dart @@ -112,7 +112,6 @@ class _GroupInviteBody extends StatelessWidget { height: 1.5, ), textAlign: TextAlign.center, - toolbarOptions: const ToolbarOptions(), ), ), const SizedBox(height: 8), diff --git a/lib/ui/home/route/responsive_navigator_state.dart b/lib/ui/home/route/responsive_navigator_state.dart index 82d9c40d22..b20c9012ab 100644 --- a/lib/ui/home/route/responsive_navigator_state.dart +++ b/lib/ui/home/route/responsive_navigator_state.dart @@ -21,8 +21,8 @@ class ResponsiveNavigatorState extends Equatable { ]; ResponsiveNavigatorState copyWith({ - final List? pages, - final bool? routeMode, + List? pages, + bool? routeMode, }) => ResponsiveNavigatorState( pages: pages ?? this.pages, diff --git a/lib/utils/system/tray.dart b/lib/utils/system/tray.dart index d93f2992a5..7fee022a1e 100644 --- a/lib/utils/system/tray.dart +++ b/lib/utils/system/tray.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:io'; -import 'package:flutter/material.dart' hide MenuItem; +import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:path/path.dart' as p; import 'package:system_tray/system_tray.dart'; diff --git a/lib/widgets/app_bar.dart b/lib/widgets/app_bar.dart index e696619c65..7ec3fd77bd 100644 --- a/lib/widgets/app_bar.dart +++ b/lib/widgets/app_bar.dart @@ -39,14 +39,12 @@ class MixinAppBar extends StatelessWidget implements PreferredSizeWidget { child: title!, ), actions: [ - ...actions - .map((e) => MoveWindowBarrier( - child: DefaultTextStyle.merge( - style: actionTextStyle, - child: e, - ), - )) - .toList(), + ...actions.map((e) => MoveWindowBarrier( + child: DefaultTextStyle.merge( + style: actionTextStyle, + child: e, + ), + )), const SizedBox(width: 8), ], elevation: 0, diff --git a/lib/widgets/az_selection.dart b/lib/widgets/az_selection.dart index 623f77bc63..1bd9e6f7d5 100644 --- a/lib/widgets/az_selection.dart +++ b/lib/widgets/az_selection.dart @@ -16,14 +16,14 @@ class AZSelection extends SingleChildRenderObjectWidget { @override RenderObject createRenderObject(BuildContext context) => AZRender() ..onSelection = onSelection - ..textStyle = textStyle ?? Theme.of(context).textTheme.bodyText1; + ..textStyle = textStyle ?? Theme.of(context).textTheme.bodyLarge; @override void updateRenderObject( BuildContext context, covariant AZRender renderObject) { renderObject ..onSelection = onSelection - ..textStyle = textStyle ?? Theme.of(context).textTheme.bodyText1; + ..textStyle = textStyle ?? Theme.of(context).textTheme.bodyLarge; } } diff --git a/lib/widgets/high_light_text.dart b/lib/widgets/high_light_text.dart index d5d9719ba0..3ebef0c3af 100644 --- a/lib/widgets/high_light_text.dart +++ b/lib/widgets/high_light_text.dart @@ -107,7 +107,7 @@ class HighlightSelectableText extends HookWidget { ), maxLines: maxLines, textWidthBasis: TextWidthBasis.longestLine, - toolbarOptions: const ToolbarOptions(), + contextMenuBuilder: (context, editState) => const SizedBox.shrink(), selectionHeightStyle: ui.BoxHeightStyle.includeLineSpacingMiddle, ); } diff --git a/lib/widgets/menu.dart b/lib/widgets/menu.dart index c6c65ed1cf..9288b9ba01 100644 --- a/lib/widgets/menu.dart +++ b/lib/widgets/menu.dart @@ -166,7 +166,8 @@ class PositionedLayoutDelegate extends SingleChildLayoutDelegate { @override Offset getPositionForChild(Size size, Size childSize) { - var dx = position.dx + _pointerPadding, dy = position.dy + _pointerPadding; + var dx = position.dx + _pointerPadding; + var dy = position.dy + _pointerPadding; if ((size.width - position.dx) < childSize.width) { dx = position.dx - childSize.width; diff --git a/lib/widgets/message/item/contact_message_widget.dart b/lib/widgets/message/item/contact_message_widget.dart index 1d978c64ef..29ece75546 100644 --- a/lib/widgets/message/item/contact_message_widget.dart +++ b/lib/widgets/message/item/contact_message_widget.dart @@ -77,36 +77,40 @@ class ContactItem extends StatelessWidget { name: fullName, ), const SizedBox(width: 8), - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - child: Text( - fullName ?? '', - style: TextStyle( - color: context.theme.text, - fontSize: MessageItemWidget.primaryFontSize, + Flexible( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: Text( + fullName?.overflow ?? '', + style: TextStyle( + color: context.theme.text, + fontSize: MessageItemWidget.primaryFontSize, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, ), ), + VerifiedOrBotWidget( + verified: isVerified, + isBot: appId != null, + ), + ], + ), + Text( + identityNumber, + style: TextStyle( + color: context.theme.secondaryText, + fontSize: MessageItemWidget.secondaryFontSize, ), - VerifiedOrBotWidget( - verified: isVerified, - isBot: appId != null, - ), - ], - ), - Text( - identityNumber, - style: TextStyle( - color: context.theme.secondaryText, - fontSize: MessageItemWidget.secondaryFontSize, ), - ), - ], + ], + ), ), ], ); diff --git a/lib/widgets/sticker_page/sticker_store.dart b/lib/widgets/sticker_page/sticker_store.dart index 1e6dd1bf0f..4af3a8d5de 100644 --- a/lib/widgets/sticker_page/sticker_store.dart +++ b/lib/widgets/sticker_page/sticker_store.dart @@ -417,17 +417,15 @@ class _StickerPage extends HookWidget { final tabController = DefaultTabController.of(context); useEffect(() { void listener() { - if (tabController == null) return; - sticker.value = stickers[tabController.index]; } - tabController?.addListener(listener); + tabController.addListener(listener); return () { - tabController?.removeListener(listener); + tabController.removeListener(listener); }; - }); + }, [tabController]); return AnimatedSize( duration: const Duration(milliseconds: 200), diff --git a/macos/Podfile.lock b/macos/Podfile.lock index ff2ba05f76..389b3fa364 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -123,7 +123,7 @@ SPEC CHECKSUMS: file_selector_macos: f1b08a781e66103e3ba279fd5d4024a2478b3af6 flutter_app_icon_badge: 099b018a4b36109fb73874411fb4e8b5febac20e flutter_local_notifications: 3805ca215b2fb7f397d78b66db91f6a747af52e4 - FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811 + FlutterMacOS: 85f90bfb3f1703249cf1539e4dfbff31e8584698 ogg_opus_player: 67fc56771b16586b9b2478f848e632f751400604 package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce pasteboard: 9b69dba6fedbb04866be632205d532fe2f6b1d99