feat: add feature flags to enable/disable functionality

This commit is contained in:
Joey Boerwinkel 2024-07-29 15:15:11 +02:00 committed by FlutterJoey
parent f3c8b5f473
commit 20881023ad
4 changed files with 103 additions and 54 deletions

View file

@ -28,6 +28,11 @@ class AvailabilityOptions {
this.timePickerBuilder,
this.loadingIndicatorBuilder = DefaultLoader.builder,
this.errorDisplayBuilder = DefaultErrorDisplayDialog.defaultErrorDisplay,
this.featureSet = const {
AvailabilityFeature.breaks,
AvailabilityFeature.customAvailability,
AvailabilityFeature.templates,
},
AvailabilityDataInterface? dataInterface,
}) : dataInterface = dataInterface ?? LocalAvailabilityDataInterface();
@ -95,6 +100,11 @@ class AvailabilityOptions {
/// base widget through [baseScreenBuilder].
final ErrorDisplayBuilder errorDisplayBuilder;
/// Enabled features when using these options
///
/// Look at [AvailabilityFeature] for more information.
final Set<AvailabilityFeature> featureSet;
final _borderRadius = BorderRadius.circular(5);
/// The border radius used on the individual elements
@ -233,3 +243,21 @@ typedef ErrorDisplayBuilder = Future<void> Function(
BuildContext context,
AvailabilityError error,
);
/// Lists all features that are toggleable
enum AvailabilityFeature {
/// Anything template related
templates,
/// Definition of breaks
breaks,
/// Definition of custom availabilities without templates
customAvailability;
}
/// Extension for validating whether a feature is enabled
extension FeatureRequirement on Set<AvailabilityFeature> {
/// Whether a required feature is enabled
bool require(AvailabilityFeature feature) => contains(feature);
}

View file

@ -241,6 +241,7 @@ class _AvailabilitiesModificationScreenLayout extends HookWidget {
Widget build(BuildContext context) {
var availabilityScope = AvailabilityScope.of(context);
var options = availabilityScope.options;
var featureSet = options.featureSet;
return options.baseScreenBuilder(
context,
@ -253,25 +254,31 @@ class _AvailabilitiesModificationScreenLayout extends HookWidget {
onChanged: onClearSection,
),
if (!viewModel.clearAvailability) ...[
const SizedBox(height: 24),
AvailabilityTemplateSelection(
selectedTemplates: selectedTemplates,
onTemplateAdd: onTemplateSelected,
onTemplatesRemoved: onTemplatesRemoved,
),
const SizedBox(height: 24),
AvailabilityTimeSelection(
viewModel: viewModel,
key: ValueKey(viewModel),
onStartChanged: onStartChanged,
onEndChanged: onEndChanged,
),
const SizedBox(height: 24),
PauseSelection(
breaks: viewModel.breaks,
editingTemplate: false,
onBreaksChanged: onBreaksChanged,
),
if (featureSet.require(AvailabilityFeature.templates)) ...[
const SizedBox(height: 24),
AvailabilityTemplateSelection(
selectedTemplates: selectedTemplates,
onTemplateAdd: onTemplateSelected,
onTemplatesRemoved: onTemplatesRemoved,
),
],
if (featureSet.require(AvailabilityFeature.customAvailability)) ...[
const SizedBox(height: 24),
AvailabilityTimeSelection(
viewModel: viewModel,
key: ValueKey(viewModel),
onStartChanged: onStartChanged,
onEndChanged: onEndChanged,
),
if (featureSet.require(AvailabilityFeature.breaks)) ...[
const SizedBox(height: 24),
PauseSelection(
breaks: viewModel.breaks,
editingTemplate: false,
onBreaksChanged: onBreaksChanged,
),
],
],
],
],
buttons: [saveButton],

View file

@ -1,4 +1,5 @@
import "package:flutter/material.dart";
import "package:flutter_availability/src/config/availability_options.dart";
import "package:flutter_availability/src/util/scope.dart";
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
@ -35,6 +36,7 @@ class _TemplateLegendState extends State<TemplateLegend> {
var options = availabilityScope.options;
var colors = options.colors;
var translations = options.translations;
var featureSet = options.featureSet;
var templatesLoading =
widget.availabilities.connectionState == ConnectionState.waiting;
@ -47,6 +49,11 @@ class _TemplateLegendState extends State<TemplateLegend> {
var templatesVisible = templatesAvailable && _templateDrawerOpen;
if (!templatesAvailable &&
!featureSet.require(AvailabilityFeature.templates)) {
return const SizedBox.shrink();
}
void onDrawerHeaderClick() {
if (!templatesAvailable && !_templateDrawerOpen) {
return;
@ -115,25 +122,23 @@ class _TemplateLegendState extends State<TemplateLegend> {
),
),
],
for (var template in templates) ...[
Padding(
padding: const EdgeInsets.only(
top: 10,
left: 12,
if (featureSet.require(AvailabilityFeature.templates)) ...[
for (var template in templates) ...[
Padding(
padding: const EdgeInsets.only(
top: 10,
left: 12,
),
child: _TemplateLegendItem(
name: template.name,
backgroundColor: Color(template.color),
),
),
child: _TemplateLegendItem(
name: template.name,
backgroundColor: Color(template.color),
),
),
],
const SizedBox(height: 10),
createNewTemplateButton,
],
Padding(
padding: const EdgeInsets.only(
top: 10,
bottom: 8,
),
child: createNewTemplateButton,
),
const SizedBox(height: 8),
],
),
),
@ -184,12 +189,14 @@ class _TemplateLegendState extends State<TemplateLegend> {
padding: const EdgeInsets.only(right: 2),
child: body,
),
if (!templatesVisible) ...[
const SizedBox(height: 12),
if (templatesLoading) ...[
options.loadingIndicatorBuilder(context),
] else ...[
createNewTemplateButton,
if (featureSet.require(AvailabilityFeature.templates)) ...[
if (!templatesVisible) ...[
const SizedBox(height: 12),
if (templatesLoading) ...[
options.loadingIndicatorBuilder(context),
] else ...[
createNewTemplateButton,
],
],
],
],

View file

@ -1,7 +1,9 @@
import "package:flutter/material.dart";
import "package:flutter_availability/src/config/availability_options.dart";
import "package:flutter_availability/src/ui/view_models/template_daydata_view_model.dart";
import "package:flutter_availability/src/ui/widgets/pause_selection.dart";
import "package:flutter_availability/src/ui/widgets/template_time_selection.dart";
import "package:flutter_availability/src/util/scope.dart";
/// Section for selecting the time and breaks for a single day
class TemplateTimeAndBreakSection extends StatelessWidget {
@ -19,17 +21,20 @@ class TemplateTimeAndBreakSection extends StatelessWidget {
final void Function(DayTemplateDataViewModel data) onDayDataChanged;
@override
Widget build(BuildContext context) => Column(
children: [
TemplateTimeSelection(
key: ValueKey([dayData.startTime, dayData.endTime]),
startTime: dayData.startTime,
endTime: dayData.endTime,
onStartChanged: (start) =>
onDayDataChanged(dayData.copyWith(startTime: start)),
onEndChanged: (end) =>
onDayDataChanged(dayData.copyWith(endTime: end)),
),
Widget build(BuildContext context) {
var featureSet = AvailabilityScope.of(context).options.featureSet;
return Column(
children: [
TemplateTimeSelection(
key: ValueKey([dayData.startTime, dayData.endTime]),
startTime: dayData.startTime,
endTime: dayData.endTime,
onStartChanged: (start) =>
onDayDataChanged(dayData.copyWith(startTime: start)),
onEndChanged: (end) =>
onDayDataChanged(dayData.copyWith(endTime: end)),
),
if (featureSet.require(AvailabilityFeature.breaks)) ...[
const SizedBox(height: 24),
PauseSelection(
editingTemplate: true,
@ -38,5 +43,7 @@ class TemplateTimeAndBreakSection extends StatelessWidget {
onDayDataChanged(dayData.copyWith(breaks: pauses)),
),
],
);
],
);
}
}