refactoring
security update
This commit is contained in:
parent
1747ab0245
commit
78fe9e7b09
39 changed files with 289 additions and 132 deletions
|
@ -1,4 +1,5 @@
|
|||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -49,5 +50,11 @@ abstract class AppSetup {
|
|||
static void Function(Object error, StackTrace stackTrace) get onUncaughtException => (
|
||||
error,
|
||||
stackTrace,
|
||||
) {};
|
||||
) {
|
||||
log(
|
||||
'Error occurred during app startup',
|
||||
error: error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ abstract class BaseViewModel<T extends Object?> extends ChangeNotifier {
|
|||
final ValueNotifier<ViewModelState> _state = ValueNotifier(ViewModelState.isInitialising);
|
||||
ValueListenable<ViewModelState> get state => _state;
|
||||
|
||||
final LoggingService _loggingService = LoggingService.locate;
|
||||
final LoggingService log = LoggingService.locate;
|
||||
|
||||
String? _errorMessage;
|
||||
String get errorMessage => _errorMessage ?? strings.somethingWentWrong;
|
||||
|
@ -27,7 +27,7 @@ abstract class BaseViewModel<T extends Object?> extends ChangeNotifier {
|
|||
_mounted = mounted;
|
||||
_isInitialised.value = true;
|
||||
_state.value = ViewModelState.isInitialised;
|
||||
_loggingService.successfulInit(location: runtimeType.toString());
|
||||
log.successfulInit(location: runtimeType.toString());
|
||||
}
|
||||
|
||||
void setBusy(bool isBusy) {
|
||||
|
@ -55,7 +55,7 @@ abstract class BaseViewModel<T extends Object?> extends ChangeNotifier {
|
|||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_loggingService.successfulDispose(location: runtimeType.toString());
|
||||
log.successfulDispose(location: runtimeType.toString());
|
||||
}
|
||||
|
||||
late final bool Function() _mounted;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mc_gallery/features/home/views/gallery/gallery_view.dart';
|
||||
import 'package:mc_gallery/features/home/views/image_carousel/image_carousel_view.dart';
|
||||
|
||||
import '/features/home/views/gallery/gallery_view.dart';
|
||||
import '/features/home/views/image_carousel/image_carousel_view.dart';
|
||||
import '../../views/error_page_view.dart';
|
||||
import 'routes.dart';
|
||||
|
||||
|
@ -15,7 +15,6 @@ class McgRouter {
|
|||
key: state.pageKey,
|
||||
child: ErrorPageView(error: state.error),
|
||||
),
|
||||
//todo(mehul): Add Redirect
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: Routes.home.routePath,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
enum Routes {
|
||||
home(RoutesInfo(
|
||||
routePath: '/gallery',
|
||||
routePath: '/',
|
||||
routeName: 'Home',
|
||||
)),
|
||||
imageCarousel(RoutesInfo(
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||
abstract class ConstColours {
|
||||
/// Smoke Gray => a neutral grey with neutral warmth/cold
|
||||
static const galleryBackgroundColour = Color.fromRGBO(127, 127, 125, 1.0);
|
||||
static const red = Colors.red;
|
||||
|
||||
static const white = Colors.white;
|
||||
static const black = Colors.black;
|
||||
|
|
|
@ -3,7 +3,7 @@ abstract class ConstValues {
|
|||
static const String backendHost = 'source.unsplash.com';
|
||||
static const List<String> backendUrlPathSegments = ['user', 'c_v_r'];
|
||||
|
||||
static const int numberOfImages = 20;
|
||||
static const int numberOfImages = 25;
|
||||
static const int minImageSize = 50;
|
||||
static const int maxImageSize = 100;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ extension MapExtensions<A, B> on Map<A, B> {
|
|||
}
|
||||
|
||||
extension LinkedHashMapExtensions<A, B> on LinkedHashMap<A, B> {
|
||||
/// Updated the value at [valueIndex] to [newValue], in addition to preserving the order.
|
||||
/// Updates the value at [valueIndex] to [newValue], in addition to preserving the order.
|
||||
void updateValueAt({
|
||||
required int valueIndex,
|
||||
required B newValue,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
extension ValueNotifierBoolExtensions on ValueNotifier<bool> {
|
||||
void flipValue() => value = !value;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mc_gallery/locator.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import '/locator.dart';
|
||||
import 'logging_service.dart';
|
||||
|
||||
typedef AddLifeCycleListener = void Function({
|
||||
|
@ -23,7 +23,8 @@ class AppLifecycleService with WidgetsBindingObserver {
|
|||
|
||||
final LoggingService _loggingService;
|
||||
|
||||
late final StreamController<AppLifecycleState> _streamController = StreamController.broadcast();
|
||||
late final StreamController<AppLifecycleState> _lifecycleStateStreamController =
|
||||
StreamController.broadcast();
|
||||
final Map<String, StreamSubscription> _appLifecycleSubscriptions = {};
|
||||
|
||||
AppLifecycleState? _appLifeCycleState;
|
||||
|
@ -43,14 +44,15 @@ class AppLifecycleService with WidgetsBindingObserver {
|
|||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
try {
|
||||
_appLifeCycleState = state;
|
||||
_streamController.add(state);
|
||||
_lifecycleStateStreamController.add(state);
|
||||
} catch (error, stackTrace) {
|
||||
_loggingService.error(
|
||||
'Something went wrong logging ${state.name} inside the didChangeAppLifeCycleState method',
|
||||
'Something went wrong with ${state.name} inside the didChangeAppLifeCycleState method',
|
||||
error,
|
||||
stackTrace,
|
||||
);
|
||||
}
|
||||
|
||||
super.didChangeAppLifecycleState(state);
|
||||
}
|
||||
|
||||
|
@ -61,17 +63,17 @@ class AppLifecycleService with WidgetsBindingObserver {
|
|||
}) {
|
||||
try {
|
||||
if (_appLifecycleSubscriptions.containsKey(tag)) {
|
||||
_loggingService.warning('Tag already active, returning!');
|
||||
_loggingService.warning('Tag already active, returning');
|
||||
} else {
|
||||
final message = 'Adding $tag appLifecycleState listener';
|
||||
_loggingService.info('$message..');
|
||||
if (_appLifeCycleState != null && tryCallListenerOnAdd) listener(_appLifeCycleState!);
|
||||
_appLifecycleSubscriptions[tag] = _streamController.stream.listen(listener);
|
||||
_appLifecycleSubscriptions[tag] = _lifecycleStateStreamController.stream.listen(listener);
|
||||
_loggingService.good('$message success!');
|
||||
}
|
||||
} catch (error, stackTrace) {
|
||||
_loggingService.error(
|
||||
'Something went wrong adding $tag appLifecycleState listener!',
|
||||
'Something went wrong adding $tag appLifecycleState listener',
|
||||
error,
|
||||
stackTrace,
|
||||
);
|
||||
|
@ -88,11 +90,11 @@ class AppLifecycleService with WidgetsBindingObserver {
|
|||
_appLifecycleSubscriptions.remove(tag);
|
||||
_loggingService.good('$message success!');
|
||||
} else {
|
||||
_loggingService.warning('Subscription was not found!');
|
||||
_loggingService.warning('Subscription was not found');
|
||||
}
|
||||
} catch (error, stackTrace) {
|
||||
_loggingService.error(
|
||||
'Something went wrong removing $tag appLifecycleState listener!',
|
||||
'Something went wrong removing $tag appLifecycleState listener',
|
||||
error,
|
||||
stackTrace,
|
||||
);
|
||||
|
|
|
@ -4,10 +4,10 @@ import 'package:connectivity_plus/connectivity_plus.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:internet_connection_checker/internet_connection_checker.dart';
|
||||
|
||||
import '/features/core/services/logging_service.dart';
|
||||
import '/locator.dart';
|
||||
import 'logging_service.dart';
|
||||
|
||||
/// Used to observe the current connection type.
|
||||
/// Used to observe the current connection type and status.
|
||||
class ConnectionsService {
|
||||
ConnectionsService({
|
||||
required Connectivity connectivity,
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import 'package:hive/hive.dart';
|
||||
import 'package:mc_gallery/features/core/services/logging_service.dart';
|
||||
import 'package:mc_gallery/locator.dart';
|
||||
|
||||
import '/locator.dart';
|
||||
import 'logging_service.dart';
|
||||
|
||||
/// Handles storing state data locally, onto the device itself
|
||||
class LocalStorageService {
|
||||
LocalStorageService() {
|
||||
_init();
|
||||
|
@ -9,10 +11,10 @@ class LocalStorageService {
|
|||
|
||||
final LoggingService _loggingService = LoggingService.locate;
|
||||
|
||||
static const String _userBoxKey = 'userBoxKey';
|
||||
|
||||
late final Box<bool> _userBox;
|
||||
|
||||
static const String _userBoxKey = 'userBoxKey';
|
||||
|
||||
Future<void> _init() async {
|
||||
_userBox = await Hive.openBox(_userBoxKey);
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:talker_dio_logger/talker_dio_logger_settings.dart';
|
|||
|
||||
import '/locator.dart';
|
||||
|
||||
/// Handles logging of events.
|
||||
class LoggingService {
|
||||
final Talker _talker = Talker(
|
||||
settings: TalkerSettings(
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mc_gallery/features/home/views/image_carousel/image_carousel_view.dart';
|
||||
import 'package:mc_gallery/locator.dart';
|
||||
|
||||
import '/features/home/views/image_carousel/image_carousel_view.dart';
|
||||
import '/locator.dart';
|
||||
import '../abstracts/router/app_router.dart';
|
||||
import '../abstracts/router/routes.dart';
|
||||
|
||||
/// Handles the navigation to and fro all the screens in the app.
|
||||
class NavigationService {
|
||||
const NavigationService({
|
||||
required McgRouter mcgRouter,
|
||||
|
@ -22,10 +23,5 @@ class NavigationService {
|
|||
extra: imageCarouselViewArguments,
|
||||
);
|
||||
|
||||
void backToGallery(BuildContext context) => context.pop();
|
||||
|
||||
void previous() {}
|
||||
void next() {}
|
||||
|
||||
static NavigationService get locate => Locator.locate();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
import 'package:mc_gallery/features/core/services/logging_service.dart';
|
||||
import 'package:mc_gallery/locator.dart';
|
||||
|
||||
import '/locator.dart';
|
||||
import 'logging_service.dart';
|
||||
|
||||
class OverlayService {
|
||||
OverlayService({
|
||||
|
|
|
@ -20,6 +20,7 @@ class Mutex {
|
|||
return value;
|
||||
}
|
||||
|
||||
/// Allows listening to the completion status of the last worker process to be released.
|
||||
Future<void> get lastOperationCompletionAwaiter =>
|
||||
_completerQueue.isNotEmpty ? _completerQueue.last.future : Future.value();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import '/l10n/generated/l10n.dart';
|
||||
import '../widgets/gap.dart';
|
||||
|
||||
class ErrorPageView extends StatelessWidget {
|
||||
|
@ -15,9 +16,8 @@ class ErrorPageView extends StatelessWidget {
|
|||
return Center(
|
||||
child: Column(
|
||||
children: [
|
||||
const Text('Oopsie, there has been an error. Hang tight till we do something about it.'),
|
||||
Text(Strings.current.errorPageMessage),
|
||||
const Gap(16),
|
||||
Text('what happened: $error'),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
59
lib/features/core/widgets/animated_column.dart
Normal file
59
lib/features/core/widgets/animated_column.dart
Normal file
|
@ -0,0 +1,59 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import '/features/core/data/constants/const_durations.dart';
|
||||
|
||||
/// [AnimatedColumn] Animates its children when they get added or removed at the end
|
||||
class AnimatedColumn extends StatelessWidget {
|
||||
const AnimatedColumn({
|
||||
required this.children,
|
||||
this.duration = ConstDurations.oneAndHalfDefaultAnimationDuration,
|
||||
this.mainAxisAlignment = MainAxisAlignment.start,
|
||||
this.mainAxisSize = MainAxisSize.max,
|
||||
this.crossAxisAlignment = CrossAxisAlignment.center,
|
||||
this.textDirection,
|
||||
this.verticalDirection = VerticalDirection.down,
|
||||
this.textBaseline,
|
||||
this.maxAnimatingChildren = 2,
|
||||
super.key,
|
||||
});
|
||||
|
||||
/// [duration] specifies the duration of the add/remove animation
|
||||
final Duration duration;
|
||||
|
||||
/// [maxAnimatingChildren] determines the maximum number of chidren that can
|
||||
/// be animating at once, if more are removed or added at within an animation
|
||||
/// duration they will pop in instead
|
||||
final int maxAnimatingChildren;
|
||||
|
||||
final MainAxisAlignment mainAxisAlignment;
|
||||
final MainAxisSize mainAxisSize;
|
||||
final CrossAxisAlignment crossAxisAlignment;
|
||||
final TextDirection? textDirection;
|
||||
final VerticalDirection verticalDirection;
|
||||
final TextBaseline? textBaseline;
|
||||
final List<Widget> children;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: crossAxisAlignment,
|
||||
children: [
|
||||
for (int i = 0; i < children.length + maxAnimatingChildren; i++)
|
||||
AnimatedSwitcher(
|
||||
duration: duration,
|
||||
switchInCurve: Curves.easeInOut,
|
||||
switchOutCurve: Curves.easeInOut,
|
||||
transitionBuilder: (child, animation) => FadeTransition(
|
||||
opacity: animation,
|
||||
child: SizeTransition(
|
||||
sizeFactor: animation,
|
||||
axisAlignment: -1,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
child: i < children.length ? children[i] : const SizedBox.shrink(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue