wip basics for bloc based state management
This commit is contained in:
parent
19aca8f97f
commit
7129c0dee8
@ -9,6 +9,10 @@
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
analyzer:
|
||||
errors:
|
||||
invalid_annotation_target: ignore
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
|
6
build.yaml
Normal file
6
build.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
targets:
|
||||
$default:
|
||||
builders:
|
||||
json_serializable:
|
||||
options:
|
||||
explicit_to_json: false
|
@ -0,0 +1,10 @@
|
||||
|
||||
import '../../../infrastructure/controller.dart';
|
||||
import 'grade_averages_state.dart';
|
||||
|
||||
class GradeAveragesController extends Controller<GradeAveragesState> {
|
||||
GradeAveragesController(super.initialState);
|
||||
|
||||
void setGradeType(GradingSchemes scheme) => emit(state.copyWith(gradingScheme: scheme));
|
||||
double average() => state.grades.reduce((a, b) => a + b) / state.grades.length;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'grade_averages_state.freezed.dart';
|
||||
part 'grade_averages_state.g.dart';
|
||||
|
||||
@freezed
|
||||
class GradeAveragesState with _$GradeAveragesState {
|
||||
const factory GradeAveragesState({
|
||||
required GradingSchemes gradingScheme,
|
||||
required List<int> grades,
|
||||
}) = _GradeAveragesState;
|
||||
|
||||
factory GradeAveragesState.fromJson(Map<String, dynamic> json) => _$GradeAveragesStateFromJson(json);
|
||||
}
|
||||
|
||||
enum GradingSchemes {
|
||||
middleSchool,
|
||||
highSchool,
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'grade_averages_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
GradeAveragesState _$GradeAveragesStateFromJson(Map<String, dynamic> json) {
|
||||
return _GradeAveragesState.fromJson(json);
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$GradeAveragesState {
|
||||
GradingSchemes get gradingScheme => throw _privateConstructorUsedError;
|
||||
List<int> get grades => throw _privateConstructorUsedError;
|
||||
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$GradeAveragesStateCopyWith<GradeAveragesState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $GradeAveragesStateCopyWith<$Res> {
|
||||
factory $GradeAveragesStateCopyWith(
|
||||
GradeAveragesState value, $Res Function(GradeAveragesState) then) =
|
||||
_$GradeAveragesStateCopyWithImpl<$Res, GradeAveragesState>;
|
||||
@useResult
|
||||
$Res call({GradingSchemes gradingScheme, List<int> grades});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$GradeAveragesStateCopyWithImpl<$Res, $Val extends GradeAveragesState>
|
||||
implements $GradeAveragesStateCopyWith<$Res> {
|
||||
_$GradeAveragesStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? gradingScheme = null,
|
||||
Object? grades = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
gradingScheme: null == gradingScheme
|
||||
? _value.gradingScheme
|
||||
: gradingScheme // ignore: cast_nullable_to_non_nullable
|
||||
as GradingSchemes,
|
||||
grades: null == grades
|
||||
? _value.grades
|
||||
: grades // ignore: cast_nullable_to_non_nullable
|
||||
as List<int>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$GradeAveragesStateImplCopyWith<$Res>
|
||||
implements $GradeAveragesStateCopyWith<$Res> {
|
||||
factory _$$GradeAveragesStateImplCopyWith(_$GradeAveragesStateImpl value,
|
||||
$Res Function(_$GradeAveragesStateImpl) then) =
|
||||
__$$GradeAveragesStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({GradingSchemes gradingScheme, List<int> grades});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$GradeAveragesStateImplCopyWithImpl<$Res>
|
||||
extends _$GradeAveragesStateCopyWithImpl<$Res, _$GradeAveragesStateImpl>
|
||||
implements _$$GradeAveragesStateImplCopyWith<$Res> {
|
||||
__$$GradeAveragesStateImplCopyWithImpl(_$GradeAveragesStateImpl _value,
|
||||
$Res Function(_$GradeAveragesStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? gradingScheme = null,
|
||||
Object? grades = null,
|
||||
}) {
|
||||
return _then(_$GradeAveragesStateImpl(
|
||||
gradingScheme: null == gradingScheme
|
||||
? _value.gradingScheme
|
||||
: gradingScheme // ignore: cast_nullable_to_non_nullable
|
||||
as GradingSchemes,
|
||||
grades: null == grades
|
||||
? _value._grades
|
||||
: grades // ignore: cast_nullable_to_non_nullable
|
||||
as List<int>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$GradeAveragesStateImpl implements _GradeAveragesState {
|
||||
const _$GradeAveragesStateImpl(
|
||||
{required this.gradingScheme, required final List<int> grades})
|
||||
: _grades = grades;
|
||||
|
||||
factory _$GradeAveragesStateImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$GradeAveragesStateImplFromJson(json);
|
||||
|
||||
@override
|
||||
final GradingSchemes gradingScheme;
|
||||
final List<int> _grades;
|
||||
@override
|
||||
List<int> get grades {
|
||||
if (_grades is EqualUnmodifiableListView) return _grades;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_grades);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'GradeAveragesState(gradingScheme: $gradingScheme, grades: $grades)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$GradeAveragesStateImpl &&
|
||||
(identical(other.gradingScheme, gradingScheme) ||
|
||||
other.gradingScheme == gradingScheme) &&
|
||||
const DeepCollectionEquality().equals(other._grades, _grades));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType, gradingScheme, const DeepCollectionEquality().hash(_grades));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$GradeAveragesStateImplCopyWith<_$GradeAveragesStateImpl> get copyWith =>
|
||||
__$$GradeAveragesStateImplCopyWithImpl<_$GradeAveragesStateImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$GradeAveragesStateImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _GradeAveragesState implements GradeAveragesState {
|
||||
const factory _GradeAveragesState(
|
||||
{required final GradingSchemes gradingScheme,
|
||||
required final List<int> grades}) = _$GradeAveragesStateImpl;
|
||||
|
||||
factory _GradeAveragesState.fromJson(Map<String, dynamic> json) =
|
||||
_$GradeAveragesStateImpl.fromJson;
|
||||
|
||||
@override
|
||||
GradingSchemes get gradingScheme;
|
||||
@override
|
||||
List<int> get grades;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$GradeAveragesStateImplCopyWith<_$GradeAveragesStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'grade_averages_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$GradeAveragesStateImpl _$$GradeAveragesStateImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$GradeAveragesStateImpl(
|
||||
gradingScheme:
|
||||
$enumDecode(_$GradingSchemesEnumMap, json['gradingScheme']),
|
||||
grades: (json['grades'] as List<dynamic>).map((e) => e as int).toList(),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$GradeAveragesStateImplToJson(
|
||||
_$GradeAveragesStateImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'gradingScheme': _$GradingSchemesEnumMap[instance.gradingScheme]!,
|
||||
'grades': instance.grades,
|
||||
};
|
||||
|
||||
const _$GradingSchemesEnumMap = {
|
||||
GradingSchemes.middleSchool: 'middleSchool',
|
||||
GradingSchemes.highSchool: 'highSchool',
|
||||
};
|
@ -0,0 +1,24 @@
|
||||
import '../../../infrastructure/controller.dart';
|
||||
import '../../../infrastructure/loadable_state.dart';
|
||||
import 'marianum_message_state.dart';
|
||||
|
||||
class MarianumMessageController extends Controller<LoadableState<MarianumMessageState>> {
|
||||
MarianumMessageController() : super(const LoadableState(loadingState: LoadingState.none, data: MarianumMessageState(test: [])));
|
||||
|
||||
void loading() {
|
||||
emit(state.loading());
|
||||
Future.delayed(const Duration(seconds: 3)).then((value) => emit(state.done(const MarianumMessageState(test: []))));
|
||||
}
|
||||
|
||||
void backgroundLoading() {
|
||||
emit(state.cached(const MarianumMessageState(test: [])));
|
||||
}
|
||||
|
||||
void done() {
|
||||
emit(state.done(const MarianumMessageState(test: [])));
|
||||
}
|
||||
|
||||
void error() {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
||||
part 'marianum_message_state.freezed.dart';
|
||||
|
||||
@freezed
|
||||
class MarianumMessageState with _$MarianumMessageState {
|
||||
const factory MarianumMessageState({
|
||||
required List<String> test
|
||||
}) = _MarianumMessageState;
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'marianum_message_state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
/// @nodoc
|
||||
mixin _$MarianumMessageState {
|
||||
List<String> get test => throw _privateConstructorUsedError;
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
$MarianumMessageStateCopyWith<MarianumMessageState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $MarianumMessageStateCopyWith<$Res> {
|
||||
factory $MarianumMessageStateCopyWith(MarianumMessageState value,
|
||||
$Res Function(MarianumMessageState) then) =
|
||||
_$MarianumMessageStateCopyWithImpl<$Res, MarianumMessageState>;
|
||||
@useResult
|
||||
$Res call({List<String> test});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$MarianumMessageStateCopyWithImpl<$Res,
|
||||
$Val extends MarianumMessageState>
|
||||
implements $MarianumMessageStateCopyWith<$Res> {
|
||||
_$MarianumMessageStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? test = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
test: null == test
|
||||
? _value.test
|
||||
: test // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$MarianumMessageStateImplCopyWith<$Res>
|
||||
implements $MarianumMessageStateCopyWith<$Res> {
|
||||
factory _$$MarianumMessageStateImplCopyWith(_$MarianumMessageStateImpl value,
|
||||
$Res Function(_$MarianumMessageStateImpl) then) =
|
||||
__$$MarianumMessageStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({List<String> test});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$MarianumMessageStateImplCopyWithImpl<$Res>
|
||||
extends _$MarianumMessageStateCopyWithImpl<$Res, _$MarianumMessageStateImpl>
|
||||
implements _$$MarianumMessageStateImplCopyWith<$Res> {
|
||||
__$$MarianumMessageStateImplCopyWithImpl(_$MarianumMessageStateImpl _value,
|
||||
$Res Function(_$MarianumMessageStateImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? test = null,
|
||||
}) {
|
||||
return _then(_$MarianumMessageStateImpl(
|
||||
test: null == test
|
||||
? _value._test
|
||||
: test // ignore: cast_nullable_to_non_nullable
|
||||
as List<String>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$MarianumMessageStateImpl implements _MarianumMessageState {
|
||||
const _$MarianumMessageStateImpl({required final List<String> test})
|
||||
: _test = test;
|
||||
|
||||
final List<String> _test;
|
||||
@override
|
||||
List<String> get test {
|
||||
if (_test is EqualUnmodifiableListView) return _test;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_test);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'MarianumMessageState(test: $test)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$MarianumMessageStateImpl &&
|
||||
const DeepCollectionEquality().equals(other._test, _test));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
Object.hash(runtimeType, const DeepCollectionEquality().hash(_test));
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$MarianumMessageStateImplCopyWith<_$MarianumMessageStateImpl>
|
||||
get copyWith =>
|
||||
__$$MarianumMessageStateImplCopyWithImpl<_$MarianumMessageStateImpl>(
|
||||
this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _MarianumMessageState implements MarianumMessageState {
|
||||
const factory _MarianumMessageState({required final List<String> test}) =
|
||||
_$MarianumMessageStateImpl;
|
||||
|
||||
@override
|
||||
List<String> get test;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$MarianumMessageStateImplCopyWith<_$MarianumMessageStateImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
0
lib/state/app/base/account/account_controller.dart
Normal file
0
lib/state/app/base/account/account_controller.dart
Normal file
5
lib/state/infrastructure/controller.dart
Normal file
5
lib/state/infrastructure/controller.dart
Normal file
@ -0,0 +1,5 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
abstract class Controller<TContentType> extends Cubit<TContentType> {
|
||||
Controller(super.initialState);
|
||||
}
|
31
lib/state/infrastructure/loadable_state.dart
Normal file
31
lib/state/infrastructure/loadable_state.dart
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
class LoadableState<TState> {
|
||||
final LoadingState loadingState;
|
||||
final TState? data;
|
||||
|
||||
const LoadableState({required this.loadingState, required this.data});
|
||||
|
||||
LoadableState<TState> loading() =>
|
||||
LoadableState<TState>(loadingState: LoadingState.loading, data: null);
|
||||
|
||||
LoadableState<TState> cached(TState state) =>
|
||||
LoadableState<TState>(loadingState: LoadingState.loading, data: state);
|
||||
|
||||
LoadableState<TState> done(TState state) =>
|
||||
LoadableState<TState>(loadingState: LoadingState.none, data: state);
|
||||
|
||||
LoadableState<TState> error(TState state) =>
|
||||
LoadableState<TState>(loadingState: LoadingState.none, data: state);
|
||||
|
||||
bool isBackgroundLoading() =>
|
||||
loadingState == LoadingState.loading && data != null;
|
||||
|
||||
bool hasStateData() =>
|
||||
data != null;
|
||||
}
|
||||
|
||||
enum LoadingState {
|
||||
loading,
|
||||
failed,
|
||||
none,
|
||||
}
|
7
lib/state/infrastructure/state_extensions.dart
Normal file
7
lib/state/infrastructure/state_extensions.dart
Normal file
@ -0,0 +1,7 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
extension StateExtensions on BuildContext {
|
||||
TState readController<TState>() => read<TState>();
|
||||
TState watchController<TState>() => watch<TState>();
|
||||
}
|
12
lib/state/widgets/controller_consumer.dart
Normal file
12
lib/state/widgets/controller_consumer.dart
Normal file
@ -0,0 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../infrastructure/controller.dart';
|
||||
|
||||
class ControllerConsumer<TController extends Controller<TState>, TState> extends StatelessWidget {
|
||||
final Widget Function(BuildContext context, TState state) child;
|
||||
const ControllerConsumer({required this.child, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => BlocBuilder<TController, TState>(builder: child);
|
||||
}
|
21
lib/state/widgets/controller_provider.dart
Normal file
21
lib/state/widgets/controller_provider.dart
Normal file
@ -0,0 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:provider/single_child_widget.dart';
|
||||
|
||||
import '../infrastructure/controller.dart';
|
||||
|
||||
|
||||
class ControllerProvider<TState extends Controller> extends SingleChildStatelessWidget {
|
||||
final TState Function(BuildContext context) create;
|
||||
final bool lazy;
|
||||
final Widget Function(BuildContext context) child;
|
||||
ControllerProvider({required this.create, this.lazy = true, required this.child, super.key})
|
||||
: super(child: Builder(builder: child));
|
||||
|
||||
@override
|
||||
Widget buildWithChild(BuildContext context, Widget? child) => BlocProvider(
|
||||
create: create,
|
||||
lazy: lazy,
|
||||
child: child,
|
||||
);
|
||||
}
|
17
lib/state/widgets/controllers_provider.dart
Normal file
17
lib/state/widgets/controllers_provider.dart
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import 'controller_provider.dart';
|
||||
|
||||
class ControllersProvider extends StatelessWidget {
|
||||
final List<ControllerProvider> controllers;
|
||||
final Widget Function(BuildContext context) child;
|
||||
const ControllersProvider({required this.controllers, required this.child, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => MultiBlocProvider(
|
||||
providers: controllers,
|
||||
child: Builder(builder: child)
|
||||
);
|
||||
}
|
39
lib/state/widgets/loadable_controller_consumer.dart
Normal file
39
lib/state/widgets/loadable_controller_consumer.dart
Normal file
@ -0,0 +1,39 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../infrastructure/controller.dart';
|
||||
import '../infrastructure/loadable_state.dart';
|
||||
import '../infrastructure/state_extensions.dart';
|
||||
|
||||
class LoadableControllerConsumer<TController extends Controller<TState>, TState extends LoadableState> extends StatelessWidget {
|
||||
final Widget Function(BuildContext context, TState state) child;
|
||||
const LoadableControllerConsumer({required this.child, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var state = context.readController<TController>().state;
|
||||
return Stack(
|
||||
children: [
|
||||
if(!state.hasStateData()) const Center(child: CircularProgressIndicator()),
|
||||
|
||||
AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 100),
|
||||
transitionBuilder: (Widget child, Animation<double> animation) => SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(0.0, -1.0),
|
||||
end: Offset.zero,
|
||||
).animate(animation),
|
||||
child: child,
|
||||
),
|
||||
child: state.isBackgroundLoading() ? const LinearProgressIndicator() : const SizedBox.shrink(),
|
||||
),
|
||||
|
||||
AnimatedOpacity(
|
||||
opacity: state.hasStateData() ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 100),
|
||||
curve: Curves.easeInOut,
|
||||
child: state.hasStateData() ? child(context, state) : const SizedBox.shrink()
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
11
lib/state/widgets/sub_selected_controller_consumer.dart
Normal file
11
lib/state/widgets/sub_selected_controller_consumer.dart
Normal file
@ -0,0 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class SubSelectedControllerConsumer<TController extends Cubit<TFullState>, TFullState, TFilteredState> extends StatelessWidget {
|
||||
final Widget Function(BuildContext context, TFilteredState state) child;
|
||||
final TFilteredState Function(TFullState state) subselect;
|
||||
const SubSelectedControllerConsumer({required this.subselect, required this.child, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => BlocSelector<TController, TFullState, TFilteredState>(selector: subselect, builder: child);
|
||||
}
|
44
lib/view/pages/more/test.dart
Normal file
44
lib/view/pages/more/test.dart
Normal file
@ -0,0 +1,44 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../state/app/application/marianumMessage/marianum_message_controller.dart';
|
||||
import '../../../state/app/application/marianumMessage/marianum_message_state.dart';
|
||||
import '../../../state/infrastructure/loadable_state.dart';
|
||||
import '../../../state/infrastructure/state_extensions.dart';
|
||||
import '../../../state/widgets/controller_consumer.dart';
|
||||
import '../../../state/widgets/loadable_controller_consumer.dart';
|
||||
import '../../../state/widgets/sub_selected_controller_consumer.dart';
|
||||
import '../../../state/widgets/controller_provider.dart';
|
||||
|
||||
class Test extends StatelessWidget {
|
||||
const Test({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => ControllerProvider<MarianumMessageController>(
|
||||
create: (context) => MarianumMessageController(),
|
||||
child: (context) => Scaffold(
|
||||
appBar: AppBar(title: const Text("TEST")),
|
||||
body: LoadableControllerConsumer<MarianumMessageController, LoadableState<MarianumMessageState>>(
|
||||
child: (context, data) => Column(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () => context.readController<MarianumMessageController>().loading(),
|
||||
child: Text(data.loadingState.toString())
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => context.readController<MarianumMessageController>().backgroundLoading(),
|
||||
child: Text(context.watchController<MarianumMessageController>().state.loadingState.toString())
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => context.readController<MarianumMessageController>().done(),
|
||||
child: Text(context.watchController<MarianumMessageController>().state.loadingState.toString())
|
||||
),
|
||||
ControllerConsumer<MarianumMessageController, LoadableState<MarianumMessageState>>(child: (context, state) => Text(state.data!.test.toString())),
|
||||
SubSelectedControllerConsumer<MarianumMessageController, LoadableState<MarianumMessageState>, LoadingState>(
|
||||
subselect: (state) => state.loadingState,
|
||||
child: (context, state) => Text(state.toString()),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
@ -16,6 +16,7 @@ import 'more/holidays/holidays.dart';
|
||||
import 'more/message/message.dart';
|
||||
import 'more/roomplan/roomplan.dart';
|
||||
import 'more/share/selectShareTypeDialog.dart';
|
||||
import 'more/test.dart';
|
||||
|
||||
class Overhang extends StatelessWidget {
|
||||
const Overhang({super.key});
|
||||
@ -74,6 +75,10 @@ class Overhang extends StatelessWidget {
|
||||
trailing: const Icon(Icons.arrow_right),
|
||||
onTap: () => pushScreen(context, withNavBar: false, screen: const FeedbackDialog()),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.science_outlined),
|
||||
onTap: () => pushScreen(context, withNavBar: false, screen: const Test()),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -52,7 +52,7 @@ class ChatMessage {
|
||||
fadeInDuration: Duration.zero,
|
||||
fadeOutDuration: Duration.zero,
|
||||
errorListener: (value) {},
|
||||
imageUrl: 'https://${AccountData().buildHttpAuthString()}@${EndpointData().nextcloud().full()}/index.php/core/preview?fileId=${file!.id}&x=100&y=-1&a=1',
|
||||
imageUrl: 'https://${AccountData().buildHttpAuthString()}@${EndpointData().nextcloud().full()}/index.php/core/preview?fileId=${file!.id}&x=100&sub_selected_controller_consumer.dart=-1&a=1',
|
||||
);
|
||||
}
|
||||
|
||||
|
10
pubspec.yaml
10
pubspec.yaml
@ -49,7 +49,7 @@ dependencies:
|
||||
shared_preferences: ^2.0.15
|
||||
provider: ^6.0.4
|
||||
jiffy: ^6.1.0
|
||||
json_annotation: ^4.8.0
|
||||
json_annotation: ^4.8.1
|
||||
localstore: ^1.2.3
|
||||
intl: ^0.18.0
|
||||
nextcloud:
|
||||
@ -98,12 +98,15 @@ dependencies:
|
||||
time_range_picker: ^2.2.0
|
||||
in_app_review: ^2.0.8
|
||||
emoji_picker_flutter: ^2.1.1
|
||||
bloc: ^8.1.4
|
||||
flutter_bloc: ^8.1.5
|
||||
freezed_annotation: ^2.4.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
json_serializable: ^6.6.1
|
||||
build_runner: ^2.3.3
|
||||
json_serializable: ^6.7.1
|
||||
build_runner: ^2.4.9
|
||||
|
||||
# The "flutter_lints" package below contains a set of recommended lints to
|
||||
# encourage good coding practices. The lint set provided by the package is
|
||||
@ -111,6 +114,7 @@ dev_dependencies:
|
||||
# package. See that file for information about deactivating specific lint
|
||||
# rules and activating additional ones.
|
||||
flutter_lints: ^3.0.1
|
||||
freezed: ^2.5.2
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
Loading…
x
Reference in New Issue
Block a user