mirror of
https://github.com/Iconica-Development/flutter_availability.git
synced 2025-05-19 05:03:44 +02:00
Compare commits
7 commits
Author | SHA1 | Date | |
---|---|---|---|
|
79d292cf4a | ||
|
9487cf2e57 | ||
|
bf591a45a2 | ||
|
38a9351bbb | ||
|
78acd0e41a | ||
|
4247cc6ba9 | ||
|
bd8bc994f8 |
26 changed files with 810 additions and 311 deletions
2
.fvmrc
2
.fvmrc
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"flutter": "3.22.2"
|
||||
"flutter": "3.24.3"
|
||||
}
|
1
.github/workflows/melos-ci.yml
vendored
1
.github/workflows/melos-ci.yml
vendored
|
@ -12,3 +12,4 @@ jobs:
|
|||
permissions: write-all
|
||||
with:
|
||||
subfolder: '.' # add optional subfolder to run workflow in
|
||||
flutter_version: 3.24.3
|
||||
|
|
14
.github/workflows/release.yml
vendored
Normal file
14
.github/workflows/release.yml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
name: Iconica Standard Component Release Workflow
|
||||
# Workflow Caller version: 1.0.0
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
call-global-iconica-workflow:
|
||||
uses: Iconica-Development/.github/.github/workflows/component-release.yml@master
|
||||
secrets: inherit
|
||||
permissions: write-all
|
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -1,3 +1,15 @@
|
|||
## 1.2.0
|
||||
|
||||
* Improve the UI for smaller screens to prevent overflows
|
||||
|
||||
## 1.1.1
|
||||
|
||||
* Removed custom definition of CustomSemantics to use the one from flutter_accessibility instead
|
||||
|
||||
## 1.1.0
|
||||
|
||||
* Added CustomSemantics widget that is used to wrap all the buttons, textfields and dynamic texts to make the userstory accessible for e2e testing.
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- T.B.D
|
||||
* First release of flutter_availability userstory
|
|
@ -0,0 +1,202 @@
|
|||
/// Accessibility identifiers for all widgets in the availability userstory that
|
||||
/// need to be interacted with by e2e tests. This includes buttons, textfields,
|
||||
/// and dynamic texts.
|
||||
class AvailabilityAccessibilityIds {
|
||||
/// default [AvailabilityAccessibilityIds] constructor where all the
|
||||
/// identifiers are required. This is to ensure that apps automatically break
|
||||
/// when new identifiers are added.
|
||||
const AvailabilityAccessibilityIds({
|
||||
required this.monthNameTextIdentifier,
|
||||
required this.previousMonthButtonIdentifier,
|
||||
required this.nextMonthButtonIdentifier,
|
||||
required this.availabilityDateButtonIdentifier,
|
||||
required this.createNewTemplateButtonIdentifier,
|
||||
required this.viewAvailabilitiesButtonIdentifier,
|
||||
required this.clearAvailabilitiesButtonIdentifier,
|
||||
required this.toggleTemplateDrawerButtonIdentifier,
|
||||
required this.availabilitiesPeriodTextIdentifier,
|
||||
required this.selectUnavailableForPeriodButtonIdentifier,
|
||||
required this.addTemplateToAvailabilitiesButtonIdentifier,
|
||||
required this.removeTemplatesFromAvailabilitiesButtonIdentifier,
|
||||
required this.createNewDayTemplateButtonIdentifier,
|
||||
required this.createNewWeekTemplateButtonIdentifier,
|
||||
required this.dayTemplateEditButtonIdentifier,
|
||||
required this.weekTemplateEditButtonIdentifier,
|
||||
required this.templateNameTextFieldIdentifier,
|
||||
required this.startTimeTextFieldIdentifier,
|
||||
required this.endTimeTextFieldIdentifier,
|
||||
required this.durationTextFieldIdentifier,
|
||||
required this.addBreaksButtonIdentifier,
|
||||
required this.editBreakButtonIdentifier,
|
||||
required this.deleteBreakButtonIdentifier,
|
||||
required this.colorSelectionButtonIdentifier,
|
||||
required this.colorSelectedButtonIdentifier,
|
||||
required this.weekDayButtonIdentifier,
|
||||
required this.weekDayTimeIdentifier,
|
||||
required this.weekDayBreakIdentifier,
|
||||
required this.templateNameIdentifier,
|
||||
required this.deleteTemplateButtonIdentifier,
|
||||
required this.saveButtonIdentifier,
|
||||
required this.addButtonIdentifier,
|
||||
required this.nextButtonIdentifier,
|
||||
required this.closeButtonIdentifier,
|
||||
});
|
||||
|
||||
/// Empty [AvailabilityAccessibilityIds] constructor where all the identifiers
|
||||
/// are already set to their default values. You can override all or some of
|
||||
/// the default values.
|
||||
const AvailabilityAccessibilityIds.empty({
|
||||
this.monthNameTextIdentifier = "text_month_name",
|
||||
this.previousMonthButtonIdentifier = "button_previous_month",
|
||||
this.nextMonthButtonIdentifier = "button_next_month",
|
||||
this.availabilityDateButtonIdentifier = "button_availability_date",
|
||||
this.createNewTemplateButtonIdentifier = "button_create_template",
|
||||
this.viewAvailabilitiesButtonIdentifier = "button_view_availabilities",
|
||||
this.clearAvailabilitiesButtonIdentifier = "button_clear_availabilities",
|
||||
this.toggleTemplateDrawerButtonIdentifier = "button_toggle_template_drawer",
|
||||
this.availabilitiesPeriodTextIdentifier = "text_availabilities_period",
|
||||
this.selectUnavailableForPeriodButtonIdentifier =
|
||||
"button_select_unavailable_for_period",
|
||||
this.addTemplateToAvailabilitiesButtonIdentifier =
|
||||
"button_add_template_to_availabilities",
|
||||
this.removeTemplatesFromAvailabilitiesButtonIdentifier =
|
||||
"button_remove_templates_from_availabilities",
|
||||
this.createNewDayTemplateButtonIdentifier = "button_create_template_day",
|
||||
this.createNewWeekTemplateButtonIdentifier = "button_create_template_week",
|
||||
this.dayTemplateEditButtonIdentifier = "button_edit_template_day",
|
||||
this.weekTemplateEditButtonIdentifier = "button_edit_template_week",
|
||||
this.templateNameTextFieldIdentifier = "textfield_template_name",
|
||||
this.startTimeTextFieldIdentifier = "textfield_start_time",
|
||||
this.endTimeTextFieldIdentifier = "textfield_end_time",
|
||||
this.durationTextFieldIdentifier = "textfield_duration",
|
||||
this.addBreaksButtonIdentifier = "button_add_breaks",
|
||||
this.editBreakButtonIdentifier = "button_edit_break",
|
||||
this.deleteBreakButtonIdentifier = "button_delete_break",
|
||||
this.colorSelectionButtonIdentifier = "button_select_color",
|
||||
this.colorSelectedButtonIdentifier = "button_selected_color",
|
||||
this.weekDayButtonIdentifier = "button_select_week_day",
|
||||
this.weekDayTimeIdentifier = "text_week_day_time",
|
||||
this.weekDayBreakIdentifier = "text_week_day_break",
|
||||
this.templateNameIdentifier = "text_template_name",
|
||||
this.deleteTemplateButtonIdentifier = "button_delete_template",
|
||||
this.saveButtonIdentifier = "button_save",
|
||||
this.addButtonIdentifier = "button_add",
|
||||
this.nextButtonIdentifier = "button_next",
|
||||
this.closeButtonIdentifier = "button_close",
|
||||
});
|
||||
|
||||
/// The identifier for the text that displays the month that is being viewed
|
||||
final String monthNameTextIdentifier;
|
||||
|
||||
/// The identifier for the button to navigate to the previous month
|
||||
final String previousMonthButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to navigate to the next month
|
||||
final String nextMonthButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to select a date in the availability view
|
||||
/// The month and day are appended to this identifier
|
||||
final String availabilityDateButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to go template overview screen
|
||||
final String createNewTemplateButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to view availabilities
|
||||
final String viewAvailabilitiesButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to clear availabilities;
|
||||
final String clearAvailabilitiesButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to toggle the template drawer
|
||||
final String toggleTemplateDrawerButtonIdentifier;
|
||||
|
||||
/// The identifier for the text that displays the period of availabilities
|
||||
/// that are being viewed
|
||||
final String availabilitiesPeriodTextIdentifier;
|
||||
|
||||
/// The identifier for the checkbox to clear all availabilities for a period
|
||||
final String selectUnavailableForPeriodButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to add a template to a selection of
|
||||
/// availabilities
|
||||
final String addTemplateToAvailabilitiesButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to remove all templates from a selection of
|
||||
/// availabilities
|
||||
final String removeTemplatesFromAvailabilitiesButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to create a new day template
|
||||
final String createNewDayTemplateButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to create a new week template
|
||||
final String createNewWeekTemplateButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to edit a specific day template, the index
|
||||
/// of the item in the list is appended to this identifier
|
||||
final String dayTemplateEditButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to edit a specific week template, the index
|
||||
/// of the item in the list is appended to this identifier
|
||||
final String weekTemplateEditButtonIdentifier;
|
||||
|
||||
/// The identifier for the textfield to edit the name of a template
|
||||
final String templateNameTextFieldIdentifier;
|
||||
|
||||
/// The identifier for the textfield to edit a start time
|
||||
final String startTimeTextFieldIdentifier;
|
||||
|
||||
/// The identifier for the textfield to edit an end time
|
||||
final String endTimeTextFieldIdentifier;
|
||||
|
||||
/// The identifier for the textfield to edit a duration
|
||||
final String durationTextFieldIdentifier;
|
||||
|
||||
/// The identifier for the button to add new breaks
|
||||
final String addBreaksButtonIdentifier;
|
||||
|
||||
/// The identifier for the break edit button to edit a specific break, the
|
||||
/// index of the item in the list is appended to this identifier
|
||||
final String editBreakButtonIdentifier;
|
||||
|
||||
/// The identifier for the break delete button to delete a specific break, the
|
||||
/// index of the item in the list is appended to this identifier
|
||||
final String deleteBreakButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to select a color from the list of colors,
|
||||
/// the index of the item in the list is appended to this identifier
|
||||
final String colorSelectionButtonIdentifier;
|
||||
|
||||
/// The identifier for the button for the currently selected color from the
|
||||
/// list of colors. This overrides [colorSelectionButtonIdentifier]
|
||||
final String colorSelectedButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to select a day of the week in the template
|
||||
/// modification screen. The index of the day is appended to this identifier
|
||||
final String weekDayButtonIdentifier;
|
||||
|
||||
/// The identifier for the time of a day in the template view
|
||||
/// The index of the day is appended to this identifier
|
||||
final String weekDayTimeIdentifier;
|
||||
|
||||
/// The identifier for the time of a break in the template view
|
||||
/// The index of the day and time is appended to this identifier
|
||||
final String weekDayBreakIdentifier;
|
||||
|
||||
/// The identifier for the name of a template
|
||||
final String templateNameIdentifier;
|
||||
|
||||
/// The identifier for the button to delete a template
|
||||
final String deleteTemplateButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to save (templates or availabilities)
|
||||
final String saveButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to save breaks
|
||||
final String addButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to navigate to next step for week templates
|
||||
final String nextButtonIdentifier;
|
||||
|
||||
/// The identifier for the button to close a dialog
|
||||
final String closeButtonIdentifier;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import "dart:async";
|
||||
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_availability/src/config/availability_accessibility_ids.dart";
|
||||
import "package:flutter_availability/src/config/availability_translations.dart";
|
||||
import "package:flutter_availability/src/service/errors.dart";
|
||||
import "package:flutter_availability/src/ui/widgets/defaults/default_base_screen.dart";
|
||||
|
@ -15,6 +16,7 @@ class AvailabilityOptions {
|
|||
/// AvailabilityOptions constructor where everything is optional.
|
||||
AvailabilityOptions({
|
||||
this.translations = const AvailabilityTranslations.empty(),
|
||||
this.accessibilityIds = const AvailabilityAccessibilityIds.empty(),
|
||||
this.baseScreenBuilder = DefaultBaseScreen.builder,
|
||||
this.primaryButtonBuilder = DefaultPrimaryButton.builder,
|
||||
this.secondaryButtonBuilder = DefaultSecondaryButton.builder,
|
||||
|
@ -39,6 +41,10 @@ class AvailabilityOptions {
|
|||
/// The translations for the availability userstory
|
||||
final AvailabilityTranslations translations;
|
||||
|
||||
/// All the accessibility ids for the availability userstory
|
||||
/// These are used to add identifiers to the elements for testing
|
||||
final AvailabilityAccessibilityIds accessibilityIds;
|
||||
|
||||
/// The implementation for communicating with the persistance layer
|
||||
final AvailabilityDataInterface dataInterface;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/flutter_availability.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/availability_view_model.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/break_view_model.dart";
|
||||
|
@ -62,6 +63,7 @@ class _AvailabilitiesModificationScreenState
|
|||
var options = availabilityScope.options;
|
||||
var spacing = options.spacing;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
useEffect(() {
|
||||
availabilityScope.popHandler.add(widget.onExit);
|
||||
|
@ -126,10 +128,13 @@ class _AvailabilitiesModificationScreenState
|
|||
}
|
||||
|
||||
var canSave = _availabilityViewModel.canSave;
|
||||
var saveButton = options.primaryButtonBuilder(
|
||||
var saveButton = CustomSemantics(
|
||||
identifier: identifiers.saveButtonIdentifier,
|
||||
child: options.primaryButtonBuilder(
|
||||
context,
|
||||
canSave ? onClickSave : null,
|
||||
Text(translations.saveButton),
|
||||
),
|
||||
);
|
||||
|
||||
// ignore: avoid_positional_boolean_parameters
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/src/ui/widgets/base_page.dart";
|
||||
import "package:flutter_availability/src/ui/widgets/calendar.dart";
|
||||
import "package:flutter_availability/src/ui/widgets/template_legend.dart";
|
||||
|
@ -43,6 +44,7 @@ class _AvailabilityOverviewState extends State<AvailabilityOverview> {
|
|||
var service = availabilityScope.service;
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
var availabilityStream = useMemoized(
|
||||
() => service.getOverviewDataForMonth(_selectedDate),
|
||||
|
@ -127,16 +129,22 @@ class _AvailabilityOverviewState extends State<AvailabilityOverview> {
|
|||
}
|
||||
}
|
||||
|
||||
var clearSelectedButton = options.bigTextButtonBuilder(
|
||||
var clearSelectedButton = CustomSemantics(
|
||||
identifier: identifiers.clearAvailabilitiesButtonIdentifier,
|
||||
child: options.bigTextButtonBuilder(
|
||||
context,
|
||||
onClearButtonClicked,
|
||||
Text(translations.clearAvailabilityButton),
|
||||
),
|
||||
);
|
||||
|
||||
var startEditButton = options.primaryButtonBuilder(
|
||||
var startEditButton = CustomSemantics(
|
||||
identifier: identifiers.viewAvailabilitiesButtonIdentifier,
|
||||
child: options.primaryButtonBuilder(
|
||||
context,
|
||||
onButtonPress,
|
||||
Text(translations.editAvailabilityButton),
|
||||
),
|
||||
);
|
||||
|
||||
return options.baseScreenBuilder(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/src/service/errors.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/day_template_view_model.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/template_daydata_view_model.dart";
|
||||
|
@ -51,6 +52,7 @@ class _DayTemplateModificationScreenState
|
|||
var service = availabilityScope.service;
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
useEffect(() {
|
||||
availabilityScope.popHandler.add(widget.onExit);
|
||||
|
@ -101,10 +103,13 @@ class _DayTemplateModificationScreenState
|
|||
|
||||
var canSave = _viewModel.canSave;
|
||||
|
||||
var deleteButton = options.bigTextButtonBuilder(
|
||||
var deleteButton = CustomSemantics(
|
||||
identifier: identifiers.deleteTemplateButtonIdentifier,
|
||||
child: options.bigTextButtonBuilder(
|
||||
context,
|
||||
onDeletePressed,
|
||||
Text(translations.deleteTemplateButton),
|
||||
),
|
||||
);
|
||||
|
||||
void onNameChanged(String name) {
|
||||
|
@ -153,11 +158,14 @@ class _DayTemplateModificationScreenState
|
|||
),
|
||||
],
|
||||
buttons: [
|
||||
options.primaryButtonBuilder(
|
||||
CustomSemantics(
|
||||
identifier: identifiers.saveButtonIdentifier,
|
||||
child: options.primaryButtonBuilder(
|
||||
context,
|
||||
canSave ? onSavePressed : null,
|
||||
Text(translations.saveButton),
|
||||
),
|
||||
),
|
||||
if (widget.template != null) ...[
|
||||
const SizedBox(height: 8),
|
||||
deleteButton,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/src/ui/widgets/base_page.dart";
|
||||
import "package:flutter_availability/src/util/scope.dart";
|
||||
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
||||
|
@ -34,6 +35,7 @@ class AvailabilityTemplateOverview extends HookWidget {
|
|||
var service = availabilityScope.service;
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
var dayTemplateStream = useMemoized(() => service.getDayTemplates());
|
||||
var weekTemplateStream = useMemoized(() => service.getWeekTemplates());
|
||||
|
@ -61,6 +63,7 @@ class AvailabilityTemplateOverview extends HookWidget {
|
|||
var dayTemplateSection = _TemplateListSection(
|
||||
sectionTitle: translations.dayTemplates,
|
||||
createButtonText: translations.createDayTemplate,
|
||||
createButtonIdentifier: identifiers.createNewDayTemplateButtonIdentifier,
|
||||
onEditTemplate: onEditTemplate,
|
||||
onSelectTemplate: onSelectTemplate,
|
||||
onAddTemplate: () => onAddTemplate(AvailabilityTemplateType.day),
|
||||
|
@ -72,6 +75,7 @@ class AvailabilityTemplateOverview extends HookWidget {
|
|||
var weekTemplateSection = _TemplateListSection(
|
||||
sectionTitle: translations.weekTemplates,
|
||||
createButtonText: translations.createWeekTemplate,
|
||||
createButtonIdentifier: identifiers.createNewWeekTemplateButtonIdentifier,
|
||||
templates: weekTemplates,
|
||||
isLoading:
|
||||
weekTemplatesSnapshot.connectionState == ConnectionState.waiting,
|
||||
|
@ -99,6 +103,7 @@ class _TemplateListSection extends StatelessWidget {
|
|||
const _TemplateListSection({
|
||||
required this.sectionTitle,
|
||||
required this.createButtonText,
|
||||
required this.createButtonIdentifier,
|
||||
required this.templates,
|
||||
required this.isLoading,
|
||||
required this.onEditTemplate,
|
||||
|
@ -108,6 +113,10 @@ class _TemplateListSection extends StatelessWidget {
|
|||
|
||||
final String sectionTitle;
|
||||
final String createButtonText;
|
||||
|
||||
/// The accessibility identifier for the create button
|
||||
final String createButtonIdentifier;
|
||||
|
||||
// transform the stream to a snapshot as low as possible to reduce rebuilds
|
||||
final List<AvailabilityTemplateModel> templates;
|
||||
final bool isLoading;
|
||||
|
@ -140,13 +149,16 @@ class _TemplateListSection extends StatelessWidget {
|
|||
children: [
|
||||
const Icon(Icons.add),
|
||||
const SizedBox(width: 8),
|
||||
options.smallTextButtonBuilder(
|
||||
CustomSemantics(
|
||||
identifier: createButtonIdentifier,
|
||||
child: options.smallTextButtonBuilder(
|
||||
context,
|
||||
onAddTemplate,
|
||||
Text(
|
||||
createButtonText,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -157,9 +169,10 @@ class _TemplateListSection extends StatelessWidget {
|
|||
Text(sectionTitle, style: textTheme.titleMedium),
|
||||
const SizedBox(height: 8),
|
||||
const Divider(height: 1),
|
||||
for (var template in templates) ...[
|
||||
for (var (index, template) in templates.indexed) ...[
|
||||
_TemplateListSectionItem(
|
||||
template: template,
|
||||
index: index,
|
||||
onTemplateClicked: onClickTemplate,
|
||||
onEditTemplate: onEditTemplate,
|
||||
),
|
||||
|
@ -177,12 +190,16 @@ class _TemplateListSection extends StatelessWidget {
|
|||
class _TemplateListSectionItem extends StatelessWidget {
|
||||
const _TemplateListSectionItem({
|
||||
required this.template,
|
||||
required this.index,
|
||||
required this.onTemplateClicked,
|
||||
required this.onEditTemplate,
|
||||
});
|
||||
|
||||
final AvailabilityTemplateModel template;
|
||||
|
||||
/// The index of the template in the list
|
||||
final int index;
|
||||
|
||||
final void Function(AvailabilityTemplateModel template) onTemplateClicked;
|
||||
final void Function(AvailabilityTemplateModel template) onEditTemplate;
|
||||
|
||||
|
@ -191,8 +208,16 @@ class _TemplateListSectionItem extends StatelessWidget {
|
|||
var theme = Theme.of(context);
|
||||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var identifiers = options.accessibilityIds;
|
||||
var templateTypeIdentifer =
|
||||
template.templateType == AvailabilityTemplateType.day
|
||||
? identifiers.dayTemplateEditButtonIdentifier
|
||||
: identifiers.weekTemplateEditButtonIdentifier;
|
||||
var templateIdentifier = "${templateTypeIdentifer}_$index";
|
||||
|
||||
return InkWell(
|
||||
return CustomSemantics(
|
||||
identifier: templateIdentifier,
|
||||
child: InkWell(
|
||||
onTap: () => onTemplateClicked(template),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
|
@ -230,6 +255,7 @@ class _TemplateListSectionItem extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/src/service/errors.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/template_daydata_view_model.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/week_template_view_models.dart";
|
||||
|
@ -53,6 +54,7 @@ class _WeekTemplateModificationScreenState
|
|||
var service = availabilityScope.service;
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
var spacing = options.spacing;
|
||||
|
||||
var weekTemplateDate = _viewModel.data;
|
||||
|
@ -134,22 +136,31 @@ class _WeekTemplateModificationScreenState
|
|||
});
|
||||
|
||||
var canSave = _viewModel.canSave;
|
||||
var nextButton = options.primaryButtonBuilder(
|
||||
var nextButton = CustomSemantics(
|
||||
identifier: identifiers.nextButtonIdentifier,
|
||||
child: options.primaryButtonBuilder(
|
||||
context,
|
||||
canSave ? onNextPressed : null,
|
||||
Text(translations.nextButton),
|
||||
),
|
||||
);
|
||||
|
||||
var saveButton = options.primaryButtonBuilder(
|
||||
var saveButton = CustomSemantics(
|
||||
identifier: identifiers.saveButtonIdentifier,
|
||||
child: options.primaryButtonBuilder(
|
||||
context,
|
||||
canSave ? onSavePressed : null,
|
||||
Text(translations.saveButton),
|
||||
),
|
||||
);
|
||||
|
||||
var deleteButton = options.bigTextButtonBuilder(
|
||||
var deleteButton = CustomSemantics(
|
||||
identifier: identifiers.deleteTemplateButtonIdentifier,
|
||||
child: options.bigTextButtonBuilder(
|
||||
context,
|
||||
onDeletePressed,
|
||||
Text(translations.deleteTemplateButton),
|
||||
),
|
||||
);
|
||||
|
||||
var title = Center(
|
||||
|
@ -230,12 +241,15 @@ class _WeekTemplateModificationScreenState
|
|||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: CustomSemantics(
|
||||
identifier: identifiers.templateNameIdentifier,
|
||||
child: Text(
|
||||
_viewModel.name ?? "",
|
||||
style: textTheme.bodyLarge,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/src/util/scope.dart";
|
||||
|
||||
///
|
||||
|
@ -30,6 +31,7 @@ class AvailabilityClearSection extends StatelessWidget {
|
|||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
var isSingleDay = range.start.isAtSameMomentAs(range.end);
|
||||
|
||||
|
@ -43,14 +45,20 @@ class AvailabilityClearSection extends StatelessWidget {
|
|||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
CustomSemantics(
|
||||
identifier: identifiers.availabilitiesPeriodTextIdentifier,
|
||||
child: Text(
|
||||
titleText,
|
||||
style: textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
CustomSemantics(
|
||||
identifier:
|
||||
identifiers.selectUnavailableForPeriodButtonIdentifier,
|
||||
child: Checkbox(
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
visualDensity: VisualDensity.compact,
|
||||
splashRadius: 0,
|
||||
|
@ -60,11 +68,14 @@ class AvailabilityClearSection extends StatelessWidget {
|
|||
onChanged(value);
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
Expanded(
|
||||
child: Text(
|
||||
unavailableText,
|
||||
style: textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/src/util/scope.dart";
|
||||
import "package:flutter_availability_data_interface/flutter_availability_data_interface.dart";
|
||||
|
||||
|
@ -34,6 +35,7 @@ class AvailabilityTemplateSelection extends StatelessWidget {
|
|||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
var titleText = translations.availabilityAddTemplateTitle;
|
||||
if (selectedTemplates.isNotEmpty) {
|
||||
|
@ -47,11 +49,14 @@ class AvailabilityTemplateSelection extends StatelessWidget {
|
|||
var addButton = options.bigTextButtonWrapperBuilder(
|
||||
context,
|
||||
onTemplateAdd,
|
||||
options.bigTextButtonBuilder(
|
||||
CustomSemantics(
|
||||
identifier: identifiers.addTemplateToAvailabilitiesButtonIdentifier,
|
||||
child: options.bigTextButtonBuilder(
|
||||
context,
|
||||
onTemplateAdd,
|
||||
Text(translations.addButton),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return Column(
|
||||
|
@ -89,6 +94,7 @@ class _TemplateList extends StatelessWidget {
|
|||
var theme = Theme.of(context);
|
||||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
|
@ -107,8 +113,8 @@ class _TemplateList extends StatelessWidget {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
for (var template in selectedTemplates) ...[
|
||||
_TemplateListItem(template: template),
|
||||
for (var (index, template) in selectedTemplates.indexed) ...[
|
||||
_TemplateListItem(template: template, index: index),
|
||||
if (template != selectedTemplates.last) ...[
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
|
@ -117,10 +123,14 @@ class _TemplateList extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
InkWell(
|
||||
CustomSemantics(
|
||||
identifier:
|
||||
identifiers.removeTemplatesFromAvailabilitiesButtonIdentifier,
|
||||
child: InkWell(
|
||||
onTap: onTemplatesRemoved,
|
||||
child: const Icon(Icons.remove),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -128,15 +138,22 @@ class _TemplateList extends StatelessWidget {
|
|||
}
|
||||
|
||||
class _TemplateListItem extends StatelessWidget {
|
||||
const _TemplateListItem({required this.template});
|
||||
const _TemplateListItem({
|
||||
required this.template,
|
||||
required this.index,
|
||||
});
|
||||
|
||||
final AvailabilityTemplateModel template;
|
||||
|
||||
/// The index of the template in the list of selected templates
|
||||
final int index;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
|
@ -150,12 +167,15 @@ class _TemplateListItem extends StatelessWidget {
|
|||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: CustomSemantics(
|
||||
identifier: "${identifiers.templateNameIdentifier}_$index",
|
||||
child: Text(
|
||||
template.name,
|
||||
style: theme.textTheme.bodyLarge,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/flutter_availability.dart";
|
||||
import "package:flutter_availability/src/ui/widgets/calendar_grid.dart";
|
||||
import "package:flutter_availability/src/util/scope.dart";
|
||||
|
@ -65,45 +66,60 @@ class CalendarView extends StatelessWidget {
|
|||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
var mappedCalendarDays = _mapAvailabilitiesToCalendarDays(availabilities);
|
||||
var existsTemplateDeviations = mappedCalendarDays.any(
|
||||
(element) => element.templateDeviation,
|
||||
);
|
||||
|
||||
var monthDateSelector = Row(
|
||||
var monthDateSelector = LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
var monthWidth =
|
||||
_calculateTextWidthOfLongestMonth(context, translations);
|
||||
var sideSpace =
|
||||
((constraints.maxWidth - monthWidth) / 2 - 44).clamp(0.0, 44.0);
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
CustomSemantics(
|
||||
identifier: identifiers.previousMonthButtonIdentifier,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: const Icon(Icons.chevron_left),
|
||||
onPressed: () {
|
||||
onMonthChanged(
|
||||
DateTime(month.year, month.month - 1),
|
||||
);
|
||||
onMonthChanged(DateTime(month.year, month.month - 1));
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 44),
|
||||
),
|
||||
SizedBox(width: sideSpace),
|
||||
SizedBox(
|
||||
width: _calculateTextWidthOfLongestMonth(context, translations),
|
||||
width: monthWidth,
|
||||
child: CustomSemantics(
|
||||
identifier: identifiers.monthNameTextIdentifier,
|
||||
child: Text(
|
||||
translations.monthYearFormatter(context, month),
|
||||
style: textTheme.titleMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 44),
|
||||
IconButton(
|
||||
),
|
||||
SizedBox(width: sideSpace),
|
||||
CustomSemantics(
|
||||
identifier: identifiers.nextMonthButtonIdentifier,
|
||||
child: IconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: const Icon(Icons.chevron_right),
|
||||
onPressed: () {
|
||||
onMonthChanged(
|
||||
DateTime(month.year, month.month + 1),
|
||||
);
|
||||
onMonthChanged(DateTime(month.year, month.month + 1));
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
var calendarGrid = CalendarGrid(
|
||||
month: month,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/flutter_availability.dart";
|
||||
import "package:flutter_availability/src/util/scope.dart";
|
||||
|
||||
|
@ -119,6 +120,7 @@ class _CalendarDay extends StatelessWidget {
|
|||
var colorScheme = theme.colorScheme;
|
||||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var identifiers = options.accessibilityIds;
|
||||
var colors = options.colors;
|
||||
|
||||
var dayColor = day.color ??
|
||||
|
@ -134,6 +136,10 @@ class _CalendarDay extends StatelessWidget {
|
|||
textStyle = textTheme.titleMedium?.copyWith(color: textColor);
|
||||
}
|
||||
|
||||
var dayIdentifier =
|
||||
"${identifiers.availabilityDateButtonIdentifier}_${day.date.year}_"
|
||||
"${day.date.month}_${day.date.day}";
|
||||
|
||||
var decoration = day.outsideMonth
|
||||
? null
|
||||
: BoxDecoration(
|
||||
|
@ -145,7 +151,9 @@ class _CalendarDay extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
|
||||
return InkWell(
|
||||
return CustomSemantics(
|
||||
identifier: dayIdentifier,
|
||||
child: InkWell(
|
||||
onTap: () => onDayTap(day.date),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
|
@ -159,9 +167,12 @@ class _CalendarDay extends StatelessWidget {
|
|||
children: [
|
||||
Center(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||
decoration: decoration,
|
||||
child: Text(day.date.day.toString(), style: textStyle),
|
||||
child: Text(
|
||||
day.date.day.toString(),
|
||||
style: textStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (day.templateDeviation) ...[
|
||||
|
@ -173,6 +184,7 @@ class _CalendarDay extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import "dart:math";
|
||||
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/src/util/scope.dart";
|
||||
|
||||
/// Widget for selecting a color for a template
|
||||
|
@ -40,9 +41,10 @@ class TemplateColorSelection extends StatelessWidget {
|
|||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: [
|
||||
for (var color in colors.templateColors) ...[
|
||||
for (var (index, color) in colors.templateColors.indexed) ...[
|
||||
_TemplateColorItem(
|
||||
color: color,
|
||||
index: index,
|
||||
selectedColor: selectedColor,
|
||||
onColorSelected: onColorSelected,
|
||||
),
|
||||
|
@ -57,6 +59,7 @@ class TemplateColorSelection extends StatelessWidget {
|
|||
class _TemplateColorItem extends StatelessWidget {
|
||||
const _TemplateColorItem({
|
||||
required this.color,
|
||||
required this.index,
|
||||
required this.selectedColor,
|
||||
required this.onColorSelected,
|
||||
});
|
||||
|
@ -66,14 +69,20 @@ class _TemplateColorItem extends StatelessWidget {
|
|||
|
||||
final Color color;
|
||||
|
||||
/// The index of the color in the list of colors
|
||||
final int index;
|
||||
|
||||
final int? selectedColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var identifiers = options.accessibilityIds;
|
||||
var colors = options.colors;
|
||||
|
||||
var isSelected = selectedColor == color.value;
|
||||
|
||||
/// If the color is selected, deselect it, otherwise select it
|
||||
void onColorClick(Color color) => onColorSelected(
|
||||
color.value == selectedColor ? null : color.value,
|
||||
|
@ -83,11 +92,15 @@ class _TemplateColorItem extends StatelessWidget {
|
|||
? colors.templateColorLightCheckmarkColor
|
||||
: colors.templateColorDarkCheckmarkColor;
|
||||
|
||||
var icon = selectedColor == color.value
|
||||
? Icon(Icons.check, color: checkMarkColor)
|
||||
: null;
|
||||
var icon = isSelected ? Icon(Icons.check, color: checkMarkColor) : null;
|
||||
|
||||
return GestureDetector(
|
||||
var colorIdentifier = isSelected
|
||||
? identifiers.colorSelectedButtonIdentifier
|
||||
: "${identifiers.colorSelectionButtonIdentifier}_$index";
|
||||
|
||||
return CustomSemantics(
|
||||
identifier: colorIdentifier,
|
||||
child: GestureDetector(
|
||||
onTap: () => onColorClick(color),
|
||||
child: Container(
|
||||
width: 40,
|
||||
|
@ -98,6 +111,7 @@ class _TemplateColorItem extends StatelessWidget {
|
|||
),
|
||||
child: icon,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ class TimeSelection extends StatelessWidget {
|
|||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: crossAxisAlignment,
|
||||
|
@ -63,6 +64,7 @@ class TimeSelection extends StatelessWidget {
|
|||
Expanded(
|
||||
flex: 2,
|
||||
child: TimeInputField(
|
||||
identifier: identifiers.startTimeTextFieldIdentifier,
|
||||
initialValue: startTime,
|
||||
onTimeChanged: onStartChanged,
|
||||
),
|
||||
|
@ -78,6 +80,7 @@ class TimeSelection extends StatelessWidget {
|
|||
Expanded(
|
||||
flex: 2,
|
||||
child: TimeInputField(
|
||||
identifier: identifiers.endTimeTextFieldIdentifier,
|
||||
initialValue: endTime,
|
||||
onTimeChanged: onEndChanged,
|
||||
),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter/services.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/src/util/scope.dart";
|
||||
|
||||
/// An input field for time selection
|
||||
|
@ -8,12 +9,16 @@ class TimeInputField extends StatelessWidget {
|
|||
const TimeInputField({
|
||||
required this.initialValue,
|
||||
required this.onTimeChanged,
|
||||
required this.identifier,
|
||||
super.key,
|
||||
});
|
||||
|
||||
///
|
||||
final TimeOfDay? initialValue;
|
||||
|
||||
/// The accessibility identifier for this input field
|
||||
final String identifier;
|
||||
|
||||
///
|
||||
final void Function(TimeOfDay) onTimeChanged;
|
||||
|
||||
|
@ -37,7 +42,10 @@ class TimeInputField extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
return TextFormField(
|
||||
return CustomSemantics(
|
||||
identifier: identifier,
|
||||
isTextField: true,
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: const Icon(Icons.access_time),
|
||||
hintText: translations.time,
|
||||
|
@ -52,6 +60,7 @@ class TimeInputField extends StatelessWidget {
|
|||
readOnly: true,
|
||||
style: options.textStyles.inputFieldTextStyle,
|
||||
onTap: onFieldtap,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -122,6 +131,7 @@ class _DurationInputFieldState extends State<DurationInputField> {
|
|||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
return Focus(
|
||||
onFocusChange: (hasFocus) {
|
||||
|
@ -131,6 +141,9 @@ class _DurationInputFieldState extends State<DurationInputField> {
|
|||
_removeOverlay();
|
||||
}
|
||||
},
|
||||
child: CustomSemantics(
|
||||
identifier: identifiers.durationTextFieldIdentifier,
|
||||
isTextField: true,
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(
|
||||
labelText: translations.time,
|
||||
|
@ -148,6 +161,7 @@ class _DurationInputFieldState extends State<DurationInputField> {
|
|||
FilteringTextInputFormatter.digitsOnly,
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/flutter_availability.dart";
|
||||
import "package:flutter_availability/src/service/pop_handler.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/break_view_model.dart";
|
||||
|
@ -32,6 +33,7 @@ class PauseSelection extends StatelessWidget {
|
|||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
var popHandler = availabilityScope.popHandler;
|
||||
|
||||
Future<BreakViewModel?> openBreakDialog(
|
||||
|
@ -73,7 +75,9 @@ class PauseSelection extends StatelessWidget {
|
|||
|
||||
var sortedBreaks = breaks.toList()..sort((a, b) => a.compareTo(b));
|
||||
|
||||
var addButton = options.bigTextButtonWrapperBuilder(
|
||||
var addButton = CustomSemantics(
|
||||
identifier: identifiers.addBreaksButtonIdentifier,
|
||||
child: options.bigTextButtonWrapperBuilder(
|
||||
context,
|
||||
onClickAddBreak,
|
||||
options.bigTextButtonBuilder(
|
||||
|
@ -81,6 +85,7 @@ class PauseSelection extends StatelessWidget {
|
|||
onClickAddBreak,
|
||||
Text(translations.addButton),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return Column(
|
||||
|
@ -99,10 +104,11 @@ class PauseSelection extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
),
|
||||
for (var breakModel in sortedBreaks) ...[
|
||||
for (var (index, breakModel) in sortedBreaks.indexed) ...[
|
||||
const SizedBox(height: 8),
|
||||
BreakDisplay(
|
||||
breakModel: breakModel,
|
||||
index: index,
|
||||
onRemove: () => onDeleteBreak(breakModel),
|
||||
onClick: () async => onEditBreak(breakModel),
|
||||
),
|
||||
|
@ -119,6 +125,7 @@ class BreakDisplay extends StatelessWidget {
|
|||
/// Creates a new break display
|
||||
const BreakDisplay({
|
||||
required this.breakModel,
|
||||
required this.index,
|
||||
required this.onRemove,
|
||||
required this.onClick,
|
||||
super.key,
|
||||
|
@ -127,6 +134,9 @@ class BreakDisplay extends StatelessWidget {
|
|||
/// The break to display
|
||||
final BreakViewModel breakModel;
|
||||
|
||||
/// The index of the break in the list
|
||||
final int index;
|
||||
|
||||
/// Callback for when the minus button is clicked
|
||||
final VoidCallback onRemove;
|
||||
|
||||
|
@ -140,6 +150,7 @@ class BreakDisplay extends StatelessWidget {
|
|||
var options = availabilityScope.options;
|
||||
var colors = options.colors;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
var starTime = translations.timeFormatter(
|
||||
context,
|
||||
|
@ -151,6 +162,9 @@ class BreakDisplay extends StatelessWidget {
|
|||
);
|
||||
|
||||
var breakDuration = breakModel.duration.inMinutes;
|
||||
var editBreakIdentifier = "${identifiers.editBreakButtonIdentifier}_$index";
|
||||
var deleteBreakIdentifier =
|
||||
"${identifiers.deleteBreakButtonIdentifier}_$index";
|
||||
|
||||
return InkWell(
|
||||
onTap: onClick,
|
||||
|
@ -163,17 +177,23 @@ class BreakDisplay extends StatelessWidget {
|
|||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
CustomSemantics(
|
||||
identifier: editBreakIdentifier,
|
||||
child: Text(
|
||||
"$breakDuration "
|
||||
"${translations.timeMinutes} | "
|
||||
"$starTime - "
|
||||
"$endTime",
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
InkWell(
|
||||
CustomSemantics(
|
||||
identifier: deleteBreakIdentifier,
|
||||
child: InkWell(
|
||||
onTap: onRemove,
|
||||
child: const Icon(Icons.remove),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -251,6 +271,7 @@ class _AvailabilityBreakSelectionDialogState
|
|||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
var spacing = options.spacing;
|
||||
|
||||
void onUpdateDuration(Duration? duration) {
|
||||
|
@ -299,7 +320,9 @@ class _AvailabilityBreakSelectionDialogState
|
|||
|
||||
var onSaveButtonPress = canSave ? onSave : null;
|
||||
|
||||
var saveButton = options.primaryButtonBuilder(
|
||||
var saveButton = CustomSemantics(
|
||||
identifier: identifiers.addButtonIdentifier,
|
||||
child: options.primaryButtonBuilder(
|
||||
context,
|
||||
onSaveButtonPress,
|
||||
Text(
|
||||
|
@ -307,6 +330,7 @@ class _AvailabilityBreakSelectionDialogState
|
|||
? translations.addButton
|
||||
: translations.saveButton,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
var descriptionText = widget.editingTemplate
|
||||
|
@ -381,12 +405,15 @@ class _AvailabilityBreakSelectionDialogState
|
|||
Positioned(
|
||||
right: 0,
|
||||
top: 0,
|
||||
child: CustomSemantics(
|
||||
identifier: identifiers.closeButtonIdentifier,
|
||||
child: IconButton(
|
||||
padding: const EdgeInsets.all(16),
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.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";
|
||||
|
@ -36,6 +37,7 @@ class _TemplateLegendState extends State<TemplateLegend> {
|
|||
var options = availabilityScope.options;
|
||||
var colors = options.colors;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
var featureSet = options.featureSet;
|
||||
|
||||
var templatesLoading =
|
||||
|
@ -63,7 +65,9 @@ class _TemplateLegendState extends State<TemplateLegend> {
|
|||
});
|
||||
}
|
||||
|
||||
var createNewTemplateButton = GestureDetector(
|
||||
var createNewTemplateButton = CustomSemantics(
|
||||
identifier: identifiers.createNewTemplateButtonIdentifier,
|
||||
child: GestureDetector(
|
||||
onTap: () => widget.onViewTemplates(),
|
||||
child: ColoredBox(
|
||||
color: Colors.transparent,
|
||||
|
@ -72,13 +76,16 @@ class _TemplateLegendState extends State<TemplateLegend> {
|
|||
const SizedBox(width: 12),
|
||||
const Icon(Icons.add, size: 20),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
Expanded(
|
||||
child: Text(
|
||||
translations.createTemplateButton,
|
||||
style: textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget body = const Divider(
|
||||
|
@ -104,6 +111,7 @@ class _TemplateLegendState extends State<TemplateLegend> {
|
|||
left: 12,
|
||||
),
|
||||
child: _TemplateLegendItem(
|
||||
index: 0,
|
||||
name: translations.templateSelectionLabel,
|
||||
backgroundColor: Colors.white,
|
||||
borderColor: colorScheme.primary,
|
||||
|
@ -116,6 +124,7 @@ class _TemplateLegendState extends State<TemplateLegend> {
|
|||
left: 12,
|
||||
),
|
||||
child: _TemplateLegendItem(
|
||||
index: 1,
|
||||
name: translations.availabilityWithoutTemplateLabel,
|
||||
backgroundColor: colors.customAvailabilityColor ??
|
||||
colorScheme.secondary,
|
||||
|
@ -123,13 +132,14 @@ class _TemplateLegendState extends State<TemplateLegend> {
|
|||
),
|
||||
],
|
||||
if (featureSet.require(AvailabilityFeature.templates)) ...[
|
||||
for (var template in templates) ...[
|
||||
for (var (index, template) in templates.indexed) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10,
|
||||
left: 12,
|
||||
),
|
||||
child: _TemplateLegendItem(
|
||||
index: index + 2,
|
||||
name: template.name,
|
||||
backgroundColor: Color(template.color),
|
||||
),
|
||||
|
@ -149,7 +159,9 @@ class _TemplateLegendState extends State<TemplateLegend> {
|
|||
return Column(
|
||||
children: [
|
||||
// a button to open/close a drawer with all the templates
|
||||
GestureDetector(
|
||||
CustomSemantics(
|
||||
identifier: identifiers.toggleTemplateDrawerButtonIdentifier,
|
||||
child: GestureDetector(
|
||||
onTap: onDrawerHeaderClick,
|
||||
child: ColoredBox(
|
||||
color: Colors.transparent,
|
||||
|
@ -173,6 +185,7 @@ class _TemplateLegendState extends State<TemplateLegend> {
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
|
@ -208,11 +221,17 @@ class _TemplateLegendItem extends StatelessWidget {
|
|||
const _TemplateLegendItem({
|
||||
required this.name,
|
||||
required this.backgroundColor,
|
||||
required this.index,
|
||||
this.borderColor,
|
||||
});
|
||||
|
||||
final String name;
|
||||
|
||||
/// The index of the color in the list of colors (index 0 is the selected
|
||||
/// color template, index 1 is the color for availabilities without a
|
||||
/// template)
|
||||
final int index;
|
||||
|
||||
final Color backgroundColor;
|
||||
|
||||
final Color? borderColor;
|
||||
|
@ -222,6 +241,9 @@ class _TemplateLegendItem extends StatelessWidget {
|
|||
var theme = Theme.of(context);
|
||||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
var templateIdentifier = "${identifiers.templateNameIdentifier}_$index";
|
||||
|
||||
return Row(
|
||||
children: [
|
||||
|
@ -238,12 +260,15 @@ class _TemplateLegendItem extends StatelessWidget {
|
|||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: CustomSemantics(
|
||||
identifier: templateIdentifier,
|
||||
child: Text(
|
||||
name,
|
||||
style: theme.textTheme.bodyLarge,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/src/util/scope.dart";
|
||||
|
||||
/// Input section for the template name
|
||||
|
@ -23,6 +24,7 @@ class TemplateNameInput extends StatelessWidget {
|
|||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
@ -32,7 +34,10 @@ class TemplateNameInput extends StatelessWidget {
|
|||
style: textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextFormField(
|
||||
CustomSemantics(
|
||||
identifier: identifiers.templateNameTextFieldIdentifier,
|
||||
isTextField: true,
|
||||
child: TextFormField(
|
||||
decoration: InputDecoration(
|
||||
hintText: translations.templateTitleHintText,
|
||||
hintStyle: theme.inputDecorationTheme.hintStyle,
|
||||
|
@ -46,6 +51,7 @@ class TemplateNameInput extends StatelessWidget {
|
|||
style: options.textStyles.inputFieldTextStyle,
|
||||
onChanged: onNameChanged,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// ignore_for_file: avoid_positional_boolean_parameters
|
||||
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/src/ui/widgets/calendar_grid.dart";
|
||||
import "package:flutter_availability/src/util/scope.dart";
|
||||
|
||||
|
@ -58,10 +59,10 @@ class _TemplateWeekDaySelectionState extends State<TemplateWeekDaySelection> {
|
|||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
for (var day in days) ...[
|
||||
for (var (index, day) in days.indexed) ...[
|
||||
_DaySelectionCard(
|
||||
day: day,
|
||||
days: days,
|
||||
index: index,
|
||||
selectedDayIndex: _selectedDayIndex,
|
||||
onDaySelected: (selected) =>
|
||||
onDaySelected(selected, days.indexOf(day)),
|
||||
|
@ -81,12 +82,12 @@ class _DaySelectionCard extends StatelessWidget {
|
|||
const _DaySelectionCard({
|
||||
required this.selectedDayIndex,
|
||||
required this.day,
|
||||
required this.days,
|
||||
required this.index,
|
||||
required this.onDaySelected,
|
||||
});
|
||||
|
||||
final String day;
|
||||
final List<String> days;
|
||||
final int index;
|
||||
|
||||
final int selectedDayIndex;
|
||||
|
||||
|
@ -94,11 +95,11 @@ class _DaySelectionCard extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var index = days.indexOf(day);
|
||||
var isSelected = index == selectedDayIndex;
|
||||
|
||||
return _DaySelectionCardLayout(
|
||||
day: day,
|
||||
index: index,
|
||||
isSelected: isSelected,
|
||||
onDaySelected: onDaySelected,
|
||||
);
|
||||
|
@ -108,6 +109,7 @@ class _DaySelectionCard extends StatelessWidget {
|
|||
class _DaySelectionCardLayout extends StatelessWidget {
|
||||
const _DaySelectionCardLayout({
|
||||
required this.day,
|
||||
required this.index,
|
||||
required this.isSelected,
|
||||
required this.onDaySelected,
|
||||
});
|
||||
|
@ -115,6 +117,9 @@ class _DaySelectionCardLayout extends StatelessWidget {
|
|||
final String day;
|
||||
final bool isSelected;
|
||||
|
||||
/// The index of the day in the list of days
|
||||
final int index;
|
||||
|
||||
final void Function(bool) onDaySelected;
|
||||
|
||||
@override
|
||||
|
@ -124,6 +129,7 @@ class _DaySelectionCardLayout extends StatelessWidget {
|
|||
var abbreviationTextStyle = textTheme.headlineMedium;
|
||||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
abbreviationTextStyle = isSelected
|
||||
? abbreviationTextStyle?.copyWith(
|
||||
|
@ -131,10 +137,14 @@ class _DaySelectionCardLayout extends StatelessWidget {
|
|||
)
|
||||
: abbreviationTextStyle;
|
||||
|
||||
var identifier = "${identifiers.weekDayButtonIdentifier}_$index";
|
||||
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
height: isSelected ? 72 : 64,
|
||||
width: isSelected ? 72 : 64,
|
||||
child: CustomSemantics(
|
||||
identifier: identifier,
|
||||
child: ChoiceChip(
|
||||
shape: RoundedRectangleBorder(borderRadius: options.borderRadius),
|
||||
padding: EdgeInsets.zero,
|
||||
|
@ -148,6 +158,7 @@ class _DaySelectionCardLayout extends StatelessWidget {
|
|||
showCheckmark: theme.chipTheme.showCheckmark ?? false,
|
||||
onSelected: onDaySelected,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import "package:flutter/material.dart";
|
||||
import "package:flutter_accessibility/flutter_accessibility.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/break_view_model.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/template_daydata_view_model.dart";
|
||||
import "package:flutter_availability/src/ui/view_models/week_template_view_models.dart";
|
||||
|
@ -28,12 +29,24 @@ class TemplateWeekOverview extends StatelessWidget {
|
|||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
var colors = options.colors;
|
||||
|
||||
var dayNames = getDaysOfTheWeekAsStrings(translations, context);
|
||||
|
||||
var templateData = template.data;
|
||||
|
||||
var editButton = CustomSemantics(
|
||||
identifier: identifiers.weekTemplateEditButtonIdentifier,
|
||||
child: options.smallTextButtonBuilder(
|
||||
context,
|
||||
onClickEdit,
|
||||
Text(
|
||||
translations.editTemplateButton,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
@ -46,13 +59,7 @@ class TemplateWeekOverview extends StatelessWidget {
|
|||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
options.smallTextButtonBuilder(
|
||||
context,
|
||||
onClickEdit,
|
||||
Text(
|
||||
translations.editTemplateButton,
|
||||
),
|
||||
),
|
||||
editButton,
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
@ -67,12 +74,13 @@ class TemplateWeekOverview extends StatelessWidget {
|
|||
),
|
||||
child: Column(
|
||||
children: [
|
||||
for (var day in WeekDay.values) ...[
|
||||
for (var (index, day) in WeekDay.values.indexed) ...[
|
||||
_TemplateDayDetailRow(
|
||||
dayName: dayNames[day.index],
|
||||
dayName: dayNames[index],
|
||||
dayData:
|
||||
templateData.containsKey(day) ? templateData[day] : null,
|
||||
isOdd: day.index.isOdd,
|
||||
index: index,
|
||||
isOdd: index.isOdd,
|
||||
),
|
||||
],
|
||||
],
|
||||
|
@ -88,6 +96,7 @@ class _TemplateDayDetailRow extends StatelessWidget {
|
|||
required this.dayName,
|
||||
required this.dayData,
|
||||
required this.isOdd,
|
||||
required this.index,
|
||||
});
|
||||
|
||||
/// The name of the day
|
||||
|
@ -97,6 +106,9 @@ class _TemplateDayDetailRow extends StatelessWidget {
|
|||
/// This causes a layered effect
|
||||
final bool isOdd;
|
||||
|
||||
/// The index of the day
|
||||
final int index;
|
||||
|
||||
/// The data of the day
|
||||
final DayTemplateDataViewModel? dayData;
|
||||
|
||||
|
@ -107,6 +119,7 @@ class _TemplateDayDetailRow extends StatelessWidget {
|
|||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
var startTime = dayData?.startTime;
|
||||
var endTime = dayData?.endTime;
|
||||
|
@ -119,6 +132,8 @@ class _TemplateDayDetailRow extends StatelessWidget {
|
|||
dayPeriod = translations.unavailable;
|
||||
}
|
||||
|
||||
var dayPeriodIdentifier = "${identifiers.weekDayTimeIdentifier}_$index";
|
||||
|
||||
var breaks = dayData?.breaks ?? <BreakViewModel>[];
|
||||
|
||||
BoxDecoration? boxDecoration;
|
||||
|
@ -145,13 +160,23 @@ class _TemplateDayDetailRow extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(dayName, style: textTheme.bodyLarge),
|
||||
Text(dayPeriod, style: textTheme.bodyLarge),
|
||||
CustomSemantics(
|
||||
identifier: dayPeriodIdentifier,
|
||||
child: Text(
|
||||
dayPeriod,
|
||||
style: textTheme.bodyLarge,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// for each break add a line
|
||||
for (var dayBreak in breaks) ...[
|
||||
for (var (breakIndex, dayBreak) in breaks.indexed) ...[
|
||||
const SizedBox(height: 4),
|
||||
_TemplateDayDetailPauseRow(dayBreakViewModel: dayBreak),
|
||||
_TemplateDayDetailPauseRow(
|
||||
dayBreakViewModel: dayBreak,
|
||||
dayIndex: index,
|
||||
breakIndex: breakIndex,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
|
@ -162,10 +187,20 @@ class _TemplateDayDetailRow extends StatelessWidget {
|
|||
class _TemplateDayDetailPauseRow extends StatelessWidget {
|
||||
const _TemplateDayDetailPauseRow({
|
||||
required this.dayBreakViewModel,
|
||||
required this.dayIndex,
|
||||
required this.breakIndex,
|
||||
});
|
||||
|
||||
final BreakViewModel dayBreakViewModel;
|
||||
|
||||
/// The index of the day in the list of days
|
||||
/// This is used to create unique identifiers when there are multiple days
|
||||
/// with breaks
|
||||
final int dayIndex;
|
||||
|
||||
/// The index of the break in the list of breaks
|
||||
final int breakIndex;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
|
@ -173,6 +208,7 @@ class _TemplateDayDetailPauseRow extends StatelessWidget {
|
|||
var availabilityScope = AvailabilityScope.of(context);
|
||||
var options = availabilityScope.options;
|
||||
var translations = options.translations;
|
||||
var identifiers = options.accessibilityIds;
|
||||
|
||||
var dayBreak = dayBreakViewModel.toBreak();
|
||||
var startTime = TimeOfDay.fromDateTime(dayBreak.startTime);
|
||||
|
@ -186,6 +222,9 @@ class _TemplateDayDetailPauseRow extends StatelessWidget {
|
|||
fontStyle: FontStyle.italic,
|
||||
);
|
||||
|
||||
var breakIdentifier =
|
||||
"${identifiers.weekDayBreakIdentifier}_${dayIndex}_$breakIndex";
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
|
@ -196,10 +235,13 @@ class _TemplateDayDetailPauseRow extends StatelessWidget {
|
|||
style: pauseTextStyle,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
CustomSemantics(
|
||||
identifier: breakIdentifier,
|
||||
child: Text(
|
||||
pausePeriod,
|
||||
style: pauseTextStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class AvailabilityScope extends InheritedWidget {
|
|||
|
||||
@override
|
||||
bool updateShouldNotify(AvailabilityScope oldWidget) =>
|
||||
oldWidget.userId != userId || options != options;
|
||||
oldWidget.userId != userId || oldWidget.options != options;
|
||||
|
||||
///
|
||||
static AvailabilityScope of(BuildContext context) =>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: flutter_availability
|
||||
description: "Flutter availability userstory package"
|
||||
version: 1.0.0
|
||||
version: 1.2.0
|
||||
|
||||
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
|
||||
|
@ -14,7 +14,10 @@ dependencies:
|
|||
flutter_hooks: ^0.20.5
|
||||
flutter_availability_data_interface:
|
||||
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
version: ^1.0.0
|
||||
version: ^1.2.0
|
||||
flutter_accessibility:
|
||||
hosted: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
version: ^0.0.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
@ -25,4 +28,3 @@ dev_dependencies:
|
|||
url: https://github.com/Iconica-Development/flutter_iconica_analysis
|
||||
ref: 7.0.0
|
||||
|
||||
flutter:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
name: flutter_availability_data_interface
|
||||
description: "The data interface for the flutter_availability component"
|
||||
version: 1.0.0
|
||||
version: 1.2.0
|
||||
|
||||
publish_to: https://forgejo.internal.iconica.nl/api/packages/internal/pub
|
||||
|
||||
|
|
Loading…
Reference in a new issue