Skip to content

Commit

Permalink
Added a bloc to validate the tier list name
Browse files Browse the repository at this point in the history
  • Loading branch information
Wolfteam committed Mar 30, 2021
1 parent 530f20b commit 478702d
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 24 deletions.
1 change: 1 addition & 0 deletions lib/application/bloc.dart
Expand Up @@ -18,6 +18,7 @@ export 'main_tab/main_tab_bloc.dart';
export 'material/material_bloc.dart';
export 'materials/materials_bloc.dart';
export 'settings/settings_bloc.dart';
export 'tier_list_form/tier_list_form_bloc.dart';
export 'tierlist/tier_list_bloc.dart';
export 'today_materials/today_materials_bloc.dart';
export 'url_page/url_page_bloc.dart';
Expand Down
33 changes: 33 additions & 0 deletions lib/application/tier_list_form/tier_list_form_bloc.dart
@@ -0,0 +1,33 @@
import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:genshindb/domain/extensions/string_extensions.dart';
import 'package:meta/meta.dart';

part 'tier_list_form_bloc.freezed.dart';
part 'tier_list_form_event.dart';
part 'tier_list_form_state.dart';

const _initialState = TierListFormState.loaded(name: '', isNameDirty: false, isNameValid: false);

class TierListFormBloc extends Bloc<TierListFormEvent, TierListFormState> {
TierListFormBloc() : super(_initialState);

static int nameMaxLength = 25;

@override
Stream<TierListFormState> mapEventToState(TierListFormEvent event) async* {
final s = event.map(
nameChanged: (e) {
final isValid = e.name.isNotNullEmptyOrWhitespace && e.name.length <= nameMaxLength;
final isDirty = e.name != state.name;

return state.copyWith.call(name: e.name, isNameDirty: isDirty, isNameValid: isValid);
},
close: (_) => _initialState,
);

yield s;
}
}
10 changes: 10 additions & 0 deletions lib/application/tier_list_form/tier_list_form_event.dart
@@ -0,0 +1,10 @@
part of 'tier_list_form_bloc.dart';

@freezed
abstract class TierListFormEvent implements _$TierListFormEvent {
const factory TierListFormEvent.nameChanged({
@required String name,
}) = _NameChanged;

const factory TierListFormEvent.close() = _Close;
}
10 changes: 10 additions & 0 deletions lib/application/tier_list_form/tier_list_form_state.dart
@@ -0,0 +1,10 @@
part of 'tier_list_form_bloc.dart';

@freezed
abstract class TierListFormState implements _$TierListFormState {
const factory TierListFormState.loaded({
@required String name,
@required bool isNameDirty,
@required bool isNameValid,
}) = _LoadedState;
}
1 change: 1 addition & 0 deletions lib/main.dart
Expand Up @@ -200,6 +200,7 @@ class MyApp extends StatelessWidget {
return CalculatorAscMaterialsOrderBloc(dataService, ctx.read<CalculatorAscMaterialsBloc>());
},
),
BlocProvider(create: (_) => TierListFormBloc()),
],
child: BlocBuilder<MainBloc, MainState>(
builder: (ctx, state) => AppWidget(),
Expand Down
65 changes: 41 additions & 24 deletions lib/presentation/tierlist/widgets/rename_tierlist_dialog.dart
Expand Up @@ -19,11 +19,13 @@ class RenameTierListRowDialog extends StatefulWidget {

class _RenameTierListRowDialogState extends State<RenameTierListRowDialog> {
TextEditingController _textController;
String _currentValue;

@override
void initState() {
final text = widget.title ?? '';
_textController = TextEditingController(text: text);
_currentValue = widget.title;
_textController = TextEditingController(text: _currentValue);
_textController.addListener(_textChanged);
super.initState();
}

Expand All @@ -33,39 +35,54 @@ class _RenameTierListRowDialogState extends State<RenameTierListRowDialog> {
return AlertDialog(
title: Text(s.rename),
actions: [
FlatButton(
onPressed: () {
Navigator.pop(context);
},
OutlinedButton(
onPressed: () => Navigator.pop(context),
child: Text(s.cancel),
),
FlatButton(
onPressed: () {
context.read<TierListBloc>().add(TierListEvent.rowTextChanged(index: widget.index, newValue: _textController.text));
Navigator.pop(context);
},
child: Text(s.ok),
)
BlocBuilder<TierListFormBloc, TierListFormState>(
builder: (ctx, state) => ElevatedButton(
onPressed: state.isNameValid ? _saveName : null,
child: Text(s.save),
),
),
],
content: TextFormField(
controller: _textController,
keyboardType: TextInputType.text,
minLines: 1,
maxLength: 40,
autofocus: true,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
alignLabelWithHint: true,
labelText: s.name,
hintText: s.tierListBuilder,
content: BlocBuilder<TierListFormBloc, TierListFormState>(
builder: (ctx, state) => TextFormField(
controller: _textController,
keyboardType: TextInputType.text,
minLines: 1,
maxLength: TierListFormBloc.nameMaxLength,
autofocus: true,
textInputAction: TextInputAction.next,
decoration: InputDecoration(
alignLabelWithHint: true,
labelText: s.name,
hintText: s.tierListBuilder,
errorText: !state.isNameValid && state.isNameDirty ? s.invalidValue : null,
),
),
),
);
}

@override
void dispose() {
_textController.removeListener(_textChanged);
_textController.dispose();
super.dispose();
}

void _saveName() {
context.read<TierListBloc>().add(TierListEvent.rowTextChanged(index: widget.index, newValue: _textController.text));
Navigator.pop(context);
}

void _textChanged() {
//Focusing the text field triggers text changed, that why we used it like this
if (_currentValue == _textController.text) {
return;
}
_currentValue = _textController.text;
context.read<TierListFormBloc>().add(TierListFormEvent.nameChanged(name: _currentValue));
}
}
1 change: 1 addition & 0 deletions lib/presentation/tierlist/widgets/tierlist_row.dart
Expand Up @@ -186,6 +186,7 @@ class TierListRow extends StatelessWidget {
index: index,
),
);
context.read<TierListFormBloc>().add(const TierListFormEvent.close());
}

Future<void> _showColorPicker(BuildContext context) async {
Expand Down

0 comments on commit 478702d

Please sign in to comment.