Skip to content
Snippets Groups Projects
Commit b8164a50 authored by Benoît Harrault's avatar Benoît Harrault
Browse files

Merge branch '4-add-activityparameters-widgets' into 'master'

Resolve "Add ActivityParameters widgets"

Closes #4

See merge request !9
parents eb9c090b 5c5a46fa
Branches master
Tags 1.0.7
1 merge request!9Resolve "Add ActivityParameters widgets"
Pipeline #7037 passed
## 0.5.0
- Add activity parameters widgets
## 0.4.0
- Add activity actions buttons
......
......@@ -23,6 +23,16 @@ export 'settings/application_settings_theme_card.dart' show ApplicationSettingsT
export 'settings/application_theme_mode_cubit.dart'
show ApplicationThemeModeCubit, ApplicationThemeModeState;
export 'parameters/application_config_definition.dart'
show
ApplicationConfigDefinition,
ApplicationSettingsParameter,
ApplicationSettingsParameterItemValue;
export 'parameters/pages/parameters.dart' show PageParameters;
export 'parameters/settings/settings_activity_cubit.dart'
show ActivitySettingsCubit, ActivitySettingsState;
export 'parameters/models/settings/settings_activity.dart' show ActivitySettings;
// dependencies
export 'package:easy_localization/easy_localization.dart'
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
class ApplicationConfigDefinition {
final String appTitle;
final List<ApplicationSettingsParameter> activitySettings;
final void Function(BuildContext context) startNewActivity;
final void Function(BuildContext context) deleteCurrentActivity;
final void Function(BuildContext context) resumeActivity;
const ApplicationConfigDefinition({
required this.appTitle,
required this.activitySettings,
required this.startNewActivity,
required this.deleteCurrentActivity,
required this.resumeActivity,
});
ApplicationSettingsParameter getFromCode(String paramCode) {
final List<ApplicationSettingsParameter> settings = activitySettings;
return settings.where((setting) => setting.code == paramCode).firstOrNull ??
ApplicationSettingsParameter.empty();
}
}
class ApplicationSettingsParameter {
final String code;
final bool displayedOnTop;
final List<ApplicationSettingsParameterItemValue> values;
final Widget Function({
required BuildContext context,
required double size,
required ApplicationSettingsParameterItemValue itemValue,
required VoidCallback onPressed,
})? builder;
final CustomPainter Function(BuildContext context, String value)? customPainter;
final int Function(String value)? intValueGetter;
final Color Function(String value)? colorGetter;
const ApplicationSettingsParameter({
required this.code,
this.displayedOnTop = true,
required this.values,
this.builder,
this.customPainter,
this.colorGetter,
this.intValueGetter,
});
List<String> get allowedValues {
return values.map((ApplicationSettingsParameterItemValue item) => item.value).toList();
}
String get defaultValue => values.firstWhere((element) => element.isDefault).value;
factory ApplicationSettingsParameter.empty() {
return ApplicationSettingsParameter(
code: '',
values: [
ApplicationSettingsParameterItemValue.empty(),
],
intValueGetter: (value) => 0,
);
}
Widget buildParameterItem({
required BuildContext context,
required ApplicationSettingsParameter parameter,
required ApplicationSettingsParameterItemValue itemValue,
required double size,
required VoidCallback? onPressed,
}) {
final Color buttonColorActive = (onPressed != null) ? Colors.blue : Colors.grey;
final Color buttonColorInactive = Theme.of(context).colorScheme.surface;
const double buttonBorderWidth = 4.0;
const double buttonBorderRadius = 12.0;
final ActivitySettingsCubit activitySettingsCubit =
BlocProvider.of<ActivitySettingsCubit>(context);
final String currentValue = activitySettingsCubit.get(code);
final bool isSelected = (currentValue == itemValue.value);
final Color buttonColor = isSelected ? buttonColorActive : buttonColorInactive;
Widget content = SizedBox.shrink();
if (builder != null) {
content = builder!(
context: context,
size: size,
itemValue: itemValue,
onPressed: onPressed ?? () {},
);
} else {
if (customPainter != null) {
content = StyledButton(
color: itemValue.color ?? Colors.grey,
onPressed: onPressed ?? () {},
child: CustomPaint(
size: Size(size, size),
willChange: false,
painter: customPainter!(context, itemValue.value),
isComplex: true,
),
);
} else {
content = StyledButton.text(
color: itemValue.color ?? Colors.grey,
caption: itemValue.text ?? itemValue.value,
onPressed: onPressed ?? () {},
);
}
}
return Container(
decoration: BoxDecoration(
color: buttonColor,
borderRadius: BorderRadius.circular(buttonBorderRadius),
border: Border.all(
color: buttonColor,
width: buttonBorderWidth,
),
),
child: content,
);
}
}
class ApplicationSettingsParameterItemValue {
final String value;
final bool isDefault;
final Color? color;
final String? text;
const ApplicationSettingsParameterItemValue({
required this.value,
this.isDefault = false,
this.color,
this.text,
});
factory ApplicationSettingsParameterItemValue.empty() {
return ApplicationSettingsParameterItemValue(
value: '',
isDefault: true,
);
}
@override
String toString() {
return value;
}
}
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
class ActivitySettings {
final Map<String, String> values;
final ApplicationConfigDefinition appConfig;
ActivitySettings({
required this.appConfig,
required this.values,
});
factory ActivitySettings.createDefault({
required ApplicationConfigDefinition appConfig,
}) {
Map<String, String> values = {};
for (var setting in appConfig.activitySettings) {
values[setting.code] = setting.defaultValue;
}
return ActivitySettings(
appConfig: appConfig,
values: values,
);
}
String get(String code) {
if (values.keys.contains(code)) {
if (appConfig.getFromCode(code).allowedValues.contains(values[code])) {
return values[code] ?? appConfig.getFromCode(code).defaultValue;
}
}
return appConfig.getFromCode(code).defaultValue;
}
int getAsInt(String parameterCode) {
final ApplicationSettingsParameter parameter = appConfig.getFromCode(parameterCode);
if (values.keys.contains(parameterCode)) {
if (parameter.allowedValues.contains(values[parameterCode])) {
if (parameter.intValueGetter != null) {
return parameter.intValueGetter!(get(parameterCode));
} else {
return int.parse(get(parameterCode));
}
}
}
if (parameter.intValueGetter != null) {
return parameter.intValueGetter!(parameter.defaultValue);
} else {
return int.parse(parameter.defaultValue);
}
}
void dump() {
printlog('$ActivitySettings:');
values.forEach((code, value) {
printlog(' $code: $value');
});
printlog('');
}
@override
String toString() {
return '$ActivitySettings(${toJson()})';
}
Map<String, dynamic>? toJson() {
return values;
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
class PageParameters extends StatelessWidget {
const PageParameters({
super.key,
required this.config,
required this.canBeResumed,
});
final ApplicationConfigDefinition config;
final bool canBeResumed;
final double separatorHeight = 8.0;
@override
Widget build(BuildContext context) {
final List<Widget> lines = [];
// Activity settings (top)
for (ApplicationSettingsParameter parameter in config.activitySettings) {
if (parameter.displayedOnTop) {
lines.add(Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: buildParametersLine(
parameter: parameter,
isEnabled: !canBeResumed,
),
));
lines.add(SizedBox(height: separatorHeight));
}
}
lines.add(Expanded(
child: SizedBox(height: separatorHeight),
));
if (canBeResumed) {
// Resume activity
lines.add(AspectRatio(
aspectRatio: 3,
child: ActivityButtonResumeSaved(
onPressed: () {
config.resumeActivity(context);
},
),
));
// Delete saved activity
lines.add(SizedBox.square(
dimension: MediaQuery.of(context).size.width / 5,
child: ActivityButtonDeleteSaved(
onPressed: () {
config.deleteCurrentActivity(context);
},
),
));
} else {
// Start new activity
lines.add(
AspectRatio(
aspectRatio: 3,
child: ActivityButtonStartNew(
onPressed: () {
config.startNewActivity(context);
},
),
),
);
}
lines.add(SizedBox(height: separatorHeight));
// Activity settings (bottom)
for (ApplicationSettingsParameter parameter in config.activitySettings) {
if (!parameter.displayedOnTop) {
lines.add(Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: buildParametersLine(
parameter: parameter,
isEnabled: !canBeResumed,
),
));
lines.add(SizedBox(height: separatorHeight));
}
}
return Column(
children: lines,
);
}
List<Widget> buildParametersLine({
required ApplicationSettingsParameter parameter,
required bool isEnabled,
}) {
final List<ApplicationSettingsParameterItemValue> items = parameter.values;
final List<Widget> parameterButtons = [];
if (items.length <= 1) {
return [];
}
for (ApplicationSettingsParameterItemValue item in items) {
final Widget parameterButton = BlocBuilder<ActivitySettingsCubit, ActivitySettingsState>(
builder: (BuildContext context, ActivitySettingsState activitySettingsState) {
final ActivitySettingsCubit activitySettingsCubit =
BlocProvider.of<ActivitySettingsCubit>(context);
final double displayWidth = MediaQuery.of(context).size.width;
final double itemWidth = displayWidth / items.length - 4;
return SizedBox.square(
dimension: itemWidth,
child: parameter.buildParameterItem(
context: context,
parameter: parameter,
itemValue: item,
size: itemWidth,
onPressed: isEnabled
? () {
activitySettingsCubit.set(parameter.code, item.value);
}
: null,
),
);
},
);
parameterButtons.add(parameterButton);
}
return parameterButtons;
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
part 'settings_activity_state.dart';
class ActivitySettingsCubit extends HydratedCubit<ActivitySettingsState> {
final ApplicationConfigDefinition appConfig;
ActivitySettingsCubit({
required this.appConfig,
}) : super(
ActivitySettingsState(
settings: ActivitySettings.createDefault(
appConfig: appConfig,
),
),
);
void setValues({
Map<String, String>? values,
}) {
emit(
ActivitySettingsState(
settings: ActivitySettings(
appConfig: appConfig,
values: values ?? state.settings.values,
),
),
);
}
String get(String code) {
return state.settings.get(code);
}
void set(String code, String value) {
Map<String, String> values = state.settings.values;
values[code] = value;
setValues(
values: values,
);
}
@override
ActivitySettingsState? fromJson(Map<String, dynamic> json) {
Map<String, String> values = {};
json.forEach((key, value) {
values[key] = value as String;
});
return ActivitySettingsState(
settings: ActivitySettings(
appConfig: appConfig,
values: values,
),
);
}
@override
Map<String, dynamic>? toJson(ActivitySettingsState state) {
return state.settings.values;
}
}
part of 'settings_activity_cubit.dart';
@immutable
class ActivitySettingsState extends Equatable {
const ActivitySettingsState({
required this.settings,
});
final ActivitySettings settings;
@override
List<dynamic> get props => <dynamic>[
settings,
];
}
......@@ -3,7 +3,7 @@ description: "Flutter custom toolbox for org.benoitharrault.* projects."
publish_to: "none"
version: 0.4.0
version: 0.5.0
homepage: https://git.harrault.fr/android/flutter-toolbox
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment