diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f9b303465f19b5fbf5ec669cd083c9cc38ecda9a
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:flutter_lints/flutter.yaml
diff --git a/android/gradle.properties b/android/gradle.properties
index 84e1e4153b337375b48ca3b51c39d9d8cbca5ba9..99e5b796c2b44f9fb9aa882d9a8b2f72b08f9a7f 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
 org.gradle.jvmargs=-Xmx1536M
 android.useAndroidX=true
 android.enableJetifier=true
-app.versionName=1.0.45
-app.versionCode=46
+app.versionName=1.0.46
+app.versionCode=47
diff --git a/lib/config/menu.dart b/lib/config/menu.dart
index 45c069261a3b14933f421d2d14a486fcc0a0c904..b06e9eb05c661cd00f4df9d6fd3675ba799f50ad 100644
--- a/lib/config/menu.dart
+++ b/lib/config/menu.dart
@@ -24,39 +24,39 @@ class MenuItem {
 
 class Menu {
   static List<MenuItem> items = [
-    MenuItem(
+    const MenuItem(
       code: 'bottom_nav_sample',
-      icon: const Icon(UniconsLine.image),
+      icon: Icon(UniconsLine.image),
       page: DemoPage(),
     ),
-    MenuItem(
+    const MenuItem(
       code: 'bottom_nav_api',
-      icon: const Icon(UniconsLine.globe),
+      icon: Icon(UniconsLine.globe),
       page: ApiPage(),
     ),
-    MenuItem(
+    const MenuItem(
       code: 'bottom_nav_camera',
-      icon: const Icon(UniconsLine.camera),
+      icon: Icon(UniconsLine.camera),
       page: CameraPage(),
     ),
-    MenuItem(
+    const MenuItem(
       code: 'bottom_nav_chart',
-      icon: const Icon(UniconsLine.pen),
+      icon: Icon(UniconsLine.pen),
       page: GraphPage(),
     ),
-    MenuItem(
+    const MenuItem(
       code: 'bottom_nav_game',
-      icon: const Icon(UniconsLine.star),
+      icon: Icon(UniconsLine.star),
       page: GamePage(),
     ),
-    MenuItem(
+    const MenuItem(
       code: 'bottom_nav_settings',
-      icon: const Icon(UniconsLine.setting),
+      icon: Icon(UniconsLine.setting),
       page: SettingsPage(),
     ),
-    MenuItem(
+    const MenuItem(
       code: 'bottom_nav_about',
-      icon: const Icon(UniconsLine.info_circle),
+      icon: Icon(UniconsLine.info_circle),
       page: AboutPage(),
     ),
   ];
diff --git a/lib/cubit/api_cubit.dart b/lib/cubit/api_cubit.dart
index 27b9f29f23600566ae274aaf16bc9b5a002e319f..5fe5dd73df67df664784117e1456b7f7cc7131e7 100644
--- a/lib/cubit/api_cubit.dart
+++ b/lib/cubit/api_cubit.dart
@@ -27,7 +27,7 @@ class ApiDataCubit extends HydratedCubit<ApiDataState> {
         }
       }
     }
-    print('emit new state: ' + stateAsString);
+    print('emit new state: $stateAsString');
 
     emit(state);
   }
diff --git a/lib/cubit/api_state.dart b/lib/cubit/api_state.dart
index a930be04aa0c3a19f072e8155bbba47cc2363107..86cbe009ed797c5a66cc6a8ccef80f78da07f5db 100644
--- a/lib/cubit/api_state.dart
+++ b/lib/cubit/api_state.dart
@@ -16,6 +16,7 @@ class ApiDataFetchInitial extends ApiDataState {}
 class ApiDataFetchLoading extends ApiDataState {}
 
 class ApiDataFetchLoaded extends ApiDataState {
+  @override
   final ApiData data;
 
   const ApiDataFetchLoaded({
diff --git a/lib/cubit/settings_cubit.dart b/lib/cubit/settings_cubit.dart
index 01d3b943b6542e57c2ba42f346dc587285173158..35d6c2da89562adea794031dc2fde2787a5f6bfa 100644
--- a/lib/cubit/settings_cubit.dart
+++ b/lib/cubit/settings_cubit.dart
@@ -35,9 +35,9 @@ class SettingsCubit extends HydratedCubit<SettingsState> {
     InterfaceType? interfaceType,
   }) {
     emit(SettingsState(
-      apiUrl: apiUrl != null ? apiUrl : state.apiUrl,
-      securityToken: securityToken != null ? securityToken : state.securityToken,
-      interfaceType: interfaceType != null ? interfaceType : state.interfaceType,
+      apiUrl: apiUrl ?? state.apiUrl,
+      securityToken: securityToken ?? state.securityToken,
+      interfaceType: interfaceType ?? state.interfaceType,
     ));
   }
 
diff --git a/lib/main.dart b/lib/main.dart
index 6b6e38b6dca4897664eb5ae5212927b9ae97574f..ca105a76396f0950f7ed21c7aa7d29091f1bf3f6 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -63,7 +63,7 @@ class MyApp extends StatelessWidget {
       child: MaterialApp(
         title: 'Random application',
         theme: appTheme,
-        home: SkeletonScreen(),
+        home: const SkeletonScreen(),
         localizationsDelegates: context.localizationDelegates,
         supportedLocales: context.supportedLocales,
         locale: context.locale,
diff --git a/lib/models/api_data.dart b/lib/models/api_data.dart
index 8124108688a3ea77eaa5167d6dae2f52938730ca..0f8b8fc1d59a57af7108ef9781ecc98a1d124f94 100644
--- a/lib/models/api_data.dart
+++ b/lib/models/api_data.dart
@@ -21,13 +21,14 @@ class ApiData {
 
   Map<String, dynamic>? toJson() {
     return <String, dynamic>{
-      'number': this.number ?? 0,
-      'md5': this.md5 ?? '',
-      'updatedAt': this.updatedAt?.toString(),
+      'number': number ?? 0,
+      'md5': md5 ?? '',
+      'updatedAt': updatedAt?.toString(),
     };
   }
 
+  @override
   String toString() {
-    return jsonEncode(this.toJson());
+    return jsonEncode(toJson());
   }
 }
diff --git a/lib/models/game/game.dart b/lib/models/game/game.dart
index bf777d743a798124664fa152ab8121e5c694442f..e099feb79495861816c21e844dcf01038b0c81d0 100644
--- a/lib/models/game/game.dart
+++ b/lib/models/game/game.dart
@@ -37,57 +37,58 @@ class Game {
   }
 
   void stop() {
-    this.isRunning = false;
-    this.isFinished = true;
+    isRunning = false;
+    isFinished = true;
   }
 
   GameCell getCell(int x, int y) {
-    return this.board.cells[y][x];
+    return board.cells[y][x];
   }
 
   int? getCellValue(int x, int y) {
-    return this.getCell(x, y).value;
+    return getCell(x, y).value;
   }
 
   void updateCellValue(int x, int y, int? value) {
-    this.board.cells[y][x].value = value;
+    board.cells[y][x].value = value;
   }
 
   void setRandomCellValue(int x, int y, GameSettings settings) {
     final int maxValue = settings.colorsCount;
-    final rand = new Random();
+    final rand = Random();
     int value = 1 + rand.nextInt(maxValue);
 
-    this.board.cells[y][x].value = value;
+    board.cells[y][x].value = value;
   }
 
   void increaseMovesCount() {
-    this.movesCount += 1;
+    movesCount += 1;
   }
 
   void increaseScore(int? count) {
-    this.score += (count ?? 0);
+    score += (count ?? 0);
   }
 
+  @override
   String toString() {
-    return 'Game(' + this.toJson().toString() + ')';
+    return 'Game(${toJson()})';
   }
 
   Map<String, dynamic>? toJson() {
     return <String, dynamic>{
-      'board': this.board.toJson(),
-      'settings': this.settings.toJson(),
-      'isRunning': this.isRunning,
-      'isFinished': this.isFinished,
-      'availableBlocksCount': this.availableBlocksCount,
-      'movesCount': this.movesCount,
-      'score': this.score,
+      'board': board.toJson(),
+      'settings': settings.toJson(),
+      'isRunning': isRunning,
+      'isFinished': isFinished,
+      'availableBlocksCount': availableBlocksCount,
+      'movesCount': movesCount,
+      'score': score,
     };
   }
 
   void dump() {
-    GameBoard.printGrid(this.board.cells);
-    print(this.settings.toJson());
-    print(this.toJson());
+    GameBoard.printGrid(board.cells);
+    print(settings.toJson());
+    print(toJson());
   }
 }
diff --git a/lib/models/game/game_board.dart b/lib/models/game/game_board.dart
index 65654940e1fea58ca44dfaf290fab8d34a9d2806..41257e021d5ea50a6c9fd8fc4fd0da3e41bf2dbd 100644
--- a/lib/models/game/game_board.dart
+++ b/lib/models/game/game_board.dart
@@ -19,7 +19,7 @@ class GameBoard {
     final int boardSizeVertical = gameSettings.boardSize;
     final int maxValue = gameSettings.colorsCount;
 
-    final rand = new Random();
+    final rand = Random();
 
     List<List<GameCell>> grid = [];
     for (var rowIndex = 0; rowIndex < boardSizeVertical; rowIndex++) {
@@ -49,13 +49,14 @@ class GameBoard {
     print('');
   }
 
+  @override
   String toString() {
-    return 'Board(' + this.toJson().toString() + ')';
+    return 'Board(${toJson()})';
   }
 
   Map<String, dynamic>? toJson() {
     return <String, dynamic>{
-      'cells': this.cells.toString(),
+      'cells': cells.toString(),
     };
   }
 }
diff --git a/lib/models/game/game_cell.dart b/lib/models/game/game_cell.dart
index 25667ccf76bfbd4ef65f8651c120a7dbaab641b8..4cba17ba8adef606942ce8932dcbf429886edd5d 100644
--- a/lib/models/game/game_cell.dart
+++ b/lib/models/game/game_cell.dart
@@ -5,13 +5,14 @@ class GameCell {
     this.value,
   );
 
+  @override
   String toString() {
-    return 'Cell(' + this.toJson().toString() + ')';
+    return 'Cell(${toJson()})';
   }
 
   Map<String, dynamic>? toJson() {
     return <String, dynamic>{
-      'value': this.value,
+      'value': value,
     };
   }
 }
diff --git a/lib/models/game/game_settings.dart b/lib/models/game/game_settings.dart
index 4610c789c81b6f0d92745b45c089035c899c0772..2b108da4f3288c8430bb199f511ee8a7125acfef 100644
--- a/lib/models/game/game_settings.dart
+++ b/lib/models/game/game_settings.dart
@@ -32,14 +32,15 @@ class GameSettings {
     );
   }
 
+  @override
   String toString() {
-    return 'GameSettings(' + this.toJson().toString() + ')';
+    return 'GameSettings(${toJson()})';
   }
 
   Map<String, dynamic>? toJson() {
     return <String, dynamic>{
-      'boardSize': this.boardSize,
-      'colorsCount': this.colorsCount,
+      'boardSize': boardSize,
+      'colorsCount': colorsCount,
     };
   }
 }
diff --git a/lib/models/interface_type.dart b/lib/models/interface_type.dart
index 05dc342a74312efd54825091623fab48122e9a27..29763214791351f2cfa0663ce0a2d20afea9b169 100644
--- a/lib/models/interface_type.dart
+++ b/lib/models/interface_type.dart
@@ -8,7 +8,7 @@ enum InterfaceType {
 
 class InterfaceTypes {
   static List<Widget> selectWidgets = <Widget>[
-    Text('interface_type_basic').tr(),
-    Text('interface_type_expert').tr(),
+    const Text('interface_type_basic').tr(),
+    const Text('interface_type_expert').tr(),
   ];
 }
diff --git a/lib/network/api.dart b/lib/network/api.dart
index 23a620791df9af6319e2ac65bfac230a008e87ad..aa759361eaf0b5dbdb2c770d83ef452fceb60340 100644
--- a/lib/network/api.dart
+++ b/lib/network/api.dart
@@ -10,10 +10,10 @@ class ApiService {
   final String baseUrl = 'https://tools.harrault.fr/tools/api';
 
   Future<Response?> getData() async {
-    String url = baseUrl + '/get.php';
+    String url = '$baseUrl/get.php';
     try {
-      print('fetching api data... ' + url);
-      final Response? response = await _dio.get(url);
+      print('fetching api data... $url');
+      final Response response = await _dio.get(url);
       print('ok got api response.');
       print(response);
       return response;
diff --git a/lib/repository/api.dart b/lib/repository/api.dart
index ce3a0ef9c2f4a65f93a6b0b7074351ce5da54d9e..d6548b04414a5015d6946dae187bb9d56d697252 100644
--- a/lib/repository/api.dart
+++ b/lib/repository/api.dart
@@ -8,7 +8,7 @@ class ApiRepository {
 
   Future<ApiData> getApiData() async {
     print('(getApiData) delayed API call...');
-    final response = await Future.delayed(Duration(milliseconds: 1000))
+    final response = await Future.delayed(const Duration(milliseconds: 1000))
         .then((value) => apiService.getData());
     if (response != null) {
       print('(getApiData) got api response');
diff --git a/lib/ui/painters/cell_painter.dart b/lib/ui/painters/cell_painter.dart
index a2cf510a27634d1d33f6b15d92c2ce843aff7f36..851f70e6d3fe584eabe370da331d7bf06fcf4e91 100644
--- a/lib/ui/painters/cell_painter.dart
+++ b/lib/ui/painters/cell_painter.dart
@@ -30,7 +30,7 @@ class CellPainter extends CustomPainter {
 
     const borderWidth = 0.05;
 
-    final Rect baseSquare = Rect.fromPoints(Offset(0, 0), Offset(size.width, size.height));
+    final Rect baseSquare = Rect.fromPoints(const Offset(0, 0), Offset(size.width, size.height));
 
     final paintBaseSquare = Paint()
       ..style = PaintingStyle.fill
diff --git a/lib/ui/painters/graph_painter.dart b/lib/ui/painters/graph_painter.dart
index ac9358cdbd5158f6cc5db0e62177805cad594e11..38a30c6b90d22f24f8149b48f61ee31e75ab9a31 100644
--- a/lib/ui/painters/graph_painter.dart
+++ b/lib/ui/painters/graph_painter.dart
@@ -35,14 +35,14 @@ class GraphPainter extends CustomPainter {
     paintBackground.color = Colors.black;
     paintBackground.style = PaintingStyle.fill;
 
-    final Rect rectBackground = Rect.fromPoints(Offset(0, 0), Offset(size.width, size.height));
+    final Rect rectBackground = Rect.fromPoints(const Offset(0, 0), Offset(size.width, size.height));
     canvas.drawRect(rectBackground, paintBackground);
 
     // Draw some lines
     Paint paintLine = Paint();
     paintLine.style = PaintingStyle.fill;
 
-    for (int i = 0; i < this.linesCount; i++) {
+    for (int i = 0; i < linesCount; i++) {
       paintLine.color = getRandomColor();
       paintLine.strokeWidth = Random().nextDouble() * 4 + 2;
 
diff --git a/lib/ui/screens/about_page.dart b/lib/ui/screens/about_page.dart
index a93505a2c023770bfb010e7baf8bd429dc9a833b..f183a4a3c2b0920fd770e3bebdbd853c2cb6df66 100644
--- a/lib/ui/screens/about_page.dart
+++ b/lib/ui/screens/about_page.dart
@@ -14,15 +14,15 @@ class AboutPage extends StatelessWidget {
       crossAxisAlignment: CrossAxisAlignment.start,
       mainAxisSize: MainAxisSize.max,
       children: <Widget>[
-        SizedBox(height: 8),
-        AppHeader(text: 'about_title'),
-        Text('about_content').tr(),
+        const SizedBox(height: 8),
+        const AppHeader(text: 'about_title'),
+        const Text('about_content').tr(),
         FutureBuilder<PackageInfo>(
           future: PackageInfo.fromPlatform(),
           builder: (context, snapshot) {
             switch (snapshot.connectionState) {
               case ConnectionState.done:
-                return Text('about_version').tr(
+                return const Text('about_version').tr(
                   namedArgs: {
                     'version': snapshot.data!.version,
                   },
diff --git a/lib/ui/screens/api_page.dart b/lib/ui/screens/api_page.dart
index 9b0253243a8513084a058be2fbcb056650d8927c..22dc963aa246496f45eeb0dcca1b29ce512292df 100644
--- a/lib/ui/screens/api_page.dart
+++ b/lib/ui/screens/api_page.dart
@@ -17,9 +17,9 @@ class ApiPage extends StatelessWidget {
         padding: const EdgeInsets.symmetric(horizontal: 4),
         physics: const BouncingScrollPhysics(),
         children: <Widget>[
-          SizedBox(height: 8),
-          AppHeader(text: 'api_page_title'),
-          SizedBox(height: 20),
+          const SizedBox(height: 8),
+          const AppHeader(text: 'api_page_title'),
+          const SizedBox(height: 20),
           BlocBuilder<ApiDataCubit, ApiDataState>(
             builder: (BuildContext context, ApiDataState apiDataState) {
               return ApiDataWidget(
diff --git a/lib/ui/screens/camera_page.dart b/lib/ui/screens/camera_page.dart
index 98c22824edbc072dd7bc89334b91fcfdaa8eb683..828c6e29a3a4bcb389701b4fc664016783382d00 100644
--- a/lib/ui/screens/camera_page.dart
+++ b/lib/ui/screens/camera_page.dart
@@ -13,12 +13,12 @@ class CameraPage extends StatelessWidget {
   Widget build(BuildContext context) {
     return Material(
       color: Theme.of(context).colorScheme.background,
-      child: Column(
+      child: const Column(
         mainAxisAlignment: MainAxisAlignment.start,
         crossAxisAlignment: CrossAxisAlignment.center,
         children: <Widget>[
-          const SizedBox(height: 8),
-          const TakePictureWidget(),
+          SizedBox(height: 8),
+          TakePictureWidget(),
         ],
       ),
     );
diff --git a/lib/ui/screens/demo_page.dart b/lib/ui/screens/demo_page.dart
index 8d10142d6697bbdcdfdd5b340058558c9e0700c4..2c7269eb436c2c403bb61600447d1358009337b3 100644
--- a/lib/ui/screens/demo_page.dart
+++ b/lib/ui/screens/demo_page.dart
@@ -18,17 +18,17 @@ class DemoPage extends StatelessWidget {
         padding: const EdgeInsets.symmetric(horizontal: 4),
         physics: const BouncingScrollPhysics(),
         children: <Widget>[
-          SizedBox(height: 8),
-          AppHeader(text: 'TOP'),
-          SizedBox(height: 20),
+          const SizedBox(height: 8),
+          const AppHeader(text: 'TOP'),
+          const SizedBox(height: 20),
           persistedCounterBlock(BlocProvider.of<DataCubit>(context)),
-          SizedBox(height: 20),
+          const SizedBox(height: 20),
           testBlocConsumer(),
           testBlocBuilder(),
-          SizedBox(height: 20),
+          const SizedBox(height: 20),
           fakeApiCall(),
-          SizedBox(height: 20),
-          AppHeader(text: 'BOTTOM'),
+          const SizedBox(height: 20),
+          const AppHeader(text: 'BOTTOM'),
         ],
       ),
     );
@@ -40,13 +40,13 @@ class DemoPage extends StatelessWidget {
       crossAxisAlignment: CrossAxisAlignment.center,
       children: [
         IconButton(
-          icon: Icon(UniconsSolid.arrow_circle_down),
+          icon: const Icon(UniconsSolid.arrow_circle_down),
           color: appTheme.primaryColor,
           onPressed: () => dataCubit.updateCounter(-1),
         ),
         testBlocConsumer(),
         IconButton(
-          icon: Icon(UniconsSolid.arrow_circle_up),
+          icon: const Icon(UniconsSolid.arrow_circle_up),
           color: appTheme.primaryColor,
           onPressed: () => dataCubit.updateCounter(1),
         ),
@@ -61,9 +61,9 @@ class DemoPage extends StatelessWidget {
           mainAxisAlignment: MainAxisAlignment.center,
           crossAxisAlignment: CrossAxisAlignment.center,
           children: [
-            Text('apiUrl: ' + settingsSate.apiUrl.toString()),
-            Text('securityToken: ' + (settingsSate.securityToken.toString())),
-            Text('interfaceType: ' + settingsSate.interfaceType.toString()),
+            Text('apiUrl: ${settingsSate.apiUrl}'),
+            Text('securityToken: ${settingsSate.securityToken}'),
+            Text('interfaceType: ${settingsSate.interfaceType}'),
           ],
         );
       },
@@ -77,7 +77,7 @@ class DemoPage extends StatelessWidget {
       },
       builder: (context, dataState) {
         // return widget here based on state
-        return Text('BlocConsumer / ' + dataState.toString());
+        return Text('BlocConsumer / $dataState');
       },
     );
   }
@@ -94,7 +94,7 @@ class DemoPage extends StatelessWidget {
     return BlocBuilder<DataCubit, DataState>(
       builder: (context, dataState) {
         // return widget here based on state
-        return Text('BlocBuilder / ' + dataState.toString());
+        return Text('BlocBuilder / $dataState');
       },
     );
   }
diff --git a/lib/ui/screens/game_page.dart b/lib/ui/screens/game_page.dart
index 7822504342cb02e8b352f05c080441c38e81fa57..1f845c855f69c09a9f7b4b5cc76bb824118be192 100644
--- a/lib/ui/screens/game_page.dart
+++ b/lib/ui/screens/game_page.dart
@@ -24,7 +24,7 @@ class _GamePageState extends State<GamePage> {
           onPressed: () {
             gameCubit.updateGameState(Game.createNew());
           },
-          icon: Icon(UniconsSolid.star),
+          icon: const Icon(UniconsSolid.star),
           color: Colors.white,
         )
       ];
@@ -38,7 +38,7 @@ class _GamePageState extends State<GamePage> {
             gameCubit.updateGameState(currentGame);
             setState(() {});
           },
-          icon: Icon(UniconsLine.exit),
+          icon: const Icon(UniconsLine.exit),
           color: Colors.white,
         ));
       }
@@ -65,9 +65,9 @@ class _GamePageState extends State<GamePage> {
             gameState.game?.isRunning == true
                 ? GameBoardWidget(
                     game: gameState.game!,
-                    widgetSize: Size(boardWidgetWidth, boardWidgetHeight),
+                    widgetSize: const Size(boardWidgetWidth, boardWidgetHeight),
                   )
-                : GameSettingsWidget(),
+                : const GameSettingsWidget(),
             buildGameActionsBloc(context),
           ],
         );
diff --git a/lib/ui/screens/graph_page.dart b/lib/ui/screens/graph_page.dart
index 892151e53c44a8611c1506d37b6b1e0d8013cc9e..6a4c24732b65d5f42b863d0a7e9812cc4fabe588 100644
--- a/lib/ui/screens/graph_page.dart
+++ b/lib/ui/screens/graph_page.dart
@@ -17,50 +17,48 @@ class _GraphPageState extends State<GraphPage> {
     double boardWidth = MediaQuery.of(context).size.width;
 
     return SizedBox.expand(
-      child: Container(
-        child: FittedBox(
-          fit: BoxFit.contain,
-          alignment: Alignment.center,
-          child: SizedBox(
-            height: (MediaQuery.of(context).size.height),
-            width: (MediaQuery.of(context).size.width),
-            child: SafeArea(
-              child: Column(
-                mainAxisAlignment: MainAxisAlignment.start,
-                crossAxisAlignment: CrossAxisAlignment.center,
-                children: [
-                  Center(
-                    child: GestureDetector(
-                      onTapUp: (details) {
-                        double xTap = details.localPosition.dx;
-                        double yTap = details.localPosition.dy;
-                        print('[' + xTap.toString() + ',' + yTap.toString() + ']');
-                      },
-                      child: Container(
-                        margin: EdgeInsets.all(4),
-                        padding: EdgeInsets.all(4),
-                        child: CustomPaint(
-                          size: Size(boardWidth, boardWidth),
-                          willChange: false,
-                          painter: GraphPainter(linesCount: _currentSliderValue.toInt()),
-                        ),
+      child: FittedBox(
+        fit: BoxFit.contain,
+        alignment: Alignment.center,
+        child: SizedBox(
+          height: (MediaQuery.of(context).size.height),
+          width: (MediaQuery.of(context).size.width),
+          child: SafeArea(
+            child: Column(
+              mainAxisAlignment: MainAxisAlignment.start,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                Center(
+                  child: GestureDetector(
+                    onTapUp: (details) {
+                      double xTap = details.localPosition.dx;
+                      double yTap = details.localPosition.dy;
+                      print('[$xTap,$yTap]');
+                    },
+                    child: Container(
+                      margin: const EdgeInsets.all(4),
+                      padding: const EdgeInsets.all(4),
+                      child: CustomPaint(
+                        size: Size(boardWidth, boardWidth),
+                        willChange: false,
+                        painter: GraphPainter(linesCount: _currentSliderValue.toInt()),
                       ),
                     ),
                   ),
-                  Slider(
-                    value: _currentSliderValue,
-                    min: 10,
-                    max: 50,
-                    divisions: 5,
-                    label: _currentSliderValue.round().toString(),
-                    onChanged: (double value) {
-                      setState(() {
-                        _currentSliderValue = value;
-                      });
-                    },
-                  ),
-                ],
-              ),
+                ),
+                Slider(
+                  value: _currentSliderValue,
+                  min: 10,
+                  max: 50,
+                  divisions: 5,
+                  label: _currentSliderValue.round().toString(),
+                  onChanged: (double value) {
+                    setState(() {
+                      _currentSliderValue = value;
+                    });
+                  },
+                ),
+              ],
             ),
           ),
         ),
diff --git a/lib/ui/screens/settings_page.dart b/lib/ui/screens/settings_page.dart
index 3e0195d470660eeb61e42d956822eef0dd177043..195d012e26cb923cc59b0b4521985e1f080a369f 100644
--- a/lib/ui/screens/settings_page.dart
+++ b/lib/ui/screens/settings_page.dart
@@ -8,7 +8,7 @@ class SettingsPage extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return Column(
+    return const Column(
       mainAxisAlignment: MainAxisAlignment.start,
       crossAxisAlignment: CrossAxisAlignment.start,
       mainAxisSize: MainAxisSize.max,
diff --git a/lib/ui/skeleton.dart b/lib/ui/skeleton.dart
index e8636195bb2a0a1caf3c6e098aad264f0fe3f1e6..513b39d7b8d6f0c2afae3b0153e523c8c354754a 100644
--- a/lib/ui/skeleton.dart
+++ b/lib/ui/skeleton.dart
@@ -19,7 +19,7 @@ class _SkeletonScreenState extends State<SkeletonScreen> {
   Widget build(BuildContext context) {
     return Scaffold(
       extendBodyBehindAppBar: false,
-      appBar: StandardAppBar(),
+      appBar: const StandardAppBar(),
       body: Swiper(
         itemCount: Menu.itemsCount,
         itemBuilder: (BuildContext context, int index) {
diff --git a/lib/ui/widgets/api_data.dart b/lib/ui/widgets/api_data.dart
index 36907922be8c5867e1d59bb1a91dc859eb885633..669de42d97f3bdc88bb9628fb9d51843164fdae2 100644
--- a/lib/ui/widgets/api_data.dart
+++ b/lib/ui/widgets/api_data.dart
@@ -19,19 +19,19 @@ class ApiDataWidget extends StatelessWidget {
       mainAxisAlignment: MainAxisAlignment.center,
       crossAxisAlignment: CrossAxisAlignment.start,
       children: [
-        Text('status: ' + status.toString()),
-        Text('number: ' + (this.data?.number.toString() ?? '')),
-        Text('md5: ' + (this.data?.md5.toString() ?? '')),
-        Text('updatedAt: ' + (this.data?.updatedAt.toString() ?? '')),
+        Text('status: $status'),
+        Text('number: ${data?.number.toString() ?? ''}'),
+        Text('md5: ${data?.md5.toString() ?? ''}'),
+        Text('updatedAt: ${data?.updatedAt.toString() ?? ''}'),
         status == ApiStatus.loading
-            ? Container(
+            ? const SizedBox(
                 width: 12,
                 height: 12,
-                child: const CircularProgressIndicator(),
+                child: CircularProgressIndicator(),
               )
             : const SizedBox.shrink(),
         status == ApiStatus.failed
-            ? ShowErrorWidget(message: 'state.failure.message')
+            ? const ShowErrorWidget(message: 'state.failure.message')
             : const SizedBox.shrink(),
       ],
     );
diff --git a/lib/ui/widgets/app_bar.dart b/lib/ui/widgets/app_bar.dart
index 648a641a98f807b8651688bee2de8017a71c669a..0d60da6f68207caaec25e048927f3bba420b32d3 100644
--- a/lib/ui/widgets/app_bar.dart
+++ b/lib/ui/widgets/app_bar.dart
@@ -8,8 +8,8 @@ class StandardAppBar extends StatelessWidget implements PreferredSizeWidget {
   @override
   Widget build(BuildContext context) {
     return AppBar(
-      title: AppHeader(text: 'app_name'),
-      actions: [
+      title: const AppHeader(text: 'app_name'),
+      actions: const [
         //
       ],
     );
diff --git a/lib/ui/widgets/debug_bloc.dart b/lib/ui/widgets/debug_bloc.dart
index 502baccfe0ea57b4b3c9bac387a9ea151e0915c0..cbc6dfeacf71bf10c6ba3435ece3233f73201a97 100644
--- a/lib/ui/widgets/debug_bloc.dart
+++ b/lib/ui/widgets/debug_bloc.dart
@@ -16,11 +16,11 @@ class DebugBloc extends StatelessWidget {
         ),
       ),
       child: Padding(
-        padding: EdgeInsets.all(5),
+        padding: const EdgeInsets.all(5),
         child: Text(
           content,
           textAlign: TextAlign.start,
-          style: TextStyle(fontSize: 13),
+          style: const TextStyle(fontSize: 13),
         ),
       ),
     );
diff --git a/lib/ui/widgets/error.dart b/lib/ui/widgets/error.dart
index e65f242fd0b657ce06ee235ea8f574689bf7089f..9aacdcb7d4796e332b8a3160284aa8ced0e4f1c3 100644
--- a/lib/ui/widgets/error.dart
+++ b/lib/ui/widgets/error.dart
@@ -9,9 +9,9 @@ class ShowErrorWidget extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return Text(
-      '⚠️ ' + tr(message),
+      '⚠️ ${tr(message)}',
       textAlign: TextAlign.start,
-      style: TextStyle(color: Colors.red),
+      style: const TextStyle(color: Colors.red),
     );
   }
 }
diff --git a/lib/ui/widgets/game/game_board.dart b/lib/ui/widgets/game/game_board.dart
index 6f11e5bac6bb4fd9c56a2cd10b7a501af7418a52..f354e213c268bd6dab8bbeb0bc8d99896bf6aa8c 100644
--- a/lib/ui/widgets/game/game_board.dart
+++ b/lib/ui/widgets/game/game_board.dart
@@ -49,7 +49,7 @@ class _GameBoardWidget extends State<GameBoardWidget> with TickerProviderStateMi
     // "move down" cells
     final controller = AnimationController(
       vsync: this,
-      duration: Duration(milliseconds: 750),
+      duration: const Duration(milliseconds: 750),
     )..addListener(() {
         if (mounted) {
           setState(() {});
@@ -99,7 +99,7 @@ class _GameBoardWidget extends State<GameBoardWidget> with TickerProviderStateMi
     final cellWidth = widgetWidth / columnsCount;
     final cellHeight = widgetHeight / rowsCount;
 
-    if (animations.length == 0) {
+    if (animations.isEmpty) {
       resetAnimations(widget.game.settings);
     }
 
@@ -110,7 +110,7 @@ class _GameBoardWidget extends State<GameBoardWidget> with TickerProviderStateMi
         final int? value = widget.game.getCellValue(x, y);
 
         if (value != null) {
-          final Animation<double>? translation = this.animations[y][x];
+          final Animation<double>? translation = animations[y][x];
 
           final Widget cellContent = CustomPaint(
             size: Size(cellWidth, cellHeight),
@@ -121,7 +121,7 @@ class _GameBoardWidget extends State<GameBoardWidget> with TickerProviderStateMi
           final Widget cellWidget = Positioned(
             left: (x * cellWidth).toDouble(),
             top: ((y + (translation?.value ?? 0)) * cellHeight).toDouble(),
-            child: Container(
+            child: SizedBox(
               width: cellWidth,
               height: cellHeight,
               child: cellContent,
@@ -154,13 +154,13 @@ class _GameBoardWidget extends State<GameBoardWidget> with TickerProviderStateMi
       child: buildBoard(),
       onTapUp: (details) {
         bool canRemoveCell = true;
-        animations.forEach((row) {
-          row.forEach((cell) {
+        for (var row in animations) {
+          for (var cell in row) {
             if (cell != null) {
               canRemoveCell = false;
             }
-          });
-        });
+          }
+        }
 
         if (canRemoveCell) {
           double xTap = details.localPosition.dx;
@@ -168,7 +168,7 @@ class _GameBoardWidget extends State<GameBoardWidget> with TickerProviderStateMi
 
           int x = (xTap / widgetWidth * columnsCount).toInt();
           int y = (yTap / widgetHeight * rowsCount).toInt();
-          print('[' + x.toString() + ',' + y.toString() + ']');
+          print('[$x,$y]');
 
           removeCell(context, x, y);
         } else {
diff --git a/lib/ui/widgets/game/game_score.dart b/lib/ui/widgets/game/game_score.dart
index e52193c8e551583a9432a22529bf26c705b9424e..cea8f9addc05677985b83856a1f5ae5878d152cf 100644
--- a/lib/ui/widgets/game/game_score.dart
+++ b/lib/ui/widgets/game/game_score.dart
@@ -14,19 +14,19 @@ class GameScoreWidget extends StatelessWidget {
   Widget build(BuildContext context) {
     return Container(
       width: MediaQuery.of(context).size.width,
-      padding: EdgeInsets.all(5),
+      padding: const EdgeInsets.all(5),
       child: Column(
         mainAxisAlignment: MainAxisAlignment.start,
         crossAxisAlignment: CrossAxisAlignment.start,
         children: [
-          Text('Settings:'),
-          Text('  board size: ' + this.game.settings.boardSize.toString()),
-          Text('  colors count: ' + this.game.settings.colorsCount.toString()),
-          Text('Game:'),
-          Text('  isRunning: ' + this.game.isRunning.toString()),
-          Text('  isFinished: ' + this.game.isFinished.toString()),
-          Text('  movesCount: ' + this.game.movesCount.toString()),
-          Text('  score: ' + this.game.score.toString()),
+          const Text('Settings:'),
+          Text('  board size: ${game.settings.boardSize}'),
+          Text('  colors count: ${game.settings.colorsCount}'),
+          const Text('Game:'),
+          Text('  isRunning: ${game.isRunning}'),
+          Text('  isFinished: ${game.isFinished}'),
+          Text('  movesCount: ${game.movesCount}'),
+          Text('  score: ${game.score}'),
         ],
       ),
     );
diff --git a/lib/ui/widgets/game/game_settings.dart b/lib/ui/widgets/game/game_settings.dart
index 3170c695f5eb4fbb6b6cf8aa1b814c79d0b1420f..783e770c7f1d2607102e03379112349d9881b4a9 100644
--- a/lib/ui/widgets/game/game_settings.dart
+++ b/lib/ui/widgets/game/game_settings.dart
@@ -7,6 +7,6 @@ class GameSettingsWidget extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return Text('(fake settings block)');
+    return const Text('(fake settings block)');
   }
 }
diff --git a/lib/ui/widgets/header_app.dart b/lib/ui/widgets/header_app.dart
index b19ad444d879c83bb8b8bf3982a27d5bdcf1e16a..39bfa864db714a3ea04cf42a2486b1ccd7fb8482 100644
--- a/lib/ui/widgets/header_app.dart
+++ b/lib/ui/widgets/header_app.dart
@@ -23,11 +23,11 @@ class AppHeader extends StatelessWidget {
           textAlign: TextAlign.start,
           style: Theme.of(context).textTheme.headlineMedium!.apply(fontWeightDelta: 2),
         ),
-        SizedBox(width: 2),
+        const SizedBox(width: 2),
         expertInterfaceIndicator(),
-        SizedBox(width: 2),
+        const SizedBox(width: 2),
         dataCounterIndicator(),
-        SizedBox(width: 2),
+        const SizedBox(width: 2),
         apiLoadingIndicator(),
       ],
     );
@@ -46,7 +46,7 @@ class AppHeader extends StatelessWidget {
   Widget dataCounterIndicator() {
     return BlocBuilder<DataCubit, DataState>(
       builder: (context, dataState) {
-        return Text('(' + dataState.counter.toString() + ')');
+        return Text('(${dataState.counter})');
       },
     );
   }
@@ -55,10 +55,10 @@ class AppHeader extends StatelessWidget {
     return BlocBuilder<ApiDataCubit, ApiDataState>(
       builder: (context, apiDataState) {
         return (apiDataState is ApiDataFetchLoading)
-            ? Text('⏳')
+            ? const Text('⏳')
             : (apiDataState is ApiDataFetchLoaded)
-                ? Text('✅')
-                : Text('⚠️');
+                ? const Text('✅')
+                : const Text('⚠️');
       },
     );
   }
diff --git a/lib/ui/widgets/settings_form.dart b/lib/ui/widgets/settings_form.dart
index ac40063bd0d2c5ebdb911ec3e744dfd31c6e3ec4..5cd634890c1575097a977b15eb289560523745e8 100644
--- a/lib/ui/widgets/settings_form.dart
+++ b/lib/ui/widgets/settings_form.dart
@@ -54,23 +54,23 @@ class _SettingsFormState extends State<SettingsForm> {
       crossAxisAlignment: CrossAxisAlignment.start,
       mainAxisSize: MainAxisSize.max,
       children: <Widget>[
-        Text('settings_label_api_url').tr(),
+        const Text('settings_label_api_url').tr(),
         TextFormField(
           controller: apiUrlController,
-          decoration: InputDecoration(
+          decoration: const InputDecoration(
             border: UnderlineInputBorder(),
           ),
         ),
-        SizedBox(height: 16),
-        Text('settings_label_security_token').tr(),
+        const SizedBox(height: 16),
+        const Text('settings_label_security_token').tr(),
         TextFormField(
           controller: securityTokenController,
-          decoration: InputDecoration(
+          decoration: const InputDecoration(
             border: UnderlineInputBorder(),
           ),
         ),
-        SizedBox(height: 16),
-        Text('settings_label_interface_type').tr(),
+        const SizedBox(height: 16),
+        const Text('settings_label_interface_type').tr(),
         ToggleButtons(
           direction: Axis.horizontal,
           onPressed: (int index) {
@@ -90,15 +90,15 @@ class _SettingsFormState extends State<SettingsForm> {
           isSelected: _selectedInterfaceType,
           children: interfaceTypesWidgets,
         ),
-        SizedBox(height: 20),
+        const SizedBox(height: 20),
         ElevatedButton(
           child: Row(
             mainAxisAlignment: MainAxisAlignment.center,
             crossAxisAlignment: CrossAxisAlignment.center,
             children: [
-              Icon(UniconsLine.save),
-              SizedBox(width: 8),
-              Text('settings_button_save').tr(),
+              const Icon(UniconsLine.save),
+              const SizedBox(width: 8),
+              const Text('settings_button_save').tr(),
             ],
           ),
           onPressed: () => saveSettings(),
diff --git a/lib/ui/widgets/take_picture_widget.dart b/lib/ui/widgets/take_picture_widget.dart
index 7a73090629bb996bdb2af68bd4ba45c97b35a3b4..efece10a4435b499e8f9557a44161329b381fab2 100644
--- a/lib/ui/widgets/take_picture_widget.dart
+++ b/lib/ui/widgets/take_picture_widget.dart
@@ -28,24 +28,20 @@ class TakePictureWidgetState extends State<TakePictureWidget> {
   }
 
   loadCamera() async {
-    final List<CameraDescription>? cameras = await availableCameras();
-    if (cameras != null) {
-      controller = CameraController(
-        cameras.first,
-        ResolutionPreset.max,
-        enableAudio: false,
-      );
+    final List<CameraDescription> cameras = await availableCameras();
+    controller = CameraController(
+      cameras.first,
+      ResolutionPreset.max,
+      enableAudio: false,
+    );
 
-      controller!.initialize().then((_) {
-        if (!mounted) {
-          return;
-        }
-        setState(() {});
-      });
-    } else {
-      print("No camera found.");
+    controller!.initialize().then((_) {
+      if (!mounted) {
+        return;
+      }
+      setState(() {});
+    });
     }
-  }
 
   @override
   void dispose() {
@@ -60,50 +56,50 @@ class TakePictureWidgetState extends State<TakePictureWidget> {
         mainAxisAlignment: MainAxisAlignment.start,
         crossAxisAlignment: CrossAxisAlignment.center,
         children: [
-          Container(
+          SizedBox(
             height: 400,
             child: controller == null
-                ? Center(child: Text("Loading camera..."))
+                ? const Center(child: Text("Loading camera..."))
                 : !controller!.value.isInitialized
-                    ? Center(child: CircularProgressIndicator())
+                    ? const Center(child: CircularProgressIndicator())
                     : CameraPreview(controller!),
           ),
           ElevatedButton.icon(
-            label: Text("Take picture"),
-            icon: Icon(UniconsLine.camera),
+            label: const Text("Take picture"),
+            icon: const Icon(UniconsLine.camera),
             onPressed: () async {
               try {
                 if ((controller != null) && (controller!.value.isInitialized)) {
                   final XFile image = await controller!.takePicture();
-                  print('image.path: ' + image.path);
-                  debug.add('image.path: ' + image.path);
+                  print('image.path: ${image.path}');
+                  debug.add('image.path: ${image.path}');
 
                   File savedFile = await storage!.writeCounter(File(image.path));
-                  debug.add('image.path: ' + image.path);
+                  debug.add('image.path: ${image.path}');
 
                   String imagePath = savedFile.path;
-                  print('imagePath: ' + imagePath);
-                  debug.add('imagePath: ' + imagePath);
+                  print('imagePath: $imagePath');
+                  debug.add('imagePath: $imagePath');
 
                   previousImages.add(imagePath);
                   setState(() {});
                 }
               } catch (e) {
-                debug.add('error: ' + e.toString());
+                debug.add('error: $e');
                 setState(() {});
 
                 print(e);
               }
             },
           ),
-          Text('debug: '),
+          const Text('debug: '),
           Column(
             children: debug.map((String line) {
               return Text(line);
             }).toList(),
           ),
-          previousImages.length == 0
-              ? Text('no previous images')
+          previousImages.isEmpty
+              ? const Text('no previous images')
               : Column(
                   children: previousImages.map((String imagePath) {
                     return Row(
diff --git a/lib/utils/picture_storage.dart b/lib/utils/picture_storage.dart
index 72e2278f677d39ef318ab24a57dd4a7e8b9ae950..ebf663b54f928c580239afa3218833fb8f4a9a65 100644
--- a/lib/utils/picture_storage.dart
+++ b/lib/utils/picture_storage.dart
@@ -13,14 +13,14 @@ class PictureStorage {
   Future<String> _localFilePath(String name) async {
     final path = await _localPath;
 
-    return path + '/' + name;
+    return '$path/$name';
   }
 
   Future<File> moveFile(File sourceFile, String newPath) async {
     try {
       return await sourceFile.rename(newPath);
     } on FileSystemException catch (e) {
-      print('Found exception while moving file: ' + e.toString());
+      print('Found exception while moving file: $e');
       final newFile = await sourceFile.copy(newPath);
       await sourceFile.delete();
       return newFile;
diff --git a/pubspec.lock b/pubspec.lock
index b3dd33c8a58e6b44e1eff2ec494b36c08e757a6d..dea0f193ddad7451373bd3ea1686cf29f5b58b8f 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -166,6 +166,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "8.1.3"
+  flutter_lints:
+    dependency: "direct dev"
+    description:
+      name: flutter_lints
+      sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.1"
   flutter_localizations:
     dependency: transitive
     description: flutter
@@ -193,7 +201,7 @@ packages:
     source: sdk
     version: "0.0.0"
   hive:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: hive
       sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
@@ -232,22 +240,30 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.18.1"
+  lints:
+    dependency: transitive
+    description:
+      name: lints
+      sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.0"
   material_color_utilities:
     dependency: transitive
     description:
       name: material_color_utilities
-      sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
+      sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
       url: "https://pub.dev"
     source: hosted
-    version: "0.5.0"
+    version: "0.8.0"
   meta:
     dependency: transitive
     description:
       name: meta
-      sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
+      sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
       url: "https://pub.dev"
     source: hosted
-    version: "1.10.0"
+    version: "1.11.0"
   nested:
     dependency: transitive
     description:
@@ -273,13 +289,13 @@ packages:
     source: hosted
     version: "2.0.1"
   path:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: path
-      sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
+      sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
       url: "https://pub.dev"
     source: hosted
-    version: "1.8.3"
+    version: "1.9.0"
   path_provider:
     dependency: "direct main"
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 96d198266d95be0ff478378d74ae4326b349f4a3..401d954712a27931b2ed700449ffdb567b84052a 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: A random application, for testing purpose only.
 
 publish_to: 'none'
 
-version: 1.0.45+46
+version: 1.0.46+47
 
 environment:
   sdk: '^3.0.0'
@@ -22,6 +22,8 @@ dependencies:
   package_info_plus: ^5.0.1
   flutter_swipe: ^1.0.1
   dio: ^5.3.3
+  hive: ^2.2.3
+  path: ^1.9.0
 
 flutter:
   uses-material-design: false
@@ -40,3 +42,5 @@ flutter:
           weight: 400
         - asset: assets/fonts/Nunito-Light.ttf
           weight: 300
+dev_dependencies:
+  flutter_lints: ^3.0.1