Compare commits
10 Commits
31981fb19e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
660cc17f56 | ||
|
|
5feda3a909 | ||
|
|
45b40d9bbd | ||
|
|
739de72051 | ||
|
|
1fa8207b01 | ||
|
|
c60f045967 | ||
|
|
140ba9374e | ||
|
|
8dcfa57122 | ||
|
|
22b06b800a | ||
|
|
d7ec54d8ca |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -29,3 +29,4 @@ migrate_working_dir/
|
|||||||
.flutter-plugins-dependencies
|
.flutter-plugins-dependencies
|
||||||
/build/
|
/build/
|
||||||
/coverage/
|
/coverage/
|
||||||
|
example/build
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:mtcore/markettakers.dart';
|
|
||||||
|
|
||||||
class SimpleStage extends StageFactory {
|
|
||||||
@override
|
|
||||||
final String title = "Test";
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<bool> get isAlreadyCompleted async {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> start(StageController controller) async {
|
|
||||||
await Future.delayed(Duration(seconds: 2));
|
|
||||||
controller.setDefiniteProgress(0.3);
|
|
||||||
controller.updateTitle("test 2");
|
|
||||||
|
|
||||||
await Future.delayed(Duration(seconds: 2));
|
|
||||||
controller.setDefiniteProgress(0.6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SimpleStage2 extends StageFactory {
|
|
||||||
@override
|
|
||||||
final String title = "Test 2";
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<bool> get isAlreadyCompleted async {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> start(StageController controller) async {
|
|
||||||
await Future.delayed(Duration(seconds: 2));
|
|
||||||
controller.setDefiniteProgress(0.3);
|
|
||||||
controller.updateTitle("test 5");
|
|
||||||
|
|
||||||
await Future.delayed(Duration(seconds: 2));
|
|
||||||
controller.setDefiniteProgress(0.6);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() async {
|
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
|
||||||
init();
|
|
||||||
final completer = Completer<void>();
|
|
||||||
completer.future.then((_) {
|
|
||||||
talker.info("Bootstrapper completed, launching app");
|
|
||||||
});
|
|
||||||
runApp(
|
|
||||||
Scaffold(
|
|
||||||
body: Bootstrapper(
|
|
||||||
stages: [SimpleStage(), SimpleStage2()],
|
|
||||||
onCompleted: completer,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:rive_native/rive_native.dart';
|
|
||||||
import 'package:talker_flutter/talker_flutter.dart';
|
import 'package:talker_flutter/talker_flutter.dart';
|
||||||
|
|
||||||
export 'package:mtcore/src/bootstrapper.dart'
|
export 'package:mtcore/src/bootstrapper.dart'
|
||||||
@@ -20,6 +19,4 @@ final ThemeData commonTheme = ThemeData(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {}
|
||||||
await RiveNative.init();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mtcore/markettakers.dart';
|
import 'package:mtcore/markettakers.dart';
|
||||||
import 'package:mtcore/src/credits.dart';
|
|
||||||
import 'package:mtcore/src/loader.dart';
|
|
||||||
import 'package:talker_flutter/talker_flutter.dart';
|
import 'package:talker_flutter/talker_flutter.dart';
|
||||||
|
|
||||||
class AboutScreen extends StatelessWidget {
|
class AboutScreen extends StatelessWidget {
|
||||||
@@ -40,7 +38,7 @@ class AboutScreen extends StatelessWidget {
|
|||||||
Credits(),
|
Credits(),
|
||||||
|
|
||||||
Footer(children: children),
|
Footer(children: children),
|
||||||
const Text("MarketTakers (c) 2025"),
|
const Text("MarketTakers (c) 2026"),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,24 +1,34 @@
|
|||||||
// ignore_for_file: annotate_overrides
|
// ignore_for_file: annotate_overrides
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'dart:ui';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
import 'package:mtcore/markettakers.dart';
|
|
||||||
import 'package:mtcore/src/loader.dart';
|
|
||||||
import 'package:percent_indicator/circular_percent_indicator.dart';
|
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:mtcore/markettakers.dart';
|
||||||
|
import 'package:percent_indicator/circular_percent_indicator.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'bootstrapper.g.dart';
|
||||||
part 'bootstrapper.freezed.dart';
|
part 'bootstrapper.freezed.dart';
|
||||||
|
|
||||||
|
/// A single bootstrap stage.
|
||||||
|
/// Implementations should report progress/title updates via [StageController].
|
||||||
abstract class StageFactory {
|
abstract class StageFactory {
|
||||||
String get title;
|
String get title;
|
||||||
|
|
||||||
|
/// Optional: if your stage can be skipped when already completed.
|
||||||
Future<bool> get isAlreadyCompleted async => false;
|
Future<bool> get isAlreadyCompleted async => false;
|
||||||
|
|
||||||
Future<void> start(StageController controller);
|
Future<void> start(StageController controller);
|
||||||
|
|
||||||
void dispose() {}
|
void dispose() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Bootstrap progress: either definite (0..1) or indefinite.
|
||||||
@freezed
|
@freezed
|
||||||
sealed class Progress with _$Progress {
|
sealed class Progress with _$Progress {
|
||||||
const factory Progress.definite(double value) = PercentageProgress;
|
const factory Progress.definite(double value) = PercentageProgress;
|
||||||
@@ -27,186 +37,277 @@ sealed class Progress with _$Progress {
|
|||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
class StageState with _$StageState {
|
class StageState with _$StageState {
|
||||||
final String title;
|
String title;
|
||||||
final Progress progress;
|
Progress progress;
|
||||||
|
|
||||||
StageState({required this.title, required this.progress});
|
StageState({required this.title, required this.progress});
|
||||||
}
|
}
|
||||||
|
|
||||||
class StageController extends Cubit<StageState> {
|
typedef Stages = List<StageFactory>;
|
||||||
StageController({required String title})
|
|
||||||
: super(StageState(title: title, progress: const Progress.indefinite()));
|
@riverpod
|
||||||
|
class CurrentStage extends _$CurrentStage {
|
||||||
|
@override
|
||||||
|
StageState? build() => null;
|
||||||
|
|
||||||
|
void set(StageState newState) => state = newState;
|
||||||
|
|
||||||
|
void setProgress(Progress progress) {
|
||||||
|
final s = state;
|
||||||
|
if (s == null) return;
|
||||||
|
state = s.copyWith(progress: progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTitle(String title) {
|
||||||
|
final s = state;
|
||||||
|
if (s == null) return;
|
||||||
|
state = s.copyWith(title: title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StageController {
|
||||||
|
final Ref _ref;
|
||||||
|
StageController(this._ref);
|
||||||
|
|
||||||
void setDefiniteProgress(double value) {
|
void setDefiniteProgress(double value) {
|
||||||
emit(state.copyWith(progress: Progress.definite(value)));
|
if (!_ref.mounted) return;
|
||||||
|
_ref
|
||||||
|
.read(currentStageProvider.notifier)
|
||||||
|
.setProgress(Progress.definite(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setIndefiniteProgress() {
|
void setIndefiniteProgress() {
|
||||||
emit(state.copyWith(progress: const Progress.indefinite()));
|
if (!_ref.mounted) return;
|
||||||
|
_ref
|
||||||
|
.read(currentStageProvider.notifier)
|
||||||
|
.setProgress(const Progress.indefinite());
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateTitle(String title) {
|
void updateTitle(String title) {
|
||||||
emit(state.copyWith(title: title));
|
if (!_ref.mounted) return;
|
||||||
|
_ref.read(currentStageProvider.notifier).setTitle(title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef Stages = List<StageFactory>;
|
@riverpod
|
||||||
|
class StagesWorker extends _$StagesWorker {
|
||||||
|
bool _hasStarted = false;
|
||||||
|
|
||||||
@freezed
|
@override
|
||||||
class BootstrapState with _$BootstrapState {
|
Future<bool> build() async => false;
|
||||||
final Stages stages;
|
|
||||||
final int currentStageIndex;
|
|
||||||
final StageController? controller;
|
|
||||||
|
|
||||||
StageFactory get currentStage => stages[currentStageIndex];
|
Future<void> start(Stages stages) async {
|
||||||
bool get areStagesCompleted => currentStageIndex >= stages.length;
|
if (_hasStarted) return;
|
||||||
|
_hasStarted = true;
|
||||||
|
|
||||||
BootstrapState(this.stages, {this.currentStageIndex = 0, this.controller});
|
state = const AsyncValue.loading();
|
||||||
}
|
state = await AsyncValue.guard(() async {
|
||||||
|
for (final stage in stages) {
|
||||||
|
talker.info("${stage.title} starting");
|
||||||
|
|
||||||
@freezed
|
// Optional skip.
|
||||||
sealed class _BootstrapEvent with _$BootstrapEvent {
|
final alreadyDone = await stage.isAlreadyCompleted;
|
||||||
const factory _BootstrapEvent.start() = StartEvent;
|
if (alreadyDone) {
|
||||||
const factory _BootstrapEvent.stageCompleted() = StageCompletedEvent;
|
talker.info("${stage.title} skipped (already completed)");
|
||||||
}
|
continue;
|
||||||
|
|
||||||
class _BootstrapController extends Bloc<_BootstrapEvent, BootstrapState> {
|
|
||||||
final Completer<void> completer;
|
|
||||||
_BootstrapController(super.initialState, this.completer) {
|
|
||||||
assert(state.stages.isNotEmpty, "Stages list cannot be empty");
|
|
||||||
|
|
||||||
on<StartEvent>((event, emit) async {
|
|
||||||
talker.info("BootstrapController: Starting bootstrap process");
|
|
||||||
|
|
||||||
if (await state.currentStage.isAlreadyCompleted) {
|
|
||||||
add(const _BootstrapEvent.stageCompleted());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final controller = launchCurrentStage(
|
ref
|
||||||
state.stages,
|
.read(currentStageProvider.notifier)
|
||||||
state.currentStageIndex,
|
.set(
|
||||||
|
StageState(
|
||||||
|
title: stage.title,
|
||||||
|
progress: const Progress.indefinite(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
emit(state.copyWith(controller: controller));
|
|
||||||
});
|
|
||||||
on<StageCompletedEvent>((event, emit) async {
|
|
||||||
talker.info("BootstrapController: ${state.currentStage.title} completed");
|
|
||||||
state.currentStage.dispose();
|
|
||||||
|
|
||||||
final nextIndex = state.currentStageIndex + 1;
|
await stage.start(StageController(ref));
|
||||||
final newState = state.copyWith(currentStageIndex: nextIndex);
|
talker.info("${stage.title} completed");
|
||||||
|
|
||||||
// all stages completed
|
|
||||||
if (newState.areStagesCompleted) {
|
|
||||||
talker.info("BootstrapController: All stages completed");
|
|
||||||
completer.complete();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
// skip already completed stages
|
|
||||||
if (await newState.currentStage.isAlreadyCompleted) {
|
|
||||||
talker.info(
|
|
||||||
"BootstrapController: Stage ${newState.currentStage.title} already completed, skipping",
|
|
||||||
);
|
|
||||||
emit(newState);
|
|
||||||
add(const _BootstrapEvent.stageCompleted());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// move to next stage
|
|
||||||
final nextStage = newState.currentStage;
|
|
||||||
talker.info("BootstrapController: Starting stage ${nextStage.title}");
|
|
||||||
launchCurrentStage(state.stages, nextIndex);
|
|
||||||
emit(newState);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
StageController launchCurrentStage(Stages stages, int index) {
|
|
||||||
final currentStage = stages[index];
|
|
||||||
final controller = StageController(title: currentStage.title);
|
|
||||||
|
|
||||||
currentStage
|
|
||||||
.start(controller)
|
|
||||||
.then((_) {
|
|
||||||
add(_BootstrapEvent.stageCompleted());
|
|
||||||
})
|
|
||||||
.catchError((error) {
|
|
||||||
talker.handle(
|
|
||||||
error,
|
|
||||||
null,
|
|
||||||
"BootstrapController: Error in ${currentStage.title}",
|
|
||||||
);
|
|
||||||
addError(error);
|
|
||||||
});
|
|
||||||
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DefiniteIndicator extends StatelessWidget {
|
class _DefiniteIndicator extends StatelessWidget {
|
||||||
final double progress; // 0.0 to 1.0
|
final double progress; // 0.0 to 1.0
|
||||||
|
|
||||||
const _DefiniteIndicator({required this.progress});
|
const _DefiniteIndicator({required this.progress});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final formattedProgress = "${(progress * 100).toStringAsFixed(0)}%";
|
// Make it adaptive and square to prevent overflow in flexible layouts.
|
||||||
return CircularPercentIndicator(
|
return AspectRatio(
|
||||||
radius: 40.0,
|
aspectRatio: 1,
|
||||||
lineWidth: 5.0,
|
child: LayoutBuilder(
|
||||||
percent: progress.clamp(0.0, 1.0),
|
builder: (context, c) {
|
||||||
center: Text(formattedProgress),
|
final side = c.maxWidth.isFinite ? c.maxWidth : 120.0;
|
||||||
|
final radius = side * 0.42; // padding around ring
|
||||||
|
final stroke = (side * 0.08).clamp(4.0, 10.0);
|
||||||
|
|
||||||
|
final value = progress.clamp(0.0, 1.0);
|
||||||
|
final formattedProgress = "${(value * 100).toStringAsFixed(0)}%";
|
||||||
|
|
||||||
|
return Center(
|
||||||
|
child: CircularPercentIndicator(
|
||||||
|
radius: radius,
|
||||||
|
lineWidth: stroke,
|
||||||
|
percent: value,
|
||||||
|
center: Text(
|
||||||
|
formattedProgress,
|
||||||
|
style: Theme.of(
|
||||||
|
context,
|
||||||
|
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700),
|
||||||
|
),
|
||||||
|
circularStrokeCap: CircularStrokeCap.round,
|
||||||
|
backgroundColor: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.onSurface.withValues(alpha: 0.12),
|
||||||
progressColor: Theme.of(context).colorScheme.secondary,
|
progressColor: Theme.of(context).colorScheme.secondary,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BootstrapFooter extends StatelessWidget {
|
class _IndefiniteIndicator extends StatelessWidget {
|
||||||
const _BootstrapFooter();
|
const _IndefiniteIndicator();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<_BootstrapController, BootstrapState>(
|
return AspectRatio(
|
||||||
builder: (context, state) {
|
aspectRatio: 1,
|
||||||
if (state.areStagesCompleted) {
|
child: LayoutBuilder(
|
||||||
return Text(
|
builder: (context, c) {
|
||||||
"All stages completed",
|
final side = c.maxWidth.isFinite ? c.maxWidth : 120.0;
|
||||||
style: Theme.of(context).textTheme.titleMedium,
|
final size = side * 0.55;
|
||||||
);
|
return Center(
|
||||||
} else if (state.controller != null) {
|
child: SizedBox(
|
||||||
return BlocBuilder<StageController, StageState>(
|
width: size,
|
||||||
bloc: state.controller,
|
height: size,
|
||||||
builder: (context, state) {
|
child: SpinKitRing(
|
||||||
final progressIndicator = state.progress.when(
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
definite: (definite) => _DefiniteIndicator(progress: definite),
|
lineWidth: (side * 0.06).clamp(3.0, 8.0),
|
||||||
indefinite: () => const CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: [
|
|
||||||
Flexible(
|
|
||||||
flex: 1,
|
|
||||||
child: Text(
|
|
||||||
state.title,
|
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Flexible(flex: 1, child: progressIndicator),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
),
|
||||||
} else {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Bootstrapper extends StatelessWidget {
|
class _FrostCard extends StatelessWidget {
|
||||||
|
const _FrostCard({required this.child});
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(22),
|
||||||
|
child: BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(sigmaX: 14, sigmaY: 14),
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: cs.surface.withValues(alpha: 0.10),
|
||||||
|
borderRadius: BorderRadius.circular(22),
|
||||||
|
border: Border.all(
|
||||||
|
color: cs.onSurface.withValues(alpha: 0.10),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BackgroundGlow extends StatelessWidget {
|
||||||
|
const _BackgroundGlow();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
|
return DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: RadialGradient(
|
||||||
|
center: const Alignment(0, -0.55),
|
||||||
|
radius: 1.25,
|
||||||
|
colors: [
|
||||||
|
cs.primary.withValues(alpha: 0.18),
|
||||||
|
cs.secondary.withValues(alpha: 0.10),
|
||||||
|
Colors.black,
|
||||||
|
],
|
||||||
|
stops: const [0.0, 0.45, 1.0],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BootstrapFooter extends ConsumerWidget {
|
||||||
|
const _BootstrapFooter();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final stage = ref.watch(currentStageProvider);
|
||||||
|
|
||||||
|
final title = stage?.title ?? "Preparing…";
|
||||||
|
final progress = stage?.progress ?? const Progress.indefinite();
|
||||||
|
|
||||||
|
final indicator = progress.when(
|
||||||
|
definite: (definite) => _DefiniteIndicator(progress: definite),
|
||||||
|
indefinite: () => const _IndefiniteIndicator(),
|
||||||
|
);
|
||||||
|
|
||||||
|
return ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 520),
|
||||||
|
child: _FrostCard(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(22),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 250),
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
key: ValueKey(title),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
letterSpacing: 0.2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
"Please don’t close the app",
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.onSurface.withValues(alpha: 0.72),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 18),
|
||||||
|
SizedBox(height: 180, child: indicator),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bootstrapper UI + lifecycle glue.
|
||||||
|
///
|
||||||
|
/// - Runs [StagesWorker.start] exactly once (using hooks).
|
||||||
|
/// - Uses `ref.listen` to complete [onCompleted] without rebuilding the logo.
|
||||||
|
/// - Watches only [CurrentStage] for UI updates.
|
||||||
|
class Bootstrapper extends HookConsumerWidget {
|
||||||
final Stages stages;
|
final Stages stages;
|
||||||
final Completer onCompleted;
|
final Completer onCompleted;
|
||||||
|
|
||||||
@@ -217,36 +318,72 @@ class Bootstrapper extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return BlocProvider(
|
useEffect(() {
|
||||||
create: (context) {
|
Future.microtask(
|
||||||
final controller = _BootstrapController(
|
() => ref.read(stagesWorkerProvider.notifier).start(stages),
|
||||||
BootstrapState(stages),
|
|
||||||
onCompleted,
|
|
||||||
);
|
);
|
||||||
controller.add(const _BootstrapEvent.start());
|
|
||||||
return controller;
|
return null;
|
||||||
|
}, const []);
|
||||||
|
ref.listen<AsyncValue<bool>>(stagesWorkerProvider, (_, next) {
|
||||||
|
if (onCompleted.isCompleted) return;
|
||||||
|
|
||||||
|
next.whenOrNull(
|
||||||
|
data: (ok) {
|
||||||
|
if (ok) onCompleted.complete();
|
||||||
},
|
},
|
||||||
child: BlocListener<_BootstrapController, BootstrapState>(
|
error: (e, st) => onCompleted.completeError(e, st),
|
||||||
listener: (context, state) {
|
);
|
||||||
if (state.areStagesCompleted) {
|
});
|
||||||
onCompleted.complete();
|
|
||||||
}
|
return Stack(
|
||||||
},
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
const _BackgroundGlow(),
|
||||||
flex: 2,
|
SafeArea(
|
||||||
child: Center(child: Loader.playing(flavour: LoaderFlavour.big)),
|
child: Padding(
|
||||||
),
|
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 24),
|
||||||
Flexible(flex: 1, child: Container()),
|
child: Column(
|
||||||
Flexible(flex: 1, child: _BootstrapFooter()),
|
children: const [
|
||||||
Flexible(flex: 1, child: Container()),
|
// Keep this as a const child so it doesn't restart animations
|
||||||
|
// when the footer rebuilds.
|
||||||
|
_LogoHeader(),
|
||||||
|
SizedBox(height: 24),
|
||||||
|
Expanded(child: Center(child: _BootstrapFooter())),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
_BottomCaption(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LogoHeader extends StatelessWidget {
|
||||||
|
const _LogoHeader();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
height: 160,
|
||||||
|
child: Center(child: Loader.playing(flavour: LoaderFlavour.big)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _BottomCaption extends StatelessWidget {
|
||||||
|
const _BottomCaption();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Text(
|
||||||
|
"Initializing secure components…",
|
||||||
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.55),
|
||||||
|
letterSpacing: 0.2,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,7 +272,7 @@ String toString() {
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$StageState {
|
mixin _$StageState {
|
||||||
|
|
||||||
String get title; Progress get progress;
|
String get title; set title(String value); Progress get progress; set progress(Progress value);
|
||||||
/// Create a copy of StageState
|
/// Create a copy of StageState
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -455,415 +455,4 @@ case _:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$BootstrapState {
|
|
||||||
|
|
||||||
Stages get stages; int get currentStageIndex; StageController? get controller;
|
|
||||||
/// Create a copy of BootstrapState
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
|
||||||
@pragma('vm:prefer-inline')
|
|
||||||
$BootstrapStateCopyWith<BootstrapState> get copyWith => _$BootstrapStateCopyWithImpl<BootstrapState>(this as BootstrapState, _$identity);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is BootstrapState&&const DeepCollectionEquality().equals(other.stages, stages)&&(identical(other.currentStageIndex, currentStageIndex) || other.currentStageIndex == currentStageIndex)&&(identical(other.controller, controller) || other.controller == controller));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(stages),currentStageIndex,controller);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'BootstrapState(stages: $stages, currentStageIndex: $currentStageIndex, controller: $controller)';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract mixin class $BootstrapStateCopyWith<$Res> {
|
|
||||||
factory $BootstrapStateCopyWith(BootstrapState value, $Res Function(BootstrapState) _then) = _$BootstrapStateCopyWithImpl;
|
|
||||||
@useResult
|
|
||||||
$Res call({
|
|
||||||
List<StageFactory> stages, int currentStageIndex, StageController? controller
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/// @nodoc
|
|
||||||
class _$BootstrapStateCopyWithImpl<$Res>
|
|
||||||
implements $BootstrapStateCopyWith<$Res> {
|
|
||||||
_$BootstrapStateCopyWithImpl(this._self, this._then);
|
|
||||||
|
|
||||||
final BootstrapState _self;
|
|
||||||
final $Res Function(BootstrapState) _then;
|
|
||||||
|
|
||||||
/// Create a copy of BootstrapState
|
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? stages = null,Object? currentStageIndex = null,Object? controller = freezed,}) {
|
|
||||||
return _then(BootstrapState(
|
|
||||||
null == stages ? _self.stages : stages // ignore: cast_nullable_to_non_nullable
|
|
||||||
as List<StageFactory>,currentStageIndex: null == currentStageIndex ? _self.currentStageIndex : currentStageIndex // ignore: cast_nullable_to_non_nullable
|
|
||||||
as int,controller: freezed == controller ? _self.controller : controller // ignore: cast_nullable_to_non_nullable
|
|
||||||
as StageController?,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Adds pattern-matching-related methods to [BootstrapState].
|
|
||||||
extension BootstrapStatePatterns on BootstrapState {
|
|
||||||
/// A variant of `map` that fallback to returning `orElse`.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return orElse();
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({required TResult orElse(),}){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _:
|
|
||||||
return orElse();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A `switch`-like method, using callbacks.
|
|
||||||
///
|
|
||||||
/// Callbacks receives the raw object, upcasted.
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case final Subclass2 value:
|
|
||||||
/// return ...;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult map<TResult extends Object?>(){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _:
|
|
||||||
throw StateError('Unexpected subclass');
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A variant of `map` that fallback to returning `null`.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return null;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _:
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A variant of `when` that fallback to an `orElse` callback.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return orElse();
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({required TResult orElse(),}) {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _:
|
|
||||||
return orElse();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A `switch`-like method, using callbacks.
|
|
||||||
///
|
|
||||||
/// As opposed to `map`, this offers destructuring.
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case Subclass2(:final field2):
|
|
||||||
/// return ...;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>() {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _:
|
|
||||||
throw StateError('Unexpected subclass');
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A variant of `when` that fallback to returning `null`
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return null;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>() {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case _:
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$BootstrapEvent {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _BootstrapEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => runtimeType.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'BootstrapEvent()';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class $BootstrapEventCopyWith<$Res> {
|
|
||||||
$BootstrapEventCopyWith(_BootstrapEvent _, $Res Function(_BootstrapEvent) __);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Adds pattern-matching-related methods to [_BootstrapEvent].
|
|
||||||
extension BootstrapEventPatterns on _BootstrapEvent {
|
|
||||||
/// A variant of `map` that fallback to returning `orElse`.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return orElse();
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( StartEvent value)? start,TResult Function( StageCompletedEvent value)? stageCompleted,required TResult orElse(),}){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case StartEvent() when start != null:
|
|
||||||
return start(_that);case StageCompletedEvent() when stageCompleted != null:
|
|
||||||
return stageCompleted(_that);case _:
|
|
||||||
return orElse();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A `switch`-like method, using callbacks.
|
|
||||||
///
|
|
||||||
/// Callbacks receives the raw object, upcasted.
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case final Subclass2 value:
|
|
||||||
/// return ...;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( StartEvent value) start,required TResult Function( StageCompletedEvent value) stageCompleted,}){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case StartEvent():
|
|
||||||
return start(_that);case StageCompletedEvent():
|
|
||||||
return stageCompleted(_that);}
|
|
||||||
}
|
|
||||||
/// A variant of `map` that fallback to returning `null`.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case final Subclass value:
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return null;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( StartEvent value)? start,TResult? Function( StageCompletedEvent value)? stageCompleted,}){
|
|
||||||
final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case StartEvent() when start != null:
|
|
||||||
return start(_that);case StageCompletedEvent() when stageCompleted != null:
|
|
||||||
return stageCompleted(_that);case _:
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A variant of `when` that fallback to an `orElse` callback.
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return orElse();
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function()? start,TResult Function()? stageCompleted,required TResult orElse(),}) {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case StartEvent() when start != null:
|
|
||||||
return start();case StageCompletedEvent() when stageCompleted != null:
|
|
||||||
return stageCompleted();case _:
|
|
||||||
return orElse();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// A `switch`-like method, using callbacks.
|
|
||||||
///
|
|
||||||
/// As opposed to `map`, this offers destructuring.
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case Subclass2(:final field2):
|
|
||||||
/// return ...;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function() start,required TResult Function() stageCompleted,}) {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case StartEvent():
|
|
||||||
return start();case StageCompletedEvent():
|
|
||||||
return stageCompleted();}
|
|
||||||
}
|
|
||||||
/// A variant of `when` that fallback to returning `null`
|
|
||||||
///
|
|
||||||
/// It is equivalent to doing:
|
|
||||||
/// ```dart
|
|
||||||
/// switch (sealedClass) {
|
|
||||||
/// case Subclass(:final field):
|
|
||||||
/// return ...;
|
|
||||||
/// case _:
|
|
||||||
/// return null;
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function()? start,TResult? Function()? stageCompleted,}) {final _that = this;
|
|
||||||
switch (_that) {
|
|
||||||
case StartEvent() when start != null:
|
|
||||||
return start();case StageCompletedEvent() when stageCompleted != null:
|
|
||||||
return stageCompleted();case _:
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
|
|
||||||
|
|
||||||
class StartEvent implements _BootstrapEvent {
|
|
||||||
const StartEvent();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is StartEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => runtimeType.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'BootstrapEvent.start()';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
|
|
||||||
|
|
||||||
class StageCompletedEvent implements _BootstrapEvent {
|
|
||||||
const StageCompletedEvent();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is StageCompletedEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => runtimeType.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'BootstrapEvent.stageCompleted()';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// dart format on
|
// dart format on
|
||||||
|
|||||||
106
lib/src/bootstrapper.g.dart
Normal file
106
lib/src/bootstrapper.g.dart
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'bootstrapper.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
|
@ProviderFor(CurrentStage)
|
||||||
|
final currentStageProvider = CurrentStageProvider._();
|
||||||
|
|
||||||
|
final class CurrentStageProvider
|
||||||
|
extends $NotifierProvider<CurrentStage, StageState?> {
|
||||||
|
CurrentStageProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'currentStageProvider',
|
||||||
|
isAutoDispose: true,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$currentStageHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
CurrentStage create() => CurrentStage();
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(StageState? value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<StageState?>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$currentStageHash() => r'7da6320c5c830e9438bf752dc990297dd410d25a';
|
||||||
|
|
||||||
|
abstract class _$CurrentStage extends $Notifier<StageState?> {
|
||||||
|
StageState? build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
final ref = this.ref as $Ref<StageState?, StageState?>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<StageState?, StageState?>,
|
||||||
|
StageState?,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleCreate(ref, build);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ProviderFor(StagesWorker)
|
||||||
|
final stagesWorkerProvider = StagesWorkerProvider._();
|
||||||
|
|
||||||
|
final class StagesWorkerProvider
|
||||||
|
extends $AsyncNotifierProvider<StagesWorker, bool> {
|
||||||
|
StagesWorkerProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'stagesWorkerProvider',
|
||||||
|
isAutoDispose: true,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$stagesWorkerHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
StagesWorker create() => StagesWorker();
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$stagesWorkerHash() => r'44d8ae0ea8910ee05343c96e4056226e293afd67';
|
||||||
|
|
||||||
|
abstract class _$StagesWorker extends $AsyncNotifier<bool> {
|
||||||
|
FutureOr<bool> build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
final ref = this.ref as $Ref<AsyncValue<bool>, bool>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<AsyncValue<bool>, bool>,
|
||||||
|
AsyncValue<bool>,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleCreate(ref, build);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ class Credits extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
const Text("Made with "),
|
const Text("Made with "),
|
||||||
const Icon(Icons.favorite, color: Colors.red),
|
const Icon(Icons.favorite, color: Colors.red),
|
||||||
const Text(" by Skipper, Clewerwild and karabyn2187"),
|
const Text(" by MT.Dev team"),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
13
pubspec.yaml
13
pubspec.yaml
@@ -1,6 +1,6 @@
|
|||||||
name: mtcore
|
name: mtcore
|
||||||
description: "MarketTakers shared/core library"
|
description: "MarketTakers shared/core library"
|
||||||
version: 1.0.3
|
version: 1.0.7
|
||||||
publish_to: https://git.markettakers.org/api/packages/MarketTakers/pub/
|
publish_to: https://git.markettakers.org/api/packages/MarketTakers/pub/
|
||||||
repository: https://git.markettakers.org/MarketTakers/markettakers-flutter
|
repository: https://git.markettakers.org/MarketTakers/markettakers-flutter
|
||||||
|
|
||||||
@@ -14,21 +14,22 @@ dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_bloc: ^9.1.1
|
flutter_bloc: ^9.1.1
|
||||||
flutter_hooks: ^0.21.3+1
|
flutter_hooks: ^0.21.3+1
|
||||||
|
flutter_riverpod: ^3.0.3
|
||||||
|
flutter_spinkit: ^5.2.2
|
||||||
freezed_annotation: ^3.1.0
|
freezed_annotation: ^3.1.0
|
||||||
hooks_riverpod: ^3.0.2
|
hooks_riverpod: ^3.0.2
|
||||||
percent_indicator: ^4.2.5
|
percent_indicator: ^4.2.5
|
||||||
rive: ^0.14.0-dev.9
|
rive: ^0.14.1
|
||||||
rive_native: ^0.0.12
|
riverpod_annotation: ^4.0.0
|
||||||
talker_flutter: ^5.0.2
|
talker_flutter: ^5.0.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_lints: ^5.0.0
|
flutter_lints: ^6.0.0
|
||||||
build_runner: ^2.7.1
|
build_runner: ^2.7.1
|
||||||
freezed: ^3.2.3
|
freezed: ^3.2.3
|
||||||
|
riverpod_generator: ^4.0.0+1
|
||||||
|
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
assets:
|
assets:
|
||||||
|
|||||||
Reference in New Issue
Block a user