From 1996ed1fa7ed76edfa188d3be34cb23a4283c7bd Mon Sep 17 00:00:00 2001 From: anfeichtinger <anfeichtingers@gmail.com> Date: Sat, 19 Jun 2021 17:37:44 +0200 Subject: [PATCH] Use flutter_lints package and update code according to stricter rules --- README.md | 4 +-- analysis_options.yaml | 12 ++++++- assets/translations/de.json | 2 +- assets/translations/en.json | 4 +-- lib/cubit/theme_cubit.dart | 2 +- lib/main.dart | 13 +++++--- lib/ui/screens/first_screen.dart | 16 ++++----- lib/ui/screens/second_screen.dart | 36 ++++++++++----------- lib/ui/screens/skeleton_screen.dart | 8 +++-- lib/ui/widgets/app_bar_gone.dart | 2 +- lib/ui/widgets/bottom_nav_bar.dart | 5 ++- lib/ui/widgets/first_screen/info_card.dart | 6 ++-- lib/ui/widgets/header.dart | 4 +-- lib/ui/widgets/second_screen/grid_item.dart | 2 +- lib/ui/widgets/second_screen/link_card.dart | 2 +- pubspec.lock | 11 +++++-- pubspec.yaml | 2 +- test/widget_test.dart | 5 --- 18 files changed, 79 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 2dd6c84d..247c3165 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Flutter Production Boilerplate -## A flutter project containing bloc, lints, hive, easy_translations and more! +## A flutter project containing bloc, flutter_lints, hive, easy_translations and more! This repository is the starting point for my personal projects. If you have any suggestions or improvements feel free to let me know. The project strives to implement best practices recommended by Google and other developers. These best practices include but are not limited to: @@ -40,7 +40,7 @@ This repository makes use of the following pub packages: | [Flutter Bloc](https://pub.dev/packages/flutter_bloc) | ^7.0.1 | State management* | [Hydrated Bloc](https://pub.dev/packages/hydrated_bloc) | ^7.0.1 | Persists Bloc state with Hive | [Equatable](https://pub.dev/packages/equatable) | ^2.0.2 | Easily compare custom classes, used for Bloc states* -| [Lints](https://pub.dev/packages/lints) | ^1.0.1 | Stricter linting rules +| [Flutter Lints](https://pub.dev/packages/flutter_lints) | ^1.0.3 | Stricter linting rules | [Path Provider](https://pub.dev/packages/path_provider) | ^2.0.2 | Get the save path for Hive | [Flutter Displaymode](https://pub.dev/packages/flutter_displaymode) | ^0.3.2 | Support high refresh rate displays | [Easy Localization](https://pub.dev/packages/easy_localization) | ^3.0.0 | Makes localization easy diff --git a/analysis_options.yaml b/analysis_options.yaml index ea2c9e94..5f347c7c 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1 +1,11 @@ -include: package:lints/recommended.yaml \ No newline at end of file +include: package:flutter_lints/flutter.yaml + +analyzer: + exclude: [build/**] + strong-mode: + implicit-casts: false + implicit-dynamic: false + +rules: + avoid_print: false + prefer_single_quotes: true \ No newline at end of file diff --git a/assets/translations/de.json b/assets/translations/de.json index 570bc3da..6aafb744 100644 --- a/assets/translations/de.json +++ b/assets/translations/de.json @@ -8,7 +8,7 @@ "localization_content": "Vereinfachte Übersetzungen mit dem Paket Easy Translations.", "linting_title": "Linting", - "linting_content": "Strengere Linting-Regeln mit Pedantic, empfohlen von Google.", + "linting_content": "Strengere Linting-Regeln mit Flutter Lints, empfohlen von Google.", "storage_title": "Speicher", "storage_content": "Extrem schnelle, in reinem Dart geschriebene Datenbank mit Hive.", diff --git a/assets/translations/en.json b/assets/translations/en.json index de6a9f9b..3a9270f6 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -8,7 +8,7 @@ "localization_content": "Simplified translations with the Easy Translations package.", "linting_title": "Linting", - "linting_content": "Stricter linting rules with lints recommended by the Dart team.", + "linting_content": "Stricter linting rules with flutter lints recommended by the Dart team.", "storage_title": "Storage", "storage_content": "Blazing fast key-value database written in pure Dart with Hive.", @@ -37,7 +37,7 @@ "bloc": "Bloc", "hydrated_bloc": "Hydrated bloc", "equatable": "Equatable", - "lints": "Lints", + "lints": "Flutter Lints", "path_provider": "Path provider", "flutter_displaymode": "Displaymode", "easy_localization": "Easy localization", diff --git a/lib/cubit/theme_cubit.dart b/lib/cubit/theme_cubit.dart index 1d0e7d0e..a131f7ff 100644 --- a/lib/cubit/theme_cubit.dart +++ b/lib/cubit/theme_cubit.dart @@ -21,7 +21,7 @@ class ThemeCubit extends HydratedCubit<ThemeState> { } @override - Map<String, dynamic>? toJson(ThemeState state) { + Map<String, bool>? toJson(ThemeState state) { return {'isDark': state.themeData.brightness == Brightness.dark}; } } diff --git a/lib/main.dart b/lib/main.dart index 8382aac6..52faed4c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:io'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -27,18 +28,20 @@ void main() async { runApp( EasyLocalization( path: 'assets/translations', - supportedLocales: [ - const Locale('en'), - const Locale('de'), + supportedLocales: const [ + Locale('en'), + Locale('de'), ], fallbackLocale: const Locale('en'), useFallbackTranslations: true, - child: MyApp(), + child: const MyApp(), ), ); } class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return BlocProvider<ThemeCubit>( @@ -49,7 +52,7 @@ class MyApp extends StatelessWidget { /// Localization is not available for the title. title: 'Flutter Production Boilerplate', theme: state.themeData, - home: SkeletonScreen(), + home: const SkeletonScreen(), debugShowCheckedModeBanner: false, localizationsDelegates: context.localizationDelegates, supportedLocales: context.supportedLocales, diff --git a/lib/ui/screens/first_screen.dart b/lib/ui/screens/first_screen.dart index 552004fc..a917732c 100644 --- a/lib/ui/screens/first_screen.dart +++ b/lib/ui/screens/first_screen.dart @@ -8,7 +8,7 @@ import 'package:flutter_production_boilerplate/ui/widgets/first_screen/info_card import 'package:ionicons/ionicons.dart'; class FirstScreen extends StatelessWidget { - const FirstScreen(); + const FirstScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -102,36 +102,36 @@ class FirstScreen extends StatelessWidget { crossAxisSpacing: 8, mainAxisSpacing: 8, childAspectRatio: 4 / 5, - children: [ + children: const [ /// Example: it is good practice to put widgets in separate files. /// This way the screen files won't become too large and /// the code becomes more clear. - const InfoCard( + InfoCard( title: 'localization_title', content: 'localization_content', icon: Ionicons.text_outline, isPrimaryColor: true), - const InfoCard( + InfoCard( title: 'linting_title', content: 'linting_content', icon: Ionicons.options_outline, isPrimaryColor: false), - const InfoCard( + InfoCard( title: 'storage_title', content: 'storage_content', icon: Ionicons.folder_outline, isPrimaryColor: false), - const InfoCard( + InfoCard( title: 'dark_mode_title', content: 'dark_mode_content', icon: Ionicons.moon_outline, isPrimaryColor: true), - const InfoCard( + InfoCard( title: 'state_title', content: 'state_content', icon: Ionicons.notifications_outline, isPrimaryColor: true), - const InfoCard( + InfoCard( title: 'display_title', content: 'display_content', icon: Ionicons.speedometer_outline, diff --git a/lib/ui/screens/second_screen.dart b/lib/ui/screens/second_screen.dart index d1109e09..b03cbfef 100644 --- a/lib/ui/screens/second_screen.dart +++ b/lib/ui/screens/second_screen.dart @@ -6,7 +6,7 @@ import 'package:flutter_production_boilerplate/ui/widgets/second_screen/text_div import 'package:ionicons/ionicons.dart'; class SecondScreen extends StatelessWidget { - const SecondScreen(); + const SecondScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -35,18 +35,18 @@ class SecondScreen extends StatelessWidget { crossAxisSpacing: 8, mainAxisSpacing: 8, shrinkWrap: true, - children: [ - const GridItem( + children: const [ + GridItem( title: 'instagram_card_title', icon: Ionicons.logo_instagram, url: 'https://www.instagram.com/anfeichtinger', ), - const GridItem( + GridItem( title: 'twitter_card_title', icon: Ionicons.logo_twitter, url: 'https://twitter.com/_pharrax', ), - const GridItem( + GridItem( title: 'donate_card_title', icon: Ionicons.heart_outline, url: @@ -62,58 +62,58 @@ class SecondScreen extends StatelessWidget { crossAxisSpacing: 8, mainAxisSpacing: 8, shrinkWrap: true, - children: [ - const GridItem( + children: const [ + GridItem( title: 'flutter_bloc', icon: Ionicons.apps_outline, url: 'https://pub.dev/packages/flutter_bloc', ), - const GridItem( + GridItem( title: 'bloc', icon: Ionicons.grid_outline, url: 'https://pub.dev/packages/bloc', ), - const GridItem( + GridItem( title: 'hydrated_bloc', icon: Ionicons.folder_open_outline, url: 'https://pub.dev/packages/hydrated_bloc', ), - const GridItem( + GridItem( title: 'equatable', icon: Ionicons.git_compare_outline, url: 'https://pub.dev/packages/equatable', ), - const GridItem( + GridItem( title: 'lints', icon: Ionicons.options_outline, - url: 'https://pub.dev/packages/lints', + url: 'https://pub.dev/packages/flutter_lints', ), - const GridItem( + GridItem( title: 'path_provider', icon: Ionicons.extension_puzzle_outline, url: 'https://pub.dev/packages/path_provider', ), - const GridItem( + GridItem( title: 'flutter_displaymode', icon: Ionicons.speedometer_outline, url: 'https://pub.dev/packages/flutter_displaymode', ), - const GridItem( + GridItem( title: 'easy_localization', icon: Ionicons.text_outline, url: 'https://pub.dev/packages/easy_localization', ), - const GridItem( + GridItem( title: 'hive', icon: Ionicons.folder_outline, url: 'https://pub.dev/packages/hive', ), - const GridItem( + GridItem( title: 'url_launcher', icon: Ionicons.share_outline, url: 'https://pub.dev/packages/url_launcher', ), - const GridItem( + GridItem( title: 'ionicons', icon: Ionicons.logo_ionic, url: 'https://pub.dev/packages/ionicons', diff --git a/lib/ui/screens/skeleton_screen.dart b/lib/ui/screens/skeleton_screen.dart index 25192a91..bb8ae4b4 100644 --- a/lib/ui/screens/skeleton_screen.dart +++ b/lib/ui/screens/skeleton_screen.dart @@ -8,9 +8,11 @@ import 'package:flutter_production_boilerplate/ui/widgets/app_bar_gone.dart'; import 'package:flutter_production_boilerplate/ui/widgets/bottom_nav_bar.dart'; class SkeletonScreen extends StatelessWidget { - final _pageNavigation = [ - const FirstScreen(), - const SecondScreen(), + const SkeletonScreen({Key? key}) : super(key: key); + + final _pageNavigation = const [ + FirstScreen(), + SecondScreen(), ]; @override diff --git a/lib/ui/widgets/app_bar_gone.dart b/lib/ui/widgets/app_bar_gone.dart index 0eb8eaf5..0f58600c 100644 --- a/lib/ui/widgets/app_bar_gone.dart +++ b/lib/ui/widgets/app_bar_gone.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; class AppBarGone extends StatelessWidget implements PreferredSizeWidget { - const AppBarGone(); + const AppBarGone({Key? key}): super(key: key); @override Widget build(BuildContext context) { diff --git a/lib/ui/widgets/bottom_nav_bar.dart b/lib/ui/widgets/bottom_nav_bar.dart index 74c3e82a..27d5356c 100644 --- a/lib/ui/widgets/bottom_nav_bar.dart +++ b/lib/ui/widgets/bottom_nav_bar.dart @@ -5,7 +5,10 @@ import 'package:flutter_production_boilerplate/cubit/bottom_nav_cubit.dart'; import 'package:ionicons/ionicons.dart'; class BottomNavBar extends StatelessWidget { - BottomNavBar(); + /// It is okay not to use a const constructor here. + /// Using const breaks updating of selected BottomNavigationBarItem. + // ignore: prefer_const_constructors_in_immutables + BottomNavBar({Key? key}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/lib/ui/widgets/first_screen/info_card.dart b/lib/ui/widgets/first_screen/info_card.dart index 53bd6f42..f0aca939 100644 --- a/lib/ui/widgets/first_screen/info_card.dart +++ b/lib/ui/widgets/first_screen/info_card.dart @@ -9,10 +9,12 @@ class InfoCard extends StatelessWidget { final bool isPrimaryColor; const InfoCard( - {required this.title, + {Key? key, + required this.title, required this.content, required this.icon, - required this.isPrimaryColor}); + required this.isPrimaryColor}) + : super(key: key); @override Widget build(BuildContext context) { diff --git a/lib/ui/widgets/header.dart b/lib/ui/widgets/header.dart index 4647d055..c0bcf1d8 100644 --- a/lib/ui/widgets/header.dart +++ b/lib/ui/widgets/header.dart @@ -2,9 +2,9 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; class Header extends StatelessWidget { - final text; + final String text; - const Header({Key? key, this.text}) : super(key: key); + const Header({Key? key, required this.text}) : super(key: key); @override Widget build(BuildContext context) { diff --git a/lib/ui/widgets/second_screen/grid_item.dart b/lib/ui/widgets/second_screen/grid_item.dart index ff0e069d..d37bca93 100644 --- a/lib/ui/widgets/second_screen/grid_item.dart +++ b/lib/ui/widgets/second_screen/grid_item.dart @@ -9,7 +9,7 @@ class GridItem extends StatelessWidget { final String url; /// Named parameters are preferred, they make the code easier to understand. - const GridItem({required this.title, required this.icon, required this.url}); + const GridItem({Key? key, required this.title, required this.icon, required this.url}): super(key: key); @override Widget build(BuildContext context) { diff --git a/lib/ui/widgets/second_screen/link_card.dart b/lib/ui/widgets/second_screen/link_card.dart index 7c304d0f..0a114caf 100644 --- a/lib/ui/widgets/second_screen/link_card.dart +++ b/lib/ui/widgets/second_screen/link_card.dart @@ -9,7 +9,7 @@ class LinkCard extends StatelessWidget { final IconData icon; final String url; - const LinkCard({required this.title, required this.icon, required this.url}); + const LinkCard({Key? key, required this.title, required this.icon, required this.url}): super(key: key); @override Widget build(BuildContext context) { diff --git a/pubspec.lock b/pubspec.lock index 288e6b9d..a2b43af9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -125,6 +125,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.3.2" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" flutter_localizations: dependency: transitive description: flutter @@ -176,7 +183,7 @@ packages: source: hosted version: "0.6.3" lints: - dependency: "direct main" + dependency: transitive description: name: lints url: "https://pub.dartlang.org" @@ -431,7 +438,7 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "2.2.0" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 97c67966..85ba8ee9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,6 @@ dependencies: flutter_bloc: ^7.0.1 hydrated_bloc: ^7.0.1 equatable: ^2.0.2 - lints: ^1.0.1 path_provider: ^2.0.2 flutter_displaymode: ^0.3.2 easy_localization: ^3.0.0 @@ -39,6 +38,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^1.0.3 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/test/widget_test.dart b/test/widget_test.dart index 11657d32..6040beeb 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -5,11 +5,6 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:flutter_production_boilerplate/main.dart'; - void main() { /* Stock test -- GitLab