From a803e091dc0d5c395a18ed523440fa624347fa11 Mon Sep 17 00:00:00 2001 From: shilangyu Date: Sun, 3 Jan 2021 17:03:59 +0000 Subject: [PATCH] Add new easy-to-fix lint rules --- analysis_options.yaml | 50 ++++++++++++++++++++- lib/main.dart | 2 +- lib/pages/communities_tab.dart | 6 +-- lib/pages/community.dart | 60 ++++++++++++------------- lib/pages/create_post.dart | 3 +- lib/pages/home_tab.dart | 3 +- lib/pages/instance.dart | 3 +- lib/pages/settings.dart | 45 +++++++++---------- lib/stores/accounts_store.dart | 5 ++- lib/util/cleanup_url.dart | 16 ++++--- lib/util/unawaited.dart | 3 ++ lib/widgets/bottom_modal.dart | 4 +- lib/widgets/comment.dart | 5 +-- lib/widgets/post.dart | 6 +-- lib/widgets/sortable_infinite_list.dart | 1 - lib/widgets/user_profile.dart | 14 +++--- 16 files changed, 133 insertions(+), 93 deletions(-) create mode 100644 lib/util/unawaited.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index e2f34ae..7612d08 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -3,9 +3,57 @@ include: package:effective_dart/analysis_options.yaml linter: rules: public_member_api_docs: false - prefer_expression_function_bodies: true + prefer_single_quotes: true prefer_final_locals: true + prefer_expression_function_bodies: true + avoid_bool_literals_in_conditional_expressions: true + exhaustive_cases: true + prefer_for_elements_to_map_fromIterable: true + prefer_if_null_operators: true + prefer_is_not_operator: true + use_is_even_rather_than_modulo: true + unnecessary_string_escapes: true + use_full_hex_values_for_flutter_colors: true + sort_unnamed_constructors_first: true + use_raw_strings: true + unnecessary_string_interpolations: true + void_checks: true + unnecessary_null_in_if_null_operators: true + unnecessary_raw_strings: true + unnecessary_null_aware_assignments: true + unnecessary_parenthesis: true + prefer_if_elements_to_conditional_expressions: true + unawaited_futures: true + prefer_typing_uninitialized_variables: true + sized_box_for_whitespace: true + recursive_getters: true + prefer_int_literals: true + prefer_spread_collections: true + prefer_null_aware_operators: true + prefer_final_in_for_each: true + prefer_contains: true + prefer_constructors_over_static_methods: true + prefer_conditional_assignment: true + prefer_asserts_in_initializer_lists: true + parameter_assignments: true + avoid_unused_constructor_parameters: true + empty_catches: true + cascade_invocations: true + await_only_futures: true + avoid_void_async: true + avoid_unnecessary_containers: true + avoid_single_cascade_in_expression_statements: true + avoid_returning_null_for_void: true + avoid_redundant_argument_values: true + avoid_escaping_inner_quotes: true + # always_declare_return_types: true + # sort_child_properties_last: true + # prefer_const_constructors: true + # prefer_const_declarations: true + # prefer_const_literals_to_create_immutables: true + # prefer_const_constructors_in_immutables: true + analyzer: exclude: - "**/*.g.dart" diff --git a/lib/main.dart b/lib/main.dart index 3558b83..c5e0b52 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -131,7 +131,7 @@ class MyHomePage extends HookWidget { bottomNavigationBar: BottomAppBar( shape: CircularNotchedRectangle(), notchMargin: 7, - child: Container( + child: SizedBox( height: 60, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, diff --git a/lib/pages/communities_tab.dart b/lib/pages/communities_tab.dart index 45a0ce7..ad36dfa 100644 --- a/lib/pages/communities_tab.dart +++ b/lib/pages/communities_tab.dart @@ -66,7 +66,7 @@ class CommunitiesTab extends HookWidget { children: [ Icon(Icons.error), Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: Text( communitiesSnap.error?.toString() ?? instancesSnap.error?.toString(), @@ -238,7 +238,7 @@ class _CommunitySubscribeToggle extends HookWidget { Widget build(BuildContext context) { final theme = Theme.of(context); final subbed = useState(true); - final delayed = useDelayedLoading(const Duration(milliseconds: 500)); + final delayed = useDelayedLoading(); final accountsStore = useAccountsStore(); handleTap() async { @@ -271,7 +271,7 @@ class _CommunitySubscribeToggle extends HookWidget { borderRadius: BorderRadius.circular(7), ), child: delayed.loading - ? Container( + ? SizedBox( width: 20, height: 20, child: CircularProgressIndicator()) : Icon( subbed.value ? Icons.done : Icons.add, diff --git a/lib/pages/community.dart b/lib/pages/community.dart index 13163c7..b7ec504 100644 --- a/lib/pages/community.dart +++ b/lib/pages/community.dart @@ -155,7 +155,6 @@ class CommunityPage extends HookWidget { // TODO: change top section to be more flexible SliverAppBar( expandedHeight: 300, - floating: false, pinned: true, elevation: 0, backgroundColor: theme.cardColor, @@ -253,7 +252,7 @@ class _CommunityOverview extends StatelessWidget { color: Colors.black.withOpacity(0.7), blurRadius: 3) ]), ), - Container( + SizedBox( width: 83, height: 83, child: FullscreenableImage( @@ -290,41 +289,38 @@ class _CommunityOverview extends StatelessWidget { child: Padding( padding: const EdgeInsets.only(top: 45), child: Column(children: [ - if (community.icon != null) - Center( - child: Padding( - padding: const EdgeInsets.only(top: 0), - child: Center(child: icon), - ), - ), + if (community.icon != null) icon, // NAME Center( - child: Padding( - padding: const EdgeInsets.only(top: 10), - child: RichText( - overflow: TextOverflow.ellipsis, // TODO: fix overflowing - text: TextSpan( - style: theme.textTheme.subtitle1.copyWith(shadows: [shadow]), - children: [ - TextSpan( - text: '!', - style: TextStyle(fontWeight: FontWeight.w200)), - TextSpan( - text: community.name, - style: TextStyle(fontWeight: FontWeight.w600)), - TextSpan( - text: '@', - style: TextStyle(fontWeight: FontWeight.w200)), - TextSpan( + child: Padding( + padding: const EdgeInsets.only(top: 10), + child: RichText( + overflow: TextOverflow.ellipsis, // TODO: fix overflowing + text: TextSpan( + style: + theme.textTheme.subtitle1.copyWith(shadows: [shadow]), + children: [ + TextSpan( + text: '!', + style: TextStyle(fontWeight: FontWeight.w200)), + TextSpan( + text: community.name, + style: TextStyle(fontWeight: FontWeight.w600)), + TextSpan( + text: '@', + style: TextStyle(fontWeight: FontWeight.w200)), + TextSpan( text: community.originInstanceHost, style: TextStyle(fontWeight: FontWeight.w600), recognizer: TapGestureRecognizer() ..onTap = () => goToInstance( - context, community.originInstanceHost)), - ], + context, community.originInstanceHost), + ), + ], + ), ), ), - )), + ), // TITLE/MOTTO Center( child: Padding( @@ -452,12 +448,12 @@ class _AboutTab extends StatelessWidget { ), _Divider(), Padding( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 0), + padding: const EdgeInsets.symmetric(horizontal: 15), child: OutlineButton( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), - child: Text('${community.categoryName}'), + child: Text(community.categoryName), onPressed: goToCategories, ), ), @@ -530,7 +526,7 @@ class _FollowButton extends HookWidget { final theme = Theme.of(context); final isSubbed = useState(community.subscribed ?? false); - final delayed = useDelayedLoading(const Duration(milliseconds: 500)); + final delayed = useDelayedLoading(); final loggedInAction = useLoggedInAction(community.instanceHost); final colorOnTopOfAccent = textColorBasedOnBackground(theme.accentColor); diff --git a/lib/pages/create_post.dart b/lib/pages/create_post.dart index 37ebc21..9719a9a 100644 --- a/lib/pages/create_post.dart +++ b/lib/pages/create_post.dart @@ -12,6 +12,7 @@ import '../hooks/stores.dart'; import '../util/extensions/spaced.dart'; import '../util/goto.dart'; import '../util/pictrs.dart'; +import '../util/unawaited.dart'; import '../widgets/markdown_text.dart'; import 'full_post.dart'; @@ -229,7 +230,7 @@ class CreatePost extends HookWidget { name: titleController.text, communityId: selectedCommunity.value.id, auth: token.raw); - goToReplace(context, (_) => FullPostPage.fromPostView(res)); + unawaited(goToReplace(context, (_) => FullPostPage.fromPostView(res))); return; // ignore: avoid_catches_without_on_clauses } catch (e) { diff --git a/lib/pages/home_tab.dart b/lib/pages/home_tab.dart index 89f4c6d..c8c3724 100644 --- a/lib/pages/home_tab.dart +++ b/lib/pages/home_tab.dart @@ -35,7 +35,7 @@ class HomeTab extends HookWidget { final instances = accStore.instances.toList(growable: false); final sites = await Future.wait(instances .map((e) => LemmyApi(e).v1.getSite().catchError((e) => null))); - for (var i in Iterable.generate(sites.length)) { + for (final i in Iterable.generate(sites.length)) { map[instances[i]] = sites[i].site.icon; } @@ -291,7 +291,6 @@ class InfiniteHomeList extends HookWidget { children: [ PostListOptions( onChange: changeSorting, - defaultSort: SortType.active, styleButton: onStyleChange != null, ), ], diff --git a/lib/pages/instance.dart b/lib/pages/instance.dart index 0ae1f78..ea546de 100644 --- a/lib/pages/instance.dart +++ b/lib/pages/instance.dart @@ -87,7 +87,6 @@ class InstancePage extends HookWidget { SliverAppBar( brightness: theme.brightness, expandedHeight: 200, - floating: false, pinned: true, elevation: 0, backgroundColor: theme.cardColor, @@ -317,7 +316,7 @@ class _AboutTab extends HookWidget { )) else if (commSnap.hasError) Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: Text("Can't load communities, ${commSnap.error}"), ) else diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index 5e2de9b..99bd6c0 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -26,26 +26,24 @@ class SettingsPage extends StatelessWidget { title: Text('Settings', style: theme.textTheme.headline6), centerTitle: true, ), - body: Container( - child: ListView( - children: [ - ListTile( - leading: Icon(Icons.person), - title: Text('Accounts'), - onTap: () { - goTo(context, (_) => AccountsConfigPage()); - }, - ), - ListTile( - leading: Icon(Icons.color_lens), - title: Text('Appearance'), - onTap: () { - goTo(context, (_) => AppearanceConfigPage()); - }, - ), - AboutTile() - ], - ), + body: ListView( + children: [ + ListTile( + leading: Icon(Icons.person), + title: Text('Accounts'), + onTap: () { + goTo(context, (_) => AccountsConfigPage()); + }, + ), + ListTile( + leading: Icon(Icons.color_lens), + title: Text('Appearance'), + onTap: () { + goTo(context, (_) => AppearanceConfigPage()); + }, + ), + AboutTile() + ], ), ); } @@ -159,7 +157,6 @@ class AccountsConfigPage extends HookWidget { ), floatingActionButton: SpeedDial( animatedIcon: AnimatedIcons.menu_close, // TODO: change to + => x - closeManually: false, curve: Curves.bounceIn, tooltip: 'Add account or instance', child: Icon(Icons.add), @@ -210,7 +207,6 @@ class AccountsConfigPage extends HookWidget { actionPane: SlidableBehindActionPane(), secondaryActions: [ IconSlideAction( - closeOnTap: true, onTap: () => removeInstanceDialog(entry.key), icon: Icons.delete_sweep, color: Colors.red, @@ -221,7 +217,7 @@ class AccountsConfigPage extends HookWidget { color: theme.canvasColor, child: ListTile( dense: true, - contentPadding: EdgeInsets.only(left: 0, top: 0), + contentPadding: EdgeInsets.zero, title: _SectionHeading(entry.key), ), ), @@ -232,7 +228,6 @@ class AccountsConfigPage extends HookWidget { key: Key('$username@${entry.key}'), secondaryActions: [ IconSlideAction( - closeOnTap: true, onTap: () => removeUserDialog(entry.key, username), icon: Icons.delete_sweep, color: Colors.red, @@ -285,7 +280,7 @@ class _SectionHeading extends StatelessWidget { return Padding( child: Text(text.toUpperCase(), style: theme.textTheme.subtitle2.copyWith(color: theme.accentColor)), - padding: EdgeInsets.only(left: 20, top: 0), + padding: EdgeInsets.only(left: 20), ); } } diff --git a/lib/stores/accounts_store.dart b/lib/stores/accounts_store.dart index b26f38d..8bb830a 100644 --- a/lib/stores/accounts_store.dart +++ b/lib/stores/accounts_store.dart @@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart'; import 'package:lemmy_api_client/lemmy_api_client.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import '../util/unawaited.dart'; import 'shared_pref_keys.dart'; /// Store that manages all accounts @@ -211,7 +212,7 @@ class AccountsStore extends ChangeNotifier { _assignDefaultAccounts(); notifyListeners(); - save(); + unawaited(save()); } /// adds a new instance with no accounts associated with it. @@ -238,7 +239,7 @@ class AccountsStore extends ChangeNotifier { _assignDefaultAccounts(); notifyListeners(); - save(); + unawaited(save()); } /// This also removes all accounts assigned to this instance diff --git a/lib/util/cleanup_url.dart b/lib/util/cleanup_url.dart index 6108c09..5f4607b 100644 --- a/lib/util/cleanup_url.dart +++ b/lib/util/cleanup_url.dart @@ -1,14 +1,16 @@ /// Strips protocol, 'www.', and trailing '/' from [url] aka. cleans it up String cleanUpUrl(String url) { - if (url.startsWith('https://')) { - url = url.substring(8); + var newUrl = url; + + if (newUrl.startsWith('https://')) { + newUrl = newUrl.substring(8); } - if (url.startsWith('www.')) { - url = url.substring(4); + if (newUrl.startsWith('www.')) { + newUrl = newUrl.substring(4); } - if (url.endsWith('/')) { - url = url.substring(0, url.length - 1); + if (newUrl.endsWith('/')) { + newUrl = newUrl.substring(0, newUrl.length - 1); } - return url; + return newUrl; } diff --git a/lib/util/unawaited.dart b/lib/util/unawaited.dart new file mode 100644 index 0000000..1b01cc0 --- /dev/null +++ b/lib/util/unawaited.dart @@ -0,0 +1,3 @@ +/// Explicitely indicate to the `unawaited_futures` lint +/// that the future is not await for on purpose +void unawaited(Future future) {} diff --git a/lib/widgets/bottom_modal.dart b/lib/widgets/bottom_modal.dart index a944da7..d9858fa 100644 --- a/lib/widgets/bottom_modal.dart +++ b/lib/widgets/bottom_modal.dart @@ -13,13 +13,13 @@ class BottomModal extends StatelessWidget { return SafeArea( child: Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: SingleChildScrollView( child: Container( padding: title != null ? const EdgeInsets.only(top: 10) : null, decoration: BoxDecoration( color: theme.scaffoldBackgroundColor, - borderRadius: BorderRadius.all(const Radius.circular(10.0)), + borderRadius: BorderRadius.all(const Radius.circular(10)), ), child: Column( mainAxisSize: MainAxisSize.min, diff --git a/lib/widgets/comment.dart b/lib/widgets/comment.dart index d003211..4cddd9f 100644 --- a/lib/widgets/comment.dart +++ b/lib/widgets/comment.dart @@ -52,8 +52,7 @@ class Comment extends HookWidget { 'upvotes': com.upvotes, 'downvotes': com.downvotes, 'score': com.score, - '% of upvotes': - '${(100 * (com.upvotes / (com.upvotes + com.downvotes)))}%', + '% of upvotes': '${100 * (com.upvotes / (com.upvotes + com.downvotes))}%', 'hotRank': com.hotRank, 'hotRankActive': com.hotRankActive, 'published': com.published, @@ -402,7 +401,7 @@ class _SaveComment extends HookWidget { Widget build(BuildContext context) { final loggedInAction = useLoggedInAction(comment.instanceHost); final isSaved = useState(comment.saved ?? false); - final delayed = useDelayedLoading(const Duration(milliseconds: 500)); + final delayed = useDelayedLoading(); handleSave(Jwt token) async { final api = LemmyApi(comment.instanceHost).v1; diff --git a/lib/widgets/post.dart b/lib/widgets/post.dart index d094d97..7465138 100644 --- a/lib/widgets/post.dart +++ b/lib/widgets/post.dart @@ -228,7 +228,6 @@ class Post extends HookWidget { IconButton( onPressed: () => showMoreMenu(context, post), icon: Icon(moreIcon), - iconSize: 24, padding: EdgeInsets.all(0), visualDensity: VisualDensity.compact, ) @@ -246,7 +245,7 @@ class Post extends HookWidget { Expanded( flex: 100, child: Text( - '${post.name}', + post.name, textAlign: TextAlign.left, softWrap: true, style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), @@ -294,7 +293,6 @@ class Post extends HookWidget { child: Container( decoration: BoxDecoration( border: Border.all( - width: 1, color: Theme.of(context).iconTheme.color.withAlpha(170)), borderRadius: BorderRadius.circular(5)), child: Padding( @@ -310,7 +308,7 @@ class Post extends HookWidget { ]), Row(children: [ Flexible( - child: Text('${post.embedTitle ?? ''}', + child: Text(post.embedTitle ?? '', style: theme.textTheme.subtitle1 .apply(fontWeightDelta: 2))) ]), diff --git a/lib/widgets/sortable_infinite_list.dart b/lib/widgets/sortable_infinite_list.dart index 71de457..67be0fe 100644 --- a/lib/widgets/sortable_infinite_list.dart +++ b/lib/widgets/sortable_infinite_list.dart @@ -36,7 +36,6 @@ class SortableInfiniteList extends HookWidget { return InfiniteScroll( prepend: PostListOptions( onChange: changeSorting, - defaultSort: SortType.active, styleButton: onStyleChange != null, ), builder: builder, diff --git a/lib/widgets/user_profile.dart b/lib/widgets/user_profile.dart index e3897fd..5cfe0e0 100644 --- a/lib/widgets/user_profile.dart +++ b/lib/widgets/user_profile.dart @@ -201,7 +201,7 @@ class _UserOverview extends HookWidget { ), Padding( padding: userView.avatar != null - ? const EdgeInsets.only(top: 8.0) + ? const EdgeInsets.only(top: 8) : const EdgeInsets.only(top: 70), child: Padding( padding: @@ -213,7 +213,7 @@ class _UserOverview extends HookWidget { ), ), Padding( - padding: const EdgeInsets.only(top: 4.0), + padding: const EdgeInsets.only(top: 4), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -225,7 +225,7 @@ class _UserOverview extends HookWidget { onTap: () => goToInstance(context, userView.originInstanceHost), child: Text( - '${userView.originInstanceHost}', + userView.originInstanceHost, style: theme.textTheme.caption, ), ) @@ -246,7 +246,7 @@ class _UserOverview extends HookWidget { color: colorOnTopOfAccentColor, ), Padding( - padding: const EdgeInsets.only(left: 4.0), + padding: const EdgeInsets.only(left: 4), child: Text( '${compactNumber(userView.numberOfPosts)}' ' Post${pluralS(userView.numberOfPosts)}', @@ -257,7 +257,7 @@ class _UserOverview extends HookWidget { ), ), Padding( - padding: const EdgeInsets.only(left: 16.0), + padding: const EdgeInsets.only(left: 16), child: Badge( child: Row( children: [ @@ -267,7 +267,7 @@ class _UserOverview extends HookWidget { color: colorOnTopOfAccentColor, ), Padding( - padding: const EdgeInsets.only(left: 4.0), + padding: const EdgeInsets.only(left: 4), child: Text( '${compactNumber(userView.numberOfComments)}' ' Comment${pluralS(userView.numberOfComments)}', @@ -299,7 +299,7 @@ class _UserOverview extends HookWidget { size: 13, ), Padding( - padding: const EdgeInsets.only(left: 4.0), + padding: const EdgeInsets.only(left: 4), child: Text( DateFormat('MMM dd, yyyy').format(userView.published), style: theme.textTheme.bodyText1,