Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies:
sdk: flutter
provider: ^6.1.5
url_launcher: ^6.3.2
sensors_plus: ^6.1.1
sensors_plus: ^7.0.0

dev_dependencies:
analysis_defaults:
Expand Down
2 changes: 1 addition & 1 deletion add_to_app/plugin/flutter_module_using_plugin/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies:
sdk: flutter
provider: ^6.0.2
url_launcher: ^6.0.20
sensors_plus: ^6.1.1
sensors_plus: ^7.0.0

dev_dependencies:
analysis_defaults:
Expand Down
2 changes: 1 addition & 1 deletion animations/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies:
flutter:
sdk: flutter
flutter_animate: ^4.1.0
go_router: ^16.0.0
go_router: ^17.0.1
window_size: # plugin is not yet part of the flutter framework
git:
url: https://github.com/google/flutter-desktop-embedding.git
Expand Down
4 changes: 2 additions & 2 deletions compass_app/app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ dependencies:
sdk: flutter
flutter_svg: ^2.0.16
freezed_annotation: ^3.0.0
go_router: ^16.0.0
go_router: ^17.0.1
google_fonts: ^6.2.1
intl: any
json_annotation: ^4.9.0
logging: ^1.3.0
provider: ^6.1.2
share_plus: ^10.1.3
share_plus: ^12.0.1
shared_preferences: ^2.3.5

dev_dependencies:
Expand Down
2 changes: 1 addition & 1 deletion deeplink_store_example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
shrine_images: ^2.0.2
go_router: ^16.0.0
go_router: ^17.0.1

dev_dependencies:
analysis_defaults:
Expand Down
2 changes: 1 addition & 1 deletion desktop_photo_search/fluent_ui/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ dev_dependencies:
analysis_defaults:
path: ../../analysis_defaults
async: ^2.11.0
build: ^3.0.0
build: ^4.0.3
build_runner: ^2.4.6
built_value_generator: ^8.6.1
flutter_test:
Expand Down
2 changes: 1 addition & 1 deletion desktop_photo_search/material/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ dev_dependencies:
analysis_defaults:
path: ../../analysis_defaults
async: ^2.11.0
build: ^3.0.0
build: ^4.0.3
build_runner: ^2.4.6
built_value_generator: ^8.6.1
flutter_test:
Expand Down
2 changes: 1 addition & 1 deletion form_app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ dependencies:
git:
url: https://github.com/google/flutter-desktop-embedding.git
path: plugins/window_size
go_router: ^16.0.0
go_router: ^17.0.1

dev_dependencies:
analysis_defaults:
Expand Down
132 changes: 132 additions & 0 deletions game_template/.github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Copilot Instructions for Flutter Game Template

## Project Overview
This is a mobile game template built with Flutter showcasing a complete starter game with navigation, audio, state management, and optional integrations (ads, in-app purchases, games services, Firebase Crashlytics). The template is intentionally low-level on state management to avoid complexity while remaining extensible.

## Architecture & Key Components

### Feature-First Organization (`lib/src/`)
Code is organized by feature, not by layer. Each feature directory is semi-independent:
- `audio/` - Music and sound effects (via `audioplayers` package)
- `player_progress/` - Game progress tracking with persistence abstraction
- `settings/` - User preferences (muted, music, sound, player name)
- `app_lifecycle/` - Lifecycle event monitoring via `WidgetsBindingObserver`
- `main_menu/`, `level_selection/`, `play_session/`, `win_game/` - Screen features
- `ads/`, `games_services/`, `in_app_purchase/` - Optional integrations (disabled by default)
- `style/` - Palette, responsive layout, custom transitions

### State Management Pattern
Uses **Provider** with a low-level, intentional approach:
- **ChangeNotifier** for mutable state (`PlayerProgress`, `SettingsController`, `AudioController`)
- **ValueNotifier** for simple reactive properties (settings values, lifecycle state)
- **MultiProvider** setup in `main.dart` with explicit dependency ordering
- Key insight: `AudioController` depends on `SettingsController` via `ProxyProvider2` for reactive attachment
- No code generation; manually attach listeners using `attachSettings()` and `attachLifecycleNotifier()` patterns

### Persistence Abstraction
All persistent data uses dependency-injected interfaces:
- `PlayerProgressPersistence` (injected in `PlayerProgress`)
- `SettingsPersistence` (injected in `SettingsController`)
- Default implementation: `LocalStoragePlayerProgressPersistence`, `LocalStorageSettingsPersistence`
- This allows easy testing or swapping implementations (e.g., Firebase, cloud sync)

### Navigation
Uses **GoRouter** (v16.0.0+) with nested route structure in `main.dart`:
- Routes are statically defined in `MyApp._router`
- Transitions use custom `buildMyTransition<void>()` helper from `src/style/my_transition.dart`
- Parameters passed via `state.pathParameters` (e.g., level number in `/play/session/:level`)
- Extra data passed via `state.extra` and validated with guards (e.g., win screen redirect)

### Audio Integration
`AudioController` is a facade over `audioplayers` package:
- Manages a music player + pool of SFX players (configurable polyphony, default 2)
- Automatically shuffles playlist and handles lifecycle pauses
- Pauses audio when app goes to background; resumes on foreground
- Settings-aware: respects muted, musicOn, soundsOn toggles
- Use `audioController.playSfx(SfxType.buttonTap)` to play sound effects

### Optional Integrations (Commented By Default)
In `main.dart`, integrations are **commented out and must be explicitly enabled**:
- **Firebase Crashlytics**: Uncomment imports and initialize block; requires `firebase_options.dart`
- **Google Mobile Ads**: Uncomment `AdsController` initialization; requires `google_mobile_ads` package
- **Games Services**: Uncomment `GamesServicesController` initialization
- **In-App Purchase**: Uncomment `InAppPurchaseController` initialization
- All integrations use platform guards: `!kIsWeb && (Platform.isIOS || Platform.isAndroid)`

## Development Workflows

### Running the App
```bash
# Default (emulator/simulator/physical device)
flutter run

# Desktop (faster iteration, no emulator needed)
flutter run -d macOS # or -d linux / -d windows

# Web (useful for demos)
flutter run -d web
```

### Building for Production
```bash
# iOS
flutter build ipa && open build/ios/archive/Runner.xcarchive

# Android
flutter build appbundle && open build/app/outputs/bundle/release

# Web (requires 'peanut' package)
flutter pub global run peanut --web-renderer canvaskit --extra-args "--base-href=/repo_name/" && git push origin --set-upstream gh-pages
```

### Analysis & Linting
Uses `flutter_lints` with minimal overrides (prefer_const_constructors and prefer_single_quotes disabled for early development). Check with:
```bash
flutter analyze
```

## Code Patterns & Conventions

### Logging
Uses `package:logging` with dev.log:
```dart
static final _log = Logger('ClassName');
_log.info('message');
_log.warning('warning');
```

### Responsive UI
Custom `ResponsiveScreen` widget in `src/style/responsive_screen.dart` provides `mainAreaProminence` and layout areas. Use for adaptive layouts across mobile/tablet/desktop.

### Snack Bar Feedback
Custom `showSnackBar()` in `src/style/snack_bar.dart`. Use a global `scaffoldMessengerKey` passed to `MaterialApp.router`.

### Palette & Theme
Centralized `Palette` provider in `src/style/palette.dart`. Inject via `context.watch<Palette>()`. Avoids hardcoding colors.

### Game Levels
Game levels defined in `src/level_selection/levels.dart` as a list. Reference by level number in routing.

### Screen State Management
Screens are typically StatelessWidget that watch providers. Mutable interactions go through provider controllers:
```dart
final audioController = context.watch<AudioController>();
audioController.playSfx(SfxType.buttonTap);
```

## Dependencies Overview
- **go_router** (v16.0.0): Navigation and routing
- **provider** (v6.0.2): State management
- **audioplayers** (v6.0.0): Audio playback
- **shared_preferences**: Local persistence (via abstraction)
- **logging**: Structured logging to dart:developer
- Optional: firebase_core, firebase_crashlytics, google_mobile_ads, games_services, in_app_purchase

## Critical Notes for Contributors
1. **Persistence is abstracted**: Always use the persistence interface, not SharedPreferences directly
2. **Controllers manage their own initialization**: Check `initialize()` methods and async setup requirements
3. **Lifecycle matters**: Audio and ads controllers must respect app lifecycle state
4. **Platform-specific code**: Use `kIsWeb` and platform checks (`Platform.isIOS`, etc.) for platform-specific logic
5. **No code generation**: Template intentionally avoids build_runner for simplicity; can be added if needed
6. **Settings require explicit toggle**: Integrations are commented out; uncomment and enable explicitly when needed
7. **Router validation**: Use `redirect` guards on sensitive routes (e.g., win screen requires score extra data)
4 changes: 2 additions & 2 deletions game_template/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ Future<void> main() async {
// await Firebase.initializeApp(
// options: DefaultFirebaseOptions.currentPlatform,
// );
//

// FlutterError.onError = (errorDetails) {
// FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails);
// };
//

// // Pass all uncaught asynchronous errors
// // that aren't handled by the Flutter framework to Crashlytics.
// PlatformDispatcher.instance.onError = (error, stack) {
Expand Down
6 changes: 3 additions & 3 deletions game_template/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ dependencies:
sdk: flutter
audioplayers: ^6.0.0
cupertino_icons: ^1.0.2
go_router: ^16.0.0
go_router: ^17.0.1
logging: ^1.1.0
provider: ^6.0.2
shared_preferences: ^2.0.13
Expand All @@ -25,8 +25,8 @@ dependencies:
# that references the dependency.
firebase_core: ^4.0.0 # Needed for Crashlytics below
firebase_crashlytics: ^5.0.0 # Error reporting
games_services: ^4.0.0 # Achievements and leaderboards
google_mobile_ads: ^6.0.0 # Ads
games_services: ^5.0.0 # Achievements and leaderboards
google_mobile_ads: ^7.0.0 # Ads
in_app_purchase: ^3.0.1 # In-app purchases

dev_dependencies:
Expand Down
7 changes: 6 additions & 1 deletion game_template/windows/flutter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake)
# https://github.com/flutter/flutter/issues/57146.
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")

# Set fallback configurations for older versions of the flutter tool.
if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
set(FLUTTER_TARGET_PLATFORM "windows-x64")
endif()

# === Flutter Library ===
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")

Expand Down Expand Up @@ -92,7 +97,7 @@ add_custom_command(
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
windows-x64 $<CONFIG>
${FLUTTER_TARGET_PLATFORM} $<CONFIG>
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
Expand Down
5 changes: 5 additions & 0 deletions game_template/windows/runner/flutter_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ bool FlutterWindow::OnCreate() {
this->Show();
});

// Flutter can complete the first frame before the "show window" callback is
// registered. The following call ensures a frame is pending to ensure the
// window is shown. It is a no-op if the first frame hasn't completed yet.
flutter_controller_->ForceRedraw();

return true;
}

Expand Down
2 changes: 1 addition & 1 deletion navigation_and_routing/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ dependencies:
cupertino_icons: ^1.0.2
flutter:
sdk: flutter
go_router: ^16.0.0
go_router: ^17.0.1
url_launcher: ^6.1.1
window_size:
git:
Expand Down
2 changes: 1 addition & 1 deletion pedometer/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ dependencies:

ffi: ^2.1.2
intl: ^0.20.0
jni: ^0.14.2
jni: ^0.15.2
fl_chart: ^1.0.0

dev_dependencies:
Expand Down
6 changes: 3 additions & 3 deletions pedometer/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ dependencies:
flutter:
sdk: flutter
plugin_platform_interface: ^2.1.8
jni: ^0.14.2
jni: ^0.15.2
ffi: ^2.1.2

dev_dependencies:
analysis_defaults:
path: ../analysis_defaults
ffigen: ^19.1.0
jnigen: ^0.14.2
ffigen: ^20.1.1
jnigen: ^0.15.0
flutter_test:
sdk: flutter
flutter_lints: ^6.0.0
Expand Down
2 changes: 1 addition & 1 deletion place_tracker/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ dependencies:
google_maps_flutter: ^2.2.0
provider: ^6.0.2
uuid: ^4.0.0
go_router: ^16.0.0
go_router: ^17.0.1

dev_dependencies:
analysis_defaults:
Expand Down
2 changes: 1 addition & 1 deletion platform_channels/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.3
go_router: ^16.0.0
go_router: ^17.0.1

dev_dependencies:
analysis_defaults:
Expand Down
2 changes: 1 addition & 1 deletion provider_shopper/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ environment:
dependencies:
flutter:
sdk: flutter
go_router: ^16.0.0
go_router: ^17.0.1
provider: ^6.0.2
window_size:
git:
Expand Down
2 changes: 1 addition & 1 deletion simplistic_calculator/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ dependencies:
flutter:
sdk: flutter
flutter_layout_grid: ^2.0.1
flutter_riverpod: ^2.0.2
flutter_riverpod: ^3.0.3
math_expressions: ^2.7.0
window_size:
git:
Expand Down
2 changes: 1 addition & 1 deletion testing_app/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies:
sdk: flutter
cupertino_icons: ^1.0.3
provider: ^6.0.2
go_router: ^16.0.0
go_router: ^17.0.1

dev_dependencies:
analysis_defaults:
Expand Down