diff --git a/assets/translations/en.json b/assets/translations/en.json index 87863ba812d671bc80c6cba6b3caa2e25520e340..00052ebc06d590d215b77244ae021930644344bf 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -1,6 +1,9 @@ { "app_name": "Reversi", + "page_home": "Home", + "page_game": "Game", + "settings_title": "Settings", "settings_label_theme": "Theme mode", diff --git a/assets/translations/fr.json b/assets/translations/fr.json index 2340d9e9b3cc2d6598b119ffe7a363efe791d793..062474ffa796d68a84e0b9c92781f4fabc56850e 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -1,6 +1,9 @@ { "app_name": "Reversi", + "page_home": "Accueil", + "page_game": "Jeu", + "settings_title": "Réglages", "settings_label_theme": "Thème de couleurs", diff --git a/fastlane/metadata/android/en-US/changelogs/23.txt b/fastlane/metadata/android/en-US/changelogs/23.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac2c90e221caf3cf01ebba168fb16a8f31c0253a --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/23.txt @@ -0,0 +1 @@ +Normalize Activity application architecture. diff --git a/fastlane/metadata/android/fr-FR/changelogs/23.txt b/fastlane/metadata/android/fr-FR/changelogs/23.txt new file mode 100644 index 0000000000000000000000000000000000000000..1d6843d89ba84ea4147528bc3d62d9ecf1a4a762 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/23.txt @@ -0,0 +1 @@ +Harmonisation des applications en Activity. diff --git a/icons/build_application_icons.sh b/icons/build_application_icons.sh deleted file mode 100755 index 27dbe2647fe4e6d562fbd99451716d1b7d448570..0000000000000000000000000000000000000000 --- a/icons/build_application_icons.sh +++ /dev/null @@ -1,118 +0,0 @@ -#! /bin/bash - -# Check dependencies -command -v inkscape >/dev/null 2>&1 || { echo >&2 "I require inkscape but it's not installed. Aborting."; exit 1; } -command -v scour >/dev/null 2>&1 || { echo >&2 "I require scour but it's not installed. Aborting."; exit 1; } -command -v optipng >/dev/null 2>&1 || { echo >&2 "I require optipng but it's not installed. Aborting."; exit 1; } - -CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" -BASE_DIR="$(dirname "${CURRENT_DIR}")" - -SOURCE_ICON="${CURRENT_DIR}/icon.svg" -SOURCE_FASTLANE="${CURRENT_DIR}/featureGraphic.svg" -SOURCE_LAUNCH_IMAGE="${CURRENT_DIR}/icon.svg" - -OPTIPNG_OPTIONS="-preserve -quiet -o7" - -if [ ! -f "${SOURCE_ICON}" ]; then - echo "Missing file: ${SOURCE_ICON}" -fi - -if [ ! -f "${SOURCE_FASTLANE}" ]; then - echo "Missing file: ${SOURCE_FASTLANE}" -fi - -if [ ! -f "${SOURCE_LAUNCH_IMAGE}" ]; then - echo "Missing file: ${SOURCE_LAUNCH_IMAGE}" -fi - -function optimize_svg() { - SVG="$1" - - cp ${SVG} ${SVG}.tmp - scour \ - --remove-descriptive-elements \ - --enable-id-stripping \ - --enable-viewboxing \ - --enable-comment-stripping \ - --nindent=4 \ - --quiet \ - -i ${SVG}.tmp \ - -o ${SVG} - rm ${SVG}.tmp -} - -# optimize source svg files -optimize_svg ${SOURCE_ICON} -optimize_svg ${SOURCE_FASTLANE} -optimize_svg ${SOURCE_LAUNCH_IMAGE} - -# build icons -function build_application_icon() { - ICON_SIZE="$1" - TARGET="$2" - - echo "Building ${TARGET}" - - TARGET_PNG="${TARGET}.png" - - inkscape \ - --export-width=${ICON_SIZE} \ - --export-height=${ICON_SIZE} \ - --export-filename=${TARGET_PNG} \ - ${SOURCE_ICON} - - optipng ${OPTIPNG_OPTIONS} ${TARGET_PNG} -} - -# build fastlane image -function build_fastlane_image() { - WIDTH="$1" - HEIGHT="$2" - TARGET="$3" - - echo "Building ${TARGET}" - - TARGET_PNG="${TARGET}.png" - - inkscape \ - --export-width=${WIDTH} \ - --export-height=${HEIGHT} \ - --export-filename=${TARGET_PNG} \ - ${SOURCE_FASTLANE} - - optipng ${OPTIPNG_OPTIONS} ${TARGET_PNG} -} - -# build launch images (splash screen) -function build_launch_image() { - ICON_SIZE="$1" - TARGET="$2" - - echo "Building ${TARGET}" - - TARGET_PNG="${TARGET}.png" - - inkscape \ - --export-width=${ICON_SIZE} \ - --export-height=${ICON_SIZE} \ - --export-filename=${TARGET_PNG} \ - ${SOURCE_LAUNCH_IMAGE} - - optipng ${OPTIPNG_OPTIONS} ${TARGET_PNG} -} - -build_application_icon 72 ${BASE_DIR}/android/app/src/main/res/mipmap-hdpi/ic_launcher -build_application_icon 48 ${BASE_DIR}/android/app/src/main/res/mipmap-mdpi/ic_launcher -build_application_icon 96 ${BASE_DIR}/android/app/src/main/res/mipmap-xhdpi/ic_launcher -build_application_icon 144 ${BASE_DIR}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher -build_application_icon 192 ${BASE_DIR}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher -build_application_icon 512 ${BASE_DIR}/fastlane/metadata/android/en-US/images/icon - -build_launch_image 72 ${BASE_DIR}/android/app/src/main/res/mipmap-hdpi/launch_image -build_launch_image 48 ${BASE_DIR}/android/app/src/main/res/mipmap-mdpi/launch_image -build_launch_image 96 ${BASE_DIR}/android/app/src/main/res/mipmap-xhdpi/launch_image -build_launch_image 144 ${BASE_DIR}/android/app/src/main/res/mipmap-xxhdpi/launch_image -build_launch_image 192 ${BASE_DIR}/android/app/src/main/res/mipmap-xxxhdpi/launch_image - -build_fastlane_image 1024 500 ${BASE_DIR}/fastlane/metadata/android/en-US/images/featureGraphic diff --git a/icons/build_repository_icons.sh b/icons/build_repository_icons.sh deleted file mode 100755 index 569a16a50dd3015a45c291a93305ff0f67f77c72..0000000000000000000000000000000000000000 --- a/icons/build_repository_icons.sh +++ /dev/null @@ -1,48 +0,0 @@ -#! /bin/bash - -# Check dependencies -command -v inkscape >/dev/null 2>&1 || { echo >&2 "I require inkscape but it's not installed. Aborting."; exit 1; } -command -v scour >/dev/null 2>&1 || { echo >&2 "I require scour but it's not installed. Aborting."; exit 1; } -command -v optipng >/dev/null 2>&1 || { echo >&2 "I require optipng but it's not installed. Aborting."; exit 1; } - -CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" -BASE_DIR="$(dirname "${CURRENT_DIR}")" - -SOURCE="${CURRENT_DIR}/icon.svg" -OPTIPNG_OPTIONS="-preserve -quiet -o7" - -# optimize svg -cp ${SOURCE} ${SOURCE}.tmp -scour \ - --remove-descriptive-elements \ - --enable-id-stripping \ - --enable-viewboxing \ - --enable-comment-stripping \ - --nindent=4 \ - -i ${SOURCE}.tmp \ - -o ${SOURCE} -rm ${SOURCE}.tmp - -# build icons -function build_icon() { - ICON_SIZE="$1" - TARGET="$2" - - TARGET_PNG="${TARGET}.png" - - inkscape \ - --export-width=${ICON_SIZE} \ - --export-height=${ICON_SIZE} \ - --export-filename=${TARGET_PNG} \ - ${SOURCE} - - optipng ${OPTIPNG_OPTIONS} ${TARGET_PNG} -} - - -build_icon 72 ${BASE_DIR}/android/app/src/main/res/mipmap-hdpi/ic_launcher -build_icon 48 ${BASE_DIR}/android/app/src/main/res/mipmap-mdpi/ic_launcher -build_icon 96 ${BASE_DIR}/android/app/src/main/res/mipmap-xhdpi/ic_launcher -build_icon 144 ${BASE_DIR}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher -build_icon 192 ${BASE_DIR}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher -build_icon 512 ${BASE_DIR}/fastlane/metadata/android/en-US/images/icon diff --git a/icons/button_back.svg b/icons/button_back.svg deleted file mode 100644 index 018d8b734d2932028fbfce1643c4e888ff1b45b1..0000000000000000000000000000000000000000 --- a/icons/button_back.svg +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path transform="matrix(1.3783 .61747 -.61747 1.3783 45.198 93.762)" d="m11.645-14.603-44.77-4.6003 26.369-36.472z" fill="#fff" stroke="#950e4f" stroke-linecap="round" stroke-linejoin="round" stroke-width="7.2832"/></svg> diff --git a/icons/button_delete_saved_game.svg b/icons/button_delete_saved_game.svg deleted file mode 100644 index c3f872e434052a6b4e7036b530ced8e6233508e4..0000000000000000000000000000000000000000 --- a/icons/button_delete_saved_game.svg +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path d="m76.652 23.303-3.6441 58.302c-0.28153 4.5103-4.0223 8.0241-8.5413 8.0241h-35.27c-4.5189 0-8.2598-3.5138-8.5413-8.0241l-3.6441-58.302h-5.4824c-1.7723 0-3.2093-1.437-3.2093-3.2093 0-1.773 1.437-3.2093 3.2093-3.2093h70.605c1.7723 0 3.2093 1.4363 3.2093 3.2093 0 1.7723-1.437 3.2093-3.2093 3.2093zm-6.8314 0h-45.979l3.0819 55.867c0.12535 2.268 2.0008 4.0433 4.2732 4.0433h31.268c2.2724 0 4.1478-1.7752 4.2732-4.0433zm-22.99 6.4188c1.6541 0 2.9952 1.3411 2.9952 2.9952v41.08c0 1.6541-1.3411 2.9952-2.9952 2.9952-1.6542 0-2.9952-1.3411-2.9952-2.9952v-41.08c0-1.6541 1.3411-2.9952 2.9952-2.9952zm-12.837 0c1.6756 0 3.0553 1.3181 3.1312 2.9921l1.8776 41.3c0.06665 1.4664-1.0681 2.7087-2.5345 2.7762-0.04011 0.0015-0.08024 0.0021-0.12108 0.0021-1.5595 0-2.8476-1.2193-2.9328-2.7774l-2.253-41.3c-0.08524-1.5646 1.114-2.9012 2.6779-2.9864 0.05157-0.0029 0.10317-0.0042 0.15474-0.0042zm25.675 0c1.5667 0 2.8361 1.2694 2.8361 2.8361 0 0.05156-6.87e-4 0.10317-0.0036 0.15474l-2.2416 41.088c-0.09171 1.6778-1.4786 2.991-3.1586 2.991-1.5667 0-2.8361-1.2694-2.8361-2.8361 0-0.05156 7.31e-4 -0.10315 0.0036-0.15474l2.2417-41.088c0.09172-1.6778 1.4786-2.991 3.1586-2.991zm-21.397-25.675h17.117c4.7265 0 8.5578 3.8313 8.5578 8.5578v4.2795h-34.231v-4.2795c0-4.7265 3.8313-8.5578 8.5578-8.5578zm0.42837 6.4188c-1.4184 0-2.5675 1.1491-2.5675 2.5675v3.8512h21.394v-3.8512c0-1.4184-1.1491-2.5675-2.5675-2.5675z" fill="#fff" fill-rule="evenodd" stroke="#050200"/></svg> diff --git a/icons/button_restart.svg b/icons/button_restart.svg deleted file mode 100644 index 630da9b7d6788ecee905f6ec60c36656c0134bfe..0000000000000000000000000000000000000000 --- a/icons/button_restart.svg +++ /dev/null @@ -1,3 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect x=".44662" y=".89101" width="92.772" height="91.894" ry="11.689" fill="#ee494c" stroke="#fff" stroke-width=".238"/><g fill="#fffefe" stroke="#a11010" stroke-width="4"><path d="m42.177 75.882-12.716 3.8216c-1.7371 0.48639-3.5437-0.48639-4.0996-2.154-0.48639-1.7371 0.48639-3.5437 2.154-4.0996l4.7249-1.3897c-8.616-5.0723-14.453-14.453-14.453-25.223 0-12.021 7.3653-22.374 17.788-26.821 2.154-0.90329 4.5859 0.69484 4.5859 2.9878 0 1.3202-0.76432 2.5014-1.9456 2.9878-8.1991 3.4742-13.897 11.465-13.897 20.845 0 8.477 4.7249 15.912 11.673 19.733l-1.6676-5.6282c-0.48639-1.7371 0.48639-3.5437 2.154-4.0996 1.7371-0.48639 3.5437 0.48639 4.0996 2.154l3.8216 12.716c0.48639 1.8066-0.48639 3.6132-2.2235 4.169z"/><path d="m66.079 20.226-4.7249 1.3897c8.6855 5.0723 14.522 14.453 14.522 25.223 0 12.021-7.3653 22.374-17.788 26.821-2.154 0.90329-4.5859-0.69484-4.5859-2.9878 0-1.3202 0.76432-2.5014 1.9456-2.9878 8.1991-3.4742 13.897-11.465 13.897-20.845 0-8.477-4.7249-15.912-11.673-19.733l1.6676 5.6282c0.48639 1.7371-0.48639 3.5437-2.154 4.0996-1.7371 0.48639-3.5437-0.48639-4.0996-2.154l-3.8216-12.716c-0.48639-1.7371 0.48639-3.5437 2.2235-4.0996l12.716-3.8911c1.7371-0.48639 3.5437 0.48639 4.0996 2.154 0.48639 1.7371-0.48639 3.6132-2.2235 4.0996z"/></g> -</svg> diff --git a/icons/button_resume_game.svg b/icons/button_resume_game.svg deleted file mode 100644 index 2bf973276aefa564ecff7d6149899298344819f9..0000000000000000000000000000000000000000 --- a/icons/button_resume_game.svg +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g transform="translate(-5.618)" fill="#fff" stroke="#105ea2" stroke-linecap="round" stroke-linejoin="round"><path transform="matrix(-1.3783 -.61747 .61747 -1.3783 55.567 -.086035)" d="m11.645-14.603-44.77-4.6003 26.369-36.472z" stroke-width="7.2832"/><path d="m15.535 12.852 2e-3 67.973z" stroke-width="11"/></g></svg> diff --git a/icons/button_start.svg b/icons/button_start.svg deleted file mode 100644 index 4d7634a9f3fb559e590ee965e1341ae2634bf80f..0000000000000000000000000000000000000000 --- a/icons/button_start.svg +++ /dev/null @@ -1,2 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><path transform="matrix(-1.3783 -.61747 .61747 -1.3783 46.954 -.086035)" d="m11.645-14.603-44.77-4.6003 26.369-36.472z" fill="#fff" stroke="#105ea2" stroke-linecap="round" stroke-linejoin="round" stroke-width="7.2832"/></svg> diff --git a/lib/ai/game_board_scorer.dart b/lib/ai/game_board_scorer.dart index 1f0d9502921dfba95b57337073ff3bbd70584e76..04dfca97c74d7695261ac23bca7768fbb93b2f0d 100644 --- a/lib/ai/game_board_scorer.dart +++ b/lib/ai/game_board_scorer.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:reversi/models/game/game_board.dart'; +import 'package:reversi/models/activity/game_board.dart'; class GameBoardScorer { // Values for each position on the board. diff --git a/lib/ai/move_finder.dart b/lib/ai/move_finder.dart index ca52de253a76250d4da6400d1ca229f31df307e5..5c5d11cf2a4c213442b45bc1026684a0c3ee7b3e 100644 --- a/lib/ai/move_finder.dart +++ b/lib/ai/move_finder.dart @@ -7,7 +7,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:reversi/ai/game_board_scorer.dart'; -import 'package:reversi/models/game/game_board.dart'; +import 'package:reversi/models/activity/game_board.dart'; class MoveSearchArgs { MoveSearchArgs({required this.board, required this.player, required this.numPlies}); diff --git a/lib/common/config/activity_page.dart b/lib/common/config/activity_page.dart new file mode 100644 index 0000000000000000000000000000000000000000..d8d600a08130d50922ee80ddfa1534bc7e58fb02 --- /dev/null +++ b/lib/common/config/activity_page.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; + +import 'package:reversi/common/ui/pages/game.dart'; +import 'package:reversi/common/ui/pages/parameters.dart'; + +class ActivityPageItem { + final String code; + final Icon icon; + final Widget page; + + const ActivityPageItem({ + required this.code, + required this.icon, + required this.page, + }); +} + +class ActivityPage { + static const bool displayBottomNavBar = false; + + static const indexHome = 0; + static const pageHome = ActivityPageItem( + code: 'page_home', + icon: Icon(UniconsLine.home), + page: PageParameters(), + ); + + static const indexGame = 1; + static const pageGame = ActivityPageItem( + code: 'page_game', + icon: Icon(UniconsLine.star), + page: PageGame(), + ); + + static const Map<int, ActivityPageItem> items = { + indexHome: pageHome, + indexGame: pageGame, + }; + + static int defaultPageIndex = indexHome; + + static bool isIndexAllowed(int pageIndex) { + return items.keys.contains(pageIndex); + } + + static Widget getWidget(int pageIndex) { + return items[pageIndex]?.page ?? pageHome.page; + } +} diff --git a/lib/common/config/screen.dart b/lib/common/config/screen.dart new file mode 100644 index 0000000000000000000000000000000000000000..010e8a1e7f5f03ee1cdf811af9c450fd04d91338 --- /dev/null +++ b/lib/common/config/screen.dart @@ -0,0 +1,55 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; + +import 'package:reversi/common/ui/screens/about.dart'; +import 'package:reversi/common/ui/screens/activity.dart'; +import 'package:reversi/common/ui/screens/settings.dart'; + +class ScreenItem { + final String code; + final Icon icon; + final Widget screen; + + const ScreenItem({ + required this.code, + required this.icon, + required this.screen, + }); +} + +class Screen { + static const indexActivity = 0; + static const screenActivity = ScreenItem( + code: 'screen_activity', + icon: Icon(UniconsLine.home), + screen: ScreenActivity(), + ); + + static const indexSettings = 1; + static const screenSettings = ScreenItem( + code: 'screen_settings', + icon: Icon(UniconsLine.setting), + screen: ScreenSettings(), + ); + + static const indexAbout = 2; + static const screenAbout = ScreenItem( + code: 'screen_about', + icon: Icon(UniconsLine.info_circle), + screen: ScreenAbout(), + ); + + static Map<int, ScreenItem> items = { + indexActivity: screenActivity, + indexSettings: screenSettings, + indexAbout: screenAbout, + }; + + static bool isIndexAllowed(int screenIndex) { + return items.keys.contains(screenIndex); + } + + static Widget getWidget(int screenIndex) { + return items[screenIndex]?.screen ?? screenActivity.screen; + } +} diff --git a/lib/common/cubit/nav/nav_cubit_pages.dart b/lib/common/cubit/nav/nav_cubit_pages.dart new file mode 100644 index 0000000000000000000000000000000000000000..27d83635ece17f8726976801b77d2600067c8cf8 --- /dev/null +++ b/lib/common/cubit/nav/nav_cubit_pages.dart @@ -0,0 +1,33 @@ +import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; + +import 'package:reversi/common/config/activity_page.dart'; + +class NavCubitPage extends HydratedCubit<int> { + NavCubitPage() : super(0); + + void updateIndex(int index) { + if (ActivityPage.isIndexAllowed(index)) { + emit(index); + } else { + emit(ActivityPage.indexHome); + } + } + + void goToPageHome() { + updateIndex(ActivityPage.indexHome); + } + + void goToPageGame() { + updateIndex(ActivityPage.indexGame); + } + + @override + int fromJson(Map<String, dynamic> json) { + return ActivityPage.indexHome; + } + + @override + Map<String, dynamic>? toJson(int state) { + return <String, int>{'index': state}; + } +} diff --git a/lib/common/cubit/nav/nav_cubit_screens.dart b/lib/common/cubit/nav/nav_cubit_screens.dart new file mode 100644 index 0000000000000000000000000000000000000000..3bafedf18387f7a30dcf6a5e1e5b4e70f740bb72 --- /dev/null +++ b/lib/common/cubit/nav/nav_cubit_screens.dart @@ -0,0 +1,37 @@ +import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; + +import 'package:reversi/common/config/screen.dart'; + +class NavCubitScreen extends HydratedCubit<int> { + NavCubitScreen() : super(0); + + void updateIndex(int index) { + if (Screen.isIndexAllowed(index)) { + emit(index); + } else { + goToScreenActivity(); + } + } + + void goToScreenActivity() { + emit(Screen.indexActivity); + } + + void goToScreenSettings() { + emit(Screen.indexSettings); + } + + void goToScreenAbout() { + emit(Screen.indexAbout); + } + + @override + int fromJson(Map<String, dynamic> json) { + return Screen.indexActivity; + } + + @override + Map<String, dynamic>? toJson(int state) { + return <String, int>{'index': state}; + } +} diff --git a/lib/common/ui/nav/bottom_nav_bar.dart b/lib/common/ui/nav/bottom_nav_bar.dart new file mode 100644 index 0000000000000000000000000000000000000000..b47fd8a284674eb7da65f519b898027c3c9f1216 --- /dev/null +++ b/lib/common/ui/nav/bottom_nav_bar.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; + +import 'package:reversi/common/config/activity_page.dart'; +import 'package:reversi/common/cubit/nav/nav_cubit_pages.dart'; + +class BottomNavBar extends StatelessWidget { + const BottomNavBar({super.key}); + + @override + Widget build(BuildContext context) { + return Card( + margin: const EdgeInsets.only(top: 1, right: 4, left: 4), + elevation: 4, + shadowColor: Theme.of(context).colorScheme.shadow, + color: Theme.of(context).colorScheme.surfaceContainerHighest, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), + ), + child: BlocBuilder<NavCubitPage, int>(builder: (BuildContext context, int state) { + final List<BottomNavigationBarItem> items = []; + + ActivityPage.items.forEach((int pageIndex, ActivityPageItem item) { + items.add(BottomNavigationBarItem( + icon: item.icon, + label: tr(item.code), + )); + }); + + return BottomNavigationBar( + currentIndex: state, + onTap: (int index) => BlocProvider.of<NavCubitPage>(context).updateIndex(index), + type: BottomNavigationBarType.fixed, + elevation: 0, + backgroundColor: Colors.transparent, + selectedItemColor: Theme.of(context).colorScheme.primary, + unselectedItemColor: Theme.of(context).textTheme.bodySmall!.color, + items: items, + ); + }), + ); + } +} diff --git a/lib/ui/widgets/global_app_bar.dart b/lib/common/ui/nav/global_app_bar.dart similarity index 60% rename from lib/ui/widgets/global_app_bar.dart rename to lib/common/ui/nav/global_app_bar.dart index 1e7ecf6d73e69a68470f4dc4087d964533c6c36a..18f79a10c00fcbb1a994bc20f94490fb4fe3caf7 100644 --- a/lib/ui/widgets/global_app_bar.dart +++ b/lib/common/ui/nav/global_app_bar.dart @@ -1,30 +1,33 @@ import 'package:flutter/material.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -import 'package:reversi/config/menu.dart'; -import 'package:reversi/cubit/game_cubit.dart'; -import 'package:reversi/cubit/nav_cubit.dart'; -import 'package:reversi/models/game/game.dart'; +import 'package:reversi/common/config/screen.dart'; +import 'package:reversi/common/cubit/nav/nav_cubit_pages.dart'; +import 'package:reversi/common/cubit/nav/nav_cubit_screens.dart'; + +import 'package:reversi/cubit/activity/activity_cubit.dart'; +import 'package:reversi/models/activity/activity.dart'; class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget { const GlobalAppBar({super.key}); @override Widget build(BuildContext context) { - return BlocBuilder<GameCubit, GameState>( - builder: (BuildContext context, GameState gameState) { - return BlocBuilder<NavCubit, int>( + return BlocBuilder<ActivityCubit, ActivityState>( + builder: (BuildContext context, ActivityState activityState) { + return BlocBuilder<NavCubitScreen, int>( builder: (BuildContext context, int pageIndex) { - final Game currentGame = gameState.currentGame; + final Activity currentActivity = activityState.currentActivity; final List<Widget> menuActions = []; - if (currentGame.isRunning && !currentGame.isFinished) { + if (currentActivity.isRunning && !currentActivity.isFinished) { menuActions.add(StyledButton( color: Colors.red, onPressed: () {}, onLongPress: () { - BlocProvider.of<GameCubit>(context).quitGame(); + BlocProvider.of<ActivityCubit>(context).quitActivity(); + BlocProvider.of<NavCubitPage>(context).goToPageHome(); }, child: const Image( image: AssetImage('assets/ui/button_back.png'), @@ -32,38 +35,38 @@ class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget { ), )); } else { - if (pageIndex == Menu.indexGame) { + if (pageIndex == Screen.indexActivity) { // go to Settings page menuActions.add(ElevatedButton( onPressed: () { - BlocProvider.of<NavCubit>(context).goToSettingsPage(); + BlocProvider.of<NavCubitScreen>(context).goToScreenSettings(); }, style: ElevatedButton.styleFrom( shape: const CircleBorder(), ), - child: Menu.menuItemSettings.icon, + child: Screen.screenSettings.icon, )); // go to About page menuActions.add(ElevatedButton( onPressed: () { - BlocProvider.of<NavCubit>(context).goToAboutPage(); + BlocProvider.of<NavCubitScreen>(context).goToScreenAbout(); }, style: ElevatedButton.styleFrom( shape: const CircleBorder(), ), - child: Menu.menuItemAbout.icon, + child: Screen.screenAbout.icon, )); } else { // back to Home page menuActions.add(ElevatedButton( onPressed: () { - BlocProvider.of<NavCubit>(context).goToGamePage(); + BlocProvider.of<NavCubitScreen>(context).goToScreenActivity(); }, style: ElevatedButton.styleFrom( shape: const CircleBorder(), ), - child: Menu.menuItemGame.icon, + child: Screen.screenActivity.icon, )); } } diff --git a/lib/ui/layouts/game_layout.dart b/lib/common/ui/pages/game.dart similarity index 87% rename from lib/ui/layouts/game_layout.dart rename to lib/common/ui/pages/game.dart index 45d1958818a712cb090ecc8a4f0439b337cfceae..393140881f7cc534e1317c48b8103b02d82dd11e 100644 --- a/lib/ui/layouts/game_layout.dart +++ b/lib/common/ui/pages/game.dart @@ -2,8 +2,8 @@ import 'package:flutter/material.dart'; import 'package:reversi/ui/widgets/game/game_board.dart'; -class GameLayout extends StatelessWidget { - const GameLayout({super.key}); +class PageGame extends StatelessWidget { + const PageGame({super.key}); @override Widget build(BuildContext context) { diff --git a/lib/common/ui/pages/parameters.dart b/lib/common/ui/pages/parameters.dart new file mode 100644 index 0000000000000000000000000000000000000000..bfb7f4ff552b60bbcb35acc18f119bbece14d927 --- /dev/null +++ b/lib/common/ui/pages/parameters.dart @@ -0,0 +1,148 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; + +import 'package:reversi/common/ui/parameters/parameter_widget.dart'; + +import 'package:reversi/config/default_activity_settings.dart'; +import 'package:reversi/config/default_global_settings.dart'; +import 'package:reversi/cubit/activity/activity_cubit.dart'; +import 'package:reversi/cubit/settings/settings_activity_cubit.dart'; +import 'package:reversi/cubit/settings/settings_global_cubit.dart'; +import 'package:reversi/models/activity/activity.dart'; +import 'package:reversi/ui/widgets/actions/button_delete_saved_game.dart'; +import 'package:reversi/ui/widgets/actions/button_game_start_new.dart'; +import 'package:reversi/ui/widgets/actions/button_resume_saved_game.dart'; + +class PageParameters extends StatelessWidget { + const PageParameters({super.key}); + + final double separatorHeight = 8.0; + + @override + Widget build(BuildContext context) { + return BlocBuilder<ActivityCubit, ActivityState>( + builder: (BuildContext context, ActivityState activityState) { + final Activity currentActivity = activityState.currentActivity; + + final List<Widget> lines = []; + + // Game settings + for (String code in DefaultActivitySettings.availableParameters) { + lines.add(Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: buildParametersLine( + code: code, + isGlobal: false, + ), + )); + + lines.add(SizedBox(height: separatorHeight)); + } + + lines.add(Expanded( + child: SizedBox(height: separatorHeight), + )); + + if (currentActivity.canBeResumed == false) { + // Start new game + lines.add( + const AspectRatio( + aspectRatio: 3, + child: StartNewGameButton(), + ), + ); + } else { + // Resume game + lines.add(const AspectRatio( + aspectRatio: 3, + child: ResumeSavedGameButton(), + )); + // Delete saved game + lines.add(SizedBox.square( + dimension: MediaQuery.of(context).size.width / 5, + child: const DeleteSavedGameButton(), + )); + } + + lines.add(SizedBox(height: separatorHeight)); + + // Global settings + for (String code in DefaultGlobalSettings.availableParameters) { + lines.add(Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: buildParametersLine( + code: code, + isGlobal: true, + ), + )); + + lines.add(SizedBox(height: separatorHeight)); + } + + return Column( + children: lines, + ); + }, + ); + } + + List<Widget> buildParametersLine({ + required String code, + required bool isGlobal, + }) { + final List<Widget> parameterButtons = []; + + final List<String> availableValues = isGlobal + ? DefaultGlobalSettings.getAvailableValues(code) + : DefaultActivitySettings.getAvailableValues(code); + + if (availableValues.length <= 1) { + return []; + } + + for (String value in availableValues) { + final Widget parameterButton = BlocBuilder<ActivitySettingsCubit, ActivitySettingsState>( + builder: (BuildContext context, ActivitySettingsState activitySettingsState) { + return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>( + builder: (BuildContext context, GlobalSettingsState globalSettingsState) { + final ActivitySettingsCubit activitySettingsCubit = + BlocProvider.of<ActivitySettingsCubit>(context); + final GlobalSettingsCubit globalSettingsCubit = + BlocProvider.of<GlobalSettingsCubit>(context); + + final String currentValue = isGlobal + ? globalSettingsCubit.getParameterValue(code) + : activitySettingsCubit.getParameterValue(code); + + final bool isSelected = (value == currentValue); + + final double displayWidth = MediaQuery.of(context).size.width; + final double itemWidth = displayWidth / availableValues.length - 4; + + return SizedBox.square( + dimension: itemWidth, + child: ParameterWidget( + code: code, + value: value, + isSelected: isSelected, + size: itemWidth, + activitySettings: activitySettingsState.settings, + globalSettings: globalSettingsState.settings, + onPressed: () { + isGlobal + ? globalSettingsCubit.setParameterValue(code, value) + : activitySettingsCubit.setParameterValue(code, value); + }, + ), + ); + }, + ); + }, + ); + + parameterButtons.add(parameterButton); + } + + return parameterButtons; + } +} diff --git a/lib/ui/parameters/parameter_painter.dart b/lib/common/ui/parameters/parameter_painter.dart similarity index 91% rename from lib/ui/parameters/parameter_painter.dart rename to lib/common/ui/parameters/parameter_painter.dart index b0832cc7e80da10662ff98270fce0861c36c2009..2c9afc3d35e3bf5ce78f965471711c65c9872225 100644 --- a/lib/ui/parameters/parameter_painter.dart +++ b/lib/common/ui/parameters/parameter_painter.dart @@ -3,20 +3,20 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -import 'package:reversi/models/settings/settings_game.dart'; +import 'package:reversi/models/settings/settings_activity.dart'; import 'package:reversi/models/settings/settings_global.dart'; class ParameterPainter extends CustomPainter { const ParameterPainter({ required this.code, required this.value, - required this.gameSettings, + required this.activitySettings, required this.globalSettings, }); final String code; final String value; - final GameSettings gameSettings; + final ActivitySettings activitySettings; final GlobalSettings globalSettings; @override diff --git a/lib/ui/parameters/parameter_widget.dart b/lib/common/ui/parameters/parameter_widget.dart similarity index 91% rename from lib/ui/parameters/parameter_widget.dart rename to lib/common/ui/parameters/parameter_widget.dart index c18f8907468b877dd8724d43c7b2d8eda1d94c6f..c572f5f541124e83a4cd430e3388248fd0832df6 100644 --- a/lib/ui/parameters/parameter_widget.dart +++ b/lib/common/ui/parameters/parameter_widget.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -import 'package:reversi/models/settings/settings_game.dart'; +import 'package:reversi/models/settings/settings_activity.dart'; import 'package:reversi/models/settings/settings_global.dart'; class ParameterWidget extends StatelessWidget { @@ -11,7 +11,7 @@ class ParameterWidget extends StatelessWidget { required this.value, required this.isSelected, required this.size, - required this.gameSettings, + required this.activitySettings, required this.globalSettings, required this.onPressed, }); @@ -20,7 +20,7 @@ class ParameterWidget extends StatelessWidget { final String value; final bool isSelected; final double size; - final GameSettings gameSettings; + final ActivitySettings activitySettings; final GlobalSettings globalSettings; final VoidCallback onPressed; diff --git a/lib/ui/screens/page_about.dart b/lib/common/ui/screens/about.dart similarity index 93% rename from lib/ui/screens/page_about.dart rename to lib/common/ui/screens/about.dart index ab73e304b8138295f6669330b928e0d1d0263565..f7a14a9a7e574a7b6f9ed181f38d08ba8c2285fe 100644 --- a/lib/ui/screens/page_about.dart +++ b/lib/common/ui/screens/about.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -class PageAbout extends StatelessWidget { - const PageAbout({super.key}); +class ScreenAbout extends StatelessWidget { + const ScreenAbout({super.key}); @override Widget build(BuildContext context) { diff --git a/lib/common/ui/screens/activity.dart b/lib/common/ui/screens/activity.dart new file mode 100644 index 0000000000000000000000000000000000000000..0ac02b9722840098d3e6d47ebf2832d2394e80a4 --- /dev/null +++ b/lib/common/ui/screens/activity.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; + +import 'package:reversi/common/config/activity_page.dart'; +import 'package:reversi/common/cubit/nav/nav_cubit_pages.dart'; + +class ScreenActivity extends StatelessWidget { + const ScreenActivity({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder<NavCubitPage, int>( + builder: (BuildContext context, int pageIndex) { + return ActivityPage.getWidget(pageIndex); + }, + ); + } +} diff --git a/lib/ui/screens/page_settings.dart b/lib/common/ui/screens/settings.dart similarity index 87% rename from lib/ui/screens/page_settings.dart rename to lib/common/ui/screens/settings.dart index 50964ef462b6e3e411347cab4e966afb0f505008..7981b1c6becc4f5b925c3058b05423750d80f62e 100644 --- a/lib/ui/screens/page_settings.dart +++ b/lib/common/ui/screens/settings.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -class PageSettings extends StatelessWidget { - const PageSettings({super.key}); +class ScreenSettings extends StatelessWidget { + const ScreenSettings({super.key}); @override Widget build(BuildContext context) { diff --git a/lib/config/application_config.dart b/lib/config/application_config.dart new file mode 100644 index 0000000000000000000000000000000000000000..2598e37d553908dad7b3d9404d03c79aa9ca61ce --- /dev/null +++ b/lib/config/application_config.dart @@ -0,0 +1,3 @@ +class ApplicationConfig { + static const String appTitle = 'Reversi'; +} diff --git a/lib/config/default_game_settings.dart b/lib/config/default_activity_settings.dart similarity index 88% rename from lib/config/default_game_settings.dart rename to lib/config/default_activity_settings.dart index 488f63aa09cd5179136c56bd049e0788b489a3ac..aed569bf987ce003926a899dbddf9d81298621bf 100644 --- a/lib/config/default_game_settings.dart +++ b/lib/config/default_activity_settings.dart @@ -1,6 +1,6 @@ import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -class DefaultGameSettings { +class DefaultActivitySettings { // available game parameters codes static const String parameterCodeGameMode = 'gameMode'; static const String parameterCodeDifficultyLevel = 'difficultyLevel'; @@ -29,9 +29,9 @@ class DefaultGameSettings { static List<String> getAvailableValues(String parameterCode) { switch (parameterCode) { case parameterCodeGameMode: - return DefaultGameSettings.allowedGameModeValues; + return DefaultActivitySettings.allowedGameModeValues; case parameterCodeDifficultyLevel: - return DefaultGameSettings.allowedDifficultyLevelValues; + return DefaultActivitySettings.allowedDifficultyLevelValues; } printlog('Did not find any available value for game parameter "$parameterCode".'); diff --git a/lib/config/menu.dart b/lib/config/menu.dart deleted file mode 100644 index febed649bd1d3938359fe487c47c9f77d3e4ab64..0000000000000000000000000000000000000000 --- a/lib/config/menu.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; - -import 'package:reversi/ui/screens/page_about.dart'; -import 'package:reversi/ui/screens/page_game.dart'; -import 'package:reversi/ui/screens/page_settings.dart'; - -class MenuItem { - final Icon icon; - final Widget page; - - const MenuItem({ - required this.icon, - required this.page, - }); -} - -class Menu { - static const indexGame = 0; - static const menuItemGame = MenuItem( - icon: Icon(UniconsLine.home), - page: PageGame(), - ); - - static const indexSettings = 1; - static const menuItemSettings = MenuItem( - icon: Icon(UniconsLine.setting), - page: PageSettings(), - ); - - static const indexAbout = 2; - static const menuItemAbout = MenuItem( - icon: Icon(UniconsLine.info_circle), - page: PageAbout(), - ); - - static Map<int, MenuItem> items = { - indexGame: menuItemGame, - indexSettings: menuItemSettings, - indexAbout: menuItemAbout, - }; - - static bool isIndexAllowed(int pageIndex) { - return items.keys.contains(pageIndex); - } - - static Widget getPageWidget(int pageIndex) { - return items[pageIndex]?.page ?? menuItemGame.page; - } - - static int itemsCount = Menu.items.length; -} diff --git a/lib/config/styling.dart b/lib/config/styling.dart index 888f74f88e1b248e7c1d7d85200ac21b5f7b1184..eddfe1a4eef5fdb5510632d54001ec8c35c4cec8 100644 --- a/lib/config/styling.dart +++ b/lib/config/styling.dart @@ -1,6 +1,6 @@ import 'package:flutter/widgets.dart'; -import 'package:reversi/models/game/game_board.dart'; +import 'package:reversi/models/activity/game_board.dart'; abstract class Styling { // **** GRADIENTS AND COLORS **** diff --git a/lib/cubit/activity/activity_cubit.dart b/lib/cubit/activity/activity_cubit.dart new file mode 100644 index 0000000000000000000000000000000000000000..46295a62f15dfa74c11c7773e9ddb468b8cd1441 --- /dev/null +++ b/lib/cubit/activity/activity_cubit.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; + +import 'package:reversi/models/activity/activity.dart'; +import 'package:reversi/models/settings/settings_activity.dart'; +import 'package:reversi/models/settings/settings_global.dart'; + +part 'activity_state.dart'; + +class ActivityCubit extends HydratedCubit<ActivityState> { + ActivityCubit() + : super(ActivityState( + currentActivity: Activity.createNull(), + )); + + void updateState(Activity activity) { + emit(ActivityState( + currentActivity: activity, + )); + } + + void refresh() { + final Activity activity = Activity( + // Settings + activitySettings: state.currentActivity.activitySettings, + globalSettings: state.currentActivity.globalSettings, + // State + isRunning: state.currentActivity.isRunning, + isStarted: state.currentActivity.isStarted, + isFinished: state.currentActivity.isFinished, + animationInProgress: state.currentActivity.animationInProgress, + // Base data + gameModel: state.currentActivity.gameModel, + // Game data + score: state.currentActivity.score, + ); + // game.dump(); + + updateState(activity); + } + + void startNewActivity({ + required ActivitySettings activitySettings, + required GlobalSettings globalSettings, + }) { + final Activity newActivity = Activity.createNew( + // Settings + activitySettings: activitySettings, + globalSettings: globalSettings, + ); + + newActivity.dump(); + + updateState(newActivity); + refresh(); + } + + void quitActivity() { + state.currentActivity.isRunning = false; + refresh(); + } + + void resumeSavedActivity() { + state.currentActivity.isRunning = true; + refresh(); + } + + void deleteSavedActivity() { + state.currentActivity.isRunning = false; + state.currentActivity.isFinished = true; + refresh(); + } + + @override + ActivityState? fromJson(Map<String, dynamic> json) { + final Activity currentActivity = json['currentActivity'] as Activity; + + return ActivityState( + currentActivity: currentActivity, + ); + } + + @override + Map<String, dynamic>? toJson(ActivityState state) { + return <String, dynamic>{ + 'currentActivity': state.currentActivity.toJson(), + }; + } +} diff --git a/lib/cubit/activity/activity_state.dart b/lib/cubit/activity/activity_state.dart new file mode 100644 index 0000000000000000000000000000000000000000..887b45e4255fd7de1cc7744569d82a38a66602f2 --- /dev/null +++ b/lib/cubit/activity/activity_state.dart @@ -0,0 +1,15 @@ +part of 'activity_cubit.dart'; + +@immutable +class ActivityState extends Equatable { + const ActivityState({ + required this.currentActivity, + }); + + final Activity currentActivity; + + @override + List<dynamic> get props => <dynamic>[ + currentActivity, + ]; +} diff --git a/lib/cubit/game_cubit.dart b/lib/cubit/game_cubit.dart deleted file mode 100644 index 8a9617fe293b3bba39753c7ad236f6b45f17a546..0000000000000000000000000000000000000000 --- a/lib/cubit/game_cubit.dart +++ /dev/null @@ -1,89 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; - -import 'package:reversi/models/game/game.dart'; -import 'package:reversi/models/settings/settings_game.dart'; -import 'package:reversi/models/settings/settings_global.dart'; - -part 'game_state.dart'; - -class GameCubit extends HydratedCubit<GameState> { - GameCubit() - : super(GameState( - currentGame: Game.createNull(), - )); - - void updateState(Game game) { - emit(GameState( - currentGame: game, - )); - } - - void refresh() { - final Game game = Game( - // Settings - gameSettings: state.currentGame.gameSettings, - globalSettings: state.currentGame.globalSettings, - // State - isRunning: state.currentGame.isRunning, - isStarted: state.currentGame.isStarted, - isFinished: state.currentGame.isFinished, - animationInProgress: state.currentGame.animationInProgress, - // Base data - gameModel: state.currentGame.gameModel, - // Game data - score: state.currentGame.score, - ); - // game.dump(); - - updateState(game); - } - - void startNewGame({ - required GameSettings gameSettings, - required GlobalSettings globalSettings, - }) { - final Game newGame = Game.createNew( - // Settings - gameSettings: gameSettings, - globalSettings: globalSettings, - ); - - newGame.dump(); - - updateState(newGame); - refresh(); - } - - void quitGame() { - state.currentGame.isRunning = false; - refresh(); - } - - void resumeSavedGame() { - state.currentGame.isRunning = true; - refresh(); - } - - void deleteSavedGame() { - state.currentGame.isRunning = false; - state.currentGame.isFinished = true; - refresh(); - } - - @override - GameState? fromJson(Map<String, dynamic> json) { - final Game currentGame = json['currentGame'] as Game; - - return GameState( - currentGame: currentGame, - ); - } - - @override - Map<String, dynamic>? toJson(GameState state) { - return <String, dynamic>{ - 'currentGame': state.currentGame.toJson(), - }; - } -} diff --git a/lib/cubit/game_state.dart b/lib/cubit/game_state.dart deleted file mode 100644 index 00e211668c3269255926939324355792abd61c41..0000000000000000000000000000000000000000 --- a/lib/cubit/game_state.dart +++ /dev/null @@ -1,15 +0,0 @@ -part of 'game_cubit.dart'; - -@immutable -class GameState extends Equatable { - const GameState({ - required this.currentGame, - }); - - final Game currentGame; - - @override - List<dynamic> get props => <dynamic>[ - currentGame, - ]; -} diff --git a/lib/cubit/nav_cubit.dart b/lib/cubit/nav_cubit.dart deleted file mode 100644 index 30c64fdc8b88d82ee2adca51ee25c98bdec3aa87..0000000000000000000000000000000000000000 --- a/lib/cubit/nav_cubit.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; - -import 'package:reversi/config/menu.dart'; - -class NavCubit extends HydratedCubit<int> { - NavCubit() : super(0); - - void updateIndex(int index) { - if (Menu.isIndexAllowed(index)) { - emit(index); - } else { - goToGamePage(); - } - } - - void goToGamePage() { - emit(Menu.indexGame); - } - - void goToSettingsPage() { - emit(Menu.indexSettings); - } - - void goToAboutPage() { - emit(Menu.indexAbout); - } - - @override - int fromJson(Map<String, dynamic> json) { - return Menu.indexGame; - } - - @override - Map<String, dynamic>? toJson(int state) { - return <String, int>{'pageIndex': state}; - } -} diff --git a/lib/cubit/settings/settings_activity_cubit.dart b/lib/cubit/settings/settings_activity_cubit.dart new file mode 100644 index 0000000000000000000000000000000000000000..b332839b5ae4709f1852594c9b7ca5f30b501b94 --- /dev/null +++ b/lib/cubit/settings/settings_activity_cubit.dart @@ -0,0 +1,73 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; + +import 'package:reversi/config/default_activity_settings.dart'; +import 'package:reversi/models/settings/settings_activity.dart'; + +part 'settings_activity_state.dart'; + +class ActivitySettingsCubit extends HydratedCubit<ActivitySettingsState> { + ActivitySettingsCubit() + : super(ActivitySettingsState(settings: ActivitySettings.createDefault())); + + void setValues({ + String? itemsCount, + String? timerValue, + }) { + emit( + ActivitySettingsState( + settings: ActivitySettings( + itemsCount: itemsCount ?? state.settings.itemsCount, + timerValue: timerValue ?? state.settings.timerValue, + ), + ), + ); + } + + String getParameterValue(String code) { + switch (code) { + case DefaultActivitySettings.parameterCodeGameMode: + return ActivitySettings.getItemsCountValueFromUnsafe(state.settings.itemsCount); + case DefaultActivitySettings.parameterCodeDifficultyLevel: + return ActivitySettings.getTimerValueFromUnsafe(state.settings.timerValue); + } + + return ''; + } + + void setParameterValue(String code, String value) { + final String itemsCount = code == DefaultActivitySettings.parameterCodeGameMode + ? value + : getParameterValue(DefaultActivitySettings.parameterCodeGameMode); + final String timerValue = code == DefaultActivitySettings.parameterCodeDifficultyLevel + ? value + : getParameterValue(DefaultActivitySettings.parameterCodeDifficultyLevel); + + setValues( + itemsCount: itemsCount, + timerValue: timerValue, + ); + } + + @override + ActivitySettingsState? fromJson(Map<String, dynamic> json) { + final String itemsCount = json[DefaultActivitySettings.parameterCodeGameMode] as String; + final String timerValue = + json[DefaultActivitySettings.parameterCodeDifficultyLevel] as String; + + return ActivitySettingsState( + settings: ActivitySettings( + itemsCount: itemsCount, + timerValue: timerValue, + ), + ); + } + + @override + Map<String, dynamic>? toJson(ActivitySettingsState state) { + return <String, dynamic>{ + DefaultActivitySettings.parameterCodeGameMode: state.settings.itemsCount, + DefaultActivitySettings.parameterCodeDifficultyLevel: state.settings.timerValue, + }; + } +} diff --git a/lib/cubit/settings/settings_activity_state.dart b/lib/cubit/settings/settings_activity_state.dart new file mode 100644 index 0000000000000000000000000000000000000000..2b2de42011634e81ae9e6f8bcaa1577f239c778b --- /dev/null +++ b/lib/cubit/settings/settings_activity_state.dart @@ -0,0 +1,15 @@ +part of 'settings_activity_cubit.dart'; + +@immutable +class ActivitySettingsState extends Equatable { + const ActivitySettingsState({ + required this.settings, + }); + + final ActivitySettings settings; + + @override + List<dynamic> get props => <dynamic>[ + settings, + ]; +} diff --git a/lib/cubit/settings_global_cubit.dart b/lib/cubit/settings/settings_global_cubit.dart similarity index 100% rename from lib/cubit/settings_global_cubit.dart rename to lib/cubit/settings/settings_global_cubit.dart diff --git a/lib/cubit/settings_global_state.dart b/lib/cubit/settings/settings_global_state.dart similarity index 100% rename from lib/cubit/settings_global_state.dart rename to lib/cubit/settings/settings_global_state.dart diff --git a/lib/cubit/settings_game_cubit.dart b/lib/cubit/settings_game_cubit.dart deleted file mode 100644 index 196c6eda0285156f6d6175936d73ddfcd1c3f4d9..0000000000000000000000000000000000000000 --- a/lib/cubit/settings_game_cubit.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; - -import 'package:reversi/config/default_game_settings.dart'; -import 'package:reversi/models/settings/settings_game.dart'; - -part 'settings_game_state.dart'; - -class GameSettingsCubit extends HydratedCubit<GameSettingsState> { - GameSettingsCubit() : super(GameSettingsState(settings: GameSettings.createDefault())); - - void setValues({ - String? itemsCount, - String? timerValue, - }) { - emit( - GameSettingsState( - settings: GameSettings( - itemsCount: itemsCount ?? state.settings.itemsCount, - timerValue: timerValue ?? state.settings.timerValue, - ), - ), - ); - } - - String getParameterValue(String code) { - switch (code) { - case DefaultGameSettings.parameterCodeGameMode: - return GameSettings.getItemsCountValueFromUnsafe(state.settings.itemsCount); - case DefaultGameSettings.parameterCodeDifficultyLevel: - return GameSettings.getTimerValueFromUnsafe(state.settings.timerValue); - } - - return ''; - } - - void setParameterValue(String code, String value) { - final String itemsCount = code == DefaultGameSettings.parameterCodeGameMode - ? value - : getParameterValue(DefaultGameSettings.parameterCodeGameMode); - final String timerValue = code == DefaultGameSettings.parameterCodeDifficultyLevel - ? value - : getParameterValue(DefaultGameSettings.parameterCodeDifficultyLevel); - - setValues( - itemsCount: itemsCount, - timerValue: timerValue, - ); - } - - @override - GameSettingsState? fromJson(Map<String, dynamic> json) { - final String itemsCount = json[DefaultGameSettings.parameterCodeGameMode] as String; - final String timerValue = json[DefaultGameSettings.parameterCodeDifficultyLevel] as String; - - return GameSettingsState( - settings: GameSettings( - itemsCount: itemsCount, - timerValue: timerValue, - ), - ); - } - - @override - Map<String, dynamic>? toJson(GameSettingsState state) { - return <String, dynamic>{ - DefaultGameSettings.parameterCodeGameMode: state.settings.itemsCount, - DefaultGameSettings.parameterCodeDifficultyLevel: state.settings.timerValue, - }; - } -} diff --git a/lib/cubit/settings_game_state.dart b/lib/cubit/settings_game_state.dart deleted file mode 100644 index 5acd85b44ba541e1c5e9c26af1c4be26a385b9ed..0000000000000000000000000000000000000000 --- a/lib/cubit/settings_game_state.dart +++ /dev/null @@ -1,15 +0,0 @@ -part of 'settings_game_cubit.dart'; - -@immutable -class GameSettingsState extends Equatable { - const GameSettingsState({ - required this.settings, - }); - - final GameSettings settings; - - @override - List<dynamic> get props => <dynamic>[ - settings, - ]; -} diff --git a/lib/game/game_engine.dart b/lib/game/game_engine.dart index 4be8afc2d89347a1fd5fb97be1dc9295c9b14cb6..2b4dda438f7794e53a2ea9074f1059f0a2945ba6 100644 --- a/lib/game/game_engine.dart +++ b/lib/game/game_engine.dart @@ -9,8 +9,8 @@ import 'package:flutter/material.dart'; import 'package:reversi/ai/move_finder.dart'; import 'package:reversi/config/styling.dart'; -import 'package:reversi/models/game/game_board.dart'; -import 'package:reversi/models/game/game_model.dart'; +import 'package:reversi/models/activity/game_board.dart'; +import 'package:reversi/models/activity/game_model.dart'; import 'package:reversi/ui/widgets/actions/button_game_quit.dart'; import 'package:reversi/ui/widgets/game/game_board_display.dart'; import 'package:reversi/ui/widgets/game/score_box.dart'; diff --git a/lib/main.dart b/lib/main.dart index 553d3d1a1f89e5b0bf29d7b49f43380135106ff7..c035ab9ef1cdebebf486779d031de76309193e7c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,11 +4,14 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; +import 'package:reversi/common/cubit/nav/nav_cubit_pages.dart'; +import 'package:reversi/common/cubit/nav/nav_cubit_screens.dart'; + +import 'package:reversi/config/application_config.dart'; import 'package:reversi/config/default_global_settings.dart'; -import 'package:reversi/cubit/game_cubit.dart'; -import 'package:reversi/cubit/nav_cubit.dart'; -import 'package:reversi/cubit/settings_game_cubit.dart'; -import 'package:reversi/cubit/settings_global_cubit.dart'; +import 'package:reversi/cubit/activity/activity_cubit.dart'; +import 'package:reversi/cubit/settings/settings_activity_cubit.dart'; +import 'package:reversi/cubit/settings/settings_global_cubit.dart'; import 'package:reversi/ui/skeleton.dart'; void main() async { @@ -46,17 +49,30 @@ class MyApp extends StatelessWidget { return MultiBlocProvider( providers: [ - BlocProvider<NavCubit>(create: (context) => NavCubit()), + // default providers + BlocProvider<NavCubitPage>( + create: (context) => NavCubitPage(), + ), + BlocProvider<NavCubitScreen>( + create: (context) => NavCubitScreen(), + ), BlocProvider<ApplicationThemeModeCubit>( - create: (context) => ApplicationThemeModeCubit()), - BlocProvider<GameCubit>(create: (context) => GameCubit()), - BlocProvider<GlobalSettingsCubit>(create: (context) => GlobalSettingsCubit()), - BlocProvider<GameSettingsCubit>(create: (context) => GameSettingsCubit()), + create: (context) => ApplicationThemeModeCubit(), + ), + BlocProvider<ActivityCubit>( + create: (context) => ActivityCubit(), + ), + BlocProvider<GlobalSettingsCubit>( + create: (context) => GlobalSettingsCubit(), + ), + BlocProvider<ActivitySettingsCubit>( + create: (context) => ActivitySettingsCubit(), + ), ], child: BlocBuilder<ApplicationThemeModeCubit, ApplicationThemeModeState>( builder: (BuildContext context, ApplicationThemeModeState state) { return MaterialApp( - title: 'Reversi', + title: ApplicationConfig.appTitle, home: const SkeletonScreen(), // Theme stuff diff --git a/lib/models/game/game.dart b/lib/models/activity/activity.dart similarity index 73% rename from lib/models/game/game.dart rename to lib/models/activity/activity.dart index 76151f13a481b560e5f29ba73d6c42dbf0f92cf2..978b3d2de8e936a69ef776b59d1f6615e7aec184 100644 --- a/lib/models/game/game.dart +++ b/lib/models/activity/activity.dart @@ -1,14 +1,14 @@ import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -import 'package:reversi/models/game/game_board.dart'; -import 'package:reversi/models/game/game_model.dart'; -import 'package:reversi/models/settings/settings_game.dart'; +import 'package:reversi/models/activity/game_board.dart'; +import 'package:reversi/models/activity/game_model.dart'; +import 'package:reversi/models/settings/settings_activity.dart'; import 'package:reversi/models/settings/settings_global.dart'; -class Game { - Game({ +class Activity { + Activity({ // Settings - required this.gameSettings, + required this.activitySettings, required this.globalSettings, // State @@ -25,7 +25,7 @@ class Game { }); // Settings - final GameSettings gameSettings; + final ActivitySettings activitySettings; final GlobalSettings globalSettings; // State @@ -40,10 +40,10 @@ class Game { // Game data int score; - factory Game.createNull() { - return Game( + factory Activity.createNull() { + return Activity( // Settings - gameSettings: GameSettings.createDefault(), + activitySettings: ActivitySettings.createDefault(), globalSettings: GlobalSettings.createDefault(), // Base data gameModel: GameModel(board: GameBoard()), @@ -52,16 +52,17 @@ class Game { ); } - factory Game.createNew({ - GameSettings? gameSettings, + factory Activity.createNew({ + ActivitySettings? activitySettings, GlobalSettings? globalSettings, }) { - final GameSettings newGameSettings = gameSettings ?? GameSettings.createDefault(); + final ActivitySettings newActivitySettings = + activitySettings ?? ActivitySettings.createDefault(); final GlobalSettings newGlobalSettings = globalSettings ?? GlobalSettings.createDefault(); - return Game( + return Activity( // Settings - gameSettings: newGameSettings, + activitySettings: newActivitySettings, globalSettings: newGlobalSettings, // State isRunning: true, @@ -78,9 +79,9 @@ class Game { printlog(''); printlog('## Current game dump:'); printlog(''); - printlog('$Game:'); + printlog('$Activity:'); printlog(' Settings'); - gameSettings.dump(); + activitySettings.dump(); globalSettings.dump(); printlog(' State'); printlog(' isRunning: $isRunning'); @@ -96,13 +97,13 @@ class Game { @override String toString() { - return '$Game(${toJson()})'; + return '$Activity(${toJson()})'; } Map<String, dynamic>? toJson() { return <String, dynamic>{ // Settings - 'gameSettings': gameSettings.toJson(), + 'activitySettings': activitySettings.toJson(), 'globalSettings': globalSettings.toJson(), // State 'isRunning': isRunning, diff --git a/lib/models/game/game_board.dart b/lib/models/activity/game_board.dart similarity index 100% rename from lib/models/game/game_board.dart rename to lib/models/activity/game_board.dart diff --git a/lib/models/game/game_model.dart b/lib/models/activity/game_model.dart similarity index 96% rename from lib/models/game/game_model.dart rename to lib/models/activity/game_model.dart index aa31385e62f2c920f64a7240a3a106a3c9f383a8..f9c391b4cffbee2b2b016a59512b1a82322ea14d 100644 --- a/lib/models/game/game_model.dart +++ b/lib/models/activity/game_model.dart @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:reversi/models/game/game_board.dart'; +import 'package:reversi/models/activity/game_board.dart'; /// A model representing the state of a game of reversi. It's a board and the /// player who's next to go, essentially. diff --git a/lib/models/settings/settings_activity.dart b/lib/models/settings/settings_activity.dart new file mode 100644 index 0000000000000000000000000000000000000000..fe5cb8c1f8420480a4b42f3df45a298d01c733cb --- /dev/null +++ b/lib/models/settings/settings_activity.dart @@ -0,0 +1,59 @@ +import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; + +import 'package:reversi/config/default_activity_settings.dart'; + +class ActivitySettings { + final String itemsCount; + final String timerValue; + + ActivitySettings({ + required this.itemsCount, + required this.timerValue, + }); + + // Getters to convert String to int + int get itemsCountValue => int.parse(itemsCount); + int get timerCountValue => int.parse(timerValue); + + static String getItemsCountValueFromUnsafe(String itemsCount) { + if (DefaultActivitySettings.allowedGameModeValues.contains(itemsCount)) { + return itemsCount; + } + + return DefaultActivitySettings.defaultGameModeValue; + } + + static String getTimerValueFromUnsafe(String timerValue) { + if (DefaultActivitySettings.allowedDifficultyLevelValues.contains(timerValue)) { + return timerValue; + } + + return DefaultActivitySettings.difficultyLevelValue; + } + + factory ActivitySettings.createDefault() { + return ActivitySettings( + itemsCount: DefaultActivitySettings.defaultGameModeValue, + timerValue: DefaultActivitySettings.difficultyLevelValue, + ); + } + + void dump() { + printlog('$ActivitySettings:'); + printlog(' ${DefaultActivitySettings.parameterCodeGameMode}: $itemsCount'); + printlog(' ${DefaultActivitySettings.parameterCodeDifficultyLevel}: $timerValue'); + printlog(''); + } + + @override + String toString() { + return '$ActivitySettings(${toJson()})'; + } + + Map<String, dynamic>? toJson() { + return <String, dynamic>{ + DefaultActivitySettings.parameterCodeGameMode: itemsCount, + DefaultActivitySettings.parameterCodeDifficultyLevel: timerValue, + }; + } +} diff --git a/lib/models/settings/settings_game.dart b/lib/models/settings/settings_game.dart deleted file mode 100644 index 828755c323af49e329e9b88ca97f47f01fe2676a..0000000000000000000000000000000000000000 --- a/lib/models/settings/settings_game.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; - -import 'package:reversi/config/default_game_settings.dart'; - -class GameSettings { - final String itemsCount; - final String timerValue; - - GameSettings({ - required this.itemsCount, - required this.timerValue, - }); - - // Getters to convert String to int - int get itemsCountValue => int.parse(itemsCount); - int get timerCountValue => int.parse(timerValue); - - static String getItemsCountValueFromUnsafe(String itemsCount) { - if (DefaultGameSettings.allowedGameModeValues.contains(itemsCount)) { - return itemsCount; - } - - return DefaultGameSettings.defaultGameModeValue; - } - - static String getTimerValueFromUnsafe(String timerValue) { - if (DefaultGameSettings.allowedDifficultyLevelValues.contains(timerValue)) { - return timerValue; - } - - return DefaultGameSettings.difficultyLevelValue; - } - - factory GameSettings.createDefault() { - return GameSettings( - itemsCount: DefaultGameSettings.defaultGameModeValue, - timerValue: DefaultGameSettings.difficultyLevelValue, - ); - } - - void dump() { - printlog('$GameSettings:'); - printlog(' ${DefaultGameSettings.parameterCodeGameMode}: $itemsCount'); - printlog(' ${DefaultGameSettings.parameterCodeDifficultyLevel}: $timerValue'); - printlog(''); - } - - @override - String toString() { - return '$GameSettings(${toJson()})'; - } - - Map<String, dynamic>? toJson() { - return <String, dynamic>{ - DefaultGameSettings.parameterCodeGameMode: itemsCount, - DefaultGameSettings.parameterCodeDifficultyLevel: timerValue, - }; - } -} diff --git a/lib/ui/layouts/parameters_layout.dart b/lib/ui/layouts/parameters_layout.dart deleted file mode 100644 index c8b9628299a8c2b4f7681ce7ee07ccef9cacc081..0000000000000000000000000000000000000000 --- a/lib/ui/layouts/parameters_layout.dart +++ /dev/null @@ -1,141 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; - -import 'package:reversi/config/default_game_settings.dart'; -import 'package:reversi/config/default_global_settings.dart'; -import 'package:reversi/cubit/settings_game_cubit.dart'; -import 'package:reversi/cubit/settings_global_cubit.dart'; -import 'package:reversi/ui/parameters/parameter_widget.dart'; -import 'package:reversi/ui/widgets/actions/button_delete_saved_game.dart'; -import 'package:reversi/ui/widgets/actions/button_game_start_new.dart'; -import 'package:reversi/ui/widgets/actions/button_resume_saved_game.dart'; - -class ParametersLayout extends StatelessWidget { - const ParametersLayout({super.key, required this.canResume}); - - final bool canResume; - - final double separatorHeight = 8.0; - - @override - Widget build(BuildContext context) { - final List<Widget> lines = []; - - // Game settings - for (String code in DefaultGameSettings.availableParameters) { - lines.add(Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: buildParametersLine( - code: code, - isGlobal: false, - ), - )); - - lines.add(SizedBox(height: separatorHeight)); - } - - lines.add(Expanded( - child: SizedBox(height: separatorHeight), - )); - - if (canResume == false) { - // Start new game - lines.add( - const AspectRatio( - aspectRatio: 3, - child: StartNewGameButton(), - ), - ); - } else { - // Resume game - lines.add(const AspectRatio( - aspectRatio: 3, - child: ResumeSavedGameButton(), - )); - // Delete saved game - lines.add(SizedBox.square( - dimension: MediaQuery.of(context).size.width / 5, - child: const DeleteSavedGameButton(), - )); - } - - lines.add(SizedBox(height: separatorHeight)); - - // Global settings - for (String code in DefaultGlobalSettings.availableParameters) { - lines.add(Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: buildParametersLine( - code: code, - isGlobal: true, - ), - )); - - lines.add(SizedBox(height: separatorHeight)); - } - - return Column( - children: lines, - ); - } - - List<Widget> buildParametersLine({ - required String code, - required bool isGlobal, - }) { - final List<Widget> parameterButtons = []; - - final List<String> availableValues = isGlobal - ? DefaultGlobalSettings.getAvailableValues(code) - : DefaultGameSettings.getAvailableValues(code); - - if (availableValues.length <= 1) { - return []; - } - - for (String value in availableValues) { - final Widget parameterButton = BlocBuilder<GameSettingsCubit, GameSettingsState>( - builder: (BuildContext context, GameSettingsState gameSettingsState) { - return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>( - builder: (BuildContext context, GlobalSettingsState globalSettingsState) { - final GameSettingsCubit gameSettingsCubit = - BlocProvider.of<GameSettingsCubit>(context); - final GlobalSettingsCubit globalSettingsCubit = - BlocProvider.of<GlobalSettingsCubit>(context); - - final String currentValue = isGlobal - ? globalSettingsCubit.getParameterValue(code) - : gameSettingsCubit.getParameterValue(code); - - final bool isSelected = (value == currentValue); - - final double displayWidth = MediaQuery.of(context).size.width; - final double itemWidth = displayWidth / availableValues.length - 4; - - return SizedBox.square( - dimension: itemWidth, - child: ParameterWidget( - code: code, - value: value, - isSelected: isSelected, - size: itemWidth, - gameSettings: gameSettingsState.settings, - globalSettings: globalSettingsState.settings, - onPressed: () { - isGlobal - ? globalSettingsCubit.setParameterValue(code, value) - : gameSettingsCubit.setParameterValue(code, value); - }, - ), - ); - }, - ); - }, - ); - - parameterButtons.add(parameterButton); - } - - return parameterButtons; - } -} diff --git a/lib/ui/screens/page_game.dart b/lib/ui/screens/page_game.dart deleted file mode 100644 index 8d40a29ee62309992965999fe5ce08167d9ddad2..0000000000000000000000000000000000000000 --- a/lib/ui/screens/page_game.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; - -import 'package:reversi/cubit/game_cubit.dart'; -import 'package:reversi/models/game/game.dart'; -import 'package:reversi/ui/layouts/parameters_layout.dart'; -import 'package:reversi/ui/layouts/game_layout.dart'; - -class PageGame extends StatelessWidget { - const PageGame({super.key}); - - @override - Widget build(BuildContext context) { - return BlocBuilder<GameCubit, GameState>( - builder: (BuildContext context, GameState gameState) { - final Game currentGame = gameState.currentGame; - - return currentGame.isRunning - ? const GameLayout() - : ParametersLayout(canResume: currentGame.canBeResumed); - }, - ); - } -} diff --git a/lib/ui/skeleton.dart b/lib/ui/skeleton.dart index 86353bcb1a0bb4d61456dbbcf98422c6bc659764..86b6e16f1f40b6dc9c3c8ff04ba59d80b58583d7 100644 --- a/lib/ui/skeleton.dart +++ b/lib/ui/skeleton.dart @@ -1,34 +1,37 @@ import 'package:flutter/material.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -import 'package:reversi/config/menu.dart'; -import 'package:reversi/cubit/nav_cubit.dart'; -import 'package:reversi/ui/widgets/global_app_bar.dart'; +import 'package:reversi/common/config/activity_page.dart'; +import 'package:reversi/common/config/screen.dart'; +import 'package:reversi/common/cubit/nav/nav_cubit_screens.dart'; +import 'package:reversi/common/ui/nav/global_app_bar.dart'; +import 'package:reversi/common/ui/nav/bottom_nav_bar.dart'; class SkeletonScreen extends StatelessWidget { const SkeletonScreen({super.key}); @override Widget build(BuildContext context) { - return Scaffold( - appBar: const GlobalAppBar(), - extendBodyBehindAppBar: false, - body: Material( - color: Theme.of(context).colorScheme.surface, - child: BlocBuilder<NavCubit, int>( - builder: (BuildContext context, int pageIndex) { - return Padding( + return BlocBuilder<NavCubitScreen, int>( + builder: (BuildContext context, int screenIndex) { + return Scaffold( + appBar: const GlobalAppBar(), + extendBodyBehindAppBar: false, + body: Material( + color: Theme.of(context).colorScheme.surface, + child: Padding( padding: const EdgeInsets.only( top: 8, left: 2, right: 2, ), - child: Menu.getPageWidget(pageIndex), - ); - }, - ), - ), - backgroundColor: Theme.of(context).colorScheme.surface, + child: Screen.getWidget(screenIndex), + ), + ), + backgroundColor: Theme.of(context).colorScheme.surface, + bottomNavigationBar: ActivityPage.displayBottomNavBar ? const BottomNavBar() : null, + ); + }, ); } } diff --git a/lib/ui/widgets/actions/button_delete_saved_game.dart b/lib/ui/widgets/actions/button_delete_saved_game.dart index 74154366eab60115019cf6e57f8725ae3ca41f5b..007ee11fee67cb96debcc5d0d96a90c2ca81c3b6 100644 --- a/lib/ui/widgets/actions/button_delete_saved_game.dart +++ b/lib/ui/widgets/actions/button_delete_saved_game.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -import 'package:reversi/cubit/game_cubit.dart'; +import 'package:reversi/cubit/activity/activity_cubit.dart'; class DeleteSavedGameButton extends StatelessWidget { const DeleteSavedGameButton({super.key}); @@ -11,7 +11,7 @@ class DeleteSavedGameButton extends StatelessWidget { return StyledButton( color: Colors.grey, onPressed: () { - BlocProvider.of<GameCubit>(context).deleteSavedGame(); + BlocProvider.of<ActivityCubit>(context).deleteSavedActivity(); }, child: const Image( image: AssetImage('assets/ui/button_delete_saved_game.png'), diff --git a/lib/ui/widgets/actions/button_game_quit.dart b/lib/ui/widgets/actions/button_game_quit.dart index d94c93b5119cf3a4fd96263bf93176e1dc542296..8c548421d79930c65bc9eb19ba8a79e20231e7a3 100644 --- a/lib/ui/widgets/actions/button_game_quit.dart +++ b/lib/ui/widgets/actions/button_game_quit.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -import 'package:reversi/cubit/game_cubit.dart'; +import 'package:reversi/common/cubit/nav/nav_cubit_pages.dart'; + +import 'package:reversi/cubit/activity/activity_cubit.dart'; class QuitGameButton extends StatelessWidget { const QuitGameButton({super.key}); @@ -11,7 +13,8 @@ class QuitGameButton extends StatelessWidget { return StyledButton( color: Colors.red, onPressed: () { - BlocProvider.of<GameCubit>(context).quitGame(); + BlocProvider.of<ActivityCubit>(context).quitActivity(); + BlocProvider.of<NavCubitPage>(context).goToPageHome(); }, child: const Image( image: AssetImage('assets/ui/button_back.png'), diff --git a/lib/ui/widgets/actions/button_game_start_new.dart b/lib/ui/widgets/actions/button_game_start_new.dart index add9761b528f37b3dbae7dbe5dbbaf55d7cceddc..f59c2fd521ef9eba6dbc93e449c00b799babec1d 100644 --- a/lib/ui/widgets/actions/button_game_start_new.dart +++ b/lib/ui/widgets/actions/button_game_start_new.dart @@ -1,26 +1,29 @@ import 'package:flutter/material.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -import 'package:reversi/cubit/game_cubit.dart'; -import 'package:reversi/cubit/settings_game_cubit.dart'; -import 'package:reversi/cubit/settings_global_cubit.dart'; +import 'package:reversi/common/cubit/nav/nav_cubit_pages.dart'; + +import 'package:reversi/cubit/activity/activity_cubit.dart'; +import 'package:reversi/cubit/settings/settings_activity_cubit.dart'; +import 'package:reversi/cubit/settings/settings_global_cubit.dart'; class StartNewGameButton extends StatelessWidget { const StartNewGameButton({super.key}); @override Widget build(BuildContext context) { - return BlocBuilder<GameSettingsCubit, GameSettingsState>( - builder: (BuildContext context, GameSettingsState gameSettingsState) { + return BlocBuilder<ActivitySettingsCubit, ActivitySettingsState>( + builder: (BuildContext context, ActivitySettingsState activitySettingsState) { return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>( builder: (BuildContext context, GlobalSettingsState globalSettingsState) { return StyledButton( color: Colors.blue, onPressed: () { - BlocProvider.of<GameCubit>(context).startNewGame( - gameSettings: gameSettingsState.settings, + BlocProvider.of<ActivityCubit>(context).startNewActivity( + activitySettings: activitySettingsState.settings, globalSettings: globalSettingsState.settings, ); + BlocProvider.of<NavCubitPage>(context).goToPageGame(); }, child: const Image( image: AssetImage('assets/ui/button_start.png'), diff --git a/lib/ui/widgets/actions/button_resume_saved_game.dart b/lib/ui/widgets/actions/button_resume_saved_game.dart index a7f8e57f1caa6d49713d94171d37051715f80246..dbf7b587b6a82486d624a32924f586de57cf1671 100644 --- a/lib/ui/widgets/actions/button_resume_saved_game.dart +++ b/lib/ui/widgets/actions/button_resume_saved_game.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -import 'package:reversi/cubit/game_cubit.dart'; +import 'package:reversi/common/cubit/nav/nav_cubit_pages.dart'; + +import 'package:reversi/cubit/activity/activity_cubit.dart'; class ResumeSavedGameButton extends StatelessWidget { const ResumeSavedGameButton({super.key}); @@ -11,7 +13,8 @@ class ResumeSavedGameButton extends StatelessWidget { return StyledButton( color: Colors.blue, onPressed: () { - BlocProvider.of<GameCubit>(context).resumeSavedGame(); + BlocProvider.of<ActivityCubit>(context).resumeSavedActivity(); + BlocProvider.of<NavCubitPage>(context).goToPageGame(); }, child: const Image( image: AssetImage('assets/ui/button_resume_game.png'), diff --git a/lib/ui/widgets/game/game_board.dart b/lib/ui/widgets/game/game_board.dart index 24c26a7cdad851b540685e3759811e75c30a450a..78e51fb668ba4dd5beabd259daca5b51230037d7 100644 --- a/lib/ui/widgets/game/game_board.dart +++ b/lib/ui/widgets/game/game_board.dart @@ -1,9 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; -import 'package:reversi/cubit/game_cubit.dart'; import 'package:reversi/game/game_engine.dart'; -import 'package:reversi/models/game/game.dart'; class GameBoardWidget extends StatelessWidget { const GameBoardWidget({super.key}); @@ -11,14 +8,7 @@ class GameBoardWidget extends StatelessWidget { @override Widget build(BuildContext context) { return Center( - child: BlocBuilder<GameCubit, GameState>( - builder: (BuildContext context, GameState gameState) { - final Game currentGame = gameState.currentGame; - printlog(currentGame.toString()); - - return const GameEngine(); - }, - ), + child: const GameEngine(), ); } } diff --git a/lib/ui/widgets/game/game_board_display.dart b/lib/ui/widgets/game/game_board_display.dart index 3bbb2a5e11dd3b6da94e6adae1c9807ecb837806..ef4417ca7a2f9e25f6e1f8c39b53392c14c3c55c 100644 --- a/lib/ui/widgets/game/game_board_display.dart +++ b/lib/ui/widgets/game/game_board_display.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:reversi/models/game/game_board.dart'; -import 'package:reversi/models/game/game_model.dart'; +import 'package:reversi/models/activity/game_board.dart'; +import 'package:reversi/models/activity/game_model.dart'; import 'package:reversi/config/styling.dart'; class GameBoardDisplay extends StatelessWidget { diff --git a/lib/ui/widgets/game/score_box.dart b/lib/ui/widgets/game/score_box.dart index d1916a728766ffb6711e95b9be91f548022b4b72..cb90ab524349a292d77b0e2a2d153122323c59ce 100644 --- a/lib/ui/widgets/game/score_box.dart +++ b/lib/ui/widgets/game/score_box.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:reversi/models/game/game_board.dart'; -import 'package:reversi/models/game/game_model.dart'; +import 'package:reversi/models/activity/game_board.dart'; +import 'package:reversi/models/activity/game_model.dart'; import 'package:reversi/config/styling.dart'; class ScoreBox extends StatelessWidget { diff --git a/pubspec.lock b/pubspec.lock index 107178ed95e1d8b3e88264e11b5dfd6409bd7aac..f1cba883c07528c7b10c77c0ff3f8b664b465e55 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -245,10 +245,10 @@ packages: dependency: transitive description: name: path_provider - sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" path_provider_android: dependency: transitive description: @@ -442,10 +442,10 @@ packages: dependency: transitive description: name: win32 - sha256: "2735daae5150e8b1dfeb3eb0544b4d3af0061e9e82cef063adcd583bdae4306a" + sha256: "10169d3934549017f0ae278ccb07f828f9d6ea21573bab0fb77b0e1ef0fce454" url: "https://pub.dev" source: hosted - version: "5.7.0" + version: "5.7.2" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ed3c8729b4ae632c40260a669766e136165c5b51..c3288b4dda443599401f1643cdcd90620cac79b0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: A reversi game application. publish_to: "none" -version: 0.2.1+22 +version: 0.3.0+23 environment: sdk: "^3.0.0"