better linting

This commit is contained in:
Mguy13 2023-01-01 13:04:22 +01:00
parent c7324a6b19
commit d683995ddd
24 changed files with 143 additions and 119 deletions

View file

@ -1,3 +1,5 @@
include: package:very_good_analysis/analysis_options.3.1.0.yaml
analyzer: analyzer:
strong-mode: strong-mode:
implicit-dynamic: true implicit-dynamic: true

View file

@ -25,7 +25,7 @@ class McgRouter {
path: Routes.imageCarousel.routePath, path: Routes.imageCarousel.routePath,
name: Routes.imageCarousel.routeName, name: Routes.imageCarousel.routeName,
builder: (context, state) => ImageCarouselView( builder: (context, state) => ImageCarouselView(
imageCarouselViewArguments: state.extra as ImageCarouselViewArguments, imageCarouselViewArguments: state.extra! as ImageCarouselViewArguments,
), ),
), ),
], ],

View file

@ -17,11 +17,11 @@ enum Routes {
} }
class RoutesInfo { class RoutesInfo {
final String routePath;
final String routeName;
const RoutesInfo({ const RoutesInfo({
required this.routePath, required this.routePath,
required this.routeName, required this.routeName,
}); });
final String routePath;
final String routeName;
} }

View file

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
abstract class ConstColours { abstract class ConstColours {
/// Smoke Gray => a neutral grey with neutral warmth/cold /// Smoke Gray => a neutral grey with neutral warmth/cold
static const galleryBackgroundColour = Color.fromRGBO(127, 127, 125, 1.0); static const galleryBackgroundColour = Color.fromRGBO(127, 127, 125, 1);
static const red = Colors.red; static const red = Colors.red;
static const white = Colors.white; static const white = Colors.white;

View file

@ -1,6 +1,7 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
extension ResponseExtensions on Response { /// Extensions on [Dio]'s [Response].
extension ResponseExtensions<T> on Response<T> {
/// Shorthand for getting response's successful state. /// Shorthand for getting response's successful state.
bool get isSuccessful => (data as Map)['response']; bool get isSuccessful => (data! as Map<String, dynamic>)['response'] as bool;
} }

View file

@ -1,3 +1,4 @@
/// String extensions
extension StringExtensions on String { extension StringExtensions on String {
/// Returns true if given word contains atleast all the characters in [targetChars], and `false` otherwise /// Returns true if given word contains atleast all the characters in [targetChars], and `false` otherwise
/// ///
@ -6,9 +7,9 @@ extension StringExtensions on String {
required String targetChars, required String targetChars,
bool ignoreCase = true, bool ignoreCase = true,
}) { }) {
final Set<String> characterSet = ignoreCase final characterSet = ignoreCase
? Set.from(targetChars.toLowerCase().split('')) ? Set<String>.from(targetChars.toLowerCase().split(''))
: Set.from(targetChars.split('')); : Set<String>.from(targetChars.split(''));
for (final testChar in ignoreCase ? toLowerCase().split('') : split('')) { for (final testChar in ignoreCase ? toLowerCase().split('') : split('')) {
characterSet.remove(testChar); characterSet.remove(testChar);
if (characterSet.isEmpty) return true; if (characterSet.isEmpty) return true;

View file

@ -64,7 +64,7 @@ class ConnectionsService {
static ConnectionsService get locate => Locator.locate(); static ConnectionsService get locate => Locator.locate();
} }
extension _connectionStatusEmojiExtension on InternetConnectionStatus { extension _ConnectionStatusEmojiExtension on InternetConnectionStatus {
String get nameWithIcon { String get nameWithIcon {
switch (this) { switch (this) {
case InternetConnectionStatus.connected: case InternetConnectionStatus.connected:
@ -75,7 +75,7 @@ extension _connectionStatusEmojiExtension on InternetConnectionStatus {
} }
} }
extension _connectivityEmojiExtension on ConnectivityResult { extension _ConnectivityEmojiExtension on ConnectivityResult {
String get nameWithIcon { String get nameWithIcon {
switch (this) { switch (this) {
case ConnectivityResult.bluetooth: case ConnectivityResult.bluetooth:

View file

@ -29,7 +29,7 @@ class LocalStorageService {
} }
void updateFavourite({ void updateFavourite({
required index, required int index,
required bool newValue, required bool newValue,
}) { }) {
try { try {

View file

@ -15,8 +15,8 @@ class LoggingService {
useHistory: false, useHistory: false,
), ),
logger: TalkerLogger( logger: TalkerLogger(
formater: formater: !Platform.isIOS ? const ColoredLoggerFormatter() : const ExtendedLoggerFormatter(),
!Platform.isIOS ? const ColoredLoggerFormatter() : const ExtendedLoggerFormatter()), ),
loggerSettings: TalkerLoggerSettings( loggerSettings: TalkerLoggerSettings(
enableColors: !Platform.isIOS, enableColors: !Platform.isIOS,
), ),
@ -49,11 +49,10 @@ class LoggingService {
TalkerDioLogger( TalkerDioLogger(
talker: Talker( talker: Talker(
logger: TalkerLogger( logger: TalkerLogger(
formater: !Platform.isIOS formater:
? const ColoredLoggerFormatter() !Platform.isIOS ? const ColoredLoggerFormatter() : const ExtendedLoggerFormatter(),
: const ExtendedLoggerFormatter()), ),
settings: TalkerSettings( settings: TalkerSettings(
useConsoleLogs: true,
useHistory: false, useHistory: false,
), ),
loggerSettings: TalkerLoggerSettings( loggerSettings: TalkerLoggerSettings(
@ -63,7 +62,6 @@ class LoggingService {
settings: const TalkerDioLoggerSettings( settings: const TalkerDioLoggerSettings(
printRequestHeaders: true, printRequestHeaders: true,
printResponseHeaders: true, printResponseHeaders: true,
printResponseMessage: true,
), ),
), ),
); );

View file

@ -24,8 +24,9 @@ class OverlayService {
//todo(mehul): Fix and not ignore Overlay building while Widget building error. //todo(mehul): Fix and not ignore Overlay building while Widget building error.
} on FlutterError catch (_) {} } on FlutterError catch (_) {}
_loggingService.info('Overlay inserted with tag: $tag'); _loggingService.info('Overlay inserted with tag: $tag');
} else } else {
_loggingService.info('Overlay with tag: $tag, NOT inserted'); _loggingService.info('Overlay with tag: $tag, NOT inserted');
}
} }
void removeOverlayEntry({ void removeOverlayEntry({
@ -37,10 +38,12 @@ class OverlayService {
_overlayEntryMap[tag.hashCode]?.remove(); _overlayEntryMap[tag.hashCode]?.remove();
_overlayEntryMap.remove(tag.hashCode); _overlayEntryMap.remove(tag.hashCode);
_loggingService.info('Overlay removed with tag: $tag'); _loggingService.info('Overlay removed with tag: $tag');
} else } else {
_loggingService.info('Overlay with tag: $tag already mounted OR not found. Skipped'); _loggingService.info('Overlay with tag: $tag already mounted OR not found. Skipped');
} else }
} else {
_loggingService.info('Overlay with tag: $tag already exists. Skipped'); _loggingService.info('Overlay with tag: $tag already exists. Skipped');
}
} }
void dispose() { void dispose() {

View file

@ -4,19 +4,19 @@ import 'dart:ui';
/// A simple Mutex implementation using a [Completer]. /// A simple Mutex implementation using a [Completer].
class Mutex { class Mutex {
final _completerQueue = Queue<Completer>(); final _completerQueue = Queue<Completer<void>>();
/// Runs the given [run] function-block in a thread-safe/blocked zone. A convenient `unlock()` /// Runs the given [run] function-block in a thread-safe/blocked zone. A convenient `unlock()`
/// is provided, which can be called anywhere to signal re-entry. /// is provided, which can be called anywhere to signal re-entry.
FutureOr<T> lockAndRun<T>({ FutureOr<T> lockAndRun<T>({
required FutureOr<T> Function(VoidCallback unlock) run, required FutureOr<T> Function(VoidCallback unlock) run,
}) async { }) async {
final completer = Completer(); final completer = Completer<void>();
_completerQueue.add(completer); _completerQueue.add(completer);
if (_completerQueue.first != completer) { if (_completerQueue.first != completer) {
await _completerQueue.removeFirst().future; await _completerQueue.removeFirst().future;
} }
final value = await run(() => completer.complete()); final value = await run(completer.complete);
return value; return value;
} }

View file

@ -17,7 +17,7 @@ class ErrorPageView extends StatelessWidget {
child: Column( child: Column(
children: [ children: [
Text(Strings.current.errorPageMessage), Text(Strings.current.errorPageMessage),
const Gap(16), Gap.size16,
], ],
), ),
); );

View file

@ -1,8 +1,12 @@
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
/// Const evenly-sized gap.
class Gap extends LeafRenderObjectWidget { class Gap extends LeafRenderObjectWidget {
const Gap(this.size, {Key? key}) : super(key: key); const Gap(
this.size, {
super.key,
});
final double size; final double size;
@ -58,13 +62,14 @@ class RenderGap extends RenderBox {
} }
} }
/// Animates [Gap] insertion.
class AnimatedGap extends StatefulWidget { class AnimatedGap extends StatefulWidget {
const AnimatedGap( const AnimatedGap(
this.gap, { this.gap, {
Key? key,
this.duration = const Duration(milliseconds: 200), this.duration = const Duration(milliseconds: 200),
this.curve = Curves.easeInOut, this.curve = Curves.easeInOut,
}) : super(key: key); super.key,
});
final Duration duration; final Duration duration;
final double gap; final double gap;
@ -107,10 +112,10 @@ class _AnimatedGapState extends State<AnimatedGap> with SingleTickerProviderStat
class AnimatedSliverGap extends StatefulWidget { class AnimatedSliverGap extends StatefulWidget {
const AnimatedSliverGap( const AnimatedSliverGap(
this.gap, { this.gap, {
Key? key,
this.duration = const Duration(milliseconds: 200), this.duration = const Duration(milliseconds: 200),
this.curve = Curves.easeInOut, this.curve = Curves.easeInOut,
}) : super(key: key); super.key,
});
final Duration duration; final Duration duration;
final double gap; final double gap;

View file

@ -8,10 +8,13 @@ class MultiValueListenableBuilder extends StatelessWidget {
required this.builder, required this.builder,
this.child, this.child,
super.key, super.key,
}) : assert(valueListenables.length != 0); }) : assert(
valueListenables.length != 0,
'Attached valueListenables must not be empty',
);
/// List of [ValueListenable]s to be listened to. /// List of [ValueListenable]s to be listened to.
final List<ValueListenable> valueListenables; final List<ValueListenable<dynamic>> valueListenables;
/// The builder function to be called when value of any of the [ValueListenable] changes. /// The builder function to be called when value of any of the [ValueListenable] changes.
/// The order of values list will be same as [valueListenables] list. /// The order of values list will be same as [valueListenables] list.

View file

@ -9,16 +9,19 @@ import '../abstracts/images_api.dart';
import '../data/dtos/image_model_dto.dart'; import '../data/dtos/image_model_dto.dart';
class UnsplashImagesApi extends ImagesApi { class UnsplashImagesApi extends ImagesApi {
UnsplashImagesApi({required super.token});
//final LoggingService _loggingService = LoggingService.locate; //final LoggingService _loggingService = LoggingService.locate;
final random = Random(); final random = Random();
UnsplashImagesApi({required super.token});
@override @override
FutureOr<Iterable<ImageModelDTO>> fetchImageUri() async { FutureOr<Iterable<ImageModelDTO>> fetchImageUri() async {
// Dummy fetching delay emulation // Dummy fetching delay emulation
await Future.delayed(const Duration( await Future<void>.delayed(
milliseconds: ConstValues.defaultEmulatedLatencyMillis * ConstValues.numberOfImages)); const Duration(
milliseconds: ConstValues.defaultEmulatedLatencyMillis * ConstValues.numberOfImages,
),
);
final Iterable<Map<String, dynamic>> fetchedImageModelDtos; final Iterable<Map<String, dynamic>> fetchedImageModelDtos;
try { try {
@ -48,8 +51,7 @@ class UnsplashImagesApi extends ImagesApi {
} }
// Emulating deserialization // Emulating deserialization
return fetchedImageModelDtos return fetchedImageModelDtos.map(ImageModelDTO.fromJson);
.map((final emulatedModelSerialized) => ImageModelDTO.fromJson(emulatedModelSerialized));
} }
@override @override
@ -59,8 +61,11 @@ class UnsplashImagesApi extends ImagesApi {
final numberOfResults = random.nextIntInRange(min: 0, max: ConstValues.numberOfImages); final numberOfResults = random.nextIntInRange(min: 0, max: ConstValues.numberOfImages);
// Dummy fetching delay emulation // Dummy fetching delay emulation
await Future.delayed( await Future<void>.delayed(
Duration(milliseconds: ConstValues.defaultEmulatedLatencyMillis * numberOfResults)); Duration(
milliseconds: ConstValues.defaultEmulatedLatencyMillis * numberOfResults,
),
);
final Iterable<Map<String, dynamic>> searchImageModelDtos; final Iterable<Map<String, dynamic>> searchImageModelDtos;
try { try {
@ -87,8 +92,7 @@ class UnsplashImagesApi extends ImagesApi {
return List.empty(); return List.empty();
} }
return searchImageModelDtos return searchImageModelDtos.map(ImageModelDTO.fromJson);
.map((final emulatedModelSerialized) => ImageModelDTO.fromJson(emulatedModelSerialized));
} }
Uri _imageUrlGenerator({required int imageSide}) => Uri( Uri _imageUrlGenerator({required int imageSide}) => Uri(

View file

@ -2,12 +2,22 @@ import '../dtos/image_model_dto.dart';
/// Represents an Image, that would be displayed in the gallery. /// Represents an Image, that would be displayed in the gallery.
class ImageModel { class ImageModel {
const ImageModel({ const ImageModel._({
required this.uri, required this.uri,
required this.imageIndex, required this.imageIndex,
required this.imageName, required this.imageName,
required this.isFavourite, required this.isFavourite,
}); });
factory ImageModel.fromDto({
required ImageModelDTO imageModelDto,
required bool isFavourite,
}) =>
ImageModel._(
uri: imageModelDto.uri,
imageIndex: imageModelDto.imageIndex,
imageName: imageModelDto.imageName,
isFavourite: isFavourite,
);
/// An image's target [Uri]. /// An image's target [Uri].
/// ///
@ -23,24 +33,13 @@ class ImageModel {
/// Whether the image was 'Starred' ot not. /// Whether the image was 'Starred' ot not.
final bool isFavourite; final bool isFavourite;
factory ImageModel.fromDto({
required ImageModelDTO imageModelDto,
required bool isFavourite,
}) =>
ImageModel(
uri: imageModelDto.uri,
imageIndex: imageModelDto.imageIndex,
imageName: imageModelDto.imageName,
isFavourite: isFavourite,
);
ImageModel copyWith({ ImageModel copyWith({
Uri? uri, Uri? uri,
int? imageIndex, int? imageIndex,
String? imageName, String? imageName,
bool? isFavourite, bool? isFavourite,
}) { }) {
return ImageModel( return ImageModel._(
uri: uri ?? this.uri, uri: uri ?? this.uri,
imageIndex: imageIndex ?? this.imageIndex, imageIndex: imageIndex ?? this.imageIndex,
imageName: imageName ?? this.imageName, imageName: imageName ?? this.imageName,

View file

@ -22,7 +22,7 @@ class ImageCacheManagerService {
final LoggingService _loggingService = LoggingService.locate; final LoggingService _loggingService = LoggingService.locate;
final _cacheManager = DefaultCacheManager(); final _cacheManager = DefaultCacheManager();
Future<void> emptyCache() async => await _cacheManager.emptyCache(); void emptyCache() => _cacheManager.emptyCache();
Future<void> _init() async { Future<void> _init() async {
_appLifecycleService.addListener( _appLifecycleService.addListener(

View file

@ -150,8 +150,8 @@ class _SearchBox extends StatelessWidget {
items: [ items: [
for (final searchOption in SearchOption.values) for (final searchOption in SearchOption.values)
DropdownMenuItem( DropdownMenuItem(
child: Center(child: Text(searchOption.name)),
value: searchOption, value: searchOption,
child: Center(child: Text(searchOption.name)),
), ),
], ],
value: searchOption, value: searchOption,

View file

@ -42,7 +42,7 @@ class GalleryViewModel extends BaseViewModel {
ValueListenable<bool> get isViewingFavouriteListenable => _isViewingFavouriteNotifier; ValueListenable<bool> get isViewingFavouriteListenable => _isViewingFavouriteNotifier;
@override @override
Future<void> initialise(bool Function() mounted, [arguments]) async { Future<void> initialise(bool Function() mounted, [Object? arguments]) async {
super.initialise(mounted, arguments); super.initialise(mounted, arguments);
} }

View file

@ -40,7 +40,7 @@ class ImageCarouselView extends StatelessWidget {
children: [ children: [
Expanded( Expanded(
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8),
child: Card( child: Card(
elevation: 8, elevation: 8,
surfaceTintColor: ConstColours.transparent, surfaceTintColor: ConstColours.transparent,
@ -110,7 +110,7 @@ class ImageCarouselView extends StatelessWidget {
), ),
), ),
), ),
const Gap(24), Gap.size24,
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 24), padding: const EdgeInsets.symmetric(horizontal: 24),
// Assuming that this data is coming from an external CRM, if it is coming with the // Assuming that this data is coming from an external CRM, if it is coming with the

View file

@ -21,9 +21,11 @@ class ImageCarouselViewModel extends BaseViewModel {
final CarouselController carouselController = CarouselController(); final CarouselController carouselController = CarouselController();
@override @override
Future<void> initialise(bool Function() mounted, [arguments]) async { Future<void> initialise(bool Function() mounted, [Object? arguments]) async {
_currentImageModelNotifier = ValueNotifier(_imagesService.imageModels _currentImageModelNotifier = ValueNotifier(
.elementAt((arguments as ImageCarouselViewArguments).imageIndexKey)); _imagesService.imageModels
.elementAt((arguments! as ImageCarouselViewArguments).imageIndexKey),
);
log.info('Initialized with image: ${_currentImageModelNotifier.value.imageIndex}'); log.info('Initialized with image: ${_currentImageModelNotifier.value.imageIndex}');
super.initialise(mounted, arguments); super.initialise(mounted, arguments);

View file

@ -58,61 +58,59 @@ class Locator {
} }
static FutureOr<void> _registerServices(GetIt it) async { static FutureOr<void> _registerServices(GetIt it) async {
it.registerLazySingleton( it
() => NavigationService( ..registerLazySingleton(
mcgRouter: McgRouter.locate, () => NavigationService(
), mcgRouter: McgRouter.locate,
); ),
)
it.registerFactory( ..registerFactory(
() => LoggingService(), LoggingService.new,
); )
..registerSingleton<ConnectionsService>(
it.registerSingleton<ConnectionsService>( ConnectionsService(
ConnectionsService( connectivity: Connectivity(),
connectivity: Connectivity(), internetConnectionChecker: InternetConnectionChecker(),
internetConnectionChecker: InternetConnectionChecker(), loggingService: LoggingService.locate,
loggingService: LoggingService.locate, ),
), signalsReady: true,
signalsReady: true, dispose: (final param) async => param.dispose(),
dispose: (final param) async => await param.dispose(), );
);
await it.isReady<ConnectionsService>(); await it.isReady<ConnectionsService>();
it.registerLazySingleton( it
() => OverlayService( ..registerLazySingleton(
loggingService: LoggingService.locate, () => OverlayService(
), loggingService: LoggingService.locate,
dispose: (param) => param.dispose(), ),
); dispose: (param) => param.dispose(),
)
it.registerSingleton<AppLifecycleService>( ..registerSingleton<AppLifecycleService>(
AppLifecycleService( AppLifecycleService(
loggingService: LoggingService.locate, loggingService: LoggingService.locate,
), ),
dispose: (final param) async => await param.dispose(), dispose: (final param) async => param.dispose(),
); )
..registerSingleton<LocalStorageService>(
it.registerSingleton<LocalStorageService>( LocalStorageService(),
LocalStorageService(), signalsReady: true,
signalsReady: true, );
);
await it.isReady<LocalStorageService>(); await it.isReady<LocalStorageService>();
it.registerSingleton<ImagesService>( it
ImagesService( ..registerSingleton<ImagesService>(
imagesApi: UnsplashImagesApi.locate, ImagesService(
localStorageService: LocalStorageService.locate, imagesApi: UnsplashImagesApi.locate,
loggingService: LoggingService.locate, localStorageService: LocalStorageService.locate,
), loggingService: LoggingService.locate,
); ),
)
it.registerSingleton( ..registerSingleton(
ImageCacheManagerService( ImageCacheManagerService(
appLifecycleService: AppLifecycleService.locate, appLifecycleService: AppLifecycleService.locate,
localStorageService: LocalStorageService.locate, localStorageService: LocalStorageService.locate,
), ),
); );
} }
static FutureOr<void> _registerRepos(GetIt locator) {} static FutureOr<void> _registerRepos(GetIt locator) {}

View file

@ -437,7 +437,7 @@ packages:
source: hosted source: hosted
version: "0.6.4" version: "0.6.4"
json_annotation: json_annotation:
dependency: "direct dev" dependency: "direct main"
description: description:
name: json_annotation name: json_annotation
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
@ -833,6 +833,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.2" version: "2.1.2"
very_good_analysis:
dependency: "direct dev"
description:
name: very_good_analysis
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:

View file

@ -36,6 +36,7 @@ dependencies:
intl_utils: ^2.8.1 intl_utils: ^2.8.1
connectivity_plus: ^3.0.2 connectivity_plus: ^3.0.2
internet_connection_checker: ^1.0.0+1 internet_connection_checker: ^1.0.0+1
json_annotation: ^4.7.0
string_similarity: ^2.0.0 string_similarity: ^2.0.0
# Util frontend # Util frontend
@ -63,8 +64,8 @@ dev_dependencies:
hive_generator: ^2.0.0 hive_generator: ^2.0.0
envied_generator: ^0.3.0 envied_generator: ^0.3.0
# Annotations # Linters
json_annotation: ^4.7.0 very_good_analysis: ^3.1.0
flutter: flutter:
uses-material-design: true uses-material-design: true