Merge pull request 'Haptisches Feedback hinzufügen' (#216) from feature/215-haptisches-feedback-hinzufügen into development
All checks were successful
All checks were successful
Reviewed-on: #216 Reviewed-by: Felix Kirchner <flixcoo@noreply.git.yannick-weigert.de>
This commit was merged in pull request #216.
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_back_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_close_button.dart';
|
||||||
|
|
||||||
/// Theme class that defines colors, border radius, padding, and decorations
|
/// Theme class that defines colors, border radius, padding, and decorations
|
||||||
class CustomTheme {
|
class CustomTheme {
|
||||||
@@ -83,6 +85,11 @@ class CustomTheme {
|
|||||||
iconTheme: IconThemeData(color: textColor),
|
iconTheme: IconThemeData(color: textColor),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static final ActionIconThemeData actionIconTheme = ActionIconThemeData(
|
||||||
|
backButtonIconBuilder: (context) => const HapticBackButton(),
|
||||||
|
closeButtonIconBuilder: (context) => const HapticCloseButton(),
|
||||||
|
);
|
||||||
|
|
||||||
static const SearchBarThemeData searchBarTheme = SearchBarThemeData(
|
static const SearchBarThemeData searchBarTheme = SearchBarThemeData(
|
||||||
textStyle: WidgetStatePropertyAll(TextStyle(color: textColor)),
|
textStyle: WidgetStatePropertyAll(TextStyle(color: textColor)),
|
||||||
hintStyle: WidgetStatePropertyAll(TextStyle(color: hintColor)),
|
hintStyle: WidgetStatePropertyAll(TextStyle(color: hintColor)),
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ class GameTracker extends StatelessWidget {
|
|||||||
scaffoldBackgroundColor: CustomTheme.backgroundColor,
|
scaffoldBackgroundColor: CustomTheme.backgroundColor,
|
||||||
// themes
|
// themes
|
||||||
appBarTheme: CustomTheme.appBarTheme,
|
appBarTheme: CustomTheme.appBarTheme,
|
||||||
|
actionIconTheme: CustomTheme.actionIconTheme,
|
||||||
inputDecorationTheme: CustomTheme.inputDecorationTheme,
|
inputDecorationTheme: CustomTheme.inputDecorationTheme,
|
||||||
searchBarTheme: CustomTheme.searchBarTheme,
|
searchBarTheme: CustomTheme.searchBarTheme,
|
||||||
radioTheme: CustomTheme.radioTheme,
|
radioTheme: CustomTheme.radioTheme,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:tallee/core/adaptive_page_route.dart';
|
import 'package:tallee/core/adaptive_page_route.dart';
|
||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
@@ -6,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 {
|
||||||
@@ -53,10 +55,10 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
|
|||||||
backgroundColor: CustomTheme.backgroundColor,
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
scrolledUnderElevation: 0,
|
scrolledUnderElevation: 0,
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
HapticIconButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await Navigator.push(
|
final navigator = Navigator.of(context);
|
||||||
context,
|
await navigator.push(
|
||||||
adaptivePageRoute(builder: (_) => const SettingsView()),
|
adaptivePageRoute(builder: (_) => const SettingsView()),
|
||||||
);
|
);
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -125,7 +127,8 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Handles tab tap events. Updates the current [index] state.
|
/// Handles tab tap events. Updates the current [index] state.
|
||||||
void onTabTapped(int index) {
|
void onTabTapped(int index) async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
setState(() {
|
setState(() {
|
||||||
currentIndex = index;
|
currentIndex = index;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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/constants.dart';
|
import 'package:tallee/core/constants.dart';
|
||||||
import 'package:tallee/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
@@ -133,8 +134,14 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
|||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
Navigator.pop(context, updatedGroup);
|
await HapticFeedback.successNotification();
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.pop(context, updatedGroup);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (mounted) {
|
||||||
|
await HapticFeedback.errorNotification();
|
||||||
|
}
|
||||||
showSnackbar(
|
showSnackbar(
|
||||||
message: widget.groupToEdit == null
|
message: widget.groupToEdit == null
|
||||||
? loc.error_creating_group
|
? loc.error_creating_group
|
||||||
|
|||||||
@@ -12,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';
|
||||||
@@ -65,7 +66,7 @@ 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 {
|
||||||
showDialog<bool>(
|
showDialog<bool>(
|
||||||
|
|||||||
@@ -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(
|
||||||
@@ -111,7 +112,10 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
|
|||||||
padding: const EdgeInsets.only(bottom: 85),
|
padding: const EdgeInsets.only(bottom: 85),
|
||||||
itemCount: filteredGroups.length,
|
itemCount: filteredGroups.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
return GestureDetector(
|
return GroupTile(
|
||||||
|
group: filteredGroups[index],
|
||||||
|
isHighlighted:
|
||||||
|
selectedGroupId == filteredGroups[index].id,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (selectedGroupId != filteredGroups[index].id) {
|
if (selectedGroupId != filteredGroups[index].id) {
|
||||||
@@ -121,11 +125,6 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: GroupTile(
|
|
||||||
group: filteredGroups[index],
|
|
||||||
isHighlighted:
|
|
||||||
selectedGroupId == filteredGroups[index].id,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_popup/flutter_popup.dart';
|
import 'package:flutter_popup/flutter_popup.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:tallee/core/common.dart';
|
import 'package:tallee/core/common.dart';
|
||||||
@@ -12,6 +13,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 +122,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;
|
||||||
@@ -329,6 +331,12 @@ class _CreateGameViewState extends State<CreateGameView> {
|
|||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 0, vertical: 10),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 0, vertical: 10),
|
||||||
barrierColor: Colors.transparent,
|
barrierColor: Colors.transparent,
|
||||||
contentDecoration: CustomTheme.standardBoxDecoration,
|
contentDecoration: CustomTheme.standardBoxDecoration,
|
||||||
|
onBeforePopup: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
},
|
||||||
|
onAfterPopup: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
},
|
||||||
content: StatefulBuilder(
|
content: StatefulBuilder(
|
||||||
builder: (context, setPopupState) => SizedBox(
|
builder: (context, setPopupState) => SizedBox(
|
||||||
width: 280,
|
width: 280,
|
||||||
@@ -338,7 +346,8 @@ class _CreateGameViewState extends State<CreateGameView> {
|
|||||||
children: List.generate(
|
children: List.generate(
|
||||||
_rulesets.length,
|
_rulesets.length,
|
||||||
(index) => GestureDetector(
|
(index) => GestureDetector(
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedRuleset = _rulesets[index].$1;
|
selectedRuleset = _rulesets[index].$1;
|
||||||
});
|
});
|
||||||
@@ -412,6 +421,12 @@ class _CreateGameViewState extends State<CreateGameView> {
|
|||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 0, vertical: 10),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 0, vertical: 10),
|
||||||
barrierColor: Colors.transparent,
|
barrierColor: Colors.transparent,
|
||||||
contentDecoration: CustomTheme.standardBoxDecoration,
|
contentDecoration: CustomTheme.standardBoxDecoration,
|
||||||
|
onBeforePopup: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
},
|
||||||
|
onAfterPopup: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
},
|
||||||
content: StatefulBuilder(
|
content: StatefulBuilder(
|
||||||
builder: (context, setPopupState) => SizedBox(
|
builder: (context, setPopupState) => SizedBox(
|
||||||
width: 150,
|
width: 150,
|
||||||
@@ -421,7 +436,8 @@ class _CreateGameViewState extends State<CreateGameView> {
|
|||||||
children: List.generate(
|
children: List.generate(
|
||||||
_colors.length,
|
_colors.length,
|
||||||
(index) => GestureDetector(
|
(index) => GestureDetector(
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedColor = _colors[index].$1;
|
selectedColor = _colors[index].$1;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -172,7 +172,6 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
) ??
|
) ??
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
selectedGroup = await Navigator.of(context).push(
|
selectedGroup = await Navigator.of(context).push(
|
||||||
adaptivePageRoute(
|
adaptivePageRoute(
|
||||||
builder: (context) => ChooseGroupView(
|
builder: (context) => ChooseGroupView(
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
@@ -9,6 +10,7 @@ import 'package:tallee/core/custom_theme.dart';
|
|||||||
import 'package:tallee/core/enums.dart';
|
import 'package:tallee/core/enums.dart';
|
||||||
import 'package:tallee/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/settings_view/licenses_view.dart';
|
import 'package:tallee/presentation/views/main_menu/settings_view/licenses_view.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/tiles/settings_list_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/settings_list_tile.dart';
|
||||||
@@ -197,19 +199,23 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
padding: const EdgeInsets.only(bottom: 12),
|
padding: const EdgeInsets.only(bottom: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
spacing: 40,
|
spacing: 10,
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
HapticIconButton(
|
||||||
child: const Icon(Icons.language),
|
color: CustomTheme.textColor,
|
||||||
onTap: () => {
|
icon: const Icon(Icons.language),
|
||||||
|
onPressed: () async => {
|
||||||
|
await HapticFeedback.lightImpact(),
|
||||||
launchUrl(
|
launchUrl(
|
||||||
Uri.parse('https://liquid-dev.de'),
|
Uri.parse('https://liquid-dev.de'),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GestureDetector(
|
HapticIconButton(
|
||||||
child: const FaIcon(FontAwesomeIcons.github),
|
color: CustomTheme.textColor,
|
||||||
onTap: () => {
|
icon: const FaIcon(FontAwesomeIcons.github),
|
||||||
|
onPressed: () async => {
|
||||||
|
await HapticFeedback.lightImpact(),
|
||||||
launchUrl(
|
launchUrl(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
'https://github.com/liquiddevelopmentde',
|
'https://github.com/liquiddevelopmentde',
|
||||||
@@ -217,15 +223,19 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
GestureDetector(
|
HapticIconButton(
|
||||||
child: Icon(
|
color: CustomTheme.textColor,
|
||||||
|
icon: Icon(
|
||||||
Platform.isIOS
|
Platform.isIOS
|
||||||
? CupertinoIcons.mail_solid
|
? CupertinoIcons.mail_solid
|
||||||
: Icons.email,
|
: Icons.email,
|
||||||
),
|
),
|
||||||
onTap: () => launchUrl(
|
onPressed: () async => {
|
||||||
Uri.parse('mailto:hi@liquid-dev.de'),
|
await HapticFeedback.lightImpact(),
|
||||||
),
|
launchUrl(
|
||||||
|
Uri.parse('mailto:hi@liquid-dev.de'),
|
||||||
|
),
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -266,21 +276,42 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
void showImportSnackBar({
|
void showImportSnackBar({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required ImportResult result,
|
required ImportResult result,
|
||||||
}) {
|
}) async {
|
||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case ImportResult.success:
|
case ImportResult.success:
|
||||||
showSnackbar(context: context, message: loc.data_successfully_imported);
|
await HapticFeedback.successNotification();
|
||||||
|
if (context.mounted) {
|
||||||
|
showSnackbar(
|
||||||
|
context: context,
|
||||||
|
message: loc.data_successfully_imported,
|
||||||
|
);
|
||||||
|
}
|
||||||
case ImportResult.invalidSchema:
|
case ImportResult.invalidSchema:
|
||||||
showSnackbar(context: context, message: loc.invalid_schema);
|
await HapticFeedback.errorNotification();
|
||||||
|
if (context.mounted) {
|
||||||
|
showSnackbar(context: context, message: loc.invalid_schema);
|
||||||
|
}
|
||||||
case ImportResult.fileReadError:
|
case ImportResult.fileReadError:
|
||||||
showSnackbar(context: context, message: loc.error_reading_file);
|
await HapticFeedback.errorNotification();
|
||||||
|
if (context.mounted) {
|
||||||
|
showSnackbar(context: context, message: loc.error_reading_file);
|
||||||
|
}
|
||||||
case ImportResult.canceled:
|
case ImportResult.canceled:
|
||||||
showSnackbar(context: context, message: loc.import_canceled);
|
await HapticFeedback.errorNotification();
|
||||||
|
if (context.mounted) {
|
||||||
|
showSnackbar(context: context, message: loc.import_canceled);
|
||||||
|
}
|
||||||
case ImportResult.formatException:
|
case ImportResult.formatException:
|
||||||
showSnackbar(context: context, message: loc.format_exception);
|
await HapticFeedback.errorNotification();
|
||||||
|
if (context.mounted) {
|
||||||
|
showSnackbar(context: context, message: loc.format_exception);
|
||||||
|
}
|
||||||
case ImportResult.unknownException:
|
case ImportResult.unknownException:
|
||||||
showSnackbar(context: context, message: loc.unknown_exception);
|
await HapticFeedback.errorNotification();
|
||||||
|
if (context.mounted) {
|
||||||
|
showSnackbar(context: context, message: loc.unknown_exception);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,15 +322,27 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
void showExportSnackBar({
|
void showExportSnackBar({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required ExportResult result,
|
required ExportResult result,
|
||||||
}) {
|
}) async {
|
||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case ExportResult.success:
|
case ExportResult.success:
|
||||||
showSnackbar(context: context, message: loc.data_successfully_exported);
|
await HapticFeedback.successNotification();
|
||||||
|
if (context.mounted) {
|
||||||
|
showSnackbar(
|
||||||
|
context: context,
|
||||||
|
message: loc.data_successfully_exported,
|
||||||
|
);
|
||||||
|
}
|
||||||
case ExportResult.canceled:
|
case ExportResult.canceled:
|
||||||
showSnackbar(context: context, message: loc.export_canceled);
|
await HapticFeedback.errorNotification();
|
||||||
|
if (context.mounted) {
|
||||||
|
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,
|
||||||
|
|||||||
23
lib/presentation/widgets/buttons/haptic_back_button.dart
Normal file
23
lib/presentation/widgets/buttons/haptic_back_button.dart
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
|
|
||||||
|
class HapticBackButton extends StatelessWidget {
|
||||||
|
const HapticBackButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final iconData = switch (defaultTargetPlatform) {
|
||||||
|
TargetPlatform.iOS ||
|
||||||
|
TargetPlatform.macOS => Icons.arrow_back_ios_new_rounded,
|
||||||
|
_ => Icons.arrow_back_rounded,
|
||||||
|
};
|
||||||
|
|
||||||
|
return HapticIconButton(
|
||||||
|
icon: Icon(iconData),
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.of(context).maybePop();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
lib/presentation/widgets/buttons/haptic_close_button.dart
Normal file
23
lib/presentation/widgets/buttons/haptic_close_button.dart
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/haptic_icon_button.dart';
|
||||||
|
|
||||||
|
class HapticCloseButton extends StatelessWidget {
|
||||||
|
const HapticCloseButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final iconData = switch (defaultTargetPlatform) {
|
||||||
|
TargetPlatform.iOS || TargetPlatform.macOS => CupertinoIcons.xmark,
|
||||||
|
_ => Icons.close_rounded,
|
||||||
|
};
|
||||||
|
|
||||||
|
return HapticIconButton(
|
||||||
|
icon: Icon(iconData),
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.of(context).maybePop();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
51
lib/presentation/widgets/buttons/haptic_icon_button.dart
Normal file
51
lib/presentation/widgets/buttons/haptic_icon_button.dart
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
class HapticIconButton extends StatelessWidget {
|
||||||
|
const HapticIconButton({
|
||||||
|
super.key,
|
||||||
|
required this.icon,
|
||||||
|
required this.onPressed,
|
||||||
|
this.iconSize,
|
||||||
|
this.color,
|
||||||
|
this.padding,
|
||||||
|
this.alignment,
|
||||||
|
this.constraints,
|
||||||
|
this.style,
|
||||||
|
this.isSelected,
|
||||||
|
this.selectedIcon,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Widget icon;
|
||||||
|
final VoidCallback? onPressed;
|
||||||
|
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(
|
||||||
|
iconSize: iconSize,
|
||||||
|
highlightColor: Colors.transparent, //disable splash animation
|
||||||
|
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.
|
||||||
@@ -65,19 +66,27 @@ class _MainMenuButtonState extends State<MainMenuButton>
|
|||||||
onTapDown: (_) {
|
onTapDown: (_) {
|
||||||
_animationController.forward();
|
_animationController.forward();
|
||||||
if (widget.onLongPressed != null) {
|
if (widget.onLongPressed != null) {
|
||||||
_longPressTimer = Timer(const Duration(milliseconds: 400), () {
|
_longPressTimer = Timer(
|
||||||
_isLongPressing = true;
|
const Duration(milliseconds: 400),
|
||||||
widget.onLongPressed?.call();
|
() async {
|
||||||
_repeatTimer = Timer.periodic(
|
_isLongPressing = true;
|
||||||
const Duration(milliseconds: 250),
|
widget.onLongPressed?.call();
|
||||||
(_) => widget.onLongPressed?.call(),
|
await HapticFeedback.heavyImpact();
|
||||||
);
|
_repeatTimer = Timer.periodic(
|
||||||
});
|
const Duration(milliseconds: 250),
|
||||||
|
(_) async {
|
||||||
|
widget.onLongPressed?.call();
|
||||||
|
await HapticFeedback.heavyImpact();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onTapUp: (_) async {
|
onTapUp: (_) async {
|
||||||
_cancelTimers();
|
_cancelTimers();
|
||||||
if (mounted && !_isLongPressing) {
|
if (mounted && !_isLongPressing) {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
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,
|
||||||
|
|||||||
@@ -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/common.dart';
|
import 'package:tallee/core/common.dart';
|
||||||
import 'package:tallee/core/constants.dart';
|
import 'package:tallee/core/constants.dart';
|
||||||
@@ -143,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]);
|
||||||
@@ -197,7 +199,8 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
|||||||
text: suggestedPlayers[index].name,
|
text: suggestedPlayers[index].name,
|
||||||
suffixText: getNameCountText(suggestedPlayers[index]),
|
suffixText: getNameCountText(suggestedPlayers[index]),
|
||||||
icon: Icons.add,
|
icon: Icons.add,
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
setState(() {
|
setState(() {
|
||||||
// If the player is not already selected
|
// If the player is not already selected
|
||||||
if (!selectedPlayers.contains(
|
if (!selectedPlayers.contains(
|
||||||
@@ -294,8 +297,10 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
|||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
_handleSuccessfulPlayerCreation(createdPlayer);
|
_handleSuccessfulPlayerCreation(createdPlayer);
|
||||||
|
await HapticFeedback.successNotification();
|
||||||
showSnackBarMessage(loc.successfully_added_player(playerName));
|
showSnackBarMessage(loc.successfully_added_player(playerName));
|
||||||
} else {
|
} else {
|
||||||
|
await HapticFeedback.errorNotification();
|
||||||
showSnackBarMessage(loc.could_not_add_player(playerName));
|
showSnackBarMessage(loc.could_not_add_player(playerName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,14 @@ class _ChooseTileState extends State<ChooseTile> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: widget.onPressed,
|
onTap: widget.onPressed != null
|
||||||
|
? () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
if (widget.onPressed != null) {
|
||||||
|
widget.onPressed!.call();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
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/common.dart';
|
import 'package:tallee/core/common.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';
|
||||||
@@ -53,8 +54,18 @@ class GameTile extends StatelessWidget {
|
|||||||
final gameColor = badgeColor ?? getColorFromGameColor(GameColor.orange);
|
final gameColor = badgeColor ?? getColorFromGameColor(GameColor.orange);
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: onTap,
|
onTap: () async {
|
||||||
onLongPress: onLongPress,
|
await HapticFeedback.selectionClick();
|
||||||
|
if (onTap != null) {
|
||||||
|
onTap!.call();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLongPress: () async {
|
||||||
|
await HapticFeedback.heavyImpact();
|
||||||
|
if (onLongPress != null) {
|
||||||
|
onLongPress!.call();
|
||||||
|
}
|
||||||
|
},
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
|
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
|
||||||
decoration: !isHighlighted
|
decoration: !isHighlighted
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.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';
|
||||||
import 'package:tallee/data/models/group.dart';
|
import 'package:tallee/data/models/group.dart';
|
||||||
@@ -33,7 +34,12 @@ class _GroupTileState extends State<GroupTile> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: widget.onTap,
|
onTap: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
if (widget.onTap != null) {
|
||||||
|
widget.onTap!.call();
|
||||||
|
}
|
||||||
|
},
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
margin: CustomTheme.standardMargin,
|
margin: CustomTheme.standardMargin,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
|
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
|
||||||
|
|||||||
@@ -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/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart';
|
import 'package:tallee/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart';
|
||||||
import 'package:tallee/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
|
import 'package:tallee/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
|
||||||
@@ -15,8 +16,10 @@ class LicenseTile extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
Navigator.of(context).push(
|
final navigator = Navigator.of(context);
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
navigator.push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => LicenseDetailView(package: package),
|
builder: (context) => LicenseDetailView(package: package),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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/presentation/widgets/colored_icon_container.dart';
|
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
|
||||||
|
|
||||||
@@ -36,7 +37,10 @@ class SettingsListTile extends StatelessWidget {
|
|||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: MediaQuery.of(context).size.width * 0.95,
|
width: MediaQuery.of(context).size.width * 0.95,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: onPressed ?? () {},
|
onTap: () async {
|
||||||
|
await HapticFeedback.selectionClick();
|
||||||
|
onPressed?.call();
|
||||||
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||||
|
|||||||
Reference in New Issue
Block a user