Haptisches Feedback hinzufügen #216
@@ -7,6 +7,7 @@ import 'package:tallee/presentation/views/main_menu/group_view/group_view.dart';
|
|||||||
import 'package:tallee/presentation/views/main_menu/match_view/match_view.dart';
|
import 'package:tallee/presentation/views/main_menu/match_view/match_view.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/settings_view/settings_view.dart';
|
import 'package:tallee/presentation/views/main_menu/settings_view/settings_view.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/statistics_view.dart';
|
import 'package:tallee/presentation/views/main_menu/statistics_view.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
import 'package:tallee/presentation/widgets/navbar_item.dart';
|
import 'package:tallee/presentation/widgets/navbar_item.dart';
|
||||||
|
|
||||||
class CustomNavigationBar extends StatefulWidget {
|
class CustomNavigationBar extends StatefulWidget {
|
||||||
@@ -54,7 +55,7 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
|
|||||||
backgroundColor: CustomTheme.backgroundColor,
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
scrolledUnderElevation: 0,
|
scrolledUnderElevation: 0,
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
HapticIconButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final navigator = Navigator.of(context);
|
final navigator = Navigator.of(context);
|
||||||
await HapticFeedback.selectionClick();
|
await HapticFeedback.selectionClick();
|
||||||
|
sneeex marked this conversation as resolved
|
|||||||
|
|||||||
@@ -135,9 +135,13 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
|||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
await HapticFeedback.successNotification();
|
await HapticFeedback.successNotification();
|
||||||
Navigator.pop(context, updatedGroup);
|
if (mounted) {
|
||||||
|
Navigator.pop(context, updatedGroup);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
await HapticFeedback.errorNotification();
|
if (mounted) {
|
||||||
|
await HapticFeedback.errorNotification();
|
||||||
|
}
|
||||||
showSnackbar(
|
showSnackbar(
|
||||||
message: widget.groupToEdit == null
|
message: widget.groupToEdit == null
|
||||||
? loc.error_creating_group
|
? loc.error_creating_group
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tallee/core/adaptive_page_route.dart';
|
import 'package:tallee/core/adaptive_page_route.dart';
|
||||||
@@ -13,6 +12,7 @@ import 'package:tallee/data/models/player.dart';
|
|||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/group_view/create_group_view.dart';
|
import 'package:tallee/presentation/views/main_menu/group_view/create_group_view.dart';
|
||||||
import 'package:tallee/presentation/widgets/app_skeleton.dart';
|
import 'package:tallee/presentation/widgets/app_skeleton.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
||||||
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
|
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
|
||||||
import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart';
|
import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart';
|
||||||
@@ -66,10 +66,9 @@ class _GroupDetailViewState extends State<GroupDetailView> {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(loc.group_profile),
|
title: Text(loc.group_profile),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
HapticIconButton(
|
||||||
icon: const Icon(Icons.delete),
|
icon: const Icon(Icons.delete),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await HapticFeedback.selectionClick();
|
|
||||||
showDialog<bool>(
|
showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => CustomAlertDialog(
|
builder: (context) => CustomAlertDialog(
|
||||||
@@ -77,17 +76,11 @@ class _GroupDetailViewState extends State<GroupDetailView> {
|
|||||||
content: Text(loc.this_cannot_be_undone),
|
content: Text(loc.this_cannot_be_undone),
|
||||||
actions: [
|
actions: [
|
||||||
CustomDialogAction(
|
CustomDialogAction(
|
||||||
onPressed: () async {
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
await HapticFeedback.warningNotification();
|
|
||||||
Navigator.of(context).pop(true);
|
|
||||||
},
|
|
||||||
text: loc.delete,
|
text: loc.delete,
|
||||||
),
|
),
|
||||||
CustomDialogAction(
|
CustomDialogAction(
|
||||||
onPressed: () async {
|
onPressed: () => Navigator.of(context).pop(false),
|
||||||
await HapticFeedback.selectionClick();
|
|
||||||
Navigator.of(context).pop(false);
|
|
||||||
},
|
|
||||||
buttonType: ButtonType.secondary,
|
buttonType: ButtonType.secondary,
|
||||||
text: loc.cancel,
|
text: loc.cancel,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tallee/core/adaptive_page_route.dart';
|
import 'package:tallee/core/adaptive_page_route.dart';
|
||||||
import 'package:tallee/core/constants.dart';
|
import 'package:tallee/core/constants.dart';
|
||||||
@@ -103,7 +102,6 @@ class _GroupViewState extends State<GroupView> {
|
|||||||
text: loc.create_group,
|
text: loc.create_group,
|
||||||
icon: Icons.group_add,
|
icon: Icons.group_add,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await HapticFeedback.selectionClick();
|
|
||||||
await Navigator.push(
|
await Navigator.push(
|
||||||
context,
|
context,
|
||||||
adaptivePageRoute(
|
adaptivePageRoute(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:tallee/data/db/database.dart';
|
|||||||
import 'package:tallee/data/models/game.dart';
|
import 'package:tallee/data/models/game.dart';
|
||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_game_view.dart';
|
import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_game_view.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
|
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/game_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/game_tile.dart';
|
||||||
import 'package:tallee/presentation/widgets/top_centered_message.dart';
|
import 'package:tallee/presentation/widgets/top_centered_message.dart';
|
||||||
@@ -70,7 +71,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
|||||||
backgroundColor: CustomTheme.backgroundColor,
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: IconButton(
|
leading: HapticIconButton(
|
||||||
icon: const Icon(Icons.arrow_back_ios),
|
icon: const Icon(Icons.arrow_back_ios),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop(
|
Navigator.of(context).pop(
|
||||||
@@ -83,7 +84,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
HapticIconButton(
|
||||||
icon: const Icon(Icons.add),
|
icon: const Icon(Icons.add),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final result = await Navigator.push(
|
final result = await Navigator.push(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:tallee/data/models/group.dart';
|
import 'package:tallee/data/models/group.dart';
|
||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
|
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/group_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/group_tile.dart';
|
||||||
import 'package:tallee/presentation/widgets/top_centered_message.dart';
|
import 'package:tallee/presentation/widgets/top_centered_message.dart';
|
||||||
@@ -45,7 +46,7 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
|
|||||||
backgroundColor: CustomTheme.backgroundColor,
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: IconButton(
|
leading: HapticIconButton(
|
||||||
icon: const Icon(Icons.arrow_back_ios),
|
icon: const Icon(Icons.arrow_back_ios),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop(
|
Navigator.of(context).pop(
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import 'package:tallee/data/models/game.dart';
|
|||||||
import 'package:tallee/data/models/group.dart';
|
import 'package:tallee/data/models/group.dart';
|
||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
|
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart';
|
import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart';
|
||||||
import 'package:tallee/presentation/widgets/dialog/custom_dialog_action.dart';
|
import 'package:tallee/presentation/widgets/dialog/custom_dialog_action.dart';
|
||||||
import 'package:tallee/presentation/widgets/text_input/text_input_field.dart';
|
import 'package:tallee/presentation/widgets/text_input/text_input_field.dart';
|
||||||
@@ -120,7 +121,7 @@ class _CreateGameViewState extends State<CreateGameView> {
|
|||||||
title: Text(isEditing ? loc.edit_game : loc.create_game),
|
title: Text(isEditing ? loc.edit_game : loc.create_game),
|
||||||
actions: [
|
actions: [
|
||||||
if (isEditMode())
|
if (isEditMode())
|
||||||
IconButton(
|
HapticIconButton(
|
||||||
icon: const Icon(Icons.delete),
|
icon: const Icon(Icons.delete),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import 'package:tallee/data/models/match.dart';
|
|||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_match_view.dart';
|
import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_match_view.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
|
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
||||||
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
|
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
|
||||||
import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart';
|
import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart';
|
||||||
@@ -60,7 +61,7 @@ class _MatchDetailViewState extends State<MatchDetailView> {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(loc.match_profile),
|
title: Text(loc.match_profile),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
HapticIconButton(
|
||||||
icon: const Icon(Icons.delete),
|
icon: const Icon(Icons.delete),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
showDialog<bool>(
|
showDialog<bool>(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:tallee/core/enums.dart';
|
import 'package:tallee/core/enums.dart';
|
||||||
@@ -8,6 +9,7 @@ import 'package:tallee/data/models/player.dart';
|
|||||||
import 'package:tallee/data/models/score_entry.dart';
|
import 'package:tallee/data/models/score_entry.dart';
|
||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
|
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/match_result_view/custom_checkbox_list_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/match_result_view/custom_checkbox_list_tile.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/match_result_view/custom_radio_list_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/match_result_view/custom_radio_list_tile.dart';
|
||||||
import 'package:tallee/presentation/widgets/tiles/match_result_view/live_edit_list_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/match_result_view/live_edit_list_tile.dart';
|
||||||
@@ -112,7 +114,7 @@ class _MatchResultViewState extends State<MatchResultView> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: CustomTheme.backgroundColor,
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: IconButton(
|
leading: HapticIconButton(
|
||||||
icon: const Icon(Icons.close),
|
icon: const Icon(Icons.close),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.onWinnerChanged?.call();
|
widget.onWinnerChanged?.call();
|
||||||
@@ -204,6 +206,7 @@ class _MatchResultViewState extends State<MatchResultView> {
|
|||||||
: RadioGroup<Player>(
|
: RadioGroup<Player>(
|
||||||
groupValue: _selectedPlayer,
|
groupValue: _selectedPlayer,
|
||||||
onChanged: (Player? value) async {
|
onChanged: (Player? value) async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedPlayer = value;
|
_selectedPlayer = value;
|
||||||
});
|
});
|
||||||
@@ -217,6 +220,7 @@ class _MatchResultViewState extends State<MatchResultView> {
|
|||||||
text: allPlayers[index].name,
|
text: allPlayers[index].name,
|
||||||
value: allPlayers[index],
|
value: allPlayers[index],
|
||||||
onContainerTap: (value) async {
|
onContainerTap: (value) async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
setState(() {
|
setState(() {
|
||||||
// Check if the already selected player is the same as the newly tapped player.
|
// Check if the already selected player is the same as the newly tapped player.
|
||||||
if (_selectedPlayer == value) {
|
if (_selectedPlayer == value) {
|
||||||
@@ -338,6 +342,12 @@ class _MatchResultViewState extends State<MatchResultView> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
onReorderStart: (int n) async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
},
|
||||||
|
onReorderEnd: (int n) async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
},
|
||||||
onReorder: (int oldIndex, int newIndex) {
|
onReorder: (int oldIndex, int newIndex) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (newIndex > oldIndex) {
|
if (newIndex > oldIndex) {
|
||||||
|
|||||||
@@ -276,35 +276,38 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case ImportResult.success:
|
case ImportResult.success:
|
||||||
|
await HapticFeedback.successNotification();
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
await HapticFeedback.successNotification();
|
showSnackbar(
|
||||||
|
context: context,
|
||||||
|
message: loc.data_successfully_imported,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
showSnackbar(context: context, message: loc.data_successfully_imported);
|
|
||||||
case ImportResult.invalidSchema:
|
case ImportResult.invalidSchema:
|
||||||
|
await HapticFeedback.errorNotification();
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
await HapticFeedback.errorNotification();
|
showSnackbar(context: context, message: loc.invalid_schema);
|
||||||
}
|
}
|
||||||
showSnackbar(context: context, message: loc.invalid_schema);
|
|
||||||
case ImportResult.fileReadError:
|
case ImportResult.fileReadError:
|
||||||
|
await HapticFeedback.errorNotification();
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
await HapticFeedback.errorNotification();
|
showSnackbar(context: context, message: loc.error_reading_file);
|
||||||
}
|
}
|
||||||
showSnackbar(context: context, message: loc.error_reading_file);
|
|
||||||
case ImportResult.canceled:
|
case ImportResult.canceled:
|
||||||
|
await HapticFeedback.errorNotification();
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
await HapticFeedback.errorNotification();
|
showSnackbar(context: context, message: loc.import_canceled);
|
||||||
}
|
}
|
||||||
showSnackbar(context: context, message: loc.import_canceled);
|
|
||||||
case ImportResult.formatException:
|
case ImportResult.formatException:
|
||||||
|
await HapticFeedback.errorNotification();
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
await HapticFeedback.errorNotification();
|
showSnackbar(context: context, message: loc.format_exception);
|
||||||
}
|
}
|
||||||
showSnackbar(context: context, message: loc.format_exception);
|
|
||||||
case ImportResult.unknownException:
|
case ImportResult.unknownException:
|
||||||
|
await HapticFeedback.errorNotification();
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
await HapticFeedback.errorNotification();
|
showSnackbar(context: context, message: loc.unknown_exception);
|
||||||
}
|
}
|
||||||
showSnackbar(context: context, message: loc.unknown_exception);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,13 +323,22 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
switch (result) {
|
switch (result) {
|
||||||
case ExportResult.success:
|
case ExportResult.success:
|
||||||
await HapticFeedback.successNotification();
|
await HapticFeedback.successNotification();
|
||||||
showSnackbar(context: context, message: loc.data_successfully_exported);
|
if (context.mounted) {
|
||||||
|
showSnackbar(
|
||||||
|
context: context,
|
||||||
|
message: loc.data_successfully_exported,
|
||||||
|
);
|
||||||
|
}
|
||||||
case ExportResult.canceled:
|
case ExportResult.canceled:
|
||||||
await HapticFeedback.errorNotification();
|
await HapticFeedback.errorNotification();
|
||||||
showSnackbar(context: context, message: loc.export_canceled);
|
if (context.mounted) {
|
||||||
await HapticFeedback.errorNotification();
|
showSnackbar(context: context, message: loc.export_canceled);
|
||||||
|
}
|
||||||
case ExportResult.unknownException:
|
case ExportResult.unknownException:
|
||||||
showSnackbar(context: context, message: loc.unknown_exception);
|
await HapticFeedback.errorNotification();
|
||||||
|
if (context.mounted) {
|
||||||
|
showSnackbar(context: context, message: loc.unknown_exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:tallee/core/enums.dart';
|
import 'package:tallee/core/enums.dart';
|
||||||
|
|
||||||
@@ -48,7 +49,12 @@ class CustomWidthButton extends StatelessWidget {
|
|||||||
)!;
|
)!;
|
||||||
|
|
||||||
return ElevatedButton(
|
return ElevatedButton(
|
||||||
onPressed: onPressed,
|
onPressed: onPressed == null
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
onPressed!.call();
|
||||||
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
foregroundColor: textcolor,
|
foregroundColor: textcolor,
|
||||||
disabledForegroundColor: disabledTextColor,
|
disabledForegroundColor: disabledTextColor,
|
||||||
@@ -78,7 +84,12 @@ class CustomWidthButton extends StatelessWidget {
|
|||||||
: Color.lerp(CustomTheme.primaryColor, Colors.black, 0.5)!;
|
: Color.lerp(CustomTheme.primaryColor, Colors.black, 0.5)!;
|
||||||
|
|
||||||
return OutlinedButton(
|
return OutlinedButton(
|
||||||
onPressed: onPressed,
|
onPressed: onPressed == null
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
onPressed!.call();
|
||||||
|
},
|
||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
foregroundColor: textcolor,
|
foregroundColor: textcolor,
|
||||||
disabledForegroundColor: disabledTextColor,
|
disabledForegroundColor: disabledTextColor,
|
||||||
@@ -110,7 +121,12 @@ class CustomWidthButton extends StatelessWidget {
|
|||||||
disabledBackgroundColor = Colors.transparent;
|
disabledBackgroundColor = Colors.transparent;
|
||||||
|
|
||||||
return TextButton(
|
return TextButton(
|
||||||
onPressed: onPressed,
|
onPressed: onPressed == null
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
onPressed!.call();
|
||||||
|
},
|
||||||
style: TextButton.styleFrom(
|
style: TextButton.styleFrom(
|
||||||
foregroundColor: textcolor,
|
foregroundColor: textcolor,
|
||||||
disabledForegroundColor: disabledTextColor,
|
disabledForegroundColor: disabledTextColor,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
|
|
||||||
class HapticBackButton extends StatelessWidget {
|
class HapticBackButton extends StatelessWidget {
|
||||||
const HapticBackButton({super.key});
|
const HapticBackButton({super.key});
|
||||||
@@ -13,10 +13,9 @@ class HapticBackButton extends StatelessWidget {
|
|||||||
_ => Icons.arrow_back_rounded,
|
_ => Icons.arrow_back_rounded,
|
||||||
};
|
};
|
||||||
|
|
||||||
return IconButton(
|
return HapticIconButton(
|
||||||
icon: Icon(iconData),
|
icon: Icon(iconData),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await HapticFeedback.mediumImpact();
|
|
||||||
Navigator.of(context).maybePop();
|
Navigator.of(context).maybePop();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
|
|
||||||
class HapticCloseButton extends StatelessWidget {
|
class HapticCloseButton extends StatelessWidget {
|
||||||
const HapticCloseButton({super.key});
|
const HapticCloseButton({super.key});
|
||||||
@@ -13,10 +13,9 @@ class HapticCloseButton extends StatelessWidget {
|
|||||||
_ => Icons.close_rounded,
|
_ => Icons.close_rounded,
|
||||||
};
|
};
|
||||||
|
|
||||||
return IconButton(
|
return HapticIconButton(
|
||||||
icon: Icon(iconData),
|
icon: Icon(iconData),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await HapticFeedback.mediumImpact();
|
|
||||||
Navigator.of(context).maybePop();
|
Navigator.of(context).maybePop();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
54
lib/presentation/widgets/buttons/haptic_icon_button.dart
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
class HapticIconButton extends StatelessWidget {
|
||||||
|
sneeex marked this conversation as resolved
flixcoo
commented
Kannst du bitte noch bei den drei neuen Buttons den Splash-Effekt entfernen und eine Scale Animation hinzufügen, ähnlich wie bei main menu button? Ggf. ersetzt du dann Kannst du bitte noch bei den drei neuen Buttons den Splash-Effekt entfernen und eine Scale Animation hinzufügen, ähnlich wie bei main menu button? Ggf. ersetzt du dann `IconButton()` einfach durch einen `Container()`, vllt ist das sogar einfacher
sneeex
commented
du meinst bei allen IconButtons? weil das ist ja dann nicht nur die drei buttons in den settings, sondern alle back buttons auch. Und was für ein scale meinst du? icon scale? button scale insgesamt? und wieso? finde das eigentlich glaube nicht so geil du meinst bei allen IconButtons? weil das ist ja dann nicht nur die drei buttons in den settings, sondern alle back buttons auch. Und was für ein scale meinst du? icon scale? button scale insgesamt? und wieso? finde das eigentlich glaube nicht so geil
flixcoo
commented
Ja bei allen Icon Buttons. Ja bei allen Icon Buttons.
Meinetwegen auch ohne Scale Effekt, aber auf jeden Fall ohne Splash. Und mit Scale meinte ich dass das Icon sich in der Größe verändert, wie beim `MainMenuButton`
sneeex
commented
Beim Main Menu Button ist aber der ganze Button mit Scale und nicht nur das Icon > Ja bei allen Icon Buttons.
> Meinetwegen auch ohne Scale Effekt, aber auf jeden Fall ohne Splash. Und mit Scale meinte ich dass das Icon sich in der Größe verändert, wie beim `MainMenuButton`
Beim Main Menu Button ist aber der ganze Button mit Scale und nicht nur das Icon
flixcoo
commented
Der Icon Button ist ja aber nur n Icon, der hat ja keinen Hintergrund Der Icon Button ist ja aber nur n Icon, der hat ja keinen Hintergrund
|
|||||||
|
const HapticIconButton({
|
||||||
|
super.key,
|
||||||
|
required this.icon,
|
||||||
|
required this.onPressed,
|
||||||
|
this.tooltip,
|
||||||
|
this.iconSize,
|
||||||
|
this.color,
|
||||||
|
this.padding,
|
||||||
|
this.alignment,
|
||||||
|
this.constraints,
|
||||||
|
this.style,
|
||||||
|
this.isSelected,
|
||||||
|
this.selectedIcon,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Widget icon;
|
||||||
|
final VoidCallback? onPressed;
|
||||||
|
|
||||||
|
final String? tooltip;
|
||||||
|
final double? iconSize;
|
||||||
|
final Color? color;
|
||||||
|
final EdgeInsetsGeometry? padding;
|
||||||
|
final AlignmentGeometry? alignment;
|
||||||
|
final BoxConstraints? constraints;
|
||||||
|
final ButtonStyle? style;
|
||||||
|
final bool? isSelected;
|
||||||
|
final Widget? selectedIcon;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return IconButton(
|
||||||
|
tooltip: tooltip,
|
||||||
|
sneeex marked this conversation as resolved
flixcoo
commented
Nicht sinnvoll, wir sind ja auf mobile, da gibts ja keinen hover state Nicht sinnvoll, wir sind ja auf mobile, da gibts ja keinen hover state
|
|||||||
|
iconSize: iconSize,
|
||||||
|
color: color,
|
||||||
|
padding: padding,
|
||||||
|
alignment: alignment ?? Alignment.center,
|
||||||
|
constraints: constraints,
|
||||||
|
style: style,
|
||||||
|
isSelected: isSelected,
|
||||||
|
selectedIcon: selectedIcon,
|
||||||
|
icon: icon,
|
||||||
|
onPressed: onPressed == null
|
||||||
|
? null
|
||||||
|
: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
onPressed!.call();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
class MainMenuButton extends StatefulWidget {
|
class MainMenuButton extends StatefulWidget {
|
||||||
/// A button for the main menu with an optional icon and a press animation.
|
/// A button for the main menu with an optional icon and a press animation.
|
||||||
@@ -78,6 +79,7 @@ class _MainMenuButtonState extends State<MainMenuButton>
|
|||||||
onTapUp: (_) async {
|
onTapUp: (_) async {
|
||||||
_cancelTimers();
|
_cancelTimers();
|
||||||
if (mounted && !_isLongPressing) {
|
if (mounted && !_isLongPressing) {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
sneeex marked this conversation as resolved
Outdated
flixcoo
commented
Warum ist hier nur auf dem Short Tab eine Vibration und nicht auf dem Long Tap? Warum ist hier nur auf dem Short Tab eine Vibration und nicht auf dem Long Tap?
sneeex
commented
nicht gecheckt, habs geändert nicht gecheckt, habs geändert
|
|||||||
widget.onPressed();
|
widget.onPressed();
|
||||||
}
|
}
|
||||||
_isLongPressing = false;
|
_isLongPressing = false;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:tallee/core/enums.dart';
|
import 'package:tallee/core/enums.dart';
|
||||||
import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart';
|
import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart';
|
||||||
|
|
||||||
@@ -26,7 +27,10 @@ class CustomDialogAction extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedDialogButton(
|
return AnimatedDialogButton(
|
||||||
onPressed: onPressed,
|
onPressed: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
onPressed.call();
|
||||||
|
},
|
||||||
buttonText: text,
|
buttonText: text,
|
||||||
buttonType: buttonType,
|
buttonType: buttonType,
|
||||||
isDescructive: isDestructive,
|
isDescructive: isDestructive,
|
||||||
|
|||||||
@@ -144,7 +144,8 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
|||||||
text: player.name,
|
text: player.name,
|
||||||
suffixText: getNameCountText(player),
|
suffixText: getNameCountText(player),
|
||||||
onIconTap: () {
|
onIconTap: () {
|
||||||
setState(() {
|
setState(() async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
// Removes the player from the selection and notifies the parent.
|
// Removes the player from the selection and notifies the parent.
|
||||||
selectedPlayers.remove(player);
|
selectedPlayers.remove(player);
|
||||||
widget.onChanged([...selectedPlayers]);
|
widget.onChanged([...selectedPlayers]);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
class ChooseTile extends StatefulWidget {
|
class ChooseTile extends StatefulWidget {
|
||||||
@@ -30,7 +31,12 @@ class _ChooseTileState extends State<ChooseTile> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: widget.onPressed,
|
onTap: () async {
|
||||||
|
await HapticFeedback.vibrate();
|
||||||
|
if (widget.onPressed != null) {
|
||||||
|
widget.onPressed!.call();
|
||||||
|
}
|
||||||
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: CustomTheme.tileMargin,
|
margin: CustomTheme.tileMargin,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
class CustomCheckboxListTile extends StatelessWidget {
|
class CustomCheckboxListTile extends StatelessWidget {
|
||||||
@@ -16,7 +17,10 @@ class CustomCheckboxListTile extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => onChanged(!value),
|
onTap: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
onChanged(!value);
|
||||||
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
|
margin: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 2),
|
padding: const EdgeInsets.symmetric(horizontal: 2),
|
||||||
@@ -29,7 +33,8 @@ class CustomCheckboxListTile extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Checkbox(
|
Checkbox(
|
||||||
value: value,
|
value: value,
|
||||||
onChanged: (bool? v) {
|
onChanged: (bool? v) async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
if (v == null) return;
|
if (v == null) return;
|
||||||
onChanged(v);
|
onChanged(v);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:core' hide Match;
|
import 'dart:core' hide Match;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:tallee/core/common.dart';
|
import 'package:tallee/core/common.dart';
|
||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
@@ -51,7 +52,10 @@ class _MatchTileState extends State<MatchTile> {
|
|||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: widget.onTap,
|
onTap: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
widget.onTap.call();
|
||||||
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
width: widget.width,
|
width: widget.width,
|
||||||
|
|||||||
Warum rufst du hier extra nochmal
HapticFeedback.selectionClick()auf?war wohl ausversehen, vmtl noch aus dem testing, habs entfernt