├── linux ├── .gitignore ├── main.cc ├── flutter │ ├── generated_plugin_registrant.h │ ├── generated_plugin_registrant.cc │ └── generated_plugins.cmake └── my_application.h ├── ios ├── Runner │ ├── Runner-Bridging-Header.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── AppFrameworkInfo.plist ├── Runner.xcodeproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── .gitignore ├── Podfile.lock └── Podfile ├── modules ├── domain │ ├── lib │ │ ├── core │ │ │ ├── core.dart │ │ │ └── extensions │ │ │ │ ├── extensions.dart │ │ │ │ ├── num_extension.dart │ │ │ │ ├── either_extension.dart │ │ │ │ └── duration_extension.dart │ │ ├── service_interfaces │ │ │ ├── service_interfaces.dart │ │ │ ├── audio_service.dart │ │ │ └── puzzle_service.dart │ │ ├── failures │ │ │ ├── failures.dart │ │ │ ├── game_not_started_failure.dart │ │ │ ├── no_available_spell_failure.dart │ │ │ ├── game_already_started_failure.dart │ │ │ ├── concurrent_method_call_failure.dart │ │ │ ├── tile_not_movable_failure.dart │ │ │ └── failure.dart │ │ ├── entities │ │ │ ├── entities.dart │ │ │ ├── position.dart │ │ │ ├── active_spell_state.dart │ │ │ ├── tile.dart │ │ │ ├── game_state.dart │ │ │ └── available_spell_state.dart │ │ └── domain.dart │ ├── analysis_options.yaml │ ├── .metadata │ ├── README.md │ ├── pubspec.yaml │ └── .gitignore ├── presentation │ ├── lib │ │ ├── assets │ │ │ ├── audio │ │ │ │ └── audio.dart │ │ │ ├── animations │ │ │ │ ├── animations.dart │ │ │ │ ├── sky_animations.dart │ │ │ │ └── puzzle_board_animations.dart │ │ │ ├── assets.dart │ │ │ └── images │ │ │ │ ├── images.dart │ │ │ │ ├── logo_assets.dart │ │ │ │ ├── throwable_assets.dart │ │ │ │ ├── spell_assets.dart │ │ │ │ └── day_cycle_assets.dart │ │ ├── helpers │ │ │ ├── strings │ │ │ │ ├── strings.dart │ │ │ │ └── join.dart │ │ │ ├── dialogs │ │ │ │ ├── dialogs.dart │ │ │ │ └── show_glass_dialog.dart │ │ │ ├── animation │ │ │ │ ├── animation.dart │ │ │ │ └── sync_rive_animation_theme.dart │ │ │ ├── widgets │ │ │ │ ├── widgets.dart │ │ │ │ ├── synced_animated_align.dart │ │ │ │ └── synced_animated_rotation.dart │ │ │ └── helpers.dart │ │ ├── constants │ │ │ ├── constants.dart │ │ │ └── breakpoints.dart │ │ ├── background_handler │ │ │ ├── painters │ │ │ │ └── painters.dart │ │ │ ├── background_handler.dart │ │ │ └── widgets │ │ │ │ ├── widgets.dart │ │ │ │ └── background_handler.dart │ │ ├── dash_animator │ │ │ ├── dialogs │ │ │ │ └── dialogs.dart │ │ │ ├── overlays │ │ │ │ ├── overlays.dart │ │ │ │ └── object_throw_animation_overlay.dart │ │ │ ├── curves │ │ │ │ ├── curves.dart │ │ │ │ ├── arc_curve.dart │ │ │ │ └── mcdonald_curve.dart │ │ │ ├── dash_animator.dart │ │ │ ├── widgets │ │ │ │ ├── widgets.dart │ │ │ │ ├── dash_face_animator.dart │ │ │ │ ├── dash_animator_group │ │ │ │ │ └── bot_dash_animator.dart │ │ │ │ ├── dash_tail_animator.dart │ │ │ │ ├── dash_comb_animator.dart │ │ │ │ └── dash_body_animator.dart │ │ │ └── cubit │ │ │ │ └── dash_animator_group_cubit.dart │ │ ├── audio_handler │ │ │ ├── audio_handler.dart │ │ │ └── enum │ │ │ │ └── audio_player_channel.dart │ │ ├── puzzle │ │ │ ├── widgets │ │ │ │ ├── app_bar │ │ │ │ │ ├── app_bar.dart │ │ │ │ │ ├── app_bar_title.dart │ │ │ │ │ └── action_item.dart │ │ │ │ ├── widgets.dart │ │ │ │ ├── floating_action_buttons │ │ │ │ │ ├── floating_action_buttons.dart │ │ │ │ │ └── theme_button.dart │ │ │ │ └── puzzle_board.dart │ │ │ ├── puzzle.dart │ │ │ └── dialogs │ │ │ │ ├── dialogs.dart │ │ │ │ └── share_app_dialog │ │ │ │ └── share_button.dart │ │ ├── presentation.dart │ │ ├── spell_handler │ │ │ ├── spell_button.dart │ │ │ ├── spell_banner.dart │ │ │ └── available_spell_indicator.dart │ │ └── themes │ │ │ └── themes.dart │ ├── analysis_options.yaml │ ├── assets │ │ ├── animations │ │ │ ├── sky.riv │ │ │ └── puzzle_board.riv │ │ ├── audio │ │ │ └── sfx │ │ │ │ ├── click.mp3 │ │ │ │ ├── magic.mp3 │ │ │ │ ├── toss.mp3 │ │ │ │ ├── complete.mp3 │ │ │ │ ├── shuffled.mp3 │ │ │ │ ├── device_fall.mp3 │ │ │ │ ├── shuffling.mp3 │ │ │ │ ├── tile_move.mp3 │ │ │ │ ├── dash_sound_1.mp3 │ │ │ │ ├── dash_sound_2.mp3 │ │ │ │ ├── dash_sound_3.mp3 │ │ │ │ ├── tile_unmovable.mp3 │ │ │ │ ├── spell_available_1.mp3 │ │ │ │ └── spell_available_2.mp3 │ │ └── images │ │ │ ├── spells │ │ │ ├── magic.webp │ │ │ ├── pizza.webp │ │ │ └── throw.webp │ │ │ ├── day_cycles │ │ │ ├── day.webp │ │ │ ├── night.webp │ │ │ └── prevening.webp │ │ │ ├── logos │ │ │ └── flutter_mono.webp │ │ │ ├── throwables │ │ │ ├── pizza.webp │ │ │ └── stone.webp │ │ │ └── dash_sprites │ │ │ ├── body │ │ │ ├── nude.webp │ │ │ ├── blue_polo.webp │ │ │ ├── green_polo.webp │ │ │ ├── yellow_tie.webp │ │ │ ├── blue_hoodie.webp │ │ │ ├── blue_ribbon.webp │ │ │ ├── green_hoodie.webp │ │ │ ├── wizard_robe.webp │ │ │ └── yellow_polo.webp │ │ │ ├── comb │ │ │ └── comb.webp │ │ │ ├── tail │ │ │ └── tail.webp │ │ │ ├── wand │ │ │ └── wand.webp │ │ │ ├── faces │ │ │ ├── face_sad.webp │ │ │ ├── face_wtf.webp │ │ │ ├── face_happy.webp │ │ │ ├── face_kawaii.webp │ │ │ ├── face_normal.webp │ │ │ ├── face_wizard.webp │ │ │ ├── face_wtfff.webp │ │ │ └── face_happy_wizard.webp │ │ │ ├── wings │ │ │ ├── left_wing.webp │ │ │ └── right_wing.webp │ │ │ └── devices │ │ │ ├── cyan_laptop.webp │ │ │ ├── green_laptop.webp │ │ │ ├── pink_laptop.webp │ │ │ └── purple_laptop.webp │ ├── fonts │ │ └── Bangers-Regular.ttf │ ├── .metadata │ ├── README.md │ ├── .gitignore │ ├── test │ │ └── widget_test.dart │ └── pubspec.yaml ├── infrastructure │ ├── test │ │ └── helpers │ │ │ ├── helpers.dart │ │ │ └── create_puzzle.dart │ ├── analysis_options.yaml │ ├── lib │ │ ├── services │ │ │ ├── puzzle_service │ │ │ │ └── puzzle_solver │ │ │ │ │ ├── models │ │ │ │ │ ├── models.dart │ │ │ │ │ └── boundary.dart │ │ │ │ │ └── a_star │ │ │ │ │ ├── a_star.dart │ │ │ │ │ └── a_star_variant_b.dart │ │ │ └── services.dart │ │ └── infrastructure.dart │ ├── .metadata │ ├── README.md │ ├── pubspec.yaml │ └── .gitignore └── application │ ├── analysis_options.yaml │ ├── lib │ ├── use_cases │ │ ├── theme │ │ │ ├── theme.dart │ │ │ └── switch_theme │ │ │ │ └── switch_theme_use_case.dart │ │ ├── use_cases.dart │ │ ├── audio │ │ │ ├── audio.dart │ │ │ ├── mute_all_audio │ │ │ │ └── mute_all_audio_use_case.dart │ │ │ ├── unmute_all_audio │ │ │ │ └── unmute_all_audio_use_case.dart │ │ │ ├── watch_all_audio_muted_state │ │ │ │ └── watch_all_audio_muted_state_use_case.dart │ │ │ └── play_local_audio │ │ │ │ └── play_local_audio_use_case.dart │ │ └── game │ │ │ ├── preview_completed_puzzle │ │ │ └── preview_completed_puzzle_use_case.dart │ │ │ ├── game.dart │ │ │ ├── start_game │ │ │ └── start_game_use_case.dart │ │ │ ├── reset_game │ │ │ └── reset_game_use_case.dart │ │ │ ├── cast_available_spell │ │ │ └── cast_available_spell_use_case.dart │ │ │ ├── watch_game │ │ │ └── watch_game_state_use_case.dart │ │ │ ├── watch_active_spell_state │ │ │ └── watch_active_spell_state_use_case.dart │ │ │ ├── watch_available_spell_state │ │ │ └── watch_available_spell_state_use_case.dart │ │ │ └── move_player_tile │ │ │ └── move_player_tile_use_case.dart │ └── application.dart │ ├── .metadata │ ├── README.md │ ├── pubspec.yaml │ └── .gitignore ├── analysis_options.yaml ├── web ├── favicon.png ├── icons │ ├── Icon-192.png │ └── Icon-512.png └── manifest.json ├── CHANGELOG.md ├── android ├── gradle.properties ├── app │ └── src │ │ ├── main │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── drawable-hdpi │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── drawable-mdpi │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── drawable-xhdpi │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ ├── ic_launcher_background.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ └── ic_launcher.xml │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ ├── values │ │ │ │ └── styles.xml │ │ │ └── values-night │ │ │ │ └── styles.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── orga │ │ │ │ └── dash_slide_puzzle │ │ │ │ └── MainActivity.kt │ │ └── AndroidManifest.xml │ │ ├── debug │ │ └── AndroidManifest.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle └── build.gradle ├── macos ├── Runner │ ├── Configs │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ ├── Warnings.xcconfig │ │ └── AppInfo.xcconfig │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_64.png │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_512.png │ │ │ └── Contents.json │ ├── AppDelegate.swift │ ├── Release.entitlements │ ├── DebugProfile.entitlements │ ├── MainFlutterWindow.swift │ └── Info.plist ├── .gitignore ├── Flutter │ ├── Flutter-Debug.xcconfig │ ├── Flutter-Release.xcconfig │ └── GeneratedPluginRegistrant.swift ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Runner.xcodeproj │ └── project.xcworkspace │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Podfile └── Podfile.lock ├── assets └── icons │ ├── app_icon_background.png │ ├── app_icon_foreground.png │ ├── app_icon_square_sharp.png │ └── app_icon_square_rounded.png ├── windows ├── runner │ ├── resources │ │ └── app_icon.ico │ ├── resource.h │ ├── CMakeLists.txt │ ├── utils.h │ ├── runner.exe.manifest │ ├── flutter_window.h │ ├── main.cpp │ ├── utils.cpp │ └── flutter_window.cpp ├── .gitignore └── flutter │ ├── generated_plugin_registrant.h │ ├── generated_plugin_registrant.cc │ └── generated_plugins.cmake ├── tool ├── gen-l10n.sh ├── gen-l10n.bat ├── prebuild.sh └── prebuild.bat ├── lib ├── main.dart └── injection_container │ ├── dependency_injectables.dart │ ├── injection_container.dart │ ├── service_injectables.dart │ └── use_case_injectables.dart ├── .metadata ├── pubspec.yaml ├── LICENSE ├── .gitignore ├── .vscode └── launch.json └── CONTRIBUTING.md /linux/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral 2 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /modules/domain/lib/core/core.dart: -------------------------------------------------------------------------------- 1 | export 'extensions/extensions.dart'; 2 | -------------------------------------------------------------------------------- /modules/presentation/lib/assets/audio/audio.dart: -------------------------------------------------------------------------------- 1 | export 'sfx_assets.dart'; 2 | -------------------------------------------------------------------------------- /modules/presentation/lib/helpers/strings/strings.dart: -------------------------------------------------------------------------------- 1 | export 'join.dart'; 2 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | -------------------------------------------------------------------------------- /modules/infrastructure/test/helpers/helpers.dart: -------------------------------------------------------------------------------- 1 | export 'create_puzzle.dart'; 2 | -------------------------------------------------------------------------------- /modules/presentation/lib/constants/constants.dart: -------------------------------------------------------------------------------- 1 | export 'breakpoints.dart'; 2 | -------------------------------------------------------------------------------- /modules/presentation/lib/helpers/dialogs/dialogs.dart: -------------------------------------------------------------------------------- 1 | export 'show_glass_dialog.dart'; 2 | -------------------------------------------------------------------------------- /modules/domain/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | -------------------------------------------------------------------------------- /modules/presentation/lib/background_handler/painters/painters.dart: -------------------------------------------------------------------------------- 1 | export 'star_painter.dart'; 2 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/web/favicon.png -------------------------------------------------------------------------------- /modules/application/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | -------------------------------------------------------------------------------- /modules/infrastructure/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml -------------------------------------------------------------------------------- /modules/presentation/lib/helpers/animation/animation.dart: -------------------------------------------------------------------------------- 1 | export 'sync_rive_animation_theme.dart'; 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.1.0 2 | 3 | - Add Youtube tutorial in menu 4 | 5 | ## 1.0.0 6 | 7 | - First release 8 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/theme/theme.dart: -------------------------------------------------------------------------------- 1 | export 'switch_theme/switch_theme_use_case.dart'; 2 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/dialogs/dialogs.dart: -------------------------------------------------------------------------------- 1 | export 'dash_animator_preview_dialog.dart'; 2 | -------------------------------------------------------------------------------- /modules/infrastructure/lib/services/puzzle_service/puzzle_solver/models/models.dart: -------------------------------------------------------------------------------- 1 | export 'boundary.dart'; 2 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/overlays/overlays.dart: -------------------------------------------------------------------------------- 1 | export 'object_throw_animation_overlay.dart'; 2 | -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/web/icons/Icon-512.png -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/curves/curves.dart: -------------------------------------------------------------------------------- 1 | export 'arc_curve.dart'; 2 | export 'mcdonald_curve.dart'; 3 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /modules/presentation/lib/assets/animations/animations.dart: -------------------------------------------------------------------------------- 1 | export 'puzzle_board_animations.dart'; 2 | export 'sky_animations.dart'; 3 | -------------------------------------------------------------------------------- /modules/presentation/lib/helpers/widgets/widgets.dart: -------------------------------------------------------------------------------- 1 | export 'synced_animated_align.dart'; 2 | export 'synced_animated_rotation.dart'; 3 | -------------------------------------------------------------------------------- /assets/icons/app_icon_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/assets/icons/app_icon_background.png -------------------------------------------------------------------------------- /assets/icons/app_icon_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/assets/icons/app_icon_foreground.png -------------------------------------------------------------------------------- /assets/icons/app_icon_square_sharp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/assets/icons/app_icon_square_sharp.png -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/use_cases.dart: -------------------------------------------------------------------------------- 1 | export 'audio/audio.dart'; 2 | export 'game/game.dart'; 3 | export 'theme/theme.dart'; 4 | -------------------------------------------------------------------------------- /modules/presentation/lib/audio_handler/audio_handler.dart: -------------------------------------------------------------------------------- 1 | export 'enum/audio_player_channel.dart'; 2 | export 'widgets/audio_handler.dart'; 3 | -------------------------------------------------------------------------------- /modules/presentation/lib/background_handler/background_handler.dart: -------------------------------------------------------------------------------- 1 | export 'painters/painters.dart'; 2 | export 'widgets/widgets.dart'; 3 | -------------------------------------------------------------------------------- /windows/runner/resources/app_icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/windows/runner/resources/app_icon.ico -------------------------------------------------------------------------------- /assets/icons/app_icon_square_rounded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/assets/icons/app_icon_square_rounded.png -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /modules/infrastructure/lib/infrastructure.dart: -------------------------------------------------------------------------------- 1 | export 'package:codenic_logger/codenic_logger.dart'; 2 | 3 | export 'services/services.dart'; 4 | -------------------------------------------------------------------------------- /modules/presentation/lib/assets/assets.dart: -------------------------------------------------------------------------------- 1 | export 'animations/animations.dart'; 2 | export 'audio/audio.dart'; 3 | export 'images/images.dart'; 4 | -------------------------------------------------------------------------------- /modules/presentation/lib/puzzle/widgets/app_bar/app_bar.dart: -------------------------------------------------------------------------------- 1 | export 'action_item.dart'; 2 | export 'app_bar_title.dart'; 3 | export 'menu.dart'; 4 | -------------------------------------------------------------------------------- /modules/presentation/lib/puzzle/puzzle.dart: -------------------------------------------------------------------------------- 1 | export 'dialogs/dialogs.dart'; 2 | export 'page/puzzle_page.dart'; 3 | export 'widgets/widgets.dart'; 4 | -------------------------------------------------------------------------------- /modules/domain/lib/core/extensions/extensions.dart: -------------------------------------------------------------------------------- 1 | export 'duration_extension.dart'; 2 | export 'either_extension.dart'; 3 | export 'num_extension.dart'; 4 | -------------------------------------------------------------------------------- /modules/presentation/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | 3 | analyzer: 4 | exclude: 5 | - lib/l10n/** -------------------------------------------------------------------------------- /modules/domain/lib/service_interfaces/service_interfaces.dart: -------------------------------------------------------------------------------- 1 | export 'audio_service.dart'; 2 | export 'game_service.dart'; 3 | export 'puzzle_service.dart'; 4 | -------------------------------------------------------------------------------- /modules/presentation/assets/animations/sky.riv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/animations/sky.riv -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/click.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/click.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/magic.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/magic.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/toss.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/toss.mp3 -------------------------------------------------------------------------------- /modules/presentation/fonts/Bangers-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/fonts/Bangers-Regular.ttf -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/complete.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/complete.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/shuffled.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/shuffled.mp3 -------------------------------------------------------------------------------- /modules/presentation/lib/background_handler/widgets/widgets.dart: -------------------------------------------------------------------------------- 1 | export 'background_handler.dart'; 2 | export 'sky_animator.dart'; 3 | export 'stars_handler.dart'; 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/device_fall.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/device_fall.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/shuffling.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/shuffling.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/tile_move.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/tile_move.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/images/spells/magic.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/spells/magic.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/spells/pizza.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/spells/pizza.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/spells/throw.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/spells/throw.webp -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /modules/presentation/assets/animations/puzzle_board.riv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/animations/puzzle_board.riv -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/dash_sound_1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/dash_sound_1.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/dash_sound_2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/dash_sound_2.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/dash_sound_3.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/dash_sound_3.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/images/day_cycles/day.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/day_cycles/day.webp -------------------------------------------------------------------------------- /modules/presentation/lib/puzzle/dialogs/dialogs.dart: -------------------------------------------------------------------------------- 1 | export 'keyboard_shortcut_dialog/keyboard_shortcut_dialog.dart'; 2 | export 'share_app_dialog/share_app_dialog.dart'; 3 | -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/tile_unmovable.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/tile_unmovable.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/images/day_cycles/night.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/day_cycles/night.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/logos/flutter_mono.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/logos/flutter_mono.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/throwables/pizza.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/throwables/pizza.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/throwables/stone.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/throwables/stone.webp -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/spell_available_1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/spell_available_1.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/audio/sfx/spell_available_2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/audio/sfx/spell_available_2.mp3 -------------------------------------------------------------------------------- /modules/presentation/assets/images/day_cycles/prevening.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/day_cycles/prevening.webp -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/body/nude.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/body/nude.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/comb/comb.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/comb/comb.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/tail/tail.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/tail/tail.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/wand/wand.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/wand/wand.webp -------------------------------------------------------------------------------- /modules/presentation/lib/helpers/helpers.dart: -------------------------------------------------------------------------------- 1 | export 'animation/animation.dart'; 2 | export 'dialogs/dialogs.dart'; 3 | export 'strings/strings.dart'; 4 | export 'widgets/widgets.dart'; 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/drawable-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/drawable-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/drawable-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/drawable-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/body/blue_polo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/body/blue_polo.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/body/green_polo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/body/green_polo.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/body/yellow_tie.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/body/yellow_tie.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/faces/face_sad.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/faces/face_sad.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/faces/face_wtf.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/faces/face_wtf.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/wings/left_wing.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/wings/left_wing.webp -------------------------------------------------------------------------------- /modules/infrastructure/lib/services/services.dart: -------------------------------------------------------------------------------- 1 | export 'audio_service/audio_service_impl.dart'; 2 | export 'game_service/game_service_impl.dart'; 3 | export 'puzzle_service/puzzle_service_impl.dart'; 4 | -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/body/blue_hoodie.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/body/blue_hoodie.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/body/blue_ribbon.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/body/blue_ribbon.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/body/green_hoodie.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/body/green_hoodie.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/body/wizard_robe.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/body/wizard_robe.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/body/yellow_polo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/body/yellow_polo.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/faces/face_happy.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/faces/face_happy.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/faces/face_kawaii.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/faces/face_kawaii.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/faces/face_normal.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/faces/face_normal.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/faces/face_wizard.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/faces/face_wizard.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/faces/face_wtfff.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/faces/face_wtfff.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/wings/right_wing.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/wings/right_wing.webp -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/devices/cyan_laptop.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/devices/cyan_laptop.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/devices/green_laptop.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/devices/green_laptop.webp -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/devices/pink_laptop.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/devices/pink_laptop.webp -------------------------------------------------------------------------------- /linux/main.cc: -------------------------------------------------------------------------------- 1 | #include "my_application.h" 2 | 3 | int main(int argc, char** argv) { 4 | g_autoptr(MyApplication) app = my_application_new(); 5 | return g_application_run(G_APPLICATION(app), argc, argv); 6 | } 7 | -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/devices/purple_laptop.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/devices/purple_laptop.webp -------------------------------------------------------------------------------- /tool/gen-l10n.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Regenerates the localization file in the Presentation layer 4 | 5 | cd modules/presentation 6 | flutter gen-l10n --arb-dir=assets/l10n --output-dir=lib/l10n --no-synthetic-package -------------------------------------------------------------------------------- /modules/presentation/assets/images/dash_sprites/faces/face_happy_wizard.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodenicCoders/dash_slide_puzzle/HEAD/modules/presentation/assets/images/dash_sprites/faces/face_happy_wizard.webp -------------------------------------------------------------------------------- /modules/presentation/lib/assets/images/images.dart: -------------------------------------------------------------------------------- 1 | export 'dash_sprite_assets.dart'; 2 | export 'day_cycle_assets.dart'; 3 | export 'logo_assets.dart'; 4 | export 'spell_assets.dart'; 5 | export 'throwable_assets.dart'; 6 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/orga/dash_slide_puzzle/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.orga.dash_slide_puzzle 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /modules/infrastructure/lib/services/puzzle_service/puzzle_solver/a_star/a_star.dart: -------------------------------------------------------------------------------- 1 | export 'a_star_helper.dart'; 2 | export 'a_star_variant_a.dart'; 3 | export 'a_star_variant_b.dart'; 4 | export 'a_star_variant_c.dart'; 5 | -------------------------------------------------------------------------------- /tool/gen-l10n.bat: -------------------------------------------------------------------------------- 1 | :: Regenerates the localization file in the Presentation layer 2 | 3 | @echo off 4 | 5 | cd modules\presentation && ^ 6 | flutter gen-l10n --arb-dir=assets\l10n --output-dir=lib\l10n --no-synthetic-package -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/dash_animator.dart: -------------------------------------------------------------------------------- 1 | export 'cubit/dash_animator_group_cubit.dart'; 2 | export 'curves/curves.dart'; 3 | export 'dialogs/dialogs.dart'; 4 | export 'overlays/overlays.dart'; 5 | export 'widgets/widgets.dart'; 6 | -------------------------------------------------------------------------------- /modules/domain/lib/failures/failures.dart: -------------------------------------------------------------------------------- 1 | export 'failure.dart'; 2 | export 'game_already_started_failure.dart'; 3 | export 'game_not_started_failure.dart'; 4 | export 'no_available_spell_failure.dart'; 5 | export 'tile_not_movable_failure.dart'; 6 | -------------------------------------------------------------------------------- /modules/domain/lib/entities/entities.dart: -------------------------------------------------------------------------------- 1 | export 'active_spell_state.dart'; 2 | export 'available_spell_state.dart'; 3 | export 'game_settings.dart'; 4 | export 'game_state.dart'; 5 | export 'position.dart'; 6 | export 'puzzle.dart'; 7 | export 'tile.dart'; 8 | -------------------------------------------------------------------------------- /macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /modules/domain/lib/core/extensions/num_extension.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | /// An extension for the [num] class. 4 | extension NumExtension on num { 5 | /// Constraints the num value between [a] and [b] inclusively. 6 | num minMax(num a, num b) => max(min(this, b), a); 7 | } 8 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip 7 | -------------------------------------------------------------------------------- /macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/audio/audio.dart: -------------------------------------------------------------------------------- 1 | export 'mute_all_audio/mute_all_audio_use_case.dart'; 2 | export 'play_local_audio/play_local_audio_use_case.dart'; 3 | export 'unmute_all_audio/unmute_all_audio_use_case.dart'; 4 | export 'watch_all_audio_muted_state/watch_all_audio_muted_state_use_case.dart'; 5 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:dash_slide_puzzle/injection_container/injection_container.dart'; 2 | import 'package:presentation/presentation.dart'; 3 | 4 | Future main() async { 5 | WidgetsFlutterBinding.ensureInitialized(); 6 | 7 | await initializeInjectionContainer(); 8 | 9 | runApp(const MainApp()); 10 | } 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /modules/application/lib/application.dart: -------------------------------------------------------------------------------- 1 | export 'package:codenic_bloc_use_case/codenic_bloc_use_case.dart'; 2 | export 'package:domain/core/core.dart'; 3 | export 'package:domain/entities/entities.dart'; 4 | export 'package:domain/failures/failures.dart'; 5 | export 'package:equatable/equatable.dart'; 6 | 7 | export 'use_cases/use_cases.dart'; 8 | -------------------------------------------------------------------------------- /modules/domain/lib/domain.dart: -------------------------------------------------------------------------------- 1 | export 'package:codenic_bloc_use_case/codenic_bloc_use_case.dart'; 2 | export 'package:collection/collection.dart'; 3 | export 'package:equatable/equatable.dart'; 4 | 5 | export 'core/core.dart'; 6 | export 'entities/entities.dart'; 7 | export 'failures/failures.dart'; 8 | export 'service_interfaces/service_interfaces.dart'; 9 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 77d935af4db863f6abd0b9c31c7e6df2a13de57b 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /modules/presentation/lib/puzzle/widgets/widgets.dart: -------------------------------------------------------------------------------- 1 | export 'app_bar/app_bar.dart'; 2 | export 'floating_action_buttons/floating_action_buttons.dart'; 3 | export 'game_action_button.dart'; 4 | export 'puzzle_board.dart'; 5 | export 'puzzle_board_group_layout.dart'; 6 | export 'puzzle_keyboard_handler.dart'; 7 | export 'puzzle_tile.dart'; 8 | export 'puzzle_tile.dart'; 9 | -------------------------------------------------------------------------------- /modules/domain/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 77d935af4db863f6abd0b9c31c7e6df2a13de57b 8 | channel: stable 9 | 10 | project_type: module 11 | -------------------------------------------------------------------------------- /modules/application/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 77d935af4db863f6abd0b9c31c7e6df2a13de57b 8 | channel: stable 9 | 10 | project_type: module 11 | -------------------------------------------------------------------------------- /modules/infrastructure/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 77d935af4db863f6abd0b9c31c7e6df2a13de57b 8 | channel: stable 9 | 10 | project_type: module 11 | -------------------------------------------------------------------------------- /modules/presentation/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 77d935af4db863f6abd0b9c31c7e6df2a13de57b 8 | channel: stable 9 | 10 | project_type: module 11 | -------------------------------------------------------------------------------- /tool/prebuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # FOR MAC OS AND LINUX SYSTEMS 4 | 5 | # This script does the following: 6 | # - Cleans the project 7 | # - Refetches all dependencies 8 | 9 | flutter clean 10 | flutter pub get modules/domain 11 | flutter pub get modules/infrastructure 12 | flutter pub get modules/application 13 | flutter pub get modules/presentation 14 | flutter pub get 15 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /modules/domain/README.md: -------------------------------------------------------------------------------- 1 | # domain 2 | 3 | A new flutter module project. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.dev/). 9 | 10 | For instructions integrating Flutter modules to your existing applications, 11 | see the [add-to-app documentation](https://flutter.dev/docs/development/add-to-app). 12 | -------------------------------------------------------------------------------- /windows/.gitignore: -------------------------------------------------------------------------------- 1 | flutter/ephemeral/ 2 | 3 | # Visual Studio user-specific files. 4 | *.suo 5 | *.user 6 | *.userosscache 7 | *.sln.docstates 8 | 9 | # Visual Studio build-related files. 10 | x64/ 11 | x86/ 12 | 13 | # Visual Studio cache files 14 | # files ending in .cache can be ignored 15 | *.[Cc]ache 16 | # but keep track of directories ending in .cache 17 | !*.[Cc]ache/ 18 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /modules/application/README.md: -------------------------------------------------------------------------------- 1 | # application 2 | 3 | A new flutter module project. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.dev/). 9 | 10 | For instructions integrating Flutter modules to your existing applications, 11 | see the [add-to-app documentation](https://flutter.dev/docs/development/add-to-app). 12 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /modules/infrastructure/README.md: -------------------------------------------------------------------------------- 1 | # infrastructure 2 | 3 | A new flutter module project. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.dev/). 9 | 10 | For instructions integrating Flutter modules to your existing applications, 11 | see the [add-to-app documentation](https://flutter.dev/docs/development/add-to-app). 12 | -------------------------------------------------------------------------------- /modules/presentation/README.md: -------------------------------------------------------------------------------- 1 | # presentation 2 | 3 | A new flutter module project. 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.dev/). 9 | 10 | For instructions integrating Flutter modules to your existing applications, 11 | see the [add-to-app documentation](https://flutter.dev/docs/development/add-to-app). 12 | -------------------------------------------------------------------------------- /tool/prebuild.bat: -------------------------------------------------------------------------------- 1 | :: FOR WINDOWS SYSTEM 2 | 3 | :: This script does the following: 4 | :: - Cleans the project 5 | :: - Refetches all dependencies 6 | 7 | @echo off 8 | 9 | flutter clean && ^ 10 | flutter pub get modules/domain && ^ 11 | flutter pub get modules/infrastructure && ^ 12 | flutter pub get modules/application && ^ 13 | flutter pub get modules/presentation && ^ 14 | flutter pub get 15 | -------------------------------------------------------------------------------- /modules/presentation/lib/constants/breakpoints.dart: -------------------------------------------------------------------------------- 1 | /// Breakpoints for determining different screen sizes. 2 | abstract class Breakpoints { 3 | /// Max width for a small layout. 4 | static const double small = 600; 5 | 6 | /// Min width for a medium layout. 7 | static const double medium = 1240; 8 | 9 | /// Max width for a medium layout. 10 | static const double large = 1440; 11 | } 12 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void fl_register_plugins(FlPluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_ 8 | #define GENERATED_PLUGIN_REGISTRANT_ 9 | 10 | #include 11 | 12 | // Registers Flutter plugins. 13 | void RegisterPlugins(flutter::PluginRegistry* registry); 14 | 15 | #endif // GENERATED_PLUGIN_REGISTRANT_ 16 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | 11 | void RegisterPlugins(flutter::PluginRegistry* registry) { 12 | UrlLauncherWindowsRegisterWithRegistrar( 13 | registry->GetRegistrarForPlugin("UrlLauncherWindows")); 14 | } 15 | -------------------------------------------------------------------------------- /macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /lib/injection_container/dependency_injectables.dart: -------------------------------------------------------------------------------- 1 | part of 'injection_container.dart'; 2 | 3 | /// Registers all external dependencies in the [serviceLocator] as a lazy 4 | /// singleton. 5 | Future _injectDependencies(GetIt serviceLocator) async { 6 | void _register(FactoryFunc factoryFunc) => 7 | serviceLocator.registerLazySingleton(factoryFunc); 8 | 9 | _register(CodenicLogger.new); 10 | } 11 | -------------------------------------------------------------------------------- /modules/presentation/lib/assets/images/logo_assets.dart: -------------------------------------------------------------------------------- 1 | import 'package:presentation/presentation.dart'; 2 | 3 | /// A class for fetching logo assets. 4 | class LogoAssets { 5 | const LogoAssets._(); 6 | 7 | static final _root = 8 | join(['packages', 'presentation', 'assets', 'images', 'logos']); 9 | 10 | /// Returns the file path of the `flutter_mono.webp` asset. 11 | static String get flutter => join([_root, 'flutter_mono.webp']); 12 | } 13 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/game/preview_completed_puzzle/preview_completed_puzzle_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart'; 2 | 3 | /// A use case for checking whether to preview the completed puzzle. 4 | class PreviewCompletedPuzzleUseCase extends Runner { 5 | @override 6 | bool get rightValue => super.rightValue ?? false; 7 | 8 | @override 9 | Future> onCall(void params) async => Right(!rightValue); 10 | } 11 | -------------------------------------------------------------------------------- /linux/my_application.h: -------------------------------------------------------------------------------- 1 | #ifndef FLUTTER_MY_APPLICATION_H_ 2 | #define FLUTTER_MY_APPLICATION_H_ 3 | 4 | #include 5 | 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, 7 | GtkApplication) 8 | 9 | /** 10 | * my_application_new: 11 | * 12 | * Creates a new Flutter-based application. 13 | * 14 | * Returns: a new #MyApplication. 15 | */ 16 | MyApplication* my_application_new(); 17 | 18 | #endif // FLUTTER_MY_APPLICATION_H_ 19 | -------------------------------------------------------------------------------- /modules/domain/lib/failures/game_not_started_failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/failures/failure.dart'; 2 | 3 | /// {@template GameNotStartedFailure} 4 | /// 5 | /// A [Failure] indicating that the game has not started yet. 6 | /// 7 | /// {@endtemplate} 8 | class GameNotStartedFailure extends Failure { 9 | /// {@macro GameNotStartedFailure} 10 | const GameNotStartedFailure({ 11 | String message = 'The game has not started yet', 12 | }) : super(message: message); 13 | } 14 | -------------------------------------------------------------------------------- /modules/domain/lib/failures/no_available_spell_failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/failures/failure.dart'; 2 | 3 | /// {@template NoAvailableSpellFailure} 4 | /// 5 | /// A [Failure] indicating that a spell is not available yet for casting. 6 | /// 7 | /// {@endtemplate} 8 | class NoAvailableSpellFailure extends Failure { 9 | /// {@macro NoAvailableSpellFailure} 10 | const NoAvailableSpellFailure({String message = 'Spells not ready'}) 11 | : super(message: message); 12 | } 13 | -------------------------------------------------------------------------------- /macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /modules/domain/lib/failures/game_already_started_failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/failures/failure.dart'; 2 | 3 | /// {@template GameAlreadyStartedFailure} 4 | /// 5 | /// A [Failure] indicating that the game is currently in progress. 6 | /// 7 | /// {@endtemplate} 8 | class GameAlreadyStartedFailure extends Failure { 9 | /// {@macro GameAlreadyStartedFailure} 10 | const GameAlreadyStartedFailure({ 11 | String message = 'The game has already started', 12 | }) : super(message: message); 13 | } 14 | -------------------------------------------------------------------------------- /windows/runner/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by Runner.rc 4 | // 5 | #define IDI_APP_ICON 101 6 | 7 | // Next default values for new objects 8 | // 9 | #ifdef APSTUDIO_INVOKED 10 | #ifndef APSTUDIO_READONLY_SYMBOLS 11 | #define _APS_NEXT_RESOURCE_VALUE 102 12 | #define _APS_NEXT_COMMAND_VALUE 40001 13 | #define _APS_NEXT_CONTROL_VALUE 1001 14 | #define _APS_NEXT_SYMED_VALUE 101 15 | #endif 16 | #endif 17 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugin_registrant.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | // clang-format off 6 | 7 | #include "generated_plugin_registrant.h" 8 | 9 | #include 10 | 11 | void fl_register_plugins(FlPluginRegistry* registry) { 12 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = 13 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); 14 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); 15 | } 16 | -------------------------------------------------------------------------------- /modules/domain/lib/failures/concurrent_method_call_failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/failures/failure.dart'; 2 | 3 | /// {@template ConcurrentMethodCallFailure} 4 | /// 5 | /// A [Failure] indicating that one or more method calls are running 6 | /// concurrently. 7 | /// 8 | /// {@endtemplate} 9 | class ConcurrentMethodCallFailure extends Failure { 10 | /// {@macro ConcurrentMethodCallFailure} 11 | const ConcurrentMethodCallFailure({ 12 | String message = 'Concurrent method call detected', 13 | }) : super(message: message); 14 | } 15 | -------------------------------------------------------------------------------- /modules/domain/lib/failures/tile_not_movable_failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/entities/tile.dart'; 2 | import 'package:domain/failures/failure.dart'; 3 | 4 | /// {@template TileOutOfBoundsFailure} 5 | /// 6 | /// A [Failure] indicating that the selected [Tile] cannot be moved. 7 | /// 8 | /// {@endtemplate} 9 | class TileNotMovableFailure extends Failure { 10 | /// {@macro TileOutOfBoundsFailure} 11 | const TileNotMovableFailure({ 12 | String message = 'Selected tile cannot be moved', 13 | }) : super(message: message); 14 | } 15 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/widgets/widgets.dart: -------------------------------------------------------------------------------- 1 | export 'dash_animator.dart'; 2 | export 'dash_animator_group/dash_animator_group.dart'; 3 | export 'dash_body_animator.dart'; 4 | export 'dash_comb_animator.dart'; 5 | export 'dash_device_animator.dart'; 6 | export 'dash_face_animator.dart'; 7 | export 'dash_hover_animator.dart'; 8 | export 'dash_left_wing_animator.dart'; 9 | export 'dash_right_wing_animator.dart'; 10 | export 'dash_tail_animator.dart'; 11 | export 'dash_wand_animator.dart'; 12 | export 'object_throw_animator.dart'; 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/game/game.dart: -------------------------------------------------------------------------------- 1 | export 'cast_available_spell/cast_available_spell_use_case.dart'; 2 | export 'move_player_tile/move_player_tile_use_case.dart'; 3 | export 'preview_completed_puzzle/preview_completed_puzzle_use_case.dart'; 4 | export 'reset_game/reset_game_use_case.dart'; 5 | export 'start_game/start_game_use_case.dart'; 6 | export 'watch_active_spell_state/watch_active_spell_state_use_case.dart'; 7 | export 'watch_available_spell_state/watch_available_spell_state_use_case.dart'; 8 | export 'watch_game/watch_game_state_use_case.dart'; 9 | -------------------------------------------------------------------------------- /windows/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | url_launcher_windows 7 | ) 8 | 9 | set(PLUGIN_BUNDLED_LIBRARIES) 10 | 11 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 12 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) 13 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 14 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 15 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 16 | endforeach(plugin) 17 | -------------------------------------------------------------------------------- /modules/domain/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: domain 2 | description: The layer containing all business objects and core business rules. 3 | 4 | version: 1.0.0+1 5 | 6 | publish_to: none 7 | 8 | environment: 9 | sdk: ">=2.15.1 <3.0.0" 10 | 11 | dependencies: 12 | codenic_bloc_use_case: ^0.1.0-dev.8 13 | collection: ^1.15.0 14 | flutter: 15 | sdk: flutter 16 | 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | very_good_analysis: ^2.4.0 21 | 22 | flutter: 23 | module: 24 | androidX: true 25 | androidPackage: com.orga.domain 26 | iosBundleIdentifier: com.orga.domain 27 | -------------------------------------------------------------------------------- /modules/application/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: application 2 | description: The layer responsible for managing the data flow between the Presentation and Domain layer. 3 | 4 | version: 1.0.0+1 5 | 6 | publish_to: none 7 | 8 | environment: 9 | sdk: ">=2.15.1 <3.0.0" 10 | 11 | dependencies: 12 | domain: 13 | path: ../domain 14 | flutter: 15 | sdk: flutter 16 | 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | 21 | very_good_analysis: ^2.4.0 22 | 23 | flutter: 24 | module: 25 | androidX: true 26 | androidPackage: com.orga.application 27 | iosBundleIdentifier: com.orga.application 28 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/game/start_game/start_game_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// {@template StartGameUseCase} 4 | /// 5 | /// A use case for starting the game. 6 | /// 7 | /// See [GameService.startGame]. 8 | /// 9 | /// {@endtemplate} 10 | class StartGameUseCase extends Runner { 11 | /// {@macro StartGameUseCase} 12 | StartGameUseCase({required GameService gameService}) 13 | : _gameService = gameService; 14 | 15 | final GameService _gameService; 16 | 17 | @override 18 | Future> onCall(void params) => _gameService.startGame(); 19 | } 20 | -------------------------------------------------------------------------------- /modules/domain/lib/core/extensions/either_extension.dart: -------------------------------------------------------------------------------- 1 | import 'package:codenic_bloc_use_case/codenic_bloc_use_case.dart'; 2 | 3 | /// An extension for the `dartz` [Either] class. 4 | extension EitherExtension on Either { 5 | 6 | /// Returns the [R] value. 7 | /// 8 | /// If there is no [R] value, then a [StateError] will be thrown. 9 | R getRight() => fold((l) => throw StateError(l.toString()), (r) => r); 10 | 11 | /// Returns the [L] value. 12 | /// 13 | /// If there is no [L] value, then a [StateError] will be thrown. 14 | L getLeft() => fold((l) => l, (r) => throw StateError(r.toString())); 15 | } 16 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/game/reset_game/reset_game_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// {@template ResetGameUseCase} 4 | /// 5 | /// A use case for resetting the game. 6 | /// 7 | /// See [GameService.resetGame]. 8 | /// 9 | /// {@endtemplate} 10 | class ResetGameUseCase extends Runner { 11 | /// {@macro ResetGameUseCase} 12 | ResetGameUseCase({required GameService gameService}) 13 | : _gameService = gameService; 14 | 15 | final GameService _gameService; 16 | 17 | @override 18 | Future> onCall(void params) => _gameService.resetGame(); 19 | } 20 | -------------------------------------------------------------------------------- /lib/injection_container/injection_container.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart'; 2 | import 'package:domain/domain.dart'; 3 | import 'package:infrastructure/infrastructure.dart'; 4 | import 'package:presentation/presentation.dart'; 5 | 6 | part 'dependency_injectables.dart'; 7 | part 'service_injectables.dart'; 8 | part 'use_case_injectables.dart'; 9 | 10 | /// Injects all service components to the [serviceLocator]. 11 | 12 | Future initializeInjectionContainer() async { 13 | await Future.wait([ 14 | _injectDependencies(serviceLocator), 15 | _injectServices(serviceLocator), 16 | _injectUseCases(serviceLocator), 17 | ]); 18 | } 19 | -------------------------------------------------------------------------------- /macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /windows/runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(runner LANGUAGES CXX) 3 | 4 | add_executable(${BINARY_NAME} WIN32 5 | "flutter_window.cpp" 6 | "main.cpp" 7 | "utils.cpp" 8 | "win32_window.cpp" 9 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" 10 | "Runner.rc" 11 | "runner.exe.manifest" 12 | ) 13 | apply_standard_settings(${BINARY_NAME}) 14 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") 15 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) 16 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") 17 | add_dependencies(${BINARY_NAME} flutter_assemble) 18 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/audio/mute_all_audio/mute_all_audio_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// {@template MuteAllAudioUseCase} 4 | /// 5 | /// A use case for muting all audio players. 6 | /// 7 | /// See [AudioService.muteAll]. 8 | /// 9 | /// {@endtemplate} 10 | class MuteAllAudioUseCase extends Runner { 11 | /// {@macro MuteAllAudioUseCase} 12 | MuteAllAudioUseCase({required AudioService audioService}) 13 | : _audioService = audioService; 14 | 15 | final AudioService _audioService; 16 | 17 | @override 18 | Future> onCall(void params) => _audioService.muteAll(); 19 | } 20 | -------------------------------------------------------------------------------- /modules/domain/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | .idea/ 8 | .vagrant/ 9 | .sconsign.dblite 10 | .svn/ 11 | 12 | *.swp 13 | profile 14 | 15 | DerivedData/ 16 | 17 | .generated/ 18 | 19 | *.pbxuser 20 | *.mode1v3 21 | *.mode2v3 22 | *.perspectivev3 23 | 24 | !default.pbxuser 25 | !default.mode1v3 26 | !default.mode2v3 27 | !default.perspectivev3 28 | 29 | xcuserdata 30 | 31 | *.moved-aside 32 | 33 | *.pyc 34 | *sync/ 35 | Icon? 36 | .tags* 37 | 38 | build/ 39 | .android/ 40 | .ios/ 41 | .flutter-plugins 42 | .flutter-plugins-dependencies 43 | 44 | # Symbolication related 45 | app.*.symbols 46 | 47 | # Obfuscation related 48 | app.*.map.json 49 | -------------------------------------------------------------------------------- /modules/application/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | .idea/ 8 | .vagrant/ 9 | .sconsign.dblite 10 | .svn/ 11 | 12 | *.swp 13 | profile 14 | 15 | DerivedData/ 16 | 17 | .generated/ 18 | 19 | *.pbxuser 20 | *.mode1v3 21 | *.mode2v3 22 | *.perspectivev3 23 | 24 | !default.pbxuser 25 | !default.mode1v3 26 | !default.mode2v3 27 | !default.perspectivev3 28 | 29 | xcuserdata 30 | 31 | *.moved-aside 32 | 33 | *.pyc 34 | *sync/ 35 | Icon? 36 | .tags* 37 | 38 | build/ 39 | .android/ 40 | .ios/ 41 | .flutter-plugins 42 | .flutter-plugins-dependencies 43 | 44 | # Symbolication related 45 | app.*.symbols 46 | 47 | # Obfuscation related 48 | app.*.map.json 49 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/audio/unmute_all_audio/unmute_all_audio_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// {@template UnmuteAllAudioUseCase} 4 | /// 5 | /// A use case for muting all audio players. 6 | /// 7 | /// See [AudioService.unmuteAll]. 8 | /// 9 | /// {@endtemplate} 10 | class UnmuteAllAudioUseCase extends Runner { 11 | /// {@macro UnmuteAllAudioUseCase} 12 | UnmuteAllAudioUseCase({required AudioService audioService}) 13 | : _audioService = audioService; 14 | 15 | final AudioService _audioService; 16 | 17 | @override 18 | Future> onCall(void params) => 19 | _audioService.unmuteAll(); 20 | } 21 | -------------------------------------------------------------------------------- /modules/infrastructure/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: infrastructure 2 | description: The layer containing all service implementations. 3 | 4 | version: 1.0.0+1 5 | 6 | publish_to: none 7 | 8 | environment: 9 | sdk: ">=2.15.1 <3.0.0" 10 | 11 | dependencies: 12 | codenic_logger: ^0.5.5 13 | domain: 14 | path: ../domain 15 | flutter: 16 | sdk: flutter 17 | just_audio: ^0.9.20 18 | rxdart: ^0.27.3 19 | 20 | dev_dependencies: 21 | flutter_test: 22 | sdk: flutter 23 | mocktail: ^0.2.0 24 | very_good_analysis: ^2.4.0 25 | 26 | flutter: 27 | module: 28 | androidX: true 29 | androidPackage: com.orga.infrastructure 30 | iosBundleIdentifier: com.orga.infrastructure 31 | -------------------------------------------------------------------------------- /modules/presentation/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | .idea/ 8 | .vagrant/ 9 | .sconsign.dblite 10 | .svn/ 11 | 12 | *.swp 13 | profile 14 | 15 | DerivedData/ 16 | 17 | .generated/ 18 | 19 | *.pbxuser 20 | *.mode1v3 21 | *.mode2v3 22 | *.perspectivev3 23 | 24 | !default.pbxuser 25 | !default.mode1v3 26 | !default.mode2v3 27 | !default.perspectivev3 28 | 29 | xcuserdata 30 | 31 | *.moved-aside 32 | 33 | *.pyc 34 | *sync/ 35 | Icon? 36 | .tags* 37 | 38 | build/ 39 | .android/ 40 | .ios/ 41 | .flutter-plugins 42 | .flutter-plugins-dependencies 43 | 44 | # Symbolication related 45 | app.*.symbols 46 | 47 | # Obfuscation related 48 | app.*.map.json 49 | -------------------------------------------------------------------------------- /modules/presentation/lib/assets/animations/sky_animations.dart: -------------------------------------------------------------------------------- 1 | import 'package:presentation/presentation.dart'; 2 | 3 | /// A class for accessing Rive animations for the sky background. 4 | class SkyAnimations { 5 | SkyAnimations._(); 6 | 7 | static final _root = 8 | join(['packages', 'presentation', 'assets', 'animations']); 9 | 10 | /// The path to the sky Rive file. 11 | static final riveFilePath = join([_root, 'sky.riv']); 12 | 13 | /// A sky artboard designed for wide layouts. 14 | static const String landscapeArtboard = 'sky_landscape'; 15 | 16 | /// A sky artboard designed for narrow layouts. 17 | static const String portraitArtboard = 'sky_portrait'; 18 | } 19 | -------------------------------------------------------------------------------- /macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import audio_session 9 | import just_audio 10 | import path_provider_macos 11 | import url_launcher_macos 12 | 13 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 14 | AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) 15 | JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) 16 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) 17 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) 18 | } 19 | -------------------------------------------------------------------------------- /macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = Dash Slide Puzzle 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.orga.dashSlidePuzzle 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2022 com.orga. All rights reserved. 15 | -------------------------------------------------------------------------------- /modules/infrastructure/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | .idea/ 8 | .vagrant/ 9 | .sconsign.dblite 10 | .svn/ 11 | 12 | *.swp 13 | profile 14 | 15 | DerivedData/ 16 | 17 | .generated/ 18 | 19 | *.pbxuser 20 | *.mode1v3 21 | *.mode2v3 22 | *.perspectivev3 23 | 24 | !default.pbxuser 25 | !default.mode1v3 26 | !default.mode2v3 27 | !default.perspectivev3 28 | 29 | xcuserdata 30 | 31 | *.moved-aside 32 | 33 | *.pyc 34 | *sync/ 35 | Icon? 36 | .tags* 37 | 38 | build/ 39 | .android/ 40 | .ios/ 41 | .flutter-plugins 42 | .flutter-plugins-dependencies 43 | 44 | # Symbolication related 45 | app.*.symbols 46 | 47 | # Obfuscation related 48 | app.*.map.json 49 | -------------------------------------------------------------------------------- /lib/injection_container/service_injectables.dart: -------------------------------------------------------------------------------- 1 | part of 'injection_container.dart'; 2 | 3 | /// Registers all services in the [serviceLocator] as a lazy singleton. 4 | Future _injectServices(GetIt serviceLocator) async { 5 | void _register(FactoryFunc factoryFunc) => 6 | serviceLocator.registerLazySingleton(factoryFunc); 7 | 8 | _register(() => AudioServiceImpl(logger: serviceLocator())); 9 | 10 | _register( 11 | () => GameServiceImpl( 12 | logger: serviceLocator(), 13 | puzzleService: serviceLocator(), 14 | ), 15 | ); 16 | 17 | _register(() => PuzzleServiceImpl(logger: serviceLocator())); 18 | } 19 | -------------------------------------------------------------------------------- /modules/presentation/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | void main() { 2 | // testWidgets('Counter increments smoke test', (WidgetTester tester) async { 3 | // // Build our app and trigger a frame. 4 | // await tester.pumpWidget(const MyApp()); 5 | 6 | // // Verify that our counter starts at 0. 7 | // expect(find.text('0'), findsOneWidget); 8 | // expect(find.text('1'), findsNothing); 9 | 10 | // // Tap the '+' icon and trigger a frame. 11 | // await tester.tap(find.byIcon(Icons.add)); 12 | // await tester.pump(); 13 | 14 | // // Verify that our counter has incremented. 15 | // expect(find.text('0'), findsNothing); 16 | // expect(find.text('1'), findsOneWidget); 17 | // }); 18 | } 19 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | 23 | subprojects { 24 | project.buildDir = "${rootProject.buildDir}/${project.name}" 25 | project.evaluationDependsOn(':app') 26 | } 27 | 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /modules/domain/lib/failures/failure.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | 3 | /// {@template Failure} 4 | /// 5 | /// The base failure object returned when an exception occurrs. 6 | /// 7 | /// Failures are adapters for exceptions to decouple the presentation layer 8 | /// from the infra layer. 9 | /// 10 | /// {@endtemplate} 11 | class Failure with EquatableMixin { 12 | /// {@macro Failure} 13 | const Failure({this.message = "Something went wrong! We're looking into it"}); 14 | 15 | /// User-friendly message often displayed to the user. 16 | /// 17 | /// Keep this message less than or equal to 60 characters. 18 | final String message; 19 | 20 | @override 21 | List get props => [message]; 22 | } 23 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/game/cast_available_spell/cast_available_spell_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// {@template CastAvailableSpellUseCase} 4 | /// 5 | /// A use case for casting the available [Spell] the returns it. 6 | /// 7 | /// See [GameService.castAvailableSpell]. 8 | /// 9 | /// {@endtemplate} 10 | class CastAvailableSpellUseCase extends Runner { 11 | /// {@macro CastAvailableSpellUseCase} 12 | CastAvailableSpellUseCase({required GameService gameService}) 13 | : _gameService = gameService; 14 | 15 | final GameService _gameService; 16 | 17 | @override 18 | Future> onCall(void params) => 19 | _gameService.castAvailableSpell(); 20 | } 21 | -------------------------------------------------------------------------------- /modules/presentation/lib/audio_handler/enum/audio_player_channel.dart: -------------------------------------------------------------------------------- 1 | /// All available channels for playing an audio. 2 | /// 3 | /// Add more audio player channels here when needed. 4 | enum AudioPlayerChannel { 5 | /// The audio channel for UI clicks. 6 | click, 7 | 8 | /// The audio channel used when the puzzle is tapped. 9 | puzzleTile, 10 | 11 | /// The audio channel shared by the player and bot Dash. 12 | dashAnimatorGroup, 13 | 14 | /// The audio channel dedicated for the player Dash. 15 | playerDash, 16 | 17 | /// The audio channel dedicated for the bot Dash. 18 | botDash, 19 | 20 | /// The audio channel for general game sounds. 21 | game, 22 | 23 | /// The audio channel when a spell is available. 24 | spellAvailable, 25 | } 26 | -------------------------------------------------------------------------------- /windows/runner/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_UTILS_H_ 2 | #define RUNNER_UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | // Creates a console for the process, and redirects stdout and stderr to 8 | // it for both the runner and the Flutter library. 9 | void CreateAndAttachConsole(); 10 | 11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string 12 | // encoded in UTF-8. Returns an empty std::string on failure. 13 | std::string Utf8FromUtf16(const wchar_t* utf16_string); 14 | 15 | // Gets the command line arguments passed in as a std::vector, 16 | // encoded in UTF-8. Returns an empty std::vector on failure. 17 | std::vector GetCommandLineArguments(); 18 | 19 | #endif // RUNNER_UTILS_H_ 20 | -------------------------------------------------------------------------------- /modules/presentation/lib/assets/images/throwable_assets.dart: -------------------------------------------------------------------------------- 1 | import 'package:presentation/presentation.dart'; 2 | 3 | /// A class for fetching throwable assets. 4 | class ThrowableAssets { 5 | const ThrowableAssets._(); 6 | 7 | static final _root = 8 | join(['packages', 'presentation', 'assets', 'images', 'throwables']); 9 | 10 | /// Returns the file path of the specified [throwable] object. 11 | static String throwable(ThrowableObject throwable) { 12 | final String fileName; 13 | 14 | switch (throwable) { 15 | case ThrowableObject.pizza: 16 | fileName = 'pizza.webp'; 17 | break; 18 | case ThrowableObject.stone: 19 | fileName = 'stone.webp'; 20 | } 21 | 22 | return join([_root, fileName]); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /modules/presentation/lib/presentation.dart: -------------------------------------------------------------------------------- 1 | import 'package:get_it/get_it.dart'; 2 | 3 | export 'package:flutter/material.dart'; 4 | export 'package:flutter_bloc/flutter_bloc.dart'; 5 | export 'package:get_it/get_it.dart'; 6 | 7 | export 'assets/assets.dart'; 8 | export 'audio_handler/audio_handler.dart'; 9 | export 'background_handler/background_handler.dart'; 10 | export 'constants/constants.dart'; 11 | export 'dash_animator/dash_animator.dart'; 12 | export 'helpers/helpers.dart'; 13 | export 'l10n/app_localizations.dart'; 14 | export 'main_app.dart'; 15 | export 'puzzle/puzzle.dart'; 16 | export 'spell_handler/spell_handler.dart'; 17 | export 'themes/themes.dart'; 18 | 19 | /// Provides access to all service components of the system. 20 | final serviceLocator = GetIt.instance; 21 | -------------------------------------------------------------------------------- /modules/presentation/lib/helpers/strings/join.dart: -------------------------------------------------------------------------------- 1 | /// Creates an asset path by combining the [parts] into a single string 2 | /// separated by `/`. 3 | /// 4 | /// e.g. 5 | /// ```dart 6 | /// join(['hello', 'world','!']) = 'hello/world/!' 7 | /// ``` 8 | /// 9 | /// Unlike the [path](https://api.flutter.dev/flutter/package-path_path/package-path_path-library.html) 10 | /// library, this doesn't change the separator to `\` on Windows since 11 | /// resource paths on Flutter uses `/` regardless of the utilized platform. 12 | String join(List parts) { 13 | final buffer = StringBuffer(); 14 | 15 | for (var i = 0; i < parts.length; i++) { 16 | buffer.write(parts[i]); 17 | 18 | if (i < parts.length - 1) { 19 | buffer.write('/'); 20 | } 21 | } 22 | 23 | return buffer.toString(); 24 | } 25 | -------------------------------------------------------------------------------- /modules/presentation/lib/assets/animations/puzzle_board_animations.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart'; 2 | import 'package:presentation/presentation.dart'; 3 | 4 | /// A class for accessing Rive animations for the puzzle board tiles. 5 | class PuzzleBoardAnimations { 6 | PuzzleBoardAnimations._(); 7 | 8 | static final _root = 9 | join(['packages', 'presentation', 'assets', 'animations']); 10 | 11 | /// The path to the puzzle board Rive file. 12 | static final riveFilePath = join([_root, 'puzzle_board.riv']); 13 | 14 | /// The main artboard of the puzzle board Rive file. 15 | static const String mainArtboard = 'main'; 16 | 17 | /// Returns the artboard of the tile at the specified [position]. 18 | static String tileArtboard(Position position) => 19 | 'tile_x${position.x}y${position.y}'; 20 | } 21 | -------------------------------------------------------------------------------- /modules/presentation/lib/assets/images/spell_assets.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart'; 2 | import 'package:presentation/presentation.dart'; 3 | 4 | /// A class for fetching spell-related assets. 5 | class SpellAssets { 6 | const SpellAssets._(); 7 | 8 | static final _root = 9 | join(['packages', 'presentation', 'assets', 'images', 'spells']); 10 | 11 | /// Returns the file path of the specified [spell]. 12 | static String spell(Spell spell) { 13 | final String fileName; 14 | 15 | switch (spell) { 16 | case Spell.slow: 17 | fileName = 'pizza.webp'; 18 | break; 19 | case Spell.stun: 20 | fileName = 'throw.webp'; 21 | break; 22 | case Spell.timeReversal: 23 | fileName = 'magic.webp'; 24 | } 25 | 26 | return join([_root, fileName]); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /linux/flutter/generated_plugins.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Generated file, do not edit. 3 | # 4 | 5 | list(APPEND FLUTTER_PLUGIN_LIST 6 | url_launcher_linux 7 | ) 8 | 9 | list(APPEND FLUTTER_FFI_PLUGIN_LIST 10 | ) 11 | 12 | set(PLUGIN_BUNDLED_LIBRARIES) 13 | 14 | foreach(plugin ${FLUTTER_PLUGIN_LIST}) 15 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) 16 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) 17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $) 18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) 19 | endforeach(plugin) 20 | 21 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) 22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) 23 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) 24 | endforeach(ffi_plugin) 25 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/game/watch_game/watch_game_state_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// {@template WatchGameStateUseCase} 4 | /// 5 | /// A use case for watching the active [GameState]. 6 | /// 7 | /// See [GameService.watchGameState]. 8 | /// 9 | /// {@endtemplate} 10 | class WatchGameStateUseCase extends Watcher, Failure, GameState> { 12 | /// {@macro WatchGameStateUseCase} 13 | WatchGameStateUseCase({required GameService gameService}) 14 | : _gameService = gameService; 15 | 16 | final GameService _gameService; 17 | 18 | @override 19 | GameState get rightEvent => super.rightEvent ?? GameState(); 20 | 21 | @override 22 | Future>> onCall( 23 | void params, 24 | ) => 25 | _gameService.watchGameState(); 26 | } 27 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/audio/watch_all_audio_muted_state/watch_all_audio_muted_state_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// {@template WatchAllAudioMutedStateUseCase} 4 | /// 5 | /// A use case for watching whether all audios are muted or not. 6 | /// 7 | /// See [AudioService.watchAllMutedState]. 8 | /// 9 | /// {@endtemplate} 10 | class WatchAllAudioMutedStateUseCase extends Watcher, Failure, bool> { 12 | /// {@macro WatchAllAudioMutedStateUseCase} 13 | WatchAllAudioMutedStateUseCase({required AudioService audioService}) 14 | : _audioService = audioService; 15 | 16 | final AudioService _audioService; 17 | 18 | @override 19 | bool get rightEvent => super.rightEvent ?? false; 20 | 21 | @override 22 | Future>> onCall(void params) => 23 | _audioService.watchAllMutedState(); 24 | } 25 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dash_slide_puzzle", 3 | "short_name": "dash_slide_puzzle", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } -------------------------------------------------------------------------------- /modules/application/lib/use_cases/game/watch_active_spell_state/watch_active_spell_state_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart'; 2 | import 'package:domain/service_interfaces/game_service.dart'; 3 | 4 | /// {@template WatchActiveSpellStateUseCase} 5 | /// 6 | /// A use case for watching the [ActiveSpellState]. 7 | /// 8 | /// See [GameService.watchActiveSpellState]. 9 | /// 10 | /// {@endtemplate} 11 | class WatchActiveSpellStateUseCase extends Watcher, Failure, ActiveSpellState?> { 13 | /// {@macro WatchActiveSpellStateUseCase} 14 | WatchActiveSpellStateUseCase({required GameService gameService}) 15 | : _gameService = gameService; 16 | 17 | final GameService _gameService; 18 | 19 | @override 20 | Future>> onCall( 21 | void params, 22 | ) => 23 | _gameService.watchActiveSpellState(); 24 | } 25 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/curves/arc_curve.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | /// {@template ArcCurve} 6 | /// 7 | /// An animation curve that moves in an arc pattern. 8 | /// 9 | /// **NOTE:** 10 | /// 11 | /// This curve interpolates the `t` value from `0`->`1`->`0`. Hence, 12 | /// it is advisable to avoid using this directly inside a `CurvedAnimation` or 13 | /// risk receiving the exception `Invalid curve endpoint at 1.0` 14 | /// (See: https://github.com/xPutnikx/flutter-passcode/issues/23). 15 | /// Instead, use the `transform` method to convert the [Animation.value] to the 16 | /// desired `t` value. 17 | /// 18 | /// ```dart 19 | /// final t = ArcCurve().transform(animation.value); 20 | /// ``` 21 | /// 22 | /// {@endtemplate} 23 | class ArcCurve extends Curve { 24 | /// {@macro ArcCurve} 25 | const ArcCurve(); 26 | 27 | @override 28 | double transform(double t) => sin(t * pi); 29 | } 30 | -------------------------------------------------------------------------------- /windows/runner/runner.exe.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PerMonitorV2 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /modules/presentation/lib/assets/images/day_cycle_assets.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart'; 2 | import 'package:presentation/presentation.dart'; 3 | 4 | /// A class for fetching the day cycle assets (day, prevening, evening). 5 | class DayCycleAssets { 6 | const DayCycleAssets._(); 7 | 8 | static final _root = 9 | join(['packages', 'presentation', 'assets', 'images', 'day_cycles']); 10 | 11 | /// Returns the file path to a day cycle asset respective to the given 12 | /// [themeOption]. 13 | static String dayCycle(ThemeOption themeOption) { 14 | final String fileName; 15 | 16 | switch (themeOption) { 17 | case ThemeOption.day: 18 | fileName = 'day.webp'; 19 | break; 20 | case ThemeOption.night: 21 | fileName = 'night.webp'; 22 | break; 23 | case ThemeOption.prevening: 24 | fileName = 'prevening.webp'; 25 | } 26 | 27 | return join([_root, fileName]); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/cubit/dash_animator_group_cubit.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:application/application.dart'; 4 | import 'package:presentation/presentation.dart'; 5 | 6 | part 'dash_animator_group_state.dart'; 7 | 8 | /// {@template DashAnimatorGroupCubit} 9 | /// 10 | /// A cubit for managing the state of the Dashes in [DashAnimatorGroup]. 11 | /// 12 | /// {@endtemplate} 13 | class DashAnimatorGroupCubit extends Cubit { 14 | /// {@macro DashAnimatorGroupCubit} 15 | DashAnimatorGroupCubit() : super(DashAnimatorGroupState.generate()); 16 | 17 | /// Generates a random attire for the player Dash. 18 | void changePlayerDashAttire() => emit( 19 | state.copyWith(playerDashAttire: state.playerDashAttire.randomize()), 20 | ); 21 | 22 | /// Generates a random attire for the bot Dash. 23 | void changeBotDashAttire() => emit( 24 | state.copyWith(botDashAttire: state.botDashAttire.randomize()), 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dash_slide_puzzle 2 | description: The root module. 3 | 4 | publish_to: "none" 5 | 6 | version: 1.1.0+9 7 | 8 | environment: 9 | sdk: ">=2.15.1 <3.0.0" 10 | 11 | dependencies: 12 | application: 13 | path: modules/application 14 | domain: 15 | path: modules/domain 16 | flutter: 17 | sdk: flutter 18 | infrastructure: 19 | path: modules/infrastructure 20 | presentation: 21 | path: modules/presentation 22 | 23 | dev_dependencies: 24 | flutter_launcher_icons: ^0.9.2 25 | 26 | flutter_test: 27 | sdk: flutter 28 | 29 | very_good_analysis: ^2.4.0 30 | 31 | flutter: 32 | uses-material-design: true 33 | 34 | flutter_icons: 35 | android: true 36 | ios: true 37 | remove_alpha_ios: true 38 | image_path_android: "assets/icons/app_icon_square_rounded.png" 39 | image_path_ios: "assets/icons/app_icon_square_sharp.png" 40 | adaptive_icon_background: "assets/icons/app_icon_background.png" 41 | adaptive_icon_foreground: "assets/icons/app_icon_foreground.png" 42 | -------------------------------------------------------------------------------- /modules/presentation/lib/helpers/dialogs/show_glass_dialog.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_animated_dialog/flutter_animated_dialog.dart'; 3 | 4 | /// A helper method for showing a white translucent dialog. 5 | Future showGlassDialog({ 6 | required BuildContext context, 7 | required Widget Function(BuildContext) builder, 8 | }) => 9 | showAnimatedDialog( 10 | context: context, 11 | barrierDismissible: true, 12 | barrierColor: Colors.transparent, 13 | animationType: DialogTransitionType.slideFromBottomFade, 14 | duration: const Duration(milliseconds: 200), 15 | builder: (context) { 16 | return SafeArea( 17 | child: AlertDialog( 18 | backgroundColor: Colors.white.withOpacity(0.87), 19 | shape: 20 | RoundedRectangleBorder(borderRadius: BorderRadius.circular(32)), 21 | content: builder(context), 22 | ), 23 | ); 24 | }, 25 | ); 26 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/game/watch_available_spell_state/watch_available_spell_state_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart'; 2 | import 'package:domain/service_interfaces/game_service.dart'; 3 | 4 | /// {@template WatchAvailableSpellStateUseCase} 5 | /// 6 | /// A use case for watching the [AvailableSpellState]. 7 | /// 8 | /// See [GameService.watchAvailableSpellState]. 9 | /// 10 | /// {@endtemplate} 11 | class WatchAvailableSpellStateUseCase extends Watcher< 12 | void, 13 | Failure, 14 | VerboseStream, 15 | Failure, 16 | AvailableSpellState?> { 17 | /// {@macro WatchAvailableSpellStateUseCase} 18 | WatchAvailableSpellStateUseCase({required GameService gameService}) 19 | : _gameService = gameService; 20 | 21 | final GameService _gameService; 22 | 23 | @override 24 | Future>> onCall( 25 | void params, 26 | ) => 27 | _gameService.watchAvailableSpellState(); 28 | } 29 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/curves/mcdonald_curve.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | /// {@template McDonaldCurve} 6 | /// 7 | /// An animation curve that moves in a double arc pattern which mimics the `M` 8 | /// logo of McDonalds. 9 | /// 10 | /// **NOTE:** 11 | /// 12 | /// This curve interpolates the `t` value from `0`->`1`->`0`->`1`->`0`. Hence, 13 | /// it is advisable to avoid using this directly inside a `CurvedAnimation` or 14 | /// risk receiving the exception `Invalid curve endpoint at 1.0` 15 | /// (See: https://github.com/xPutnikx/flutter-passcode/issues/23). 16 | /// Instead, use the `transform` method to convert the [Animation.value] to the 17 | /// desired `t` value. 18 | /// 19 | /// ```dart 20 | /// final t = ArcCurve().transform(animation.value); 21 | /// ``` 22 | /// 23 | /// {@endtemplate} 24 | class McDonaldCurve extends Curve { 25 | /// {@macro McDonaldCurve} 26 | const McDonaldCurve(); 27 | 28 | @override 29 | double transform(double t) => sin(t * pi * 2).abs(); 30 | } 31 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /modules/presentation/lib/helpers/animation/sync_rive_animation_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart' as app; 2 | import 'package:presentation/presentation.dart'; 3 | import 'package:rive/rive.dart'; 4 | 5 | /// Syncs the theme of the tile to the current theme of the app. 6 | Future syncRiveAnimationTheme( 7 | State state, 8 | SMIInput themeSMIInput, 9 | ) async { 10 | if (!state.mounted) { 11 | return; 12 | } 13 | 14 | final context = state.context; 15 | 16 | final currentTheme = context.read().rightValue; 17 | 18 | final currentThemeIndex = app.ThemeOption.values.indexOf(currentTheme); 19 | 20 | final smiValue = themeSMIInput.value; 21 | 22 | if (smiValue != currentThemeIndex) { 23 | themeSMIInput.value = (smiValue + 1) % app.ThemeOption.values.length; 24 | 25 | await Future.delayed( 26 | const Duration(milliseconds: 300).randomInBetween( 27 | const Duration(milliseconds: 320), 28 | ), 29 | () => syncRiveAnimationTheme(state, themeSMIInput), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /modules/infrastructure/lib/services/puzzle_service/puzzle_solver/models/boundary.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// {@template Boundary} 4 | /// 5 | /// A rectangle boundary created by using two [Position]s for defining the 6 | /// lesser bound and higher bound. 7 | /// 8 | /// Comparison between the [lesserBound] and the [higherBound] is done via 9 | /// [Position.compareTo]. 10 | /// 11 | /// {@endtemplate} 12 | class Boundary with EquatableMixin { 13 | /// {@macro Boundary} 14 | Boundary({required this.lesserBound, required this.higherBound}) 15 | : assert( 16 | lesserBound.compareTo(higherBound) == -1, 17 | 'Lesser bound must be less than the higher bound', 18 | ); 19 | 20 | /// The smallest of the two bounds. This should be less than the 21 | /// [higherBound]. 22 | final Position lesserBound; 23 | 24 | /// The highest of the two bounds. This should be greater than the 25 | /// [lesserBound]. 26 | final Position higherBound; 27 | 28 | @override 29 | List get props => [lesserBound, higherBound]; 30 | } 31 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.h: -------------------------------------------------------------------------------- 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_ 2 | #define RUNNER_FLUTTER_WINDOW_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include "win32_window.h" 10 | 11 | // A window that does nothing but host a Flutter view. 12 | class FlutterWindow : public Win32Window { 13 | public: 14 | // Creates a new FlutterWindow hosting a Flutter view running |project|. 15 | explicit FlutterWindow(const flutter::DartProject& project); 16 | virtual ~FlutterWindow(); 17 | 18 | protected: 19 | // Win32Window: 20 | bool OnCreate() override; 21 | void OnDestroy() override; 22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, 23 | LPARAM const lparam) noexcept override; 24 | 25 | private: 26 | // The project to run. 27 | flutter::DartProject project_; 28 | 29 | // The Flutter instance hosted by this window. 30 | std::unique_ptr flutter_controller_; 31 | }; 32 | 33 | #endif // RUNNER_FLUTTER_WINDOW_H_ 34 | -------------------------------------------------------------------------------- /modules/domain/lib/service_interfaces/audio_service.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | import 'package:domain/domain.dart'; 4 | 5 | /// A service for playing audio. 6 | abstract class AudioService { 7 | /// Plays a locally stored audio referenced by the [localFilePath]. 8 | /// 9 | /// A specific audio player can be selected via the [audioPlayerChannel]. 10 | /// 11 | /// If the [localFilePath] does not point to an audio file or 12 | /// [audioPlayerChannel] does not reference any audio player, then an 13 | /// [ArgumentError] will be thrown. 14 | Future> playLocalAudio({ 15 | required String localFilePath, 16 | dynamic audioPlayerChannel, 17 | }); 18 | 19 | /// A stream that returns `true` when all audio players are muted. Otherwise, 20 | /// `false` is returned. 21 | Future>> watchAllMutedState(); 22 | 23 | /// Mutes all the audio player channels. 24 | Future> muteAll(); 25 | 26 | /// Unmutes all the audio player channels. 27 | Future> unmuteAll(); 28 | } 29 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/theme/switch_theme/switch_theme_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart'; 2 | 3 | /// The available theme options. 4 | enum ThemeOption { 5 | /// The identifier for the day theme. 6 | day, 7 | 8 | /// The identifier for the prevening theme. 9 | /// 10 | /// See https://bit.ly/3HkobC5. 11 | prevening, 12 | 13 | /// The identifier for the evening theme. 14 | night, 15 | } 16 | 17 | /// Switches the current theme to the next one. 18 | class SwitchThemeUseCase extends Runner { 19 | @override 20 | ThemeOption get rightValue => super.rightValue ?? ThemeOption.day; 21 | 22 | @override 23 | Future> onCall(void params) async { 24 | final oldThemeOption = rightValue; 25 | 26 | switch (oldThemeOption) { 27 | case ThemeOption.day: 28 | return const Right(ThemeOption.prevening); 29 | case ThemeOption.prevening: 30 | return const Right(ThemeOption.night); 31 | case ThemeOption.night: 32 | return const Right(ThemeOption.day); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Dominic Orga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | coverage/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Web related 36 | lib/generated_plugin_registrant.dart 37 | 38 | # Symbolication related 39 | app.*.symbols 40 | 41 | # Obfuscation related 42 | app.*.map.json 43 | 44 | # Android Studio will place build artifacts here 45 | /android/app/debug 46 | /android/app/profile 47 | /android/app/release 48 | 49 | # Firebase 50 | **/*.cache 51 | firebase.json 52 | .firebaserc 53 | .firebase 54 | 55 | # Android related 56 | **/debug.keystore 57 | **/release.keystore 58 | **/debugkey.properties 59 | **/releasekey.properties -------------------------------------------------------------------------------- /modules/presentation/lib/puzzle/widgets/floating_action_buttons/floating_action_buttons.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:presentation/puzzle/page/puzzle_page.dart'; 3 | import 'package:presentation/puzzle/widgets/floating_action_buttons/puzzle_preview_button.dart'; 4 | import 'package:presentation/puzzle/widgets/floating_action_buttons/theme_button.dart'; 5 | 6 | /// {@template FloatingActionButtons} 7 | /// 8 | /// A widget containing all the floating action buttons for the [PuzzlePage]. 9 | /// 10 | /// {@endtemplate} 11 | class FloatingActionButtons extends StatelessWidget { 12 | /// {@macro FloatingActionButtons} 13 | const FloatingActionButtons({Key? key}) : super(key: key); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Row( 18 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 19 | crossAxisAlignment: CrossAxisAlignment.end, 20 | children: const [ 21 | Padding( 22 | padding: EdgeInsets.all(16), 23 | child: PuzzlePreviewButton(), 24 | ), 25 | Padding( 26 | padding: EdgeInsets.all(16), 27 | child: ThemeButton(), 28 | ), 29 | ], 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /modules/presentation/lib/puzzle/widgets/app_bar/app_bar_title.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:presentation/assets/assets.dart'; 3 | import 'package:presentation/l10n/app_localizations.dart'; 4 | import 'package:presentation/puzzle/page/puzzle_page.dart'; 5 | import 'package:simple_shadow/simple_shadow.dart'; 6 | 7 | /// {@template AppBarTitle} 8 | /// 9 | /// The app bar title for the [PuzzlePage]. 10 | /// 11 | /// {@endtemplate} 12 | class AppBarTitle extends StatelessWidget { 13 | /// {@macro AppBarTitle} 14 | const AppBarTitle({Key? key}) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return FittedBox( 19 | child: Row( 20 | mainAxisAlignment: MainAxisAlignment.center, 21 | mainAxisSize: MainAxisSize.min, 22 | children: [ 23 | SimpleShadow( 24 | offset: Offset.zero, 25 | child: Image.asset(LogoAssets.flutter, scale: 6), 26 | ), 27 | const SizedBox(width: 8), 28 | SimpleShadow( 29 | offset: Offset.zero, 30 | child: Text(AppLocalizations.of(context).appTitle), 31 | ), 32 | ], 33 | ), 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/game/move_player_tile/move_player_tile_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// {@template MovePlayerTileUseCase} 4 | /// 5 | /// A use case for moving the player's puzzle tile. 6 | /// 7 | /// See [GameService.movePlayerTile]. 8 | /// 9 | /// {@endtemplate} 10 | class MovePlayerTileUseCase 11 | extends Runner { 12 | /// {@macro MovePlayerTileUseCase} 13 | MovePlayerTileUseCase({required GameService gameService}) 14 | : _gameService = gameService; 15 | 16 | final GameService _gameService; 17 | 18 | @override 19 | Future> onCall(MovePlayerTileParams params) => 20 | _gameService.movePlayerTile( 21 | tileCurrentPosition: params.tileCurrentPosition, 22 | ); 23 | } 24 | 25 | /// {@template MovePlayerTileParams} 26 | /// 27 | /// The parameter for [MovePlayerTileUseCase]. 28 | /// 29 | /// {@endtemplate} 30 | class MovePlayerTileParams with EquatableMixin { 31 | /// {@macro MovePlayerTileParams} 32 | const MovePlayerTileParams({required this.tileCurrentPosition}); 33 | 34 | /// The current [Position] of the tile to move. 35 | final Position tileCurrentPosition; 36 | 37 | @override 38 | List get props => [tileCurrentPosition]; 39 | } 40 | -------------------------------------------------------------------------------- /modules/domain/lib/entities/position.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:equatable/equatable.dart'; 4 | 5 | /// {@template position} 6 | /// 7 | /// 2-dimensional position model. 8 | /// 9 | /// (0, 0) is the top left corner of the board. 10 | /// 11 | /// {@endtemplate} 12 | class Position extends Equatable implements Comparable { 13 | /// {@macro position} 14 | const Position({required this.x, required this.y}); 15 | 16 | /// The x position. 17 | final int x; 18 | 19 | /// The y position. 20 | final int y; 21 | 22 | /// Calculates the distance between two [Position]s. 23 | double distance(Position other) => 24 | sqrt(pow(other.x - x, 2) + pow(other.y - y, 2)); 25 | 26 | /// Generates a new [Position] generated by adding this position with the 27 | /// given [position]. 28 | Position move(Position position) => 29 | Position(x: x + position.x, y: y + position.y); 30 | 31 | @override 32 | List get props => [x, y]; 33 | 34 | @override 35 | int compareTo(Position other) { 36 | if (y < other.y) { 37 | return -1; 38 | } else if (y > other.y) { 39 | return 1; 40 | } else if (x < other.x) { 41 | return -1; 42 | } else if (x > other.x) { 43 | return 1; 44 | } 45 | 46 | return 0; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - audio_session (0.0.1): 3 | - Flutter 4 | - Flutter (1.0.0) 5 | - just_audio (0.0.1): 6 | - Flutter 7 | - path_provider_ios (0.0.1): 8 | - Flutter 9 | - url_launcher_ios (0.0.1): 10 | - Flutter 11 | 12 | DEPENDENCIES: 13 | - audio_session (from `.symlinks/plugins/audio_session/ios`) 14 | - Flutter (from `Flutter`) 15 | - just_audio (from `.symlinks/plugins/just_audio/ios`) 16 | - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) 17 | - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) 18 | 19 | EXTERNAL SOURCES: 20 | audio_session: 21 | :path: ".symlinks/plugins/audio_session/ios" 22 | Flutter: 23 | :path: Flutter 24 | just_audio: 25 | :path: ".symlinks/plugins/just_audio/ios" 26 | path_provider_ios: 27 | :path: ".symlinks/plugins/path_provider_ios/ios" 28 | url_launcher_ios: 29 | :path: ".symlinks/plugins/url_launcher_ios/ios" 30 | 31 | SPEC CHECKSUMS: 32 | audio_session: 4f3e461722055d21515cf3261b64c973c062f345 33 | Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a 34 | just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa 35 | path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5 36 | url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de 37 | 38 | PODFILE CHECKSUM: cafcbad29b805125edbdc1ce6f6d247ad33727cc 39 | 40 | COCOAPODS: 1.11.2 41 | -------------------------------------------------------------------------------- /macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Dash Slide Puzzle 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | $(FLUTTER_BUILD_NAME) 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSApplicationCategoryType 26 | public.app-category.puzzle-games 27 | LSMinimumSystemVersion 28 | $(MACOSX_DEPLOYMENT_TARGET) 29 | NSHumanReadableCopyright 30 | $(PRODUCT_COPYRIGHT) 31 | NSMainNibFile 32 | MainMenu 33 | NSPrincipalClass 34 | NSApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /modules/domain/lib/entities/active_spell_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// {@template SpellState} 4 | /// 5 | /// A model for tracking the active spell casted on the bot. 6 | /// 7 | /// {@endtemplate} 8 | class ActiveSpellState with EquatableMixin { 9 | /// {@macro SpellState} 10 | const ActiveSpellState({ 11 | required this.spell, 12 | required this.startTime, 13 | required this.remainingTime, 14 | }) : assert( 15 | remainingTime >= 0 && remainingTime <= 1, 16 | 'Energy must have a value between 0 and 1 inclusively', 17 | ); 18 | 19 | /// The spell casted on the bot. 20 | final Spell spell; 21 | 22 | /// The time the spell took effect. 23 | final DateTime startTime; 24 | 25 | /// The remaining time for the [spell] starting from `1.0` going down to 26 | /// `0.0`. 27 | final double remainingTime; 28 | 29 | /// Creates a copy of this [ActiveSpellState] but with the given fields 30 | /// replaced with the new values. 31 | ActiveSpellState copyWith({ 32 | Spell? spell, 33 | DateTime? startTime, 34 | double? remainingTime, 35 | }) { 36 | return ActiveSpellState( 37 | spell: spell ?? this.spell, 38 | startTime: startTime ?? this.startTime, 39 | remainingTime: remainingTime ?? this.remainingTime, 40 | ); 41 | } 42 | 43 | @override 44 | List get props => [spell, startTime, remainingTime]; 45 | } 46 | -------------------------------------------------------------------------------- /modules/presentation/lib/background_handler/widgets/background_handler.dart: -------------------------------------------------------------------------------- 1 | import 'package:presentation/presentation.dart'; 2 | 3 | /// {@template BackgroundHandler} 4 | /// 5 | /// Renders the appropriate background based on the app's layout. 6 | /// 7 | /// {@endtemplate} 8 | class BackgroundHandler extends StatelessWidget { 9 | /// {@macro BackgroundHandler} 10 | const BackgroundHandler({required this.child, Key? key}) : super(key: key); 11 | 12 | /// The widget below this widget in the tree. 13 | final Widget child; 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return Stack( 18 | fit: StackFit.expand, 19 | children: [ 20 | LayoutBuilder( 21 | builder: (context, constraints) { 22 | return AnimatedSwitcher( 23 | duration: const Duration(milliseconds: 300), 24 | child: constraints.maxWidth <= Breakpoints.small 25 | ? const SkyAnimator( 26 | key: ValueKey(Orientation.portrait), 27 | orientation: Orientation.portrait, 28 | ) 29 | : const SkyAnimator( 30 | key: ValueKey(Orientation.landscape), 31 | orientation: Orientation.landscape, 32 | ), 33 | ); 34 | }, 35 | ), 36 | const StarsHandler(), 37 | child, 38 | ], 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /modules/presentation/lib/helpers/widgets/synced_animated_align.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// {@template SyncedAnimatedAlign} 4 | /// 5 | /// A widget with support for animating its aligned position that smoothly 6 | /// syncs with a new [startAlignment] or [endAlignment]. 7 | /// 8 | /// {@endtemplate} 9 | class SyncedAnimatedAlign extends AnimatedWidget { 10 | /// {@macro SyncedAnimatedAlign} 11 | const SyncedAnimatedAlign({ 12 | required this.startAlignment, 13 | required this.endAlignment, 14 | required this.child, 15 | required Animation animation, 16 | this.curve = Curves.linear, 17 | Key? key, 18 | }) : super(key: key, listenable: animation); 19 | 20 | /// The start alignment of the [child]. 21 | final Alignment startAlignment; 22 | 23 | /// The end alignment of the [child]. 24 | final Alignment endAlignment; 25 | 26 | /// The widget below this widget in the tree. 27 | final Widget child; 28 | 29 | /// The animation curve. 30 | final Curve curve; 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | final animation = listenable as Animation; 35 | 36 | final newAlignment = Tween(begin: startAlignment, end: endAlignment) 37 | .transform(curve.transform(animation.value)); 38 | 39 | return AnimatedAlign( 40 | alignment: newAlignment, 41 | duration: const Duration(milliseconds: 300), 42 | child: child, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /windows/runner/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "flutter_window.h" 6 | #include "utils.h" 7 | 8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, 9 | _In_ wchar_t *command_line, _In_ int show_command) { 10 | // Attach to console when present (e.g., 'flutter run') or create a 11 | // new console when running with a debugger. 12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { 13 | CreateAndAttachConsole(); 14 | } 15 | 16 | // Initialize COM, so that it is available for use in the library and/or 17 | // plugins. 18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); 19 | 20 | flutter::DartProject project(L"data"); 21 | 22 | std::vector command_line_arguments = 23 | GetCommandLineArguments(); 24 | 25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); 26 | 27 | FlutterWindow window(project); 28 | Win32Window::Point origin(10, 10); 29 | Win32Window::Size size(1280, 720); 30 | if (!window.CreateAndShow(L"dash_slide_puzzle", origin, size)) { 31 | return EXIT_FAILURE; 32 | } 33 | window.SetQuitOnClose(true); 34 | 35 | ::MSG msg; 36 | while (::GetMessage(&msg, nullptr, 0, 0)) { 37 | ::TranslateMessage(&msg); 38 | ::DispatchMessage(&msg); 39 | } 40 | 41 | ::CoUninitialize(); 42 | return EXIT_SUCCESS; 43 | } 44 | -------------------------------------------------------------------------------- /modules/application/lib/use_cases/audio/play_local_audio/play_local_audio_use_case.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// {@template PlayLocalAudioUseCase} 4 | /// 5 | /// A use case for playing an audio file stored locally. 6 | /// 7 | /// See [AudioService.playLocalAudio]. 8 | /// 9 | /// {@endtemplate} 10 | class PlayLocalAudioUseCase 11 | extends Runner { 12 | /// {@macro PlayLocalAudioUseCase} 13 | PlayLocalAudioUseCase({required AudioService audioService}) 14 | : _audioService = audioService; 15 | 16 | final AudioService _audioService; 17 | 18 | @override 19 | Future> onCall(PlayLocalAudioParams params) => 20 | _audioService.playLocalAudio( 21 | localFilePath: params.audioFilePath, 22 | audioPlayerChannel: params.audioPlayerChannel, 23 | ); 24 | } 25 | 26 | /// {@template PlayLocalAudioParams} 27 | /// 28 | /// The parameters for the [PlayLocalAudioUseCase]. 29 | /// 30 | /// {@endtemplate} 31 | class PlayLocalAudioParams with EquatableMixin { 32 | /// {@macro PlayLocalAudioParams} 33 | const PlayLocalAudioParams({ 34 | required this.audioFilePath, 35 | required this.audioPlayerChannel, 36 | }); 37 | 38 | /// The path to the audio file to play. 39 | final String audioFilePath; 40 | 41 | /// The audio player channel to use. 42 | final dynamic audioPlayerChannel; 43 | 44 | @override 45 | List get props => [audioFilePath]; 46 | } 47 | -------------------------------------------------------------------------------- /macos/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '11' 2 | 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 5 | 6 | project 'Runner', { 7 | 'Debug' => :debug, 8 | 'Profile' => :release, 9 | 'Release' => :release, 10 | } 11 | 12 | def flutter_root 13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) 14 | unless File.exist?(generated_xcode_build_settings_path) 15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" 16 | end 17 | 18 | File.foreach(generated_xcode_build_settings_path) do |line| 19 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 20 | return matches[1].strip if matches 21 | end 22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" 23 | end 24 | 25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 26 | 27 | flutter_macos_podfile_setup 28 | 29 | target 'Runner' do 30 | use_frameworks! 31 | use_modular_headers! 32 | 33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) 34 | end 35 | 36 | post_install do |installer| 37 | installer.pods_project.targets.each do |target| 38 | flutter_additional_macos_build_settings(target) 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /modules/presentation/lib/spell_handler/spell_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart' as app; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:presentation/assets/assets.dart'; 5 | 6 | /// {@template SpellButton} 7 | /// 8 | /// A button for activating the available spell. 9 | /// 10 | /// {@endtemplate} 11 | class SpellButton extends StatelessWidget { 12 | /// {@macro SpellButton} 13 | const SpellButton({Key? key}) : super(key: key); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | final availableSpell = 18 | context.select( 19 | (useCase) => useCase.rightEvent?.spell, 20 | ); 21 | 22 | return GestureDetector( 23 | onTap: () => 24 | context.read().run(params: null), 25 | child: AnimatedSwitcher( 26 | duration: const Duration(seconds: 1), 27 | reverseDuration: const Duration(milliseconds: 300), 28 | switchInCurve: Curves.elasticOut, 29 | switchOutCurve: Curves.easeOutQuart, 30 | transitionBuilder: (child, animation) => 31 | ScaleTransition(scale: animation, child: child), 32 | child: availableSpell == null 33 | ? null 34 | : Image.asset( 35 | SpellAssets.spell(availableSpell), 36 | key: ValueKey(availableSpell), 37 | ), 38 | ), 39 | ); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /modules/presentation/lib/themes/themes.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:google_fonts/google_fonts.dart'; 4 | 5 | /// Contains the available themes for the app. 6 | class Themes { 7 | /// Returns the correct theme based on the given [themeOption]. 8 | static ThemeData theme(ThemeOption themeOption) { 9 | final Color primaryColor; 10 | final Color primaryColorDark; 11 | final Color primaryColorLight; 12 | 13 | switch (themeOption) { 14 | case ThemeOption.day: 15 | primaryColor = Colors.blue.shade600; 16 | primaryColorLight = const Color(0xff69b6ff); 17 | primaryColorDark = const Color(0xff005bb2); 18 | break; 19 | case ThemeOption.prevening: 20 | primaryColor = Colors.purple; 21 | primaryColorLight = const Color(0xffc158dc); 22 | primaryColorDark = const Color(0xff5c007a); 23 | break; 24 | case ThemeOption.night: 25 | primaryColor = Colors.indigo; 26 | primaryColorLight = const Color(0xff6f74dd); 27 | primaryColorDark = const Color(0xff00227b); 28 | break; 29 | } 30 | 31 | return ThemeData( 32 | typography: Typography.material2018(), 33 | colorScheme: const ColorScheme.light().copyWith(primary: primaryColor), 34 | primaryColor: primaryColor, 35 | primaryColorDark: primaryColorDark, 36 | primaryColorLight: primaryColorLight, 37 | textTheme: GoogleFonts.bangersTextTheme(), 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/injection_container/use_case_injectables.dart: -------------------------------------------------------------------------------- 1 | part of 'injection_container.dart'; 2 | 3 | /// Registers all use cases in the [serviceLocator] as a factory. 4 | Future _injectUseCases(GetIt serviceLocator) async { 5 | void _register(FactoryFunc factoryFunc) => 6 | serviceLocator.registerFactory(factoryFunc); 7 | 8 | /// CCC 9 | 10 | _register(() => CastAvailableSpellUseCase(gameService: serviceLocator())); 11 | 12 | /// MMM 13 | 14 | _register(() => MovePlayerTileUseCase(gameService: serviceLocator())); 15 | 16 | _register(() => MuteAllAudioUseCase(audioService: serviceLocator())); 17 | 18 | /// PPP 19 | 20 | _register(() => PlayLocalAudioUseCase(audioService: serviceLocator())); 21 | 22 | _register(PreviewCompletedPuzzleUseCase.new); 23 | 24 | /// RRR 25 | _register(() => ResetGameUseCase(gameService: serviceLocator())); 26 | 27 | /// SSS 28 | 29 | _register(() => StartGameUseCase(gameService: serviceLocator())); 30 | 31 | _register(SwitchThemeUseCase.new); 32 | 33 | /// UUU 34 | 35 | _register(() => UnmuteAllAudioUseCase(audioService: serviceLocator())); 36 | 37 | /// WWW 38 | 39 | _register( 40 | () => WatchActiveSpellStateUseCase(gameService: serviceLocator()), 41 | ); 42 | 43 | _register( 44 | () => WatchAllAudioMutedStateUseCase(audioService: serviceLocator()), 45 | ); 46 | 47 | _register( 48 | () => WatchAvailableSpellStateUseCase(gameService: serviceLocator()), 49 | ); 50 | 51 | _register(() => WatchGameStateUseCase(gameService: serviceLocator())); 52 | } 53 | -------------------------------------------------------------------------------- /macos/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - audio_session (0.0.1): 3 | - FlutterMacOS 4 | - FlutterMacOS (1.0.0) 5 | - just_audio (0.0.1): 6 | - FlutterMacOS 7 | - path_provider_macos (0.0.1): 8 | - FlutterMacOS 9 | - url_launcher_macos (0.0.1): 10 | - FlutterMacOS 11 | 12 | DEPENDENCIES: 13 | - audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`) 14 | - FlutterMacOS (from `Flutter/ephemeral`) 15 | - just_audio (from `Flutter/ephemeral/.symlinks/plugins/just_audio/macos`) 16 | - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`) 17 | - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) 18 | 19 | EXTERNAL SOURCES: 20 | audio_session: 21 | :path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos 22 | FlutterMacOS: 23 | :path: Flutter/ephemeral 24 | just_audio: 25 | :path: Flutter/ephemeral/.symlinks/plugins/just_audio/macos 26 | path_provider_macos: 27 | :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos 28 | url_launcher_macos: 29 | :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos 30 | 31 | SPEC CHECKSUMS: 32 | audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72 33 | FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424 34 | just_audio: 9b67ca7b97c61cfc9784ea23cd8cc55eb226d489 35 | path_provider_macos: 160cab0d5461f0c0e02995469a98f24bdb9a3f1f 36 | url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3 37 | 38 | PODFILE CHECKSUM: f123aa273a6e264bc3e7f1cdc07e8b0ccfdecac7 39 | 40 | COCOAPODS: 1.11.2 41 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "debug_mobile", 9 | "request": "launch", 10 | "type": "dart", 11 | "program": "lib/main.dart", 12 | "args": [ 13 | "--debug" 14 | ] 15 | }, 16 | { 17 | "name": "profile_mobile", 18 | "request": "launch", 19 | "type": "dart", 20 | "program": "lib/main.dart", 21 | "args": [ 22 | "--profile" 23 | ] 24 | }, 25 | { 26 | "name": "debug_web", 27 | "request": "launch", 28 | "type": "dart", 29 | "program": "lib/main.dart", 30 | "args": [ 31 | "--debug", 32 | "-d", 33 | "chrome" 34 | ] 35 | }, 36 | { 37 | "name": "profile_web", 38 | "request": "launch", 39 | "type": "dart", 40 | "program": "lib/main.dart", 41 | "args": [ 42 | "--profile", 43 | "-d", 44 | "chrome" 45 | ] 46 | }, 47 | { 48 | "name": "debug_macos", 49 | "request": "launch", 50 | "type": "dart", 51 | "program": "lib/main.dart", 52 | "args": [ 53 | "--debug", 54 | "-d", 55 | "macos" 56 | ] 57 | }, 58 | { 59 | "name": "profile_macos", 60 | "request": "launch", 61 | "type": "dart", 62 | "program": "lib/main.dart", 63 | "args": [ 64 | "--profile", 65 | "-d", 66 | "macos" 67 | ] 68 | } 69 | ] 70 | } -------------------------------------------------------------------------------- /modules/presentation/lib/spell_handler/spell_banner.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart' as app; 2 | import 'package:flutter/material.dart'; 3 | import 'package:presentation/assets/assets.dart'; 4 | 5 | /// {@template SpellBanner} 6 | /// 7 | /// A widget displayed to indicate that a spell has been casted. 8 | /// 9 | /// {@endtemplate} 10 | class SpellBanner extends StatelessWidget { 11 | /// {@macro SpelLBanner} 12 | const SpellBanner({required this.spell, Key? key}) : super(key: key); 13 | 14 | /// The spell casted. 15 | final app.Spell spell; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | return Column( 20 | children: [ 21 | Expanded( 22 | flex: 2, 23 | child: Image.asset(SpellAssets.spell(spell)), 24 | ), 25 | const SizedBox(height: 8), 26 | Expanded( 27 | child: FittedBox( 28 | child: Text( 29 | _spellDescription(spell), 30 | textAlign: TextAlign.center, 31 | style: Theme.of(context).textTheme.headlineMedium?.copyWith( 32 | color: Colors.white, 33 | shadows: [const Shadow(blurRadius: 3)], 34 | ), 35 | ), 36 | ), 37 | ), 38 | ], 39 | ); 40 | } 41 | 42 | String _spellDescription(app.Spell spell) { 43 | switch (spell) { 44 | case app.Spell.slow: 45 | return 'You slowed down Dash by throwing a pizza'; 46 | case app.Spell.stun: 47 | return "You skillfully knocked off Dash's device"; 48 | case app.Spell.timeReversal: 49 | return 'You casted a time reversal spell on Dash'; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /modules/presentation/lib/helpers/widgets/synced_animated_rotation.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | /// {@template SyncedAnimatedRotation} 6 | /// 7 | /// A widget with support for animating its rotation that smoothly syncs with 8 | /// a new [minRotation], [maxRotation] or [anchorPoint]. 9 | /// 10 | /// {@endtemplate} 11 | class SyncedAnimatedRotation extends AnimatedWidget { 12 | /// {@macro SyncedAnimatedRotation} 13 | const SyncedAnimatedRotation({ 14 | required this.child, 15 | required this.minRotation, 16 | required this.maxRotation, 17 | required this.anchorPoint, 18 | required Animation animation, 19 | this.curve = Curves.linear, 20 | Key? key, 21 | }) : super(key: key, listenable: animation); 22 | 23 | /// The max rotation in degrees. 24 | final double maxRotation; 25 | 26 | /// The min rotation in degrees. 27 | final double minRotation; 28 | 29 | /// See [AnimatedContainer.transformAlignment]. 30 | final AlignmentGeometry anchorPoint; 31 | 32 | /// The widget below this widget in the tree. 33 | final Widget child; 34 | 35 | /// The animation curve. 36 | final Curve curve; 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | final animation = listenable as Animation; 41 | 42 | final newRotation = Tween(begin: minRotation, end: maxRotation) 43 | .transform(curve.transform(animation.value)); 44 | 45 | return AnimatedContainer( 46 | transformAlignment: anchorPoint, 47 | transform: Matrix4.rotationZ(newRotation * pi / 180), 48 | duration: const Duration(milliseconds: 300), 49 | child: child, 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/overlays/object_throw_animation_overlay.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:presentation/dash_animator/widgets/widgets.dart'; 4 | 5 | /// Renders the [ObjectThrowAnimator] widget in an overlay. 6 | class ObjectThrowAnimationOverlay { 7 | ObjectThrowAnimationOverlay._(); 8 | 9 | /// See [ObjectThrowAnimator]. 10 | static void throwObject({ 11 | required BuildContext context, 12 | required ThrowableObject throwableObject, 13 | required GlobalKey startObject, 14 | required GlobalKey endObject, 15 | Duration throwDuration = const Duration(milliseconds: 900), 16 | Duration preThrowDuration = Duration.zero, 17 | Duration postThrowDuration = const Duration(milliseconds: 3850), 18 | Duration inOutAnimationDuration = const Duration(milliseconds: 100), 19 | }) { 20 | final overlayEntry = OverlayEntry( 21 | builder: (context) => ObjectThrowAnimator( 22 | throwableObject: throwableObject, 23 | startObject: startObject, 24 | endObject: endObject, 25 | preThrowDuration: preThrowDuration, 26 | throwDuration: throwDuration, 27 | postThrowDuration: postThrowDuration, 28 | inOutAnimationDuration: inOutAnimationDuration, 29 | ), 30 | ); 31 | 32 | Overlay.of(context)?.insert(overlayEntry); 33 | 34 | final totalDuration = throwDuration.addAll([ 35 | preThrowDuration, 36 | postThrowDuration, 37 | inOutAnimationDuration, 38 | inOutAnimationDuration, // Add this twice for the in and out animation 39 | ]); 40 | 41 | Future.delayed(totalDuration, overlayEntry.remove); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /modules/presentation/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: presentation 2 | description: The layer managing all the UI widgets and user interaction. 3 | 4 | version: 1.0.0+1 5 | 6 | publish_to: none 7 | 8 | environment: 9 | sdk: ">=2.15.1 <3.0.0" 10 | 11 | dependencies: 12 | application: 13 | path: ../application 14 | draggable_fab: ^0.1.4 15 | flutter: 16 | sdk: flutter 17 | flutter_animated_dialog: ^2.0.1 18 | flutter_bloc: 19 | ^8.0.1 20 | flutter_localizations: 21 | sdk: flutter 22 | flutter_social_button: ^1.1.4 23 | font_awesome_flutter: ^9.2.0 24 | get_it: ^7.2.0 25 | google_fonts: ^2.3.1 26 | image: ^3.1.3 27 | intl: ^0.17.0 28 | liquid_progress_indicator: ^0.4.0 29 | loading_animations: ^2.2.0 30 | rive: ^0.8.1 31 | simple_shadow: ^0.3.0 32 | url_launcher: ^6.0.20 33 | 34 | dev_dependencies: 35 | flutter_test: 36 | sdk: flutter 37 | very_good_analysis: ^2.4.0 38 | 39 | 40 | flutter: 41 | uses-material-design: true 42 | 43 | assets: 44 | - assets/animations/ 45 | - assets/audio/sfx/ 46 | - assets/images/day_cycles/ 47 | - assets/images/dash_sprites/body/ 48 | - assets/images/dash_sprites/comb/ 49 | - assets/images/dash_sprites/devices/ 50 | - assets/images/dash_sprites/faces/ 51 | - assets/images/dash_sprites/tail/ 52 | - assets/images/dash_sprites/wand/ 53 | - assets/images/dash_sprites/wings/ 54 | - assets/images/logos/ 55 | - assets/images/spells/ 56 | - assets/images/throwables/ 57 | 58 | fonts: 59 | - family: Bangers 60 | fonts: 61 | - asset: fonts/Bangers-Regular.ttf 62 | 63 | 64 | module: 65 | androidX: true 66 | androidPackage: com.orga.presentation 67 | iosBundleIdentifier: com.orga.presentation 68 | -------------------------------------------------------------------------------- /modules/domain/lib/entities/tile.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/entities/position.dart'; 2 | import 'package:domain/entities/puzzle.dart'; 3 | import 'package:equatable/equatable.dart'; 4 | 5 | /// {@template Tile} 6 | /// 7 | /// A tile within a [Puzzle]. 8 | /// 9 | /// {@endtemplate} 10 | class Tile with EquatableMixin { 11 | /// {@macro Tile} 12 | const Tile({ 13 | required this.currentPosition, 14 | required this.targetPosition, 15 | this.isWhitespace = false, 16 | }); 17 | 18 | /// The current position of this tile within a [Puzzle]. 19 | final Position currentPosition; 20 | 21 | /// The target position of this tile within a [Puzzle]. 22 | final Position targetPosition; 23 | 24 | /// Indicates whether this tile is the whitespace tile in a [Puzzle]. 25 | final bool isWhitespace; 26 | 27 | /// Returns `true` when the [currentPosition] has reached the 28 | /// [targetPosition]. Otherwise, `false` is returned. 29 | bool get isCompleted => targetPosition == currentPosition; 30 | 31 | /// Calculates the distance between the [currentPosition] and the 32 | /// [targetPosition]. 33 | double get distanceToTargetPosition => 34 | currentPosition.distance(targetPosition); 35 | 36 | /// Creates a copy of this [Tile] but with the given fields replaced with the 37 | /// new values. 38 | Tile copyWith({ 39 | Position? currentPosition, 40 | Position? targetPosition, 41 | bool? isWhitespace, 42 | }) { 43 | return Tile( 44 | currentPosition: currentPosition ?? this.currentPosition, 45 | targetPosition: targetPosition ?? this.targetPosition, 46 | isWhitespace: isWhitespace ?? this.isWhitespace, 47 | ); 48 | } 49 | 50 | @override 51 | List get props => [currentPosition, targetPosition, isWhitespace]; 52 | } 53 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Dash Slide Puzzle 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | dash_slide_puzzle 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | end 36 | 37 | post_install do |installer| 38 | installer.pods_project.targets.each do |target| 39 | flutter_additional_ios_build_settings(target) 40 | 41 | # Disables microphone permission request by the just_audio package 42 | # See: https://pub.dev/packages/audio_session#ios-setup 43 | target.build_configurations.each do |config| 44 | config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ 45 | '$(inherited)', 46 | 'AUDIO_SESSION_MICROPHONE=0' 47 | ] 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /modules/domain/lib/entities/game_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// Contains all the possible status of game. 4 | enum GameStatus { 5 | /// A status wherein the game has not started yet. 6 | notStarted, 7 | 8 | /// A status that the game is being initialized. 9 | initializing, 10 | 11 | /// A status the the puzzles are being shuffled. 12 | shuffling, 13 | 14 | /// A status the the game is in progress. 15 | playing, 16 | 17 | /// A status that the player has won. 18 | playerWon, 19 | 20 | /// A status that the bot has won. 21 | botWon, 22 | } 23 | 24 | /// {@template GameState} 25 | /// 26 | /// A class containing the state of the game. 27 | /// 28 | /// {@endtemplate} 29 | class GameState with EquatableMixin { 30 | /// {@macro GameState} 31 | GameState({ 32 | this.status = GameStatus.notStarted, 33 | Puzzle? playerPuzzle, 34 | Puzzle? botPuzzle, 35 | }) : playerPuzzle = playerPuzzle ?? Puzzle.defaults(), 36 | botPuzzle = botPuzzle ?? Puzzle.defaults(); 37 | 38 | /// The status of the game. 39 | final GameStatus status; 40 | 41 | /// The player's puzzle. 42 | final Puzzle playerPuzzle; 43 | 44 | /// The bot's puzzle. 45 | final Puzzle botPuzzle; 46 | 47 | /// The dimension of the player and the bot puzzles. 48 | int get puzzleDimension => playerPuzzle.dimension; 49 | 50 | /// Creates a copy of this [GameState] but with the given fields 51 | /// replaced with the new values. 52 | GameState copyWith({ 53 | GameStatus? status, 54 | Puzzle? playerPuzzle, 55 | Puzzle? botPuzzle, 56 | }) { 57 | return GameState( 58 | status: status ?? this.status, 59 | playerPuzzle: playerPuzzle ?? this.playerPuzzle, 60 | botPuzzle: botPuzzle ?? this.botPuzzle, 61 | ); 62 | } 63 | 64 | @override 65 | List get props => [status, playerPuzzle, botPuzzle]; 66 | } 67 | -------------------------------------------------------------------------------- /modules/presentation/lib/puzzle/widgets/floating_action_buttons/theme_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart' as app; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:presentation/assets/assets.dart'; 5 | 6 | /// {@template ThemeButton} 7 | /// 8 | /// A button for changing the app's theme. 9 | /// 10 | /// {@endTemplate} 11 | class ThemeButton extends StatelessWidget { 12 | /// {@macro ThemeButton} 13 | const ThemeButton({Key? key}) : super(key: key); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | final theme = context.select( 18 | (useCase) => useCase.rightValue, 19 | ); 20 | 21 | return Builder( 22 | builder: (context) { 23 | return Stack( 24 | alignment: Alignment.bottomCenter, 25 | children: [ 26 | Material( 27 | color: Colors.transparent, 28 | elevation: 8, 29 | borderRadius: BorderRadius.circular(24), 30 | child: const SizedBox.square(dimension: 47), 31 | ), 32 | AnimatedSwitcher( 33 | duration: const Duration(milliseconds: 500), 34 | child: Image.asset( 35 | DayCycleAssets.dayCycle(theme), 36 | key: UniqueKey(), 37 | scale: 10.5, 38 | ), 39 | ), 40 | ClipOval( 41 | child: Material( 42 | color: Colors.transparent, 43 | child: InkWell( 44 | onTap: () { 45 | context.read().run(params: null); 46 | }, 47 | child: const SizedBox.square(dimension: 47), 48 | ), 49 | ), 50 | ), 51 | ], 52 | ); 53 | }, 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /windows/runner/utils.cpp: -------------------------------------------------------------------------------- 1 | #include "utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | void CreateAndAttachConsole() { 11 | if (::AllocConsole()) { 12 | FILE *unused; 13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) { 14 | _dup2(_fileno(stdout), 1); 15 | } 16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) { 17 | _dup2(_fileno(stdout), 2); 18 | } 19 | std::ios::sync_with_stdio(); 20 | FlutterDesktopResyncOutputStreams(); 21 | } 22 | } 23 | 24 | std::vector GetCommandLineArguments() { 25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. 26 | int argc; 27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); 28 | if (argv == nullptr) { 29 | return std::vector(); 30 | } 31 | 32 | std::vector command_line_arguments; 33 | 34 | // Skip the first argument as it's the binary name. 35 | for (int i = 1; i < argc; i++) { 36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i])); 37 | } 38 | 39 | ::LocalFree(argv); 40 | 41 | return command_line_arguments; 42 | } 43 | 44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) { 45 | if (utf16_string == nullptr) { 46 | return std::string(); 47 | } 48 | int target_length = ::WideCharToMultiByte( 49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 50 | -1, nullptr, 0, nullptr, nullptr); 51 | if (target_length == 0) { 52 | return std::string(); 53 | } 54 | std::string utf8_string; 55 | utf8_string.resize(target_length); 56 | int converted_length = ::WideCharToMultiByte( 57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, 58 | -1, utf8_string.data(), 59 | target_length, nullptr, nullptr); 60 | if (converted_length == 0) { 61 | return std::string(); 62 | } 63 | return utf8_string; 64 | } 65 | -------------------------------------------------------------------------------- /windows/runner/flutter_window.cpp: -------------------------------------------------------------------------------- 1 | #include "flutter_window.h" 2 | 3 | #include 4 | 5 | #include "flutter/generated_plugin_registrant.h" 6 | 7 | FlutterWindow::FlutterWindow(const flutter::DartProject& project) 8 | : project_(project) {} 9 | 10 | FlutterWindow::~FlutterWindow() {} 11 | 12 | bool FlutterWindow::OnCreate() { 13 | if (!Win32Window::OnCreate()) { 14 | return false; 15 | } 16 | 17 | RECT frame = GetClientArea(); 18 | 19 | // The size here must match the window dimensions to avoid unnecessary surface 20 | // creation / destruction in the startup path. 21 | flutter_controller_ = std::make_unique( 22 | frame.right - frame.left, frame.bottom - frame.top, project_); 23 | // Ensure that basic setup of the controller was successful. 24 | if (!flutter_controller_->engine() || !flutter_controller_->view()) { 25 | return false; 26 | } 27 | RegisterPlugins(flutter_controller_->engine()); 28 | SetChildContent(flutter_controller_->view()->GetNativeWindow()); 29 | return true; 30 | } 31 | 32 | void FlutterWindow::OnDestroy() { 33 | if (flutter_controller_) { 34 | flutter_controller_ = nullptr; 35 | } 36 | 37 | Win32Window::OnDestroy(); 38 | } 39 | 40 | LRESULT 41 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message, 42 | WPARAM const wparam, 43 | LPARAM const lparam) noexcept { 44 | // Give Flutter, including plugins, an opportunity to handle window messages. 45 | if (flutter_controller_) { 46 | std::optional result = 47 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, 48 | lparam); 49 | if (result) { 50 | return *result; 51 | } 52 | } 53 | 54 | switch (message) { 55 | case WM_FONTCHANGE: 56 | flutter_controller_->engine()->ReloadSystemFonts(); 57 | break; 58 | } 59 | 60 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam); 61 | } 62 | -------------------------------------------------------------------------------- /modules/infrastructure/test/helpers/create_puzzle.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// Creates a [Puzzle] with the given [dimension]. 4 | /// 5 | /// The created puzzle will be in its completed state if not changed. 6 | /// 7 | /// If [whitespaceTileCurrentPosition] is not `null`, then the whitespace 8 | /// [Tile] will be swapped with the respective tile which may create an 9 | /// unsolvable tile. 10 | /// 11 | /// A 3x3 puzzle visualization: 12 | /// 13 | /// ``` 14 | /// ┌─────0───────1───────2────► x 15 | /// │ ┌─────┐ ┌─────┐ ┌─────┐ 16 | /// 0 │ 0 │ │ 1 │ │ 2 │ 17 | /// │ └─────┘ └─────┘ └─────┘ 18 | /// │ ┌─────┐ ┌─────┐ ┌─────┐ 19 | /// 1 │ 3 │ │ 4 │ │ 5 │ 20 | /// │ └─────┘ └─────┘ └─────┘ 21 | /// │ ┌─────┐ ┌─────┐ ┌─────┐ 22 | /// 2 │ 6 │ │ 7 │ │ │ 23 | /// │ └─────┘ └─────┘ └─────┘ 24 | /// ▼ 25 | /// y 26 | /// ``` 27 | Puzzle createPuzzle( 28 | int dimension, { 29 | Position? whitespaceTileCurrentPosition, 30 | }) { 31 | final targetPositions = [ 32 | for (var y = 0; y < dimension; y++) 33 | for (var x = 0; x < dimension; x++) Position(x: x, y: y) 34 | ]; 35 | 36 | final currentPositions = targetPositions.toList(); 37 | 38 | if (whitespaceTileCurrentPosition != null) { 39 | // Swap the whitespace tile position with the respective tile position 40 | 41 | final positionIndex = currentPositions 42 | .indexWhere((position) => position == whitespaceTileCurrentPosition); 43 | 44 | final whitespacePositionIndex = dimension * dimension - 1; 45 | 46 | currentPositions[positionIndex] = currentPositions[whitespacePositionIndex]; 47 | currentPositions[whitespacePositionIndex] = whitespaceTileCurrentPosition; 48 | } 49 | 50 | final tiles = [ 51 | for (var i = 0; i < targetPositions.length; i++) 52 | Tile( 53 | targetPosition: targetPositions[i], 54 | currentPosition: currentPositions[i], 55 | isWhitespace: targetPositions[i].x == dimension - 1 && 56 | targetPositions[i].y == dimension - 1, 57 | ), 58 | ]; 59 | 60 | return Puzzle(tiles: tiles); 61 | } 62 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/widgets/dash_face_animator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:presentation/assets/assets.dart'; 3 | import 'package:presentation/dash_animator/widgets/widgets.dart'; 4 | 5 | /// {@template DashFaceAnimator} 6 | /// 7 | /// A widget for animating Dash's plump face. 8 | /// 9 | /// {@endtemplate} 10 | class DashFaceAnimator extends StatelessWidget { 11 | /// {@macro DashFaceAnimator} 12 | const DashFaceAnimator({ 13 | required this.animationState, 14 | required this.boundingSize, 15 | Key? key, 16 | }) : super(key: key); 17 | 18 | /// Dictates the animated pose of the face. 19 | final DashAnimationState animationState; 20 | 21 | /// The bounding box of Dash. 22 | /// 23 | /// This is used to determine the proportion of the face. 24 | final double boundingSize; 25 | 26 | @override 27 | Widget build(BuildContext context) { 28 | const alignment = FractionalOffset(5 / 12, 8 / 12); 29 | 30 | final DashFace face; 31 | 32 | switch (animationState) { 33 | case DashAnimationState.idle: 34 | case DashAnimationState.toss: 35 | face = DashFace.normal; 36 | break; 37 | case DashAnimationState.happy: 38 | case DashAnimationState.taunt: 39 | case DashAnimationState.wave: 40 | face = DashFace.happy; 41 | break; 42 | case DashAnimationState.wizardTaunt: 43 | face = DashFace.happyWizard; 44 | break; 45 | case DashAnimationState.excited: 46 | face = DashFace.kawaii; 47 | break; 48 | case DashAnimationState.wtf: 49 | face = DashFace.wtf; 50 | break; 51 | case DashAnimationState.wtfff: 52 | face = DashFace.wtfff; 53 | break; 54 | case DashAnimationState.loser: 55 | face = DashFace.sad; 56 | break; 57 | case DashAnimationState.spellcast: 58 | face = DashFace.wizard; 59 | } 60 | 61 | return Align( 62 | alignment: alignment, 63 | child: SizedBox.square( 64 | dimension: boundingSize * 0.6, 65 | child: AnimatedSwitcher( 66 | duration: const Duration(milliseconds: 300), 67 | child: Image.asset(DashSpriteAssets.face(face), key: ValueKey(face)), 68 | ), 69 | ), 70 | ); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /modules/presentation/lib/puzzle/widgets/puzzle_board.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:application/application.dart' as app; 4 | import 'package:presentation/presentation.dart'; 5 | 6 | /// {@template PuzzleBoard} 7 | /// 8 | /// A widget for rendering the puzzle. 9 | /// 10 | /// {@endtemplate} 11 | class PuzzleBoard extends StatefulWidget { 12 | /// {@macro PuzzleBoard} 13 | const PuzzleBoard({ 14 | required this.puzzle, 15 | this.isInteractive = false, 16 | this.isReactiveToSpells = false, 17 | Key? key, 18 | }) : super(key: key); 19 | 20 | /// The [app.Puzzle] being rendered. 21 | final app.Puzzle puzzle; 22 | 23 | /// See [PuzzleTile.isInteractive]. 24 | final bool isInteractive; 25 | 26 | /// See [PuzzleTile.isReactiveToSpells]. 27 | final bool isReactiveToSpells; 28 | 29 | @override 30 | State createState() => _PuzzleBoardState(); 31 | } 32 | 33 | class _PuzzleBoardState extends State 34 | with AutomaticKeepAliveClientMixin { 35 | @override 36 | bool get wantKeepAlive => true; 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | super.build(context); 41 | 42 | return LayoutBuilder( 43 | builder: (context, constraints) { 44 | final size = min(constraints.maxWidth, constraints.maxHeight); 45 | 46 | return Container( 47 | width: size, 48 | height: size, 49 | padding: const EdgeInsets.all(8), 50 | decoration: BoxDecoration( 51 | color: Colors.white54, 52 | borderRadius: BorderRadius.circular(8), 53 | ), 54 | child: Stack( 55 | children: widget.puzzle.tiles 56 | .map( 57 | (tile) => tile.isWhitespace 58 | ? const SizedBox() 59 | : PuzzleTile( 60 | key: Key('puzzle_tile_${tile.targetPosition}'), 61 | puzzle: widget.puzzle, 62 | tile: tile, 63 | isInteractive: widget.isInteractive, 64 | isReactiveToSpells: widget.isReactiveToSpells, 65 | ), 66 | ) 67 | .toList(), 68 | ), 69 | ); 70 | }, 71 | ); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/widgets/dash_animator_group/bot_dash_animator.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart' as app; 2 | import 'package:presentation/presentation.dart'; 3 | 4 | /// {@template BotDashAnimator} 5 | /// 6 | /// The [DashAnimator] for the bot. 7 | /// 8 | /// {@endtemplate} 9 | class BotDashAnimator extends StatelessWidget { 10 | /// {@macro BotDashAnimator} 11 | const BotDashAnimator({required this.dashAnimatorKey, Key? key}) 12 | : super(key: key); 13 | 14 | /// The key assigned to the nested [DashAnimator]. 15 | final GlobalKey dashAnimatorKey; 16 | 17 | @override 18 | Widget build(BuildContext context) { 19 | final gameStatus = 20 | context.select( 21 | (useCase) => useCase.rightEvent.status, 22 | ); 23 | 24 | final activeSpell = 25 | context.select( 26 | (useCase) => useCase.rightEvent?.spell, 27 | ); 28 | 29 | final dashAttire = context.select( 30 | (cubit) => cubit.state.botDashAttire, 31 | ); 32 | 33 | final DashAnimationState animationState; 34 | 35 | switch (gameStatus) { 36 | case app.GameStatus.notStarted: 37 | case app.GameStatus.initializing: 38 | case app.GameStatus.shuffling: 39 | animationState = DashAnimationState.idle; 40 | break; 41 | case app.GameStatus.playing: 42 | animationState = _mapActiveSpellToDashAnimation(activeSpell); 43 | break; 44 | case app.GameStatus.playerWon: 45 | animationState = DashAnimationState.loser; 46 | break; 47 | case app.GameStatus.botWon: 48 | animationState = DashAnimationState.taunt; 49 | break; 50 | } 51 | 52 | return DashAnimator( 53 | key: dashAnimatorKey, 54 | animationState: animationState, 55 | dashAttire: dashAttire, 56 | ); 57 | } 58 | 59 | DashAnimationState _mapActiveSpellToDashAnimation(app.Spell? spell) { 60 | switch (spell) { 61 | case app.Spell.slow: 62 | return DashAnimationState.excited; 63 | case app.Spell.stun: 64 | return DashAnimationState.wtf; 65 | case app.Spell.timeReversal: 66 | return DashAnimationState.wtfff; 67 | case null: 68 | return DashAnimationState.idle; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /modules/domain/lib/entities/available_spell_state.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | 3 | /// The spells that can be casted by the player to the bot. 4 | enum Spell { 5 | /// Slows down the bot. 6 | slow, 7 | 8 | /// Stuns the bot. 9 | stun, 10 | 11 | /// Reverses the puzzle steps taken by the bot. 12 | timeReversal, 13 | } 14 | 15 | /// {@template SpellState} 16 | /// 17 | /// A model for tracking the available spell and energy of the player. 18 | /// 19 | /// {@endtemplate} 20 | class AvailableSpellState with EquatableMixin { 21 | /// {@macro SpellState} 22 | const AvailableSpellState({ 23 | required this.energy, 24 | required this.lastSpellCastedTime, 25 | this.isRecentSpell = false, 26 | this.spell, 27 | }) : assert( 28 | energy >= 0 && energy <= 1, 29 | 'Energy must have a value between 0 and 1 inclusively', 30 | ); 31 | 32 | /// {@macro SpellState} 33 | /// 34 | /// This returns an [AvailableSpellState] with initial values. 35 | factory AvailableSpellState.initial() => AvailableSpellState( 36 | energy: 0, 37 | lastSpellCastedTime: DateTime.now(), 38 | ); 39 | 40 | /// The current energy level starting from `0` going up to `1` which defines 41 | /// what the available [spell] is. 42 | final double energy; 43 | 44 | /// The last time that a spell has been casted. 45 | final DateTime lastSpellCastedTime; 46 | 47 | /// This is `true` if the [spell] has just been added and is emitted for the 48 | /// first time. Once the [spell] has 49 | /// been emitted more than once, then this becomes `false`. 50 | final bool isRecentSpell; 51 | 52 | /// The spell that can be casted by the user. 53 | final Spell? spell; 54 | 55 | /// Creates a copy of this [AvailableSpellState] but with the given fields 56 | /// replaced with the new values. 57 | AvailableSpellState copyWith({ 58 | double? energy, 59 | bool? isRecentSpell, 60 | Spell? spell, 61 | DateTime? lastSpellCastedTime, 62 | }) { 63 | return AvailableSpellState( 64 | energy: energy ?? this.energy, 65 | isRecentSpell: isRecentSpell ?? this.isRecentSpell, 66 | spell: spell ?? this.spell, 67 | lastSpellCastedTime: lastSpellCastedTime ?? this.lastSpellCastedTime, 68 | ); 69 | } 70 | 71 | @override 72 | List get props => [ 73 | energy, 74 | spell, 75 | lastSpellCastedTime, 76 | isRecentSpell, 77 | ]; 78 | } 79 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /modules/domain/lib/service_interfaces/puzzle_service.dart: -------------------------------------------------------------------------------- 1 | import 'package:codenic_bloc_use_case/codenic_bloc_use_case.dart'; 2 | import 'package:domain/entities/position.dart'; 3 | import 'package:domain/entities/puzzle.dart'; 4 | import 'package:domain/entities/tile.dart'; 5 | import 'package:domain/failures/failure.dart'; 6 | import 'package:domain/failures/tile_not_movable_failure.dart'; 7 | 8 | /// {@template PuzzleService} 9 | /// 10 | /// A service that generates a sliding puzzle with available controls to 11 | /// interact with it. 12 | /// 13 | /// {@endtemplate} 14 | abstract class PuzzleService { 15 | /// {@macro PuzzleService} 16 | const PuzzleService(); 17 | 18 | /// Creates a solvable slider [Puzzle] with the given [dimension]. 19 | /// 20 | /// If [shuffle] is `true`, then the generated puzzle will be shuffled. 21 | /// Otherwise, the returned [Puzzle] will be in its completed state. 22 | /// 23 | /// A [puzzleId] can be assigned to the generated [Puzzle] for identification 24 | /// purposes. 25 | /// 26 | /// The [dimension] must be greater than `1`. 27 | Future> createPuzzle({ 28 | required int dimension, 29 | bool shuffle = true, 30 | String? puzzleId, 31 | }); 32 | 33 | /// Returns `true` if the [puzzle] can be solved. Otherwise, `false` is 34 | /// returned. 35 | Future> isPuzzleSolvable({required Puzzle puzzle}); 36 | 37 | /// Checks whether the [Tile] with [tileCurrentPosition] within [puzzle] can 38 | /// be moved in the direction of the whitespace [Tile]. 39 | /// 40 | /// Throws an [ArgumentError] if the [tileCurrentPosition] is not within the 41 | /// [puzzle] dimension. 42 | Future> isTileMovable({ 43 | required Puzzle puzzle, 44 | required Position tileCurrentPosition, 45 | }); 46 | 47 | /// Moves the tile with [tileCurrentPosition] within the [puzzle] then 48 | /// returns a new updated [Puzzle] containing the previous state. 49 | /// 50 | /// A [Failure] may be returned: 51 | /// - [TileNotMovableFailure] 52 | Future> moveTile({ 53 | required Puzzle puzzle, 54 | required Position tileCurrentPosition, 55 | }); 56 | 57 | /// Accepts an incomplete [puzzle] then returns a new solved [Puzzle] 58 | /// containing all its previous states leading to its completion. 59 | /// 60 | /// Throws an [ArgumentError] if the given [puzzle] is not solvable or is 61 | /// already completed. 62 | Future> solvePuzzle({required Puzzle puzzle}); 63 | } 64 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/widgets/dash_tail_animator.dart: -------------------------------------------------------------------------------- 1 | import 'package:presentation/presentation.dart'; 2 | 3 | /// {@template DashTailAnimator} 4 | /// 5 | /// A widget for animating Dash's tail. 6 | /// 7 | /// {@endtemplate} 8 | class DashTailAnimator extends StatelessWidget { 9 | /// {@macro DashTailAnimator} 10 | const DashTailAnimator({ 11 | required this.animationState, 12 | required this.animation, 13 | required this.boundingSize, 14 | Key? key, 15 | }) : super(key: key); 16 | 17 | /// Dictates the animated pose of the tail. 18 | final DashAnimationState animationState; 19 | 20 | /// The [Animation] for moving the tail. 21 | final Animation animation; 22 | 23 | /// The bounding box of Dash. 24 | /// 25 | /// This is used to determine the proportion of the tail. 26 | final double boundingSize; 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | const anchorPoint = Alignment.bottomLeft; 31 | const alignment = FractionalOffset(10.5 / 12, 4 / 12); 32 | const maxRotation = 0.0; 33 | 34 | final Curve curve; 35 | final double minRotation; 36 | 37 | switch (animationState) { 38 | case DashAnimationState.idle: 39 | case DashAnimationState.happy: 40 | case DashAnimationState.wave: 41 | case DashAnimationState.loser: 42 | case DashAnimationState.spellcast: 43 | case DashAnimationState.toss: 44 | curve = Curves.easeInOutSine; 45 | minRotation = -15; 46 | break; 47 | case DashAnimationState.excited: 48 | curve = Curves.easeInOutBack; 49 | minRotation = -20; 50 | break; 51 | case DashAnimationState.taunt: 52 | case DashAnimationState.wizardTaunt: 53 | curve = const McDonaldCurve(); 54 | minRotation = -30; 55 | break; 56 | case DashAnimationState.wtf: 57 | curve = Curves.easeInOutSine; 58 | minRotation = 0; 59 | break; 60 | case DashAnimationState.wtfff: 61 | curve = Curves.easeOutBack; 62 | minRotation = -30; 63 | break; 64 | } 65 | 66 | return Align( 67 | alignment: alignment, 68 | child: SizedBox.square( 69 | dimension: boundingSize * 0.25, 70 | child: SyncedAnimatedRotation( 71 | animation: animation, 72 | curve: curve, 73 | minRotation: minRotation, 74 | maxRotation: maxRotation, 75 | anchorPoint: anchorPoint, 76 | child: Image.asset(DashSpriteAssets.tail), 77 | ), 78 | ), 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/widgets/dash_comb_animator.dart: -------------------------------------------------------------------------------- 1 | import 'package:presentation/presentation.dart'; 2 | 3 | /// {@template DashCombAnimator} 4 | /// 5 | /// A widget for animating Dash's comb. 6 | /// 7 | /// {@endtemplate} 8 | class DashCombAnimator extends StatelessWidget { 9 | /// {@macro DashCombAnimator} 10 | const DashCombAnimator({ 11 | required this.animationState, 12 | required this.animation, 13 | required this.boundingSize, 14 | Key? key, 15 | }) : super(key: key); 16 | 17 | /// Dictates the animated pose of the comb. 18 | final DashAnimationState animationState; 19 | 20 | /// The [Animation] for moving the comb. 21 | final Animation animation; 22 | 23 | /// The bounding box of Dash. 24 | /// 25 | /// This is used to determine the proportion of the comb. 26 | final double boundingSize; 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | const anchorPoint = FractionalOffset(0.5 / 12, 10 / 12); 31 | const alignment = FractionalOffset(5.9 / 12, 0.5 / 12); 32 | const maxRotation = 0.0; 33 | 34 | final Curve curve; 35 | final double minRotation; 36 | 37 | switch (animationState) { 38 | case DashAnimationState.idle: 39 | case DashAnimationState.happy: 40 | case DashAnimationState.wave: 41 | case DashAnimationState.loser: 42 | case DashAnimationState.spellcast: 43 | case DashAnimationState.toss: 44 | curve = Curves.easeInOutSine; 45 | minRotation = -15; 46 | break; 47 | case DashAnimationState.excited: 48 | curve = Curves.easeInOutBack; 49 | minRotation = -20; 50 | break; 51 | case DashAnimationState.taunt: 52 | case DashAnimationState.wizardTaunt: 53 | curve = const McDonaldCurve(); 54 | minRotation = -30; 55 | break; 56 | case DashAnimationState.wtf: 57 | curve = Curves.easeInOutSine; 58 | minRotation = 0; 59 | break; 60 | case DashAnimationState.wtfff: 61 | curve = Curves.easeOutBack; 62 | minRotation = -30; 63 | break; 64 | } 65 | 66 | return Align( 67 | alignment: alignment, 68 | child: SizedBox.square( 69 | dimension: boundingSize * 0.28, 70 | child: SyncedAnimatedRotation( 71 | animation: animation, 72 | curve: curve, 73 | minRotation: minRotation, 74 | maxRotation: maxRotation, 75 | anchorPoint: anchorPoint, 76 | child: Image.asset(DashSpriteAssets.comb), 77 | ), 78 | ), 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /modules/presentation/lib/dash_animator/widgets/dash_body_animator.dart: -------------------------------------------------------------------------------- 1 | import 'package:presentation/presentation.dart'; 2 | 3 | /// {@template DashBodyAnimator} 4 | /// 5 | /// A widget for animating Dash's plump body. 6 | /// 7 | /// {@endtemplate} 8 | class DashBodyAnimator extends StatelessWidget { 9 | /// {@macro DashBodyAnimator} 10 | const DashBodyAnimator({ 11 | required this.animationState, 12 | required this.animation, 13 | required this.boundingSize, 14 | required this.dashBody, 15 | Key? key, 16 | }) : super(key: key); 17 | 18 | /// Dictates the animated pose of the body. 19 | final DashAnimationState animationState; 20 | 21 | /// The [Animation] for moving the body. 22 | final Animation animation; 23 | 24 | /// The bounding box of Dash. 25 | /// 26 | /// This is used to determine the proportion of the body. 27 | final double boundingSize; 28 | 29 | /// The clothing for the body. 30 | final DashBody dashBody; 31 | 32 | @override 33 | Widget build(BuildContext context) { 34 | const alignment = FractionalOffset(5 / 12, 9 / 12); 35 | final DashBody preferredDashBody; 36 | 37 | switch (animationState) { 38 | case DashAnimationState.idle: 39 | case DashAnimationState.toss: 40 | case DashAnimationState.happy: 41 | case DashAnimationState.wtf: 42 | case DashAnimationState.wtfff: 43 | case DashAnimationState.loser: 44 | case DashAnimationState.wave: 45 | preferredDashBody = dashBody; 46 | break; 47 | case DashAnimationState.taunt: 48 | case DashAnimationState.excited: 49 | preferredDashBody = dashBody; 50 | break; 51 | case DashAnimationState.wizardTaunt: 52 | preferredDashBody = DashBody.wizardRobe; 53 | break; 54 | case DashAnimationState.spellcast: 55 | preferredDashBody = DashBody.wizardRobe; 56 | break; 57 | } 58 | 59 | return Align( 60 | alignment: alignment, 61 | child: SizedBox.square( 62 | dimension: boundingSize, 63 | child: AnimatedSwitcher( 64 | duration: const Duration(milliseconds: 300), 65 | reverseDuration: const Duration(milliseconds: 600), 66 | switchOutCurve: Curves.easeOutExpo, 67 | transitionBuilder: (child, animation) => FadeTransition( 68 | opacity: animation, 69 | child: SizeTransition(sizeFactor: animation, child: child), 70 | ), 71 | child: Image.asset( 72 | DashSpriteAssets.body(preferredDashBody), 73 | key: ValueKey(preferredDashBody), 74 | ), 75 | ), 76 | ), 77 | ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /modules/presentation/lib/spell_handler/available_spell_indicator.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart' as app; 2 | import 'package:liquid_progress_indicator/liquid_progress_indicator.dart'; 3 | import 'package:presentation/presentation.dart'; 4 | import 'package:presentation/spell_handler/spell_button.dart'; 5 | 6 | /// {@template AvailableSpellIndicator} 7 | /// 8 | /// An animated widget that renders the available spell and energy of the 9 | /// player. 10 | /// 11 | /// {@endtemplate} 12 | class AvailableSpellIndicator extends StatelessWidget { 13 | /// {@macro AvailableSpellIndicator} 14 | const AvailableSpellIndicator({Key? key}) : super(key: key); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | return Stack( 19 | alignment: Alignment.centerLeft, 20 | children: [ 21 | Container( 22 | padding: const EdgeInsets.all(4), 23 | decoration: BoxDecoration( 24 | color: Colors.white54, 25 | borderRadius: BorderRadius.circular(108), 26 | ), 27 | constraints: const BoxConstraints(maxWidth: 512, maxHeight: 24), 28 | child: const _ProgressIndicator(), 29 | ), 30 | AspectRatio( 31 | aspectRatio: 1, 32 | child: Container( 33 | decoration: BoxDecoration( 34 | borderRadius: BorderRadius.circular(108), 35 | color: Colors.white54, 36 | ), 37 | padding: const EdgeInsets.all(4), 38 | child: Container( 39 | decoration: BoxDecoration( 40 | borderRadius: BorderRadius.circular(108), 41 | color: Theme.of(context).primaryColor, 42 | ), 43 | child: Stack( 44 | alignment: Alignment.center, 45 | clipBehavior: Clip.none, 46 | children: const [SpellButton()], 47 | ), 48 | ), 49 | ), 50 | ), 51 | ], 52 | ); 53 | } 54 | } 55 | 56 | class _ProgressIndicator extends StatelessWidget { 57 | const _ProgressIndicator({Key? key}) : super(key: key); 58 | 59 | @override 60 | Widget build(BuildContext context) { 61 | final spellEnergy = 62 | context.select( 63 | (useCase) => useCase.rightEvent?.energy ?? 0, 64 | ); 65 | 66 | return LiquidLinearProgressIndicator( 67 | value: spellEnergy, 68 | backgroundColor: Colors.transparent, 69 | valueColor: AlwaysStoppedAnimation(Theme.of(context).primaryColor), 70 | borderColor: Colors.transparent, 71 | borderWidth: 0, 72 | borderRadius: 108, 73 | ); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to the Package 2 | 3 | 👍🎉 First off, thanks for taking the time to contribute! 🎉👍 4 | 5 | The following is a set of guidelines for contributing to this package. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request. 6 | 7 | ## Proposing a Change 8 | 9 | If you intend to change the public API, or make any non-trivial changes to the implementation, we recommend filing an issue. This lets us reach an agreement on your proposal before you put significant effort into it. 10 | 11 | If you’re only fixing a bug, it’s fine to submit a pull request right away but we still recommend to file an issue detailing what you’re fixing. This is helpful in case we don’t accept that specific fix but want to keep track of the issue. 12 | 13 | ## Creating a Pull Request 14 | 15 | Before creating a pull request please: 16 | 17 | 1. Fork the repository and create your branch from `master`. 18 | 2. Install all dependencies (`dart pub get`). 19 | 3. Squash your commits and ensure you have a meaningful commit message. 20 | 4. If you’ve fixed a bug or added code that should be tested, add tests and ensure at 100% test coverage. (`flutter test --coverage --test-randomize-ordering-seed random && genhtml coverage/lcov.info --output=coverage`). 21 | - Flutter command is used for better reliability 22 | - You can use [Coverage Gutters](https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters) in VSCode to check the coverage report 23 | 5. Ensure the test suite passes. 24 | 6. If you've changed the public API, make sure to update/add documentation. 25 | 7. Format your code (`dart format .`). 26 | 8. Analyze your code (`dart analyze --fatal-infos --fatal-warnings .`). 27 | 9. Verify you code for perfect Pub score (`pana . --no-warning`). 28 | - See 29 | 10. Create the Pull Request. 30 | 11. Verify that all status checks are passing. 31 | 32 | While the prerequisites above must be satisfied prior to having your pull request reviewed, the reviewer(s) may ask you to complete additional design work, tests, or other changes before your pull request can be ultimately accepted. 33 | 34 | ## Getting in Touch 35 | 36 | If you want to just ask a question or get feedback on an idea you email at . 37 | 38 | ## License 39 | 40 | By contributing to Equatable, you agree that your contributions will be licensed under its MIT license. 41 | 42 | ## Attribution 43 | 44 | This contributing guide is adapted from Felix Angelov's [Equatable Package](https://github.com/felangel/equatable), available at 45 | -------------------------------------------------------------------------------- /modules/domain/lib/core/extensions/duration_extension.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | /// An extension for the [Duration] class. 4 | extension DurationExtension on Duration { 5 | /// Sums this duration and the [other] duration. 6 | Duration add(Duration other) { 7 | final totalMicroseconds = inMicroseconds + other.inMicroseconds; 8 | return Duration(microseconds: totalMicroseconds); 9 | } 10 | 11 | /// Sums this duration with all the other [durations]. 12 | Duration addAll(Iterable durations) { 13 | final totalMicroseconds = durations.fold( 14 | inMicroseconds, 15 | (previousTotal, duration) => previousTotal + duration.inMicroseconds, 16 | ); 17 | 18 | return Duration(microseconds: totalMicroseconds); 19 | } 20 | 21 | /// Subtracts this duration with the [other] duration. 22 | /// 23 | /// If the new [Duration] equates to a negative value, then it will be set to 24 | /// [Duration.zero]. 25 | Duration subtract(Duration other) { 26 | final totalMicroseconds = inMicroseconds - other.inMicroseconds; 27 | return totalMicroseconds < 0 28 | ? Duration.zero 29 | : Duration(microseconds: totalMicroseconds); 30 | } 31 | 32 | /// Subtracts this duration with the other [durations]. 33 | /// 34 | /// If the new [Duration] equates to a negative value, then it will be set to 35 | /// [Duration.zero]. 36 | Duration subtractAll(Iterable durations) { 37 | final totalMicroseconds = durations.fold( 38 | inMicroseconds, 39 | (previousTotal, duration) => previousTotal - duration.inMicroseconds, 40 | ); 41 | 42 | return totalMicroseconds < 0 43 | ? Duration.zero 44 | : Duration(microseconds: totalMicroseconds); 45 | } 46 | 47 | /// Returns a random [Duration] between this and the [other] duration. 48 | Duration randomInBetween(Duration other) { 49 | final durationInMicro = inMicroseconds; 50 | final durationInMicroOther = other.inMicroseconds; 51 | 52 | final largerValue = max(durationInMicro, durationInMicroOther); 53 | final smallerValue = min(durationInMicro, durationInMicroOther); 54 | 55 | final newDurationInMicro = 56 | (largerValue - smallerValue) * Random().nextDouble() + smallerValue; 57 | 58 | return Duration(microseconds: newDurationInMicro.toInt()); 59 | } 60 | 61 | /// Returns the mid [Duration] between this and the [other] duration. 62 | Duration inBetween(Duration other) { 63 | final durationInMicro = inMicroseconds; 64 | final durationInMicroOther = other.inMicroseconds; 65 | 66 | final largerValue = max(durationInMicro, durationInMicroOther); 67 | final smallerValue = min(durationInMicro, durationInMicroOther); 68 | 69 | final newDurationInMicro = (largerValue - smallerValue) + smallerValue; 70 | 71 | return Duration(microseconds: newDurationInMicro); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /modules/presentation/lib/puzzle/widgets/app_bar/action_item.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart' as app; 2 | import 'package:font_awesome_flutter/font_awesome_flutter.dart'; 3 | import 'package:presentation/presentation.dart'; 4 | import 'package:simple_shadow/simple_shadow.dart'; 5 | 6 | /// {@template ActionItem} 7 | /// 8 | /// The root widget for all the action items in [PuzzlePage]. 9 | /// 10 | /// {@endtemplate} 11 | class ActionItem extends StatelessWidget { 12 | /// {@macro ActionItem} 13 | const ActionItem({required this.onPressed, required this.iconData, Key? key}) 14 | : super(key: key); 15 | 16 | /// The callback button when this item is pressed. 17 | final VoidCallback onPressed; 18 | 19 | /// The icon for this action item. 20 | final IconData iconData; 21 | 22 | @override 23 | Widget build(BuildContext context) { 24 | return IconButton( 25 | color: Colors.white, 26 | onPressed: onPressed, 27 | icon: SimpleShadow(offset: Offset.zero, child: Icon(iconData)), 28 | ); 29 | } 30 | } 31 | 32 | /// {@template ShareActionItem} 33 | /// 34 | /// An app bar action item for sharing the app. 35 | /// 36 | /// {@endtemplate} 37 | class ShareActionItem extends StatelessWidget { 38 | /// {@macro ShareActionItem} 39 | const ShareActionItem({Key? key}) : super(key: key); 40 | 41 | @override 42 | Widget build(BuildContext context) { 43 | return ActionItem( 44 | onPressed: () { 45 | context.read().run( 46 | params: app.PlayLocalAudioParams( 47 | audioFilePath: SFXAssets.click, 48 | audioPlayerChannel: AudioPlayerChannel.click, 49 | ), 50 | ); 51 | 52 | ShareAppDialog.show(context: context); 53 | }, 54 | iconData: FontAwesomeIcons.shareAlt, 55 | ); 56 | } 57 | } 58 | 59 | /// {@template VolumeActionItem} 60 | /// 61 | /// An app bar action item for enabling or disabling the audio. 62 | /// 63 | /// {@endtemplate} 64 | class VolumeActionItem extends StatelessWidget { 65 | /// {@macro VolumeActionItem} 66 | const VolumeActionItem({Key? key}) : super(key: key); 67 | 68 | @override 69 | Widget build(BuildContext context) { 70 | final isAllAudioMuted = 71 | context.select( 72 | (useCase) => useCase.rightEvent, 73 | ); 74 | 75 | return AnimatedSwitcher( 76 | duration: const Duration(milliseconds: 200), 77 | child: isAllAudioMuted 78 | ? ActionItem( 79 | key: ValueKey(isAllAudioMuted), 80 | onPressed: () => 81 | context.read().run(params: null), 82 | iconData: FontAwesomeIcons.volumeOff, 83 | ) 84 | : ActionItem( 85 | key: ValueKey(isAllAudioMuted), 86 | onPressed: () => 87 | context.read().run(params: null), 88 | iconData: FontAwesomeIcons.volumeUp, 89 | ), 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /modules/presentation/lib/puzzle/dialogs/share_app_dialog/share_button.dart: -------------------------------------------------------------------------------- 1 | import 'package:application/application.dart' as app; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:flutter_social_button/flutter_social_button.dart'; 5 | import 'package:url_launcher/url_launcher.dart'; 6 | 7 | /// Contains the available social media for sharing the app. 8 | enum SocialMedia { 9 | /// A share button identifier for Twitter 10 | twitter, 11 | 12 | /// A share button identifier for Facebook 13 | facebook, 14 | } 15 | 16 | /// {@template ShareButton} 17 | /// 18 | /// A button for sharing the app to select social media platforms via HTTPs. 19 | /// 20 | /// {@endtemplate} 21 | class ShareButton extends StatelessWidget { 22 | /// {@macro ShareButton} 23 | const ShareButton({required this.socialMedia, Key? key}) : super(key: key); 24 | 25 | static const _appUrl = 'https://dominicorga.codenic.dev/dash-slide-puzzle'; 26 | 27 | /// The target social media for sharing the app. 28 | final SocialMedia socialMedia; 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return FlutterSocialButton( 33 | buttonType: _buttonType(), 34 | mini: true, 35 | onTap: () async { 36 | final watchGameStateUseCase = context.read(); 37 | final gameStatus = watchGameStateUseCase.rightEvent.status; 38 | 39 | final shareUrl = _shareUrl(gameStatus); 40 | 41 | if (await canLaunch(shareUrl)) { 42 | await launch(shareUrl); 43 | } 44 | }, 45 | ); 46 | } 47 | 48 | ButtonType _buttonType() { 49 | switch (socialMedia) { 50 | case SocialMedia.twitter: 51 | return ButtonType.twitter; 52 | case SocialMedia.facebook: 53 | return ButtonType.facebook; 54 | } 55 | } 56 | 57 | String _shareUrl(app.GameStatus? gameStatus) { 58 | final shareText = _message(gameStatus); 59 | final shareTextEncoded = Uri.encodeComponent(shareText); 60 | 61 | switch (socialMedia) { 62 | case SocialMedia.twitter: 63 | return 'https://twitter.com/intent/tweet?url=$_appUrl&text=$shareTextEncoded'; 64 | case SocialMedia.facebook: 65 | return 'https://www.facebook.com/sharer.php?u=$_appUrl"e=$shareTextEncoded'; 66 | } 67 | } 68 | 69 | String _message(app.GameStatus? gameStatus) { 70 | switch (gameStatus) { 71 | case app.GameStatus.playerWon: 72 | return 'Just beat Dash in this Slide Puzzle game from ' 73 | '#FlutterPuzzleHack! Check it out ↓'; 74 | case app.GameStatus.botWon: 75 | return "I can't beat Dash in this Slide Puzzle game from " 76 | '#FlutterPuzzleHack! Maybe you can? ↓'; 77 | case app.GameStatus.notStarted: 78 | case app.GameStatus.initializing: 79 | case app.GameStatus.shuffling: 80 | case app.GameStatus.playing: 81 | case null: 82 | return 'Can you beat Dash in this Slide Puzzle game from ' 83 | '#FlutterPuzzleHack? ↓'; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /modules/infrastructure/lib/services/puzzle_service/puzzle_solver/a_star/a_star_variant_b.dart: -------------------------------------------------------------------------------- 1 | import 'package:domain/domain.dart'; 2 | import 'package:infrastructure/services/puzzle_service/puzzle_solver/a_star/a_star_helper.dart'; 3 | import 'package:infrastructure/services/puzzle_service/puzzle_solver/a_star/a_star_variant_a.dart'; 4 | import 'package:infrastructure/services/puzzle_service/puzzle_solver/a_star/a_star_variant_c.dart'; 5 | 6 | /// An A* variant for helping solve the [Tile]s located at `B` in the graph 7 | /// below. 8 | /// 9 | /// ``` 10 | /// {solve order}.{A* variant} 11 | /// ┌─────0───────1───────2───────3────► x 12 | /// │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ 13 | /// 0 │ │ │ │ │ │ │ 0.B │ 14 | /// │ └─────┘ └─────┘ └─────┘ └─────┘ 15 | /// │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ 16 | /// 1 │ │ │ │ │ │ │ 2.B │ 17 | /// │ └─────┘ └─────┘ └─────┘ └─────┘ 18 | /// │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ 19 | /// 2 │ │ │ │ │ │ │ │ 20 | /// │ └─────┘ └─────┘ └─────┘ └─────┘ 21 | /// │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ 22 | /// 3 │ 1.B │ │ 3.B │ │ │ │ │ 23 | /// │ └─────┘ └─────┘ └─────┘ └─────┘ 24 | /// ▼ 25 | /// y 26 | /// ``` 27 | /// 28 | /// Note that this is a helper variant for the [AStarVariantC] and does not 29 | /// entirely solve tiles at `B`. Instead, this brings the `B` tiles within 30 | /// their respective `optimizer bounds` so that they can be solved by 31 | /// [AStarVariantC]. 32 | /// 33 | /// For more info on optimizer bounds, see [AStarHelper.createOptimizerBounds]. 34 | class AStarVariantB { 35 | const AStarVariantB._(); // coverage:ignore-line 36 | 37 | /// Returns the calculated path cost between the start [Node] and the current 38 | /// [puzzle] node. 39 | /// 40 | /// This is an implementation of [G]. 41 | static int g(Node puzzle) => puzzle.depth; 42 | 43 | /// {@macro AStarVariantA.h} 44 | static double h(Node puzzle, Position targetPosition) => 45 | AStarVariantA.h(puzzle, targetPosition); 46 | 47 | /// Returns `true` if both the [Tile] with the [targetPosition] and the 48 | /// whitespace [Tile] is within the respective `optimizer bounds` defined by 49 | /// [targetPosition]. 50 | /// 51 | /// For more info on optimizer bounds, see 52 | /// [AStarHelper.createOptimizerBounds]. 53 | /// 54 | /// An implementation of [Goal]. 55 | static bool goal(Node puzzle, Position targetPosition) { 56 | final dimension = puzzle.dimension; 57 | 58 | final bounds = AStarHelper.createOptimizerBounds(dimension, targetPosition); 59 | 60 | final tile = puzzle.tileWithTargetPosition(targetPosition)!; 61 | final whitespaceTile = puzzle.whitespaceTile; 62 | 63 | return AStarHelper.isWithinBounds(tile.currentPosition, bounds) && 64 | AStarHelper.isWithinBounds(whitespaceTile.currentPosition, bounds); 65 | } 66 | 67 | /// {@macro AStarVariantA.childNodes} 68 | static Future> childNodes( 69 | PuzzleService puzzleService, 70 | Node puzzle, 71 | Position targetPosition, 72 | ) => 73 | AStarVariantA.childNodes(puzzleService, puzzle, targetPosition); 74 | } 75 | --------------------------------------------------------------------------------