Add new easy-to-fix lint rules

This commit is contained in:
shilangyu 2021-01-03 17:03:59 +00:00
parent e82c1fa576
commit a803e091dc
16 changed files with 133 additions and 93 deletions

View File

@ -3,9 +3,57 @@ include: package:effective_dart/analysis_options.yaml
linter: linter:
rules: rules:
public_member_api_docs: false public_member_api_docs: false
prefer_expression_function_bodies: true
prefer_single_quotes: true prefer_single_quotes: true
prefer_final_locals: 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: analyzer:
exclude: exclude:
- "**/*.g.dart" - "**/*.g.dart"

View File

@ -131,7 +131,7 @@ class MyHomePage extends HookWidget {
bottomNavigationBar: BottomAppBar( bottomNavigationBar: BottomAppBar(
shape: CircularNotchedRectangle(), shape: CircularNotchedRectangle(),
notchMargin: 7, notchMargin: 7,
child: Container( child: SizedBox(
height: 60, height: 60,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround, mainAxisAlignment: MainAxisAlignment.spaceAround,

View File

@ -66,7 +66,7 @@ class CommunitiesTab extends HookWidget {
children: [ children: [
Icon(Icons.error), Icon(Icons.error),
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Text( child: Text(
communitiesSnap.error?.toString() ?? communitiesSnap.error?.toString() ??
instancesSnap.error?.toString(), instancesSnap.error?.toString(),
@ -238,7 +238,7 @@ class _CommunitySubscribeToggle extends HookWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final subbed = useState(true); final subbed = useState(true);
final delayed = useDelayedLoading(const Duration(milliseconds: 500)); final delayed = useDelayedLoading();
final accountsStore = useAccountsStore(); final accountsStore = useAccountsStore();
handleTap() async { handleTap() async {
@ -271,7 +271,7 @@ class _CommunitySubscribeToggle extends HookWidget {
borderRadius: BorderRadius.circular(7), borderRadius: BorderRadius.circular(7),
), ),
child: delayed.loading child: delayed.loading
? Container( ? SizedBox(
width: 20, height: 20, child: CircularProgressIndicator()) width: 20, height: 20, child: CircularProgressIndicator())
: Icon( : Icon(
subbed.value ? Icons.done : Icons.add, subbed.value ? Icons.done : Icons.add,

View File

@ -155,7 +155,6 @@ class CommunityPage extends HookWidget {
// TODO: change top section to be more flexible // TODO: change top section to be more flexible
SliverAppBar( SliverAppBar(
expandedHeight: 300, expandedHeight: 300,
floating: false,
pinned: true, pinned: true,
elevation: 0, elevation: 0,
backgroundColor: theme.cardColor, backgroundColor: theme.cardColor,
@ -253,7 +252,7 @@ class _CommunityOverview extends StatelessWidget {
color: Colors.black.withOpacity(0.7), blurRadius: 3) color: Colors.black.withOpacity(0.7), blurRadius: 3)
]), ]),
), ),
Container( SizedBox(
width: 83, width: 83,
height: 83, height: 83,
child: FullscreenableImage( child: FullscreenableImage(
@ -290,41 +289,38 @@ class _CommunityOverview extends StatelessWidget {
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 45), padding: const EdgeInsets.only(top: 45),
child: Column(children: [ child: Column(children: [
if (community.icon != null) if (community.icon != null) icon,
Center(
child: Padding(
padding: const EdgeInsets.only(top: 0),
child: Center(child: icon),
),
),
// NAME // NAME
Center( Center(
child: Padding( child: Padding(
padding: const EdgeInsets.only(top: 10), padding: const EdgeInsets.only(top: 10),
child: RichText( child: RichText(
overflow: TextOverflow.ellipsis, // TODO: fix overflowing overflow: TextOverflow.ellipsis, // TODO: fix overflowing
text: TextSpan( text: TextSpan(
style: theme.textTheme.subtitle1.copyWith(shadows: [shadow]), style:
children: [ theme.textTheme.subtitle1.copyWith(shadows: [shadow]),
TextSpan( children: [
text: '!', TextSpan(
style: TextStyle(fontWeight: FontWeight.w200)), text: '!',
TextSpan( style: TextStyle(fontWeight: FontWeight.w200)),
text: community.name, TextSpan(
style: TextStyle(fontWeight: FontWeight.w600)), text: community.name,
TextSpan( style: TextStyle(fontWeight: FontWeight.w600)),
text: '@', TextSpan(
style: TextStyle(fontWeight: FontWeight.w200)), text: '@',
TextSpan( style: TextStyle(fontWeight: FontWeight.w200)),
TextSpan(
text: community.originInstanceHost, text: community.originInstanceHost,
style: TextStyle(fontWeight: FontWeight.w600), style: TextStyle(fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () => goToInstance( ..onTap = () => goToInstance(
context, community.originInstanceHost)), context, community.originInstanceHost),
], ),
],
),
), ),
), ),
)), ),
// TITLE/MOTTO // TITLE/MOTTO
Center( Center(
child: Padding( child: Padding(
@ -452,12 +448,12 @@ class _AboutTab extends StatelessWidget {
), ),
_Divider(), _Divider(),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 0), padding: const EdgeInsets.symmetric(horizontal: 15),
child: OutlineButton( child: OutlineButton(
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
child: Text('${community.categoryName}'), child: Text(community.categoryName),
onPressed: goToCategories, onPressed: goToCategories,
), ),
), ),
@ -530,7 +526,7 @@ class _FollowButton extends HookWidget {
final theme = Theme.of(context); final theme = Theme.of(context);
final isSubbed = useState(community.subscribed ?? false); final isSubbed = useState(community.subscribed ?? false);
final delayed = useDelayedLoading(const Duration(milliseconds: 500)); final delayed = useDelayedLoading();
final loggedInAction = useLoggedInAction(community.instanceHost); final loggedInAction = useLoggedInAction(community.instanceHost);
final colorOnTopOfAccent = textColorBasedOnBackground(theme.accentColor); final colorOnTopOfAccent = textColorBasedOnBackground(theme.accentColor);

View File

@ -12,6 +12,7 @@ import '../hooks/stores.dart';
import '../util/extensions/spaced.dart'; import '../util/extensions/spaced.dart';
import '../util/goto.dart'; import '../util/goto.dart';
import '../util/pictrs.dart'; import '../util/pictrs.dart';
import '../util/unawaited.dart';
import '../widgets/markdown_text.dart'; import '../widgets/markdown_text.dart';
import 'full_post.dart'; import 'full_post.dart';
@ -229,7 +230,7 @@ class CreatePost extends HookWidget {
name: titleController.text, name: titleController.text,
communityId: selectedCommunity.value.id, communityId: selectedCommunity.value.id,
auth: token.raw); auth: token.raw);
goToReplace(context, (_) => FullPostPage.fromPostView(res)); unawaited(goToReplace(context, (_) => FullPostPage.fromPostView(res)));
return; return;
// ignore: avoid_catches_without_on_clauses // ignore: avoid_catches_without_on_clauses
} catch (e) { } catch (e) {

View File

@ -35,7 +35,7 @@ class HomeTab extends HookWidget {
final instances = accStore.instances.toList(growable: false); final instances = accStore.instances.toList(growable: false);
final sites = await Future.wait(instances final sites = await Future.wait(instances
.map((e) => LemmyApi(e).v1.getSite().catchError((e) => null))); .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; map[instances[i]] = sites[i].site.icon;
} }
@ -291,7 +291,6 @@ class InfiniteHomeList extends HookWidget {
children: [ children: [
PostListOptions( PostListOptions(
onChange: changeSorting, onChange: changeSorting,
defaultSort: SortType.active,
styleButton: onStyleChange != null, styleButton: onStyleChange != null,
), ),
], ],

View File

@ -87,7 +87,6 @@ class InstancePage extends HookWidget {
SliverAppBar( SliverAppBar(
brightness: theme.brightness, brightness: theme.brightness,
expandedHeight: 200, expandedHeight: 200,
floating: false,
pinned: true, pinned: true,
elevation: 0, elevation: 0,
backgroundColor: theme.cardColor, backgroundColor: theme.cardColor,
@ -317,7 +316,7 @@ class _AboutTab extends HookWidget {
)) ))
else if (commSnap.hasError) else if (commSnap.hasError)
Padding( Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Text("Can't load communities, ${commSnap.error}"), child: Text("Can't load communities, ${commSnap.error}"),
) )
else else

View File

@ -26,26 +26,24 @@ class SettingsPage extends StatelessWidget {
title: Text('Settings', style: theme.textTheme.headline6), title: Text('Settings', style: theme.textTheme.headline6),
centerTitle: true, centerTitle: true,
), ),
body: Container( body: ListView(
child: ListView( children: [
children: [ ListTile(
ListTile( leading: Icon(Icons.person),
leading: Icon(Icons.person), title: Text('Accounts'),
title: Text('Accounts'), onTap: () {
onTap: () { goTo(context, (_) => AccountsConfigPage());
goTo(context, (_) => AccountsConfigPage()); },
}, ),
), ListTile(
ListTile( leading: Icon(Icons.color_lens),
leading: Icon(Icons.color_lens), title: Text('Appearance'),
title: Text('Appearance'), onTap: () {
onTap: () { goTo(context, (_) => AppearanceConfigPage());
goTo(context, (_) => AppearanceConfigPage()); },
}, ),
), AboutTile()
AboutTile() ],
],
),
), ),
); );
} }
@ -159,7 +157,6 @@ class AccountsConfigPage extends HookWidget {
), ),
floatingActionButton: SpeedDial( floatingActionButton: SpeedDial(
animatedIcon: AnimatedIcons.menu_close, // TODO: change to + => x animatedIcon: AnimatedIcons.menu_close, // TODO: change to + => x
closeManually: false,
curve: Curves.bounceIn, curve: Curves.bounceIn,
tooltip: 'Add account or instance', tooltip: 'Add account or instance',
child: Icon(Icons.add), child: Icon(Icons.add),
@ -210,7 +207,6 @@ class AccountsConfigPage extends HookWidget {
actionPane: SlidableBehindActionPane(), actionPane: SlidableBehindActionPane(),
secondaryActions: [ secondaryActions: [
IconSlideAction( IconSlideAction(
closeOnTap: true,
onTap: () => removeInstanceDialog(entry.key), onTap: () => removeInstanceDialog(entry.key),
icon: Icons.delete_sweep, icon: Icons.delete_sweep,
color: Colors.red, color: Colors.red,
@ -221,7 +217,7 @@ class AccountsConfigPage extends HookWidget {
color: theme.canvasColor, color: theme.canvasColor,
child: ListTile( child: ListTile(
dense: true, dense: true,
contentPadding: EdgeInsets.only(left: 0, top: 0), contentPadding: EdgeInsets.zero,
title: _SectionHeading(entry.key), title: _SectionHeading(entry.key),
), ),
), ),
@ -232,7 +228,6 @@ class AccountsConfigPage extends HookWidget {
key: Key('$username@${entry.key}'), key: Key('$username@${entry.key}'),
secondaryActions: [ secondaryActions: [
IconSlideAction( IconSlideAction(
closeOnTap: true,
onTap: () => removeUserDialog(entry.key, username), onTap: () => removeUserDialog(entry.key, username),
icon: Icons.delete_sweep, icon: Icons.delete_sweep,
color: Colors.red, color: Colors.red,
@ -285,7 +280,7 @@ class _SectionHeading extends StatelessWidget {
return Padding( return Padding(
child: Text(text.toUpperCase(), child: Text(text.toUpperCase(),
style: theme.textTheme.subtitle2.copyWith(color: theme.accentColor)), style: theme.textTheme.subtitle2.copyWith(color: theme.accentColor)),
padding: EdgeInsets.only(left: 20, top: 0), padding: EdgeInsets.only(left: 20),
); );
} }
} }

View File

@ -5,6 +5,7 @@ import 'package:flutter/foundation.dart';
import 'package:lemmy_api_client/lemmy_api_client.dart'; import 'package:lemmy_api_client/lemmy_api_client.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import '../util/unawaited.dart';
import 'shared_pref_keys.dart'; import 'shared_pref_keys.dart';
/// Store that manages all accounts /// Store that manages all accounts
@ -211,7 +212,7 @@ class AccountsStore extends ChangeNotifier {
_assignDefaultAccounts(); _assignDefaultAccounts();
notifyListeners(); notifyListeners();
save(); unawaited(save());
} }
/// adds a new instance with no accounts associated with it. /// adds a new instance with no accounts associated with it.
@ -238,7 +239,7 @@ class AccountsStore extends ChangeNotifier {
_assignDefaultAccounts(); _assignDefaultAccounts();
notifyListeners(); notifyListeners();
save(); unawaited(save());
} }
/// This also removes all accounts assigned to this instance /// This also removes all accounts assigned to this instance

View File

@ -1,14 +1,16 @@
/// Strips protocol, 'www.', and trailing '/' from [url] aka. cleans it up /// Strips protocol, 'www.', and trailing '/' from [url] aka. cleans it up
String cleanUpUrl(String url) { String cleanUpUrl(String url) {
if (url.startsWith('https://')) { var newUrl = url;
url = url.substring(8);
if (newUrl.startsWith('https://')) {
newUrl = newUrl.substring(8);
} }
if (url.startsWith('www.')) { if (newUrl.startsWith('www.')) {
url = url.substring(4); newUrl = newUrl.substring(4);
} }
if (url.endsWith('/')) { if (newUrl.endsWith('/')) {
url = url.substring(0, url.length - 1); newUrl = newUrl.substring(0, newUrl.length - 1);
} }
return url; return newUrl;
} }

3
lib/util/unawaited.dart Normal file
View File

@ -0,0 +1,3 @@
/// Explicitely indicate to the `unawaited_futures` lint
/// that the future is not await for on purpose
void unawaited<T>(Future<T> future) {}

View File

@ -13,13 +13,13 @@ class BottomModal extends StatelessWidget {
return SafeArea( return SafeArea(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Container( child: Container(
padding: title != null ? const EdgeInsets.only(top: 10) : null, padding: title != null ? const EdgeInsets.only(top: 10) : null,
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.scaffoldBackgroundColor, color: theme.scaffoldBackgroundColor,
borderRadius: BorderRadius.all(const Radius.circular(10.0)), borderRadius: BorderRadius.all(const Radius.circular(10)),
), ),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

View File

@ -52,8 +52,7 @@ class Comment extends HookWidget {
'upvotes': com.upvotes, 'upvotes': com.upvotes,
'downvotes': com.downvotes, 'downvotes': com.downvotes,
'score': com.score, 'score': com.score,
'% of upvotes': '% of upvotes': '${100 * (com.upvotes / (com.upvotes + com.downvotes))}%',
'${(100 * (com.upvotes / (com.upvotes + com.downvotes)))}%',
'hotRank': com.hotRank, 'hotRank': com.hotRank,
'hotRankActive': com.hotRankActive, 'hotRankActive': com.hotRankActive,
'published': com.published, 'published': com.published,
@ -402,7 +401,7 @@ class _SaveComment extends HookWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loggedInAction = useLoggedInAction(comment.instanceHost); final loggedInAction = useLoggedInAction(comment.instanceHost);
final isSaved = useState(comment.saved ?? false); final isSaved = useState(comment.saved ?? false);
final delayed = useDelayedLoading(const Duration(milliseconds: 500)); final delayed = useDelayedLoading();
handleSave(Jwt token) async { handleSave(Jwt token) async {
final api = LemmyApi(comment.instanceHost).v1; final api = LemmyApi(comment.instanceHost).v1;

View File

@ -228,7 +228,6 @@ class Post extends HookWidget {
IconButton( IconButton(
onPressed: () => showMoreMenu(context, post), onPressed: () => showMoreMenu(context, post),
icon: Icon(moreIcon), icon: Icon(moreIcon),
iconSize: 24,
padding: EdgeInsets.all(0), padding: EdgeInsets.all(0),
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
) )
@ -246,7 +245,7 @@ class Post extends HookWidget {
Expanded( Expanded(
flex: 100, flex: 100,
child: Text( child: Text(
'${post.name}', post.name,
textAlign: TextAlign.left, textAlign: TextAlign.left,
softWrap: true, softWrap: true,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600), style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
@ -294,7 +293,6 @@ class Post extends HookWidget {
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all( border: Border.all(
width: 1,
color: Theme.of(context).iconTheme.color.withAlpha(170)), color: Theme.of(context).iconTheme.color.withAlpha(170)),
borderRadius: BorderRadius.circular(5)), borderRadius: BorderRadius.circular(5)),
child: Padding( child: Padding(
@ -310,7 +308,7 @@ class Post extends HookWidget {
]), ]),
Row(children: [ Row(children: [
Flexible( Flexible(
child: Text('${post.embedTitle ?? ''}', child: Text(post.embedTitle ?? '',
style: theme.textTheme.subtitle1 style: theme.textTheme.subtitle1
.apply(fontWeightDelta: 2))) .apply(fontWeightDelta: 2)))
]), ]),

View File

@ -36,7 +36,6 @@ class SortableInfiniteList<T> extends HookWidget {
return InfiniteScroll<T>( return InfiniteScroll<T>(
prepend: PostListOptions( prepend: PostListOptions(
onChange: changeSorting, onChange: changeSorting,
defaultSort: SortType.active,
styleButton: onStyleChange != null, styleButton: onStyleChange != null,
), ),
builder: builder, builder: builder,

View File

@ -201,7 +201,7 @@ class _UserOverview extends HookWidget {
), ),
Padding( Padding(
padding: userView.avatar != null padding: userView.avatar != null
? const EdgeInsets.only(top: 8.0) ? const EdgeInsets.only(top: 8)
: const EdgeInsets.only(top: 70), : const EdgeInsets.only(top: 70),
child: Padding( child: Padding(
padding: padding:
@ -213,7 +213,7 @@ class _UserOverview extends HookWidget {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.only(top: 4.0), padding: const EdgeInsets.only(top: 4),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@ -225,7 +225,7 @@ class _UserOverview extends HookWidget {
onTap: () => onTap: () =>
goToInstance(context, userView.originInstanceHost), goToInstance(context, userView.originInstanceHost),
child: Text( child: Text(
'${userView.originInstanceHost}', userView.originInstanceHost,
style: theme.textTheme.caption, style: theme.textTheme.caption,
), ),
) )
@ -246,7 +246,7 @@ class _UserOverview extends HookWidget {
color: colorOnTopOfAccentColor, color: colorOnTopOfAccentColor,
), ),
Padding( Padding(
padding: const EdgeInsets.only(left: 4.0), padding: const EdgeInsets.only(left: 4),
child: Text( child: Text(
'${compactNumber(userView.numberOfPosts)}' '${compactNumber(userView.numberOfPosts)}'
' Post${pluralS(userView.numberOfPosts)}', ' Post${pluralS(userView.numberOfPosts)}',
@ -257,7 +257,7 @@ class _UserOverview extends HookWidget {
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.only(left: 16.0), padding: const EdgeInsets.only(left: 16),
child: Badge( child: Badge(
child: Row( child: Row(
children: [ children: [
@ -267,7 +267,7 @@ class _UserOverview extends HookWidget {
color: colorOnTopOfAccentColor, color: colorOnTopOfAccentColor,
), ),
Padding( Padding(
padding: const EdgeInsets.only(left: 4.0), padding: const EdgeInsets.only(left: 4),
child: Text( child: Text(
'${compactNumber(userView.numberOfComments)}' '${compactNumber(userView.numberOfComments)}'
' Comment${pluralS(userView.numberOfComments)}', ' Comment${pluralS(userView.numberOfComments)}',
@ -299,7 +299,7 @@ class _UserOverview extends HookWidget {
size: 13, size: 13,
), ),
Padding( Padding(
padding: const EdgeInsets.only(left: 4.0), padding: const EdgeInsets.only(left: 4),
child: Text( child: Text(
DateFormat('MMM dd, yyyy').format(userView.published), DateFormat('MMM dd, yyyy').format(userView.published),
style: theme.textTheme.bodyText1, style: theme.textTheme.bodyText1,