├── .fvm
└── fvm_config.json
├── .gitattributes
├── .github
└── workflows
│ └── cd.yml
├── .gitignore
├── .metadata
├── .vscode
├── launch.json
└── settings.json
├── LICENSE
├── Makefile
├── README.md
├── analysis_options.yaml
├── lib
├── app.dart
├── core
│ └── ui
│ │ └── component
│ │ ├── material.dart
│ │ ├── scaffold_messenger.dart
│ │ ├── scaffold_messenger.g.dart
│ │ ├── theme_data.dart
│ │ └── theme_data.g.dart
├── feature
│ ├── home
│ │ └── ui
│ │ │ └── home_page.dart
│ └── traffic_light
│ │ ├── state
│ │ ├── traffic_light_state.dart
│ │ ├── traffic_light_state.freezed.dart
│ │ └── traffic_light_state.g.dart
│ │ ├── ui
│ │ └── component
│ │ │ ├── crosswalk_button.dart
│ │ │ └── traffic_light.dart
│ │ └── use_case
│ │ ├── press_crosswalk_button.dart
│ │ └── press_crosswalk_button.g.dart
├── main.dart
└── util
│ └── logger.dart
├── pubspec.lock
├── pubspec.yaml
└── web
├── favicon.png
├── icons
├── Icon-192.png
├── Icon-512.png
├── Icon-maskable-192.png
└── Icon-maskable-512.png
├── index.html
└── manifest.json
/.fvm/fvm_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "flutterSdkVersion": "3.16.0",
3 | "flavors": {}
4 | }
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # see: https://zenn.dev/mamushi/articles/hide_generated_file_diff
2 | *.freezed.dart linguist-generated=true
3 | *.g.dart linguist-generated=true
4 | *.gen.dart linguist-generated=true
5 | *.gr.dart linguist-generated=true
6 |
--------------------------------------------------------------------------------
/.github/workflows/cd.yml:
--------------------------------------------------------------------------------
1 | name: Deploy to GitHub Pages
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | workflow_dispatch:
9 |
10 | jobs:
11 | deploy:
12 | runs-on: ubuntu-latest
13 | timeout-minutes: 30
14 | steps:
15 | - name: Check out repository
16 | uses: actions/checkout@v3
17 |
18 | - name: Check fvm
19 | uses: kuhnroyal/flutter-fvm-config-action@v1
20 |
21 | - name: Setup flutter environment
22 | uses: subosito/flutter-action@v2
23 | with:
24 | flutter-version: ${{ env.FLUTTER_VERSION }}
25 | channel: ${{ env.FLUTTER_CHANNEL }}
26 | cache: true
27 | cache-key: 'flutter-:os:-:channel:-:version:-:arch:-:hash:'
28 | cache-path: '${{ runner.tool_cache }}/flutter/:channel:-:version:-:arch:'
29 |
30 | - name: Cache Pub
31 | uses: actions/cache@v3
32 | id: pub-cache
33 | with:
34 | path: |
35 | ${{ env.FLUTTER_HOME }}/.pub-cache
36 | **/.packages
37 | **/.flutter-plugins
38 | **/.flutter-plugin-dependencies
39 | **/.dart_tool/package_config.json
40 | key: build-pubspec-${{ hashFiles('**/pubspec.lock') }}
41 | restore-keys: build-pubspec-
42 |
43 | - name: Read Repository
44 | id: version
45 | run: |
46 | REPOSITORY=$(echo ${{ github.repository }} | sed -e "s#.*/##")
47 | echo ::set-output name=repository::$REPOSITORY
48 |
49 | - name: Build web
50 | run: |
51 | flutter config --enable-web
52 | flutter build web \
53 | --web-renderer canvaskit \
54 | --release \
55 | --base-href /${{ steps.version.outputs.repository }}/
56 |
57 | - name: Deploy to GitHub Pages
58 | uses: peaceiris/actions-gh-pages@v3
59 | with:
60 | github_token: ${{ secrets.GITHUB_TOKEN }}
61 | publish_dir: ./build/web
62 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 | migrate_working_dir/
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 | # Symbolication related
36 | app.*.symbols
37 |
38 | # Obfuscation related
39 | app.*.map.json
40 |
41 | # Android Studio will place build artifacts here
42 | /android/app/debug
43 | /android/app/profile
44 | /android/app/release
45 |
46 | # fvm related
47 | .fvm/flutter_sdk
48 |
--------------------------------------------------------------------------------
/.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: "d211f42860350d914a5ad8102f9ec32764dc6d06"
8 | channel: "stable"
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
17 | base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
18 | - platform: android
19 | create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
20 | base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
21 | - platform: ios
22 | create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
23 | base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
24 | - platform: linux
25 | create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
26 | base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
27 | - platform: macos
28 | create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
29 | base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
30 | - platform: web
31 | create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
32 | base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
33 | - platform: windows
34 | create_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
35 | base_revision: d211f42860350d914a5ad8102f9ec32764dc6d06
36 |
37 | # User provided section
38 |
39 | # List of Local paths (relative to this file) that should be
40 | # ignored by the migrate tool.
41 | #
42 | # Files that are not part of the templates will be ignored by default.
43 | unmanaged_files:
44 | - 'lib/main.dart'
45 | - 'ios/Runner.xcodeproj/project.pbxproj'
46 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "app",
6 | "type": "dart",
7 | "request": "launch",
8 | "flutterMode": "debug",
9 | "program": "lib/main.dart",
10 | "args": [
11 | "--web-hostname",
12 | "localhost",
13 | "--web-port",
14 | "5000",
15 | ]
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Dart Recommended Settings: https://dartcode.org/docs/recommended-settings/
2 | {
3 | "debug.openDebug": "openOnDebugBreak",
4 | "editor.rulers": [80],
5 | "editor.renderWhitespace": "all",
6 | "editor.renderControlCharacters": true,
7 | "editor.minimap.enabled": false,
8 | "editor.bracketPairColorization.enabled": true,
9 | "[dart]": {
10 | "editor.formatOnSave": true,
11 | "editor.formatOnType": true,
12 | "editor.selectionHighlight": false,
13 | "editor.suggest.snippetsPreventQuickSuggestions": false,
14 | "editor.suggestSelection": "recentlyUsedByPrefix",
15 | "editor.tabCompletion": "onlySnippets",
16 | "editor.wordBasedSuggestions": false,
17 | "editor.codeActionsOnSave": {
18 | "source.organizeImports": "always",
19 | "source.addMissingImports": "always",
20 | "quickfix.insertSemicolon": "always",
21 | "source.fixAll": "always",
22 | }
23 | },
24 | "[css]": {
25 | "editor.formatOnSave": true,
26 | "editor.formatOnType": true,
27 | },
28 | "dart.flutterSdkPath": ".fvm/flutter_sdk",
29 | "dart.debugSdkLibraries": false,
30 | "dart.showSkippedTests": false,
31 | "dart.runPubGetOnPubspecChanges": "always",
32 | "search.exclude": {
33 | "**/.fvm": true,
34 | "**/*.freezed.dart": true,
35 | "**/*.g.dart": true
36 | },
37 | "files.watcherExclude": {
38 | "**/.fvm": true
39 | },
40 | "git.autofetch": true,
41 | "explorer.confirmDragAndDrop": false,
42 | "explorer.fileNesting.enabled": true,
43 | "explorer.fileNesting.expand": false,
44 | "explorer.fileNesting.patterns": {
45 | "pubspec.yaml": ".flutter-plugins, .packages, .dart_tool, .flutter-plugins-dependencies, .metadata, template.iml, .packages, pubspec.lock, build.yaml, analysis_options.yaml, all_lint_rules.yaml, flutter_launcher_icons-*.yaml, flutter_native_splash.yaml, lefthook.yaml",
46 | ".env.example": ".env.*",
47 | ".gitignore": ".gitattributes, .gitmodules, .gitmessage, .mailmap, .git-blame*",
48 | "readme.*": "authors, backers.md, changelog*, citation*, code_of_conduct.md, codeowners, contributing.md, contributors, copying, credits, governance.md, history.md, license*, maintainers, readme*, security.md, sponsors.md",
49 | "*.dart": "$(capture).g.dart, $(capture).gr.dart, $(capture).freezed.dart"
50 | },
51 | "commentTranslate.multiLineMerge": true
52 | }
53 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 susatthi
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.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | FVM := $(shell which fvm)
2 | FLUTTER := $(FVM) flutter
3 |
4 | .PHONY: get-dependencies
5 | get-dependencies:
6 | $(FLUTTER) pub get
7 |
8 | .PHONY: pub-upgrade
9 | pub-upgrade:
10 | $(FLUTTER) pub upgrade
11 |
12 | .PHONY: clean
13 | clean:
14 | $(FLUTTER) clean
15 |
16 | .PHONY: build-runner
17 | build-runner:
18 | $(FLUTTER) packages pub run build_runner build --delete-conflicting-outputs
19 |
20 | .PHONY: build-runner-watch
21 | build-runner-watch:
22 | $(FLUTTER) packages pub run build_runner clean
23 | $(FLUTTER) packages pub run build_runner watch --delete-conflicting-outputs
24 |
25 | .PHONY: flutter-launcher-icons
26 | flutter-launcher-icons:
27 | $(FLUTTER) pub run flutter_launcher_icons:main
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 信号機シミュレーター
2 |
3 | Flutter における「状態」を解説するためのサンプル。Riverpod を利用しています。
4 |
5 |
6 |
7 | ## デモサイト
8 |
9 | https://susatthi.github.io/flutter-traffic-light/
10 |
11 | ## License
12 |
13 | MIT
14 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # https://pub.dev/packages/pedantic_mono
2 | include: package:pedantic_mono/analysis_options.yaml
3 |
4 | linter:
5 | rules:
6 | avoid_classes_with_only_static_members: false
7 | cascade_invocations: false
8 | comment_references: false
9 | constant_identifier_names: true
10 | library_private_types_in_public_api: false
11 | one_member_abstracts: false
12 | prefer_relative_imports: true
13 | use_build_context_synchronously: false
14 | lines_longer_than_80_chars: false
15 | use_setters_to_change_properties: false
16 |
17 | # see: https://github.com/rrousselGit/freezed/issues/488#issuecomment-894358980
18 | analyzer:
19 | exclude:
20 | - '**/*.freezed.dart'
21 | - '**/*.g.dart'
22 | - '**/*.gr.dart'
23 | - '**/*.gen.dart'
24 | - "**/generated_plugin_registrant.dart"
25 | - "**/firebase_options_*.dart"
26 | errors:
27 | invalid_annotation_target: ignore
28 | todo: ignore
29 | plugins:
30 | - custom_lint
31 |
32 | custom_lint:
33 | rules:
34 | - missing_provider_scope: false
35 |
--------------------------------------------------------------------------------
/lib/app.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 |
4 | import 'core/ui/component/scaffold_messenger.dart';
5 | import 'core/ui/component/theme_data.dart';
6 | import 'feature/home/ui/home_page.dart';
7 |
8 | class App extends ConsumerWidget {
9 | const App({super.key});
10 |
11 | @override
12 | Widget build(BuildContext context, WidgetRef ref) {
13 | return MaterialApp(
14 | title: 'Traffic Light',
15 | theme: ref.watch(themeDataProvider),
16 | debugShowCheckedModeBanner: false,
17 | scaffoldMessengerKey: ref.watch(scaffoldMessengerProvider),
18 | home: const HomePage(),
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/core/ui/component/material.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | // ignore: depend_on_referenced_packages
3 | import 'package:material_color_utilities/material_color_utilities.dart';
4 |
5 | extension BuildContextX on BuildContext {
6 | /// ダークモードかどうかを返す
7 | bool get isDark => Theme.of(this).brightness == Brightness.dark;
8 |
9 | /// カラーを返す
10 | ColorScheme get _colorScheme => Theme.of(this).colorScheme;
11 | Color get primary => _colorScheme.primary;
12 | Color get onPrimary => _colorScheme.onPrimary;
13 | Color get primaryContainer => _colorScheme.primaryContainer;
14 | Color get onPrimaryContainer => _colorScheme.onPrimaryContainer;
15 | Color get secondary => _colorScheme.secondary;
16 | Color get onSecondary => _colorScheme.onSecondary;
17 | Color get secondaryContainer => _colorScheme.secondaryContainer;
18 | Color get onSecondaryContainer => _colorScheme.onSecondaryContainer;
19 | Color get tertiary => _colorScheme.tertiary;
20 | Color get onTertiary => _colorScheme.onTertiary;
21 | Color get tertiaryContainer => _colorScheme.tertiaryContainer;
22 | Color get onTertiaryContainer => _colorScheme.onTertiaryContainer;
23 | Color get error => _colorScheme.error;
24 | Color get onError => _colorScheme.onError;
25 | Color get errorContainer => _colorScheme.errorContainer;
26 | Color get onErrorContainer => _colorScheme.onErrorContainer;
27 | Color get background => _colorScheme.background;
28 | Color get onBackground => _colorScheme.onBackground;
29 | Color get surface => _colorScheme.surface;
30 | Color get onSurface => _colorScheme.onSurface;
31 | Color get outline => _colorScheme.outline;
32 | Color get outlineVariant => _colorScheme.outlineVariant;
33 | Color get surfaceVariant => _colorScheme.surfaceVariant;
34 | Color get onSurfaceVariant => _colorScheme.onSurfaceVariant;
35 | Color get surfaceTint => _colorScheme.surfaceTint;
36 | Color get inversePrimary => _colorScheme.inversePrimary;
37 | Color get inverseSurface => _colorScheme.inverseSurface;
38 | Color get onInverseSurface => _colorScheme.onInverseSurface;
39 |
40 | /// テキストテーマを返す
41 | TextTheme get _textTheme => Theme.of(this).textTheme;
42 | TextStyle? get displayLarge => _textTheme.displayLarge;
43 | TextStyle? get displayMedium => _textTheme.displayMedium;
44 | TextStyle? get displaySmall => _textTheme.displaySmall;
45 | TextStyle? get headlineLarge => _textTheme.headlineLarge;
46 | TextStyle? get headlineMedium => _textTheme.headlineMedium;
47 | TextStyle? get headlineSmall => _textTheme.headlineSmall;
48 | TextStyle? get titleLarge => _textTheme.titleLarge;
49 | TextStyle? get titleMedium => _textTheme.titleMedium;
50 | TextStyle? get titleSmall => _textTheme.titleSmall;
51 | TextStyle? get labelLarge => _textTheme.labelLarge;
52 | TextStyle? get labelMedium => _textTheme.labelMedium;
53 | TextStyle? get labelSmall => _textTheme.labelSmall;
54 | TextStyle? get bodyLarge => _textTheme.bodyLarge;
55 | TextStyle? get bodyMedium => _textTheme.bodyMedium;
56 | TextStyle? get bodySmall => _textTheme.bodySmall;
57 | TextStyle? get caption => labelSmall?.copyWith(color: outline);
58 | }
59 |
60 | extension CorePaletteX on CorePalette {
61 | MaterialColor get primaryMaterial => primary.toMaterialColor();
62 | MaterialColor get secondaryMaterial => secondary.toMaterialColor();
63 | MaterialColor get tertiaryMaterial => tertiary.toMaterialColor();
64 | MaterialColor get errorMaterial => error.toMaterialColor();
65 | MaterialColor get neutralMaterial => neutral.toMaterialColor();
66 | MaterialColor get neutralVariantMaterial => neutralVariant.toMaterialColor();
67 | }
68 |
69 | extension TonalPaletteX on TonalPalette {
70 | /// MaterialColorに変換する
71 | MaterialColor toMaterialColor() {
72 | final primary = get(40);
73 | return MaterialColor(primary, {
74 | 1: Color(get(99)),
75 | 50: Color(get(95)),
76 | 100: Color(get(90)),
77 | 200: Color(get(80)),
78 | 300: Color(get(70)),
79 | 400: Color(get(60)),
80 | 500: Color(get(50)),
81 | 600: Color(primary),
82 | 700: Color(get(30)),
83 | 800: Color(get(20)),
84 | 900: Color(get(10)),
85 | });
86 | }
87 | }
88 |
89 | extension MaterialColorX on MaterialColor {
90 | /// 標準のMaterialColorで一番明るいのはshade50だが、それよりももっと明るく
91 | /// ほぼ白色だがほんの少しだけ色がついている色
92 | Color? get shade1 => this[1];
93 | }
94 |
95 | class MaterialSurfaceColor {
96 | const MaterialSurfaceColor._({
97 | required this.surfaceContainerLowest,
98 | required this.surfaceContainerLow,
99 | required this.surfaceContainer,
100 | required this.surfaceContainerHigh,
101 | required this.surfaceContainerHighest,
102 | required this.surfaceDim,
103 | required this.surfaceBright,
104 | });
105 |
106 | factory MaterialSurfaceColor.fromSeed({
107 | required Color seedColor,
108 | Brightness brightness = Brightness.light,
109 | }) {
110 | final neutralPalette = CorePalette.of(seedColor.value).neutral;
111 | switch (brightness) {
112 | case Brightness.light:
113 | return MaterialSurfaceColor._(
114 | surfaceContainerLowest: Color(neutralPalette.get(100)),
115 | surfaceContainerLow: Color(neutralPalette.get(96)),
116 | surfaceContainer: Color(neutralPalette.get(94)),
117 | surfaceContainerHigh: Color(neutralPalette.get(92)),
118 | surfaceContainerHighest: Color(neutralPalette.get(90)),
119 | surfaceDim: Color(neutralPalette.get(87)),
120 | surfaceBright: Color(neutralPalette.get(98)),
121 | );
122 | case Brightness.dark:
123 | return MaterialSurfaceColor._(
124 | surfaceContainerLowest: Color(neutralPalette.get(4)),
125 | surfaceContainerLow: Color(neutralPalette.get(10)),
126 | surfaceContainer: Color(neutralPalette.get(12)),
127 | surfaceContainerHigh: Color(neutralPalette.get(17)),
128 | surfaceContainerHighest: Color(neutralPalette.get(22)),
129 | surfaceDim: Color(neutralPalette.get(6)),
130 | surfaceBright: Color(neutralPalette.get(24)),
131 | );
132 | }
133 | }
134 |
135 | final Color surfaceContainerLowest;
136 | final Color surfaceContainerLow;
137 | final Color surfaceContainer;
138 | final Color surfaceContainerHigh;
139 | final Color surfaceContainerHighest;
140 | final Color surfaceDim;
141 | final Color surfaceBright;
142 | }
143 |
--------------------------------------------------------------------------------
/lib/core/ui/component/scaffold_messenger.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:riverpod_annotation/riverpod_annotation.dart';
3 |
4 | part 'scaffold_messenger.g.dart';
5 |
6 | @riverpod
7 | class ScaffoldMessenger extends _$ScaffoldMessenger {
8 | @override
9 | GlobalKey build() =>
10 | GlobalKey();
11 |
12 | ScaffoldMessengerState? get _currentState => state.currentState;
13 |
14 | ScaffoldFeatureController? showSnackBar(
15 | SnackBar snackBar,
16 | ) {
17 | return _currentState?.showSnackBar(snackBar);
18 | }
19 |
20 | void hideCurrentSnackBar({
21 | SnackBarClosedReason reason = SnackBarClosedReason.hide,
22 | }) {
23 | _currentState?.hideCurrentSnackBar(reason: reason);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/core/ui/component/scaffold_messenger.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'scaffold_messenger.dart';
4 |
5 | // **************************************************************************
6 | // RiverpodGenerator
7 | // **************************************************************************
8 |
9 | String _$scaffoldMessengerHash() => r'd5314077ec9536ad8855ab048d92df2ac6ea5b05';
10 |
11 | /// See also [ScaffoldMessenger].
12 | @ProviderFor(ScaffoldMessenger)
13 | final scaffoldMessengerProvider = AutoDisposeNotifierProvider>.internal(
15 | ScaffoldMessenger.new,
16 | name: r'scaffoldMessengerProvider',
17 | debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
18 | ? null
19 | : _$scaffoldMessengerHash,
20 | dependencies: null,
21 | allTransitiveDependencies: null,
22 | );
23 |
24 | typedef _$ScaffoldMessenger
25 | = AutoDisposeNotifier>;
26 | // ignore_for_file: type=lint
27 | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
28 |
--------------------------------------------------------------------------------
/lib/core/ui/component/theme_data.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:riverpod_annotation/riverpod_annotation.dart';
3 |
4 | part 'theme_data.g.dart';
5 |
6 | @riverpod
7 | Color seedColor(SeedColorRef ref) {
8 | return Colors.green;
9 | }
10 |
11 | @riverpod
12 | ThemeData themeData(ThemeDataRef ref) {
13 | final seedColor = ref.watch(seedColorProvider);
14 | return ThemeData(
15 | useMaterial3: true,
16 | colorSchemeSeed: seedColor,
17 | brightness: Brightness.light,
18 | snackBarTheme: const SnackBarThemeData(
19 | behavior: SnackBarBehavior.floating,
20 | ),
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/lib/core/ui/component/theme_data.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'theme_data.dart';
4 |
5 | // **************************************************************************
6 | // RiverpodGenerator
7 | // **************************************************************************
8 |
9 | String _$seedColorHash() => r'd45536b6a339adf3f49f4f27fddf7444b5931042';
10 |
11 | /// See also [seedColor].
12 | @ProviderFor(seedColor)
13 | final seedColorProvider = AutoDisposeProvider.internal(
14 | seedColor,
15 | name: r'seedColorProvider',
16 | debugGetCreateSourceHash:
17 | const bool.fromEnvironment('dart.vm.product') ? null : _$seedColorHash,
18 | dependencies: null,
19 | allTransitiveDependencies: null,
20 | );
21 |
22 | typedef SeedColorRef = AutoDisposeProviderRef;
23 | String _$themeDataHash() => r'302a5b779d7220a0a5ea204d1e4f137db767fa45';
24 |
25 | /// See also [themeData].
26 | @ProviderFor(themeData)
27 | final themeDataProvider = AutoDisposeProvider.internal(
28 | themeData,
29 | name: r'themeDataProvider',
30 | debugGetCreateSourceHash:
31 | const bool.fromEnvironment('dart.vm.product') ? null : _$themeDataHash,
32 | dependencies: null,
33 | allTransitiveDependencies: null,
34 | );
35 |
36 | typedef ThemeDataRef = AutoDisposeProviderRef;
37 | // ignore_for_file: type=lint
38 | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
39 |
--------------------------------------------------------------------------------
/lib/feature/home/ui/home_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:gap/gap.dart';
3 |
4 | import '../../traffic_light/ui/component/crosswalk_button.dart';
5 | import '../../traffic_light/ui/component/traffic_light.dart';
6 |
7 | class HomePage extends StatelessWidget {
8 | const HomePage({super.key});
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return const Scaffold(
13 | body: _Body(),
14 | );
15 | }
16 | }
17 |
18 | class _Body extends StatelessWidget {
19 | const _Body();
20 |
21 | @override
22 | Widget build(BuildContext context) {
23 | return const SingleChildScrollView(
24 | child: Column(
25 | mainAxisAlignment: MainAxisAlignment.center,
26 | children: [
27 | Gap(32),
28 | TrafficLight(),
29 | Gap(32),
30 | CrosswalkButton(),
31 | Gap(32),
32 | ],
33 | ),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/feature/traffic_light/state/traffic_light_state.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 | import 'package:riverpod_annotation/riverpod_annotation.dart';
3 |
4 | part 'traffic_light_state.freezed.dart';
5 | part 'traffic_light_state.g.dart';
6 |
7 | @freezed
8 | class TrafficLightState with _$TrafficLightState {
9 | const factory TrafficLightState({
10 | /// 現在の信号機の状態
11 | required TrafficLightStatus status,
12 |
13 | /// 現在の信号機の状態の残り時間
14 | required int remainingTime,
15 | }) = _TrafficLightState;
16 | }
17 |
18 | enum TrafficLightStatus {
19 | red,
20 | yellow,
21 | green,
22 | ;
23 |
24 | /// 次の信号機の状態を返す。
25 | TrafficLightStatus get next => switch (this) {
26 | TrafficLightStatus.red => TrafficLightStatus.green,
27 | TrafficLightStatus.yellow => TrafficLightStatus.red,
28 | TrafficLightStatus.green => TrafficLightStatus.yellow,
29 | };
30 | }
31 |
32 | @riverpod
33 | class TrafficLightStateNotifier extends _$TrafficLightStateNotifier {
34 | @override
35 | TrafficLightState build() {
36 | const status = TrafficLightStatus.green;
37 | return TrafficLightState(
38 | status: status,
39 | remainingTime: _getStayingTime(status),
40 | );
41 | }
42 |
43 | /// 時間を進める。
44 | void tick() {
45 | final remainingTime = state.remainingTime - 1;
46 | if (remainingTime <= 0) {
47 | final nextStatus = state.status.next;
48 | state = state.copyWith(
49 | status: nextStatus,
50 | remainingTime: _getStayingTime(nextStatus),
51 | );
52 | } else {
53 | state = state.copyWith(
54 | remainingTime: remainingTime,
55 | );
56 | }
57 | }
58 |
59 | /// 信号機の状態ごとの滞在時間を返す。
60 | static int _getStayingTime(TrafficLightStatus status) => switch (status) {
61 | TrafficLightStatus.red => 10,
62 | TrafficLightStatus.yellow => 3,
63 | TrafficLightStatus.green => 8,
64 | };
65 |
66 | /// 強制的に信号機の状態を変える。
67 | Future updateStatus(TrafficLightStatus nextStatus) async {
68 | // 非同期処理にしたいので1秒待つ。
69 | await Future.delayed(const Duration(seconds: 1));
70 |
71 | // 赤信号 => 青信号
72 | if (state.status == TrafficLightStatus.red &&
73 | nextStatus == TrafficLightStatus.green) {
74 | state = state.copyWith(
75 | status: nextStatus,
76 | remainingTime: _getStayingTime(nextStatus),
77 | );
78 | return;
79 | }
80 |
81 | // 上記以外であればエラーを返す。
82 | throw Exception();
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/lib/feature/traffic_light/state/traffic_light_state.freezed.dart:
--------------------------------------------------------------------------------
1 | // coverage:ignore-file
2 | // GENERATED CODE - DO NOT MODIFY BY HAND
3 | // ignore_for_file: type=lint
4 | // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
5 |
6 | part of 'traffic_light_state.dart';
7 |
8 | // **************************************************************************
9 | // FreezedGenerator
10 | // **************************************************************************
11 |
12 | T _$identity(T value) => value;
13 |
14 | final _privateConstructorUsedError = UnsupportedError(
15 | 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
16 |
17 | /// @nodoc
18 | mixin _$TrafficLightState {
19 | /// 現在の信号機の状態
20 | TrafficLightStatus get status => throw _privateConstructorUsedError;
21 |
22 | /// 現在の信号機の状態の残り時間
23 | int get remainingTime => throw _privateConstructorUsedError;
24 |
25 | @JsonKey(ignore: true)
26 | $TrafficLightStateCopyWith get copyWith =>
27 | throw _privateConstructorUsedError;
28 | }
29 |
30 | /// @nodoc
31 | abstract class $TrafficLightStateCopyWith<$Res> {
32 | factory $TrafficLightStateCopyWith(
33 | TrafficLightState value, $Res Function(TrafficLightState) then) =
34 | _$TrafficLightStateCopyWithImpl<$Res, TrafficLightState>;
35 | @useResult
36 | $Res call({TrafficLightStatus status, int remainingTime});
37 | }
38 |
39 | /// @nodoc
40 | class _$TrafficLightStateCopyWithImpl<$Res, $Val extends TrafficLightState>
41 | implements $TrafficLightStateCopyWith<$Res> {
42 | _$TrafficLightStateCopyWithImpl(this._value, this._then);
43 |
44 | // ignore: unused_field
45 | final $Val _value;
46 | // ignore: unused_field
47 | final $Res Function($Val) _then;
48 |
49 | @pragma('vm:prefer-inline')
50 | @override
51 | $Res call({
52 | Object? status = null,
53 | Object? remainingTime = null,
54 | }) {
55 | return _then(_value.copyWith(
56 | status: null == status
57 | ? _value.status
58 | : status // ignore: cast_nullable_to_non_nullable
59 | as TrafficLightStatus,
60 | remainingTime: null == remainingTime
61 | ? _value.remainingTime
62 | : remainingTime // ignore: cast_nullable_to_non_nullable
63 | as int,
64 | ) as $Val);
65 | }
66 | }
67 |
68 | /// @nodoc
69 | abstract class _$$TrafficLightStateImplCopyWith<$Res>
70 | implements $TrafficLightStateCopyWith<$Res> {
71 | factory _$$TrafficLightStateImplCopyWith(_$TrafficLightStateImpl value,
72 | $Res Function(_$TrafficLightStateImpl) then) =
73 | __$$TrafficLightStateImplCopyWithImpl<$Res>;
74 | @override
75 | @useResult
76 | $Res call({TrafficLightStatus status, int remainingTime});
77 | }
78 |
79 | /// @nodoc
80 | class __$$TrafficLightStateImplCopyWithImpl<$Res>
81 | extends _$TrafficLightStateCopyWithImpl<$Res, _$TrafficLightStateImpl>
82 | implements _$$TrafficLightStateImplCopyWith<$Res> {
83 | __$$TrafficLightStateImplCopyWithImpl(_$TrafficLightStateImpl _value,
84 | $Res Function(_$TrafficLightStateImpl) _then)
85 | : super(_value, _then);
86 |
87 | @pragma('vm:prefer-inline')
88 | @override
89 | $Res call({
90 | Object? status = null,
91 | Object? remainingTime = null,
92 | }) {
93 | return _then(_$TrafficLightStateImpl(
94 | status: null == status
95 | ? _value.status
96 | : status // ignore: cast_nullable_to_non_nullable
97 | as TrafficLightStatus,
98 | remainingTime: null == remainingTime
99 | ? _value.remainingTime
100 | : remainingTime // ignore: cast_nullable_to_non_nullable
101 | as int,
102 | ));
103 | }
104 | }
105 |
106 | /// @nodoc
107 |
108 | class _$TrafficLightStateImpl implements _TrafficLightState {
109 | const _$TrafficLightStateImpl(
110 | {required this.status, required this.remainingTime});
111 |
112 | /// 現在の信号機の状態
113 | @override
114 | final TrafficLightStatus status;
115 |
116 | /// 現在の信号機の状態の残り時間
117 | @override
118 | final int remainingTime;
119 |
120 | @override
121 | String toString() {
122 | return 'TrafficLightState(status: $status, remainingTime: $remainingTime)';
123 | }
124 |
125 | @override
126 | bool operator ==(dynamic other) {
127 | return identical(this, other) ||
128 | (other.runtimeType == runtimeType &&
129 | other is _$TrafficLightStateImpl &&
130 | (identical(other.status, status) || other.status == status) &&
131 | (identical(other.remainingTime, remainingTime) ||
132 | other.remainingTime == remainingTime));
133 | }
134 |
135 | @override
136 | int get hashCode => Object.hash(runtimeType, status, remainingTime);
137 |
138 | @JsonKey(ignore: true)
139 | @override
140 | @pragma('vm:prefer-inline')
141 | _$$TrafficLightStateImplCopyWith<_$TrafficLightStateImpl> get copyWith =>
142 | __$$TrafficLightStateImplCopyWithImpl<_$TrafficLightStateImpl>(
143 | this, _$identity);
144 | }
145 |
146 | abstract class _TrafficLightState implements TrafficLightState {
147 | const factory _TrafficLightState(
148 | {required final TrafficLightStatus status,
149 | required final int remainingTime}) = _$TrafficLightStateImpl;
150 |
151 | @override
152 |
153 | /// 現在の信号機の状態
154 | TrafficLightStatus get status;
155 | @override
156 |
157 | /// 現在の信号機の状態の残り時間
158 | int get remainingTime;
159 | @override
160 | @JsonKey(ignore: true)
161 | _$$TrafficLightStateImplCopyWith<_$TrafficLightStateImpl> get copyWith =>
162 | throw _privateConstructorUsedError;
163 | }
164 |
--------------------------------------------------------------------------------
/lib/feature/traffic_light/state/traffic_light_state.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'traffic_light_state.dart';
4 |
5 | // **************************************************************************
6 | // RiverpodGenerator
7 | // **************************************************************************
8 |
9 | String _$trafficLightStateNotifierHash() =>
10 | r'aba3071fbb8d91a1e34c16a8c6730211c5835e4e';
11 |
12 | /// See also [TrafficLightStateNotifier].
13 | @ProviderFor(TrafficLightStateNotifier)
14 | final trafficLightStateNotifierProvider = AutoDisposeNotifierProvider<
15 | TrafficLightStateNotifier, TrafficLightState>.internal(
16 | TrafficLightStateNotifier.new,
17 | name: r'trafficLightStateNotifierProvider',
18 | debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
19 | ? null
20 | : _$trafficLightStateNotifierHash,
21 | dependencies: null,
22 | allTransitiveDependencies: null,
23 | );
24 |
25 | typedef _$TrafficLightStateNotifier = AutoDisposeNotifier;
26 | // ignore_for_file: type=lint
27 | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
28 |
--------------------------------------------------------------------------------
/lib/feature/traffic_light/ui/component/crosswalk_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 | import 'package:gap/gap.dart';
4 |
5 | import '../../../../core/ui/component/material.dart';
6 | import '../../../../core/ui/component/scaffold_messenger.dart';
7 | import '../../use_case/press_crosswalk_button.dart';
8 |
9 | class CrosswalkButton extends StatelessWidget {
10 | const CrosswalkButton({super.key});
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return ColoredBox(
15 | color: const Color(0xFFFFD444),
16 | child: Padding(
17 | padding: const EdgeInsets.all(16),
18 | child: Column(
19 | children: [
20 | Text(
21 | 'おしてください',
22 | style: context.headlineMedium?.copyWith(
23 | fontWeight: FontWeight.bold,
24 | ),
25 | ),
26 | const Gap(32),
27 | const _Button(),
28 | const Gap(16),
29 | Text(
30 | '横断歩行者は\nボタンをおしてください',
31 | style: context.titleLarge,
32 | textAlign: TextAlign.center,
33 | ),
34 | ],
35 | ),
36 | ),
37 | );
38 | }
39 | }
40 |
41 | class _Button extends ConsumerWidget {
42 | const _Button();
43 |
44 | @override
45 | Widget build(BuildContext context, WidgetRef ref) {
46 | ref.listen(pressCrosswalkButtonUseCaseProvider, (previous, next) {
47 | next.when(
48 | data: (_) {},
49 | error: (e, s) {
50 | ref.read(scaffoldMessengerProvider).currentState?.showSnackBar(
51 | const SnackBar(
52 | content: Text('青にできませんでした。'),
53 | duration: Duration(seconds: 2),
54 | width: 300,
55 | ),
56 | );
57 | },
58 | loading: () {},
59 | );
60 | });
61 | final isLoading = ref.watch(pressCrosswalkButtonUseCaseProvider).isLoading;
62 | return SizedBox.square(
63 | dimension: 80,
64 | child: IconButton(
65 | onPressed: isLoading
66 | ? null
67 | : () =>
68 | ref.read(pressCrosswalkButtonUseCaseProvider.notifier).invoke(),
69 | style: IconButton.styleFrom(
70 | foregroundColor: context.onError,
71 | backgroundColor: context.error,
72 | disabledBackgroundColor: context.onSurface.withOpacity(0.12),
73 | hoverColor: context.onError.withOpacity(0.08),
74 | focusColor: context.onError.withOpacity(0.12),
75 | highlightColor: context.onError.withOpacity(0.12),
76 | ),
77 | icon: const Icon(
78 | null,
79 | color: Colors.transparent,
80 | ),
81 | ),
82 | );
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/lib/feature/traffic_light/ui/component/traffic_light.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_riverpod/flutter_riverpod.dart';
5 | import 'package:gap/gap.dart';
6 |
7 | import '../../state/traffic_light_state.dart';
8 |
9 | class TrafficLight extends StatelessWidget {
10 | const TrafficLight({super.key});
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | return TrafficLightBuilder(
15 | builder: (state) {
16 | return Row(
17 | mainAxisAlignment: MainAxisAlignment.center,
18 | crossAxisAlignment: CrossAxisAlignment.end,
19 | children: [
20 | SizedBox(
21 | height: 360,
22 | width: 180,
23 | child: _TrafficLight(
24 | state: state,
25 | iconSize: 150,
26 | ),
27 | ),
28 | const Gap(8),
29 | SizedBox(
30 | width: 80,
31 | height: 180,
32 | child: _RemainingSignage(
33 | // 黄色の場合は残り時間を表示しない。
34 | remainingTime: state.status == TrafficLightStatus.yellow
35 | ? 0
36 | : state.remainingTime,
37 | ),
38 | ),
39 | ],
40 | );
41 | },
42 | );
43 | }
44 | }
45 |
46 | class _TrafficLight extends StatelessWidget {
47 | const _TrafficLight({
48 | required this.state,
49 | required this.iconSize,
50 | });
51 |
52 | final TrafficLightState state;
53 | final double iconSize;
54 |
55 | @override
56 | Widget build(BuildContext context) {
57 | return switch (state.status) {
58 | TrafficLightStatus.red => Column(
59 | children: [
60 | _RedLightOn(
61 | iconSize: iconSize,
62 | ),
63 | _GreenLightOff(
64 | iconSize: iconSize,
65 | ),
66 | ],
67 | ),
68 | TrafficLightStatus.yellow => Column(
69 | children: [
70 | _RedLightOff(
71 | iconSize: iconSize,
72 | ),
73 | _GreenLightBlinking(
74 | iconSize: iconSize,
75 | ),
76 | ],
77 | ),
78 | TrafficLightStatus.green => Column(
79 | children: [
80 | _RedLightOff(
81 | iconSize: iconSize,
82 | ),
83 | _GreenLightOn(
84 | iconSize: iconSize,
85 | ),
86 | ],
87 | ),
88 | };
89 | }
90 | }
91 |
92 | const _redOnBackgroundColor = Color(0xFFEA5350);
93 | const _greenOnBackgroundColor = Color(0xFF62C0B5);
94 | const _offBackgroundColor = Color(0xFF3B2B29);
95 | const _onForegroundColor = Color(0xFFFEE799);
96 | const _offForegroundColor = Color(0xFF5E504F);
97 |
98 | class _RedLightOn extends StatelessWidget {
99 | const _RedLightOn({
100 | required this.iconSize,
101 | });
102 | final double iconSize;
103 |
104 | @override
105 | Widget build(BuildContext context) {
106 | return _Light(
107 | icon: Icons.accessibility,
108 | iconSize: iconSize,
109 | backgroundColor: _redOnBackgroundColor,
110 | foregroundColor: _onForegroundColor,
111 | );
112 | }
113 | }
114 |
115 | class _RedLightOff extends StatelessWidget {
116 | const _RedLightOff({
117 | required this.iconSize,
118 | });
119 | final double iconSize;
120 |
121 | @override
122 | Widget build(BuildContext context) {
123 | return _Light(
124 | icon: Icons.accessibility,
125 | iconSize: iconSize,
126 | backgroundColor: _offBackgroundColor,
127 | foregroundColor: _offForegroundColor,
128 | );
129 | }
130 | }
131 |
132 | class _GreenLightBlinking extends StatefulWidget {
133 | const _GreenLightBlinking({
134 | required this.iconSize,
135 | });
136 | final double iconSize;
137 |
138 | @override
139 | State<_GreenLightBlinking> createState() => _GreenLightBlinkingState();
140 | }
141 |
142 | class _GreenLightBlinkingState extends State<_GreenLightBlinking> {
143 | late final Timer timer;
144 | bool _isOn = false;
145 |
146 | @override
147 | void initState() {
148 | super.initState();
149 | timer = Timer.periodic(const Duration(milliseconds: 300), (timer) {
150 | setState(() {
151 | _isOn = !_isOn;
152 | });
153 | });
154 | }
155 |
156 | @override
157 | void dispose() {
158 | timer.cancel();
159 | super.dispose();
160 | }
161 |
162 | @override
163 | Widget build(BuildContext context) {
164 | return _Light(
165 | icon: Icons.directions_walk,
166 | iconSize: widget.iconSize,
167 | backgroundColor: _greenOnBackgroundColor,
168 | foregroundColor: _isOn ? _onForegroundColor : _offForegroundColor,
169 | );
170 | }
171 | }
172 |
173 | class _GreenLightOn extends StatelessWidget {
174 | const _GreenLightOn({
175 | required this.iconSize,
176 | });
177 | final double iconSize;
178 |
179 | @override
180 | Widget build(BuildContext context) {
181 | return _Light(
182 | icon: Icons.directions_walk,
183 | iconSize: iconSize,
184 | backgroundColor: _greenOnBackgroundColor,
185 | foregroundColor: _onForegroundColor,
186 | );
187 | }
188 | }
189 |
190 | class _GreenLightOff extends StatelessWidget {
191 | const _GreenLightOff({
192 | required this.iconSize,
193 | });
194 | final double iconSize;
195 |
196 | @override
197 | Widget build(BuildContext context) {
198 | return _Light(
199 | icon: Icons.directions_walk,
200 | iconSize: iconSize,
201 | backgroundColor: _offBackgroundColor,
202 | foregroundColor: _offForegroundColor,
203 | );
204 | }
205 | }
206 |
207 | class _Light extends StatelessWidget {
208 | const _Light({
209 | required this.icon,
210 | required this.iconSize,
211 | required this.backgroundColor,
212 | required this.foregroundColor,
213 | });
214 |
215 | final IconData icon;
216 | final double iconSize;
217 | final Color backgroundColor;
218 | final Color foregroundColor;
219 |
220 | @override
221 | Widget build(BuildContext context) {
222 | return Expanded(
223 | child: SizedBox(
224 | width: double.infinity,
225 | child: ColoredBox(
226 | color: backgroundColor,
227 | child: Icon(
228 | icon,
229 | color: foregroundColor,
230 | size: iconSize,
231 | ),
232 | ),
233 | ),
234 | );
235 | }
236 | }
237 |
238 | class _RemainingSignage extends StatelessWidget {
239 | const _RemainingSignage({
240 | required this.remainingTime,
241 | });
242 |
243 | final int remainingTime;
244 |
245 | static const _maxBarCount = 10;
246 |
247 | @override
248 | Widget build(BuildContext context) {
249 | return ColoredBox(
250 | color: _offForegroundColor,
251 | child: Padding(
252 | padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
253 | child: Column(
254 | children: [
255 | for (var i = _maxBarCount + 1; i > 1; i--)
256 | Expanded(
257 | child: _RemainingBar(
258 | isOn: i <= remainingTime,
259 | ),
260 | ),
261 | ],
262 | ),
263 | ),
264 | );
265 | }
266 | }
267 |
268 | class _RemainingBar extends StatelessWidget {
269 | const _RemainingBar({
270 | required this.isOn,
271 | });
272 |
273 | final bool isOn;
274 |
275 | @override
276 | Widget build(BuildContext context) {
277 | return Padding(
278 | padding: const EdgeInsets.symmetric(vertical: 4),
279 | child: SizedBox(
280 | width: double.infinity,
281 | child: ColoredBox(
282 | color: isOn ? _onForegroundColor : _offForegroundColor,
283 | ),
284 | ),
285 | );
286 | }
287 | }
288 |
289 | class TrafficLightBuilder extends ConsumerStatefulWidget {
290 | const TrafficLightBuilder({
291 | super.key,
292 | required this.builder,
293 | });
294 |
295 | final Widget Function(TrafficLightState state) builder;
296 |
297 | @override
298 | ConsumerState createState() =>
299 | _TrafficLightBuilderState();
300 | }
301 |
302 | class _TrafficLightBuilderState extends ConsumerState {
303 | late final Timer timer;
304 |
305 | @override
306 | void initState() {
307 | super.initState();
308 | timer = Timer.periodic(const Duration(seconds: 1), (timer) {
309 | ref.read(trafficLightStateNotifierProvider.notifier).tick();
310 | });
311 | }
312 |
313 | @override
314 | void dispose() {
315 | timer.cancel();
316 | super.dispose();
317 | }
318 |
319 | @override
320 | Widget build(BuildContext context) {
321 | final state = ref.watch(trafficLightStateNotifierProvider);
322 | return widget.builder(state);
323 | }
324 | }
325 |
--------------------------------------------------------------------------------
/lib/feature/traffic_light/use_case/press_crosswalk_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:riverpod_annotation/riverpod_annotation.dart';
2 |
3 | import '../state/traffic_light_state.dart';
4 |
5 | part 'press_crosswalk_button.g.dart';
6 |
7 | @riverpod
8 | class PressCrosswalkButtonUseCase extends _$PressCrosswalkButtonUseCase {
9 | @override
10 | FutureOr build() {
11 | return null;
12 | }
13 |
14 | Future invoke() async {
15 | if (state.isLoading) {
16 | return;
17 | }
18 |
19 | state = const AsyncValue.loading();
20 | state = await AsyncValue.guard(() async {
21 | await ref
22 | .read(trafficLightStateNotifierProvider.notifier)
23 | .updateStatus(TrafficLightStatus.green);
24 | });
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/lib/feature/traffic_light/use_case/press_crosswalk_button.g.dart:
--------------------------------------------------------------------------------
1 | // GENERATED CODE - DO NOT MODIFY BY HAND
2 |
3 | part of 'press_crosswalk_button.dart';
4 |
5 | // **************************************************************************
6 | // RiverpodGenerator
7 | // **************************************************************************
8 |
9 | String _$pressCrosswalkButtonUseCaseHash() =>
10 | r'5f2d94a9e9b28daa38ed8268d6e88dc767cdd24d';
11 |
12 | /// See also [PressCrosswalkButtonUseCase].
13 | @ProviderFor(PressCrosswalkButtonUseCase)
14 | final pressCrosswalkButtonUseCaseProvider = AutoDisposeAsyncNotifierProvider<
15 | PressCrosswalkButtonUseCase, void>.internal(
16 | PressCrosswalkButtonUseCase.new,
17 | name: r'pressCrosswalkButtonUseCaseProvider',
18 | debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
19 | ? null
20 | : _$pressCrosswalkButtonUseCaseHash,
21 | dependencies: null,
22 | allTransitiveDependencies: null,
23 | );
24 |
25 | typedef _$PressCrosswalkButtonUseCase = AutoDisposeAsyncNotifier;
26 | // ignore_for_file: type=lint
27 | // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
28 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_riverpod/flutter_riverpod.dart';
3 | // ignore: depend_on_referenced_packages
4 | import 'package:flutter_web_plugins/url_strategy.dart';
5 |
6 | import 'app.dart';
7 |
8 | Future main() async {
9 | WidgetsFlutterBinding.ensureInitialized();
10 | usePathUrlStrategy();
11 | runApp(
12 | const ProviderScope(
13 | child: App(),
14 | ),
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/lib/util/logger.dart:
--------------------------------------------------------------------------------
1 | import 'package:roggle/roggle.dart';
2 |
3 | const _loggerName = '[APP]';
4 |
5 | final logger = Roggle(
6 | printer: SinglePrettyPrinter(
7 | loggerName: _loggerName,
8 | // error 以上のときはスタックトレースを出力する
9 | stackTraceLevel: Level.error,
10 | // ログが長くなるので非表示
11 | printCaller: false,
12 | ),
13 | );
14 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | _fe_analyzer_shared:
5 | dependency: transitive
6 | description:
7 | name: _fe_analyzer_shared
8 | sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051
9 | url: "https://pub.dev"
10 | source: hosted
11 | version: "64.0.0"
12 | analyzer:
13 | dependency: transitive
14 | description:
15 | name: analyzer
16 | sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893"
17 | url: "https://pub.dev"
18 | source: hosted
19 | version: "6.2.0"
20 | analyzer_plugin:
21 | dependency: transitive
22 | description:
23 | name: analyzer_plugin
24 | sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161"
25 | url: "https://pub.dev"
26 | source: hosted
27 | version: "0.11.3"
28 | args:
29 | dependency: transitive
30 | description:
31 | name: args
32 | sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
33 | url: "https://pub.dev"
34 | source: hosted
35 | version: "2.4.2"
36 | async:
37 | dependency: transitive
38 | description:
39 | name: async
40 | sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
41 | url: "https://pub.dev"
42 | source: hosted
43 | version: "2.11.0"
44 | boolean_selector:
45 | dependency: transitive
46 | description:
47 | name: boolean_selector
48 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
49 | url: "https://pub.dev"
50 | source: hosted
51 | version: "2.1.1"
52 | build:
53 | dependency: transitive
54 | description:
55 | name: build
56 | sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
57 | url: "https://pub.dev"
58 | source: hosted
59 | version: "2.4.1"
60 | build_config:
61 | dependency: transitive
62 | description:
63 | name: build_config
64 | sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
65 | url: "https://pub.dev"
66 | source: hosted
67 | version: "1.1.1"
68 | build_daemon:
69 | dependency: transitive
70 | description:
71 | name: build_daemon
72 | sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1"
73 | url: "https://pub.dev"
74 | source: hosted
75 | version: "4.0.1"
76 | build_resolvers:
77 | dependency: transitive
78 | description:
79 | name: build_resolvers
80 | sha256: "64e12b0521812d1684b1917bc80945625391cb9bdd4312536b1d69dcb6133ed8"
81 | url: "https://pub.dev"
82 | source: hosted
83 | version: "2.4.1"
84 | build_runner:
85 | dependency: "direct dev"
86 | description:
87 | name: build_runner
88 | sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b"
89 | url: "https://pub.dev"
90 | source: hosted
91 | version: "2.4.6"
92 | build_runner_core:
93 | dependency: transitive
94 | description:
95 | name: build_runner_core
96 | sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185
97 | url: "https://pub.dev"
98 | source: hosted
99 | version: "7.2.11"
100 | built_collection:
101 | dependency: transitive
102 | description:
103 | name: built_collection
104 | sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
105 | url: "https://pub.dev"
106 | source: hosted
107 | version: "5.1.1"
108 | built_value:
109 | dependency: transitive
110 | description:
111 | name: built_value
112 | sha256: "723b4021e903217dfc445ec4cf5b42e27975aece1fc4ebbc1ca6329c2d9fb54e"
113 | url: "https://pub.dev"
114 | source: hosted
115 | version: "8.7.0"
116 | characters:
117 | dependency: transitive
118 | description:
119 | name: characters
120 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
121 | url: "https://pub.dev"
122 | source: hosted
123 | version: "1.3.0"
124 | checked_yaml:
125 | dependency: transitive
126 | description:
127 | name: checked_yaml
128 | sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
129 | url: "https://pub.dev"
130 | source: hosted
131 | version: "2.0.3"
132 | ci:
133 | dependency: transitive
134 | description:
135 | name: ci
136 | sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13"
137 | url: "https://pub.dev"
138 | source: hosted
139 | version: "0.1.0"
140 | cli_util:
141 | dependency: transitive
142 | description:
143 | name: cli_util
144 | sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7
145 | url: "https://pub.dev"
146 | source: hosted
147 | version: "0.4.0"
148 | clock:
149 | dependency: transitive
150 | description:
151 | name: clock
152 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
153 | url: "https://pub.dev"
154 | source: hosted
155 | version: "1.1.1"
156 | code_builder:
157 | dependency: transitive
158 | description:
159 | name: code_builder
160 | sha256: b2151ce26a06171005b379ecff6e08d34c470180ffe16b8e14b6d52be292b55f
161 | url: "https://pub.dev"
162 | source: hosted
163 | version: "4.8.0"
164 | collection:
165 | dependency: "direct main"
166 | description:
167 | name: collection
168 | sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
169 | url: "https://pub.dev"
170 | source: hosted
171 | version: "1.18.0"
172 | color:
173 | dependency: transitive
174 | description:
175 | name: color
176 | sha256: ddcdf1b3badd7008233f5acffaf20ca9f5dc2cd0172b75f68f24526a5f5725cb
177 | url: "https://pub.dev"
178 | source: hosted
179 | version: "3.0.0"
180 | convert:
181 | dependency: transitive
182 | description:
183 | name: convert
184 | sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
185 | url: "https://pub.dev"
186 | source: hosted
187 | version: "3.1.1"
188 | crypto:
189 | dependency: transitive
190 | description:
191 | name: crypto
192 | sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
193 | url: "https://pub.dev"
194 | source: hosted
195 | version: "3.0.3"
196 | cupertino_icons:
197 | dependency: "direct main"
198 | description:
199 | name: cupertino_icons
200 | sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
201 | url: "https://pub.dev"
202 | source: hosted
203 | version: "1.0.6"
204 | custom_lint:
205 | dependency: "direct dev"
206 | description:
207 | name: custom_lint
208 | sha256: "198ec6b8e084d22f508a76556c9afcfb71706ad3f42b083fe0ee923351a96d90"
209 | url: "https://pub.dev"
210 | source: hosted
211 | version: "0.5.7"
212 | custom_lint_builder:
213 | dependency: transitive
214 | description:
215 | name: custom_lint_builder
216 | sha256: dfcfa987d2bd9d0ba751ef4bdef0f6c1aa0062f2a67fe716fd5f3f8b709d6418
217 | url: "https://pub.dev"
218 | source: hosted
219 | version: "0.5.7"
220 | custom_lint_core:
221 | dependency: transitive
222 | description:
223 | name: custom_lint_core
224 | sha256: f84c3fe2f27ef3b8831953e477e59d4a29c2952623f9eac450d7b40d9cdd94cc
225 | url: "https://pub.dev"
226 | source: hosted
227 | version: "0.5.7"
228 | dart_style:
229 | dependency: transitive
230 | description:
231 | name: dart_style
232 | sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368"
233 | url: "https://pub.dev"
234 | source: hosted
235 | version: "2.3.4"
236 | dartx:
237 | dependency: transitive
238 | description:
239 | name: dartx
240 | sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244"
241 | url: "https://pub.dev"
242 | source: hosted
243 | version: "1.2.0"
244 | fake_async:
245 | dependency: transitive
246 | description:
247 | name: fake_async
248 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
249 | url: "https://pub.dev"
250 | source: hosted
251 | version: "1.3.1"
252 | file:
253 | dependency: transitive
254 | description:
255 | name: file
256 | sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
257 | url: "https://pub.dev"
258 | source: hosted
259 | version: "7.0.0"
260 | fixnum:
261 | dependency: transitive
262 | description:
263 | name: fixnum
264 | sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
265 | url: "https://pub.dev"
266 | source: hosted
267 | version: "1.1.0"
268 | flutter:
269 | dependency: "direct main"
270 | description: flutter
271 | source: sdk
272 | version: "0.0.0"
273 | flutter_gen_core:
274 | dependency: transitive
275 | description:
276 | name: flutter_gen_core
277 | sha256: "8b4ff1d45d125e576e26ea99d15e0419bb3c45b53696e022880866b78bb6b830"
278 | url: "https://pub.dev"
279 | source: hosted
280 | version: "5.3.2"
281 | flutter_gen_runner:
282 | dependency: "direct dev"
283 | description:
284 | name: flutter_gen_runner
285 | sha256: fd197f8c657e79313d53d3934de602ebe604ba722a84c88ae3a43cd90428c67a
286 | url: "https://pub.dev"
287 | source: hosted
288 | version: "5.3.2"
289 | flutter_lints:
290 | dependency: transitive
291 | description:
292 | name: flutter_lints
293 | sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
294 | url: "https://pub.dev"
295 | source: hosted
296 | version: "2.0.3"
297 | flutter_riverpod:
298 | dependency: "direct main"
299 | description:
300 | name: flutter_riverpod
301 | sha256: d261b0f2461e0595b96f92ed807841eb72cea84a6b12b8fd0c76e5ed803e7921
302 | url: "https://pub.dev"
303 | source: hosted
304 | version: "2.4.8"
305 | flutter_test:
306 | dependency: "direct dev"
307 | description: flutter
308 | source: sdk
309 | version: "0.0.0"
310 | flutter_web_plugins:
311 | dependency: "direct main"
312 | description: flutter
313 | source: sdk
314 | version: "0.0.0"
315 | freezed:
316 | dependency: "direct dev"
317 | description:
318 | name: freezed
319 | sha256: "21bf2825311de65501d22e563e3d7605dff57fb5e6da982db785ae5372ff018a"
320 | url: "https://pub.dev"
321 | source: hosted
322 | version: "2.4.5"
323 | freezed_annotation:
324 | dependency: "direct main"
325 | description:
326 | name: freezed_annotation
327 | sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d
328 | url: "https://pub.dev"
329 | source: hosted
330 | version: "2.4.1"
331 | frontend_server_client:
332 | dependency: transitive
333 | description:
334 | name: frontend_server_client
335 | sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
336 | url: "https://pub.dev"
337 | source: hosted
338 | version: "3.2.0"
339 | gap:
340 | dependency: "direct main"
341 | description:
342 | name: gap
343 | sha256: f19387d4e32f849394758b91377f9153a1b41d79513ef7668c088c77dbc6955d
344 | url: "https://pub.dev"
345 | source: hosted
346 | version: "3.0.1"
347 | glob:
348 | dependency: transitive
349 | description:
350 | name: glob
351 | sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
352 | url: "https://pub.dev"
353 | source: hosted
354 | version: "2.1.2"
355 | graphs:
356 | dependency: transitive
357 | description:
358 | name: graphs
359 | sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
360 | url: "https://pub.dev"
361 | source: hosted
362 | version: "2.3.1"
363 | hotreloader:
364 | dependency: transitive
365 | description:
366 | name: hotreloader
367 | sha256: "94ee21a60ea2836500799f3af035dc3212b1562027f1e0031c14e087f0231449"
368 | url: "https://pub.dev"
369 | source: hosted
370 | version: "4.1.0"
371 | http_multi_server:
372 | dependency: transitive
373 | description:
374 | name: http_multi_server
375 | sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
376 | url: "https://pub.dev"
377 | source: hosted
378 | version: "3.2.1"
379 | http_parser:
380 | dependency: transitive
381 | description:
382 | name: http_parser
383 | sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
384 | url: "https://pub.dev"
385 | source: hosted
386 | version: "4.0.2"
387 | io:
388 | dependency: transitive
389 | description:
390 | name: io
391 | sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
392 | url: "https://pub.dev"
393 | source: hosted
394 | version: "1.0.4"
395 | js:
396 | dependency: transitive
397 | description:
398 | name: js
399 | sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
400 | url: "https://pub.dev"
401 | source: hosted
402 | version: "0.6.7"
403 | json_annotation:
404 | dependency: transitive
405 | description:
406 | name: json_annotation
407 | sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
408 | url: "https://pub.dev"
409 | source: hosted
410 | version: "4.8.1"
411 | lints:
412 | dependency: transitive
413 | description:
414 | name: lints
415 | sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
416 | url: "https://pub.dev"
417 | source: hosted
418 | version: "2.1.1"
419 | logger:
420 | dependency: transitive
421 | description:
422 | name: logger
423 | sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
424 | url: "https://pub.dev"
425 | source: hosted
426 | version: "2.0.2+1"
427 | logging:
428 | dependency: transitive
429 | description:
430 | name: logging
431 | sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
432 | url: "https://pub.dev"
433 | source: hosted
434 | version: "1.2.0"
435 | matcher:
436 | dependency: transitive
437 | description:
438 | name: matcher
439 | sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
440 | url: "https://pub.dev"
441 | source: hosted
442 | version: "0.12.16"
443 | material_color_utilities:
444 | dependency: transitive
445 | description:
446 | name: material_color_utilities
447 | sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
448 | url: "https://pub.dev"
449 | source: hosted
450 | version: "0.5.0"
451 | meta:
452 | dependency: transitive
453 | description:
454 | name: meta
455 | sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
456 | url: "https://pub.dev"
457 | source: hosted
458 | version: "1.10.0"
459 | mime:
460 | dependency: transitive
461 | description:
462 | name: mime
463 | sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
464 | url: "https://pub.dev"
465 | source: hosted
466 | version: "1.0.4"
467 | package_config:
468 | dependency: transitive
469 | description:
470 | name: package_config
471 | sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
472 | url: "https://pub.dev"
473 | source: hosted
474 | version: "2.1.0"
475 | path:
476 | dependency: transitive
477 | description:
478 | name: path
479 | sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
480 | url: "https://pub.dev"
481 | source: hosted
482 | version: "1.8.3"
483 | pedantic_mono:
484 | dependency: "direct dev"
485 | description:
486 | name: pedantic_mono
487 | sha256: b7ac7d8a9f8824ab053773599918d6c99d643ed63ce20b440a19fed028a80d63
488 | url: "https://pub.dev"
489 | source: hosted
490 | version: "1.24.0+1"
491 | petitparser:
492 | dependency: transitive
493 | description:
494 | name: petitparser
495 | sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
496 | url: "https://pub.dev"
497 | source: hosted
498 | version: "5.4.0"
499 | pool:
500 | dependency: transitive
501 | description:
502 | name: pool
503 | sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
504 | url: "https://pub.dev"
505 | source: hosted
506 | version: "1.5.1"
507 | pub_semver:
508 | dependency: transitive
509 | description:
510 | name: pub_semver
511 | sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
512 | url: "https://pub.dev"
513 | source: hosted
514 | version: "2.1.4"
515 | pubspec_parse:
516 | dependency: transitive
517 | description:
518 | name: pubspec_parse
519 | sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
520 | url: "https://pub.dev"
521 | source: hosted
522 | version: "1.2.3"
523 | riverpod:
524 | dependency: transitive
525 | description:
526 | name: riverpod
527 | sha256: "08451ddbaad6eae73e2422d8109775885623340d721c6637b8719c9f4b478848"
528 | url: "https://pub.dev"
529 | source: hosted
530 | version: "2.4.8"
531 | riverpod_analyzer_utils:
532 | dependency: transitive
533 | description:
534 | name: riverpod_analyzer_utils
535 | sha256: d4dabc35358413bf4611fcb6abb46308a67c4ef4cd5e69fd3367b11925c59f57
536 | url: "https://pub.dev"
537 | source: hosted
538 | version: "0.5.0"
539 | riverpod_annotation:
540 | dependency: "direct main"
541 | description:
542 | name: riverpod_annotation
543 | sha256: "02c9bced96ed3ed8d9970820d1ce7b16600955bc01aa8b2276f09dd3d9d29ed9"
544 | url: "https://pub.dev"
545 | source: hosted
546 | version: "2.3.2"
547 | riverpod_generator:
548 | dependency: "direct dev"
549 | description:
550 | name: riverpod_generator
551 | sha256: "94b6c49bba879729611d690d434796e3b4e7c72a27e88b482b92c505e90f90d9"
552 | url: "https://pub.dev"
553 | source: hosted
554 | version: "2.3.8"
555 | riverpod_lint:
556 | dependency: "direct dev"
557 | description:
558 | name: riverpod_lint
559 | sha256: "6fc64ae102ba39b0889b7aa7f4ef6c5a8f71a2ad215b90c787f319a9407a128b"
560 | url: "https://pub.dev"
561 | source: hosted
562 | version: "2.3.6"
563 | roggle:
564 | dependency: "direct main"
565 | description:
566 | name: roggle
567 | sha256: d2b3550cf952cb7e55929c7f4b8e8e6cf1536b4652218e44846122c7bac78f45
568 | url: "https://pub.dev"
569 | source: hosted
570 | version: "0.4.2+1"
571 | rxdart:
572 | dependency: transitive
573 | description:
574 | name: rxdart
575 | sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb"
576 | url: "https://pub.dev"
577 | source: hosted
578 | version: "0.27.7"
579 | shelf:
580 | dependency: transitive
581 | description:
582 | name: shelf
583 | sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
584 | url: "https://pub.dev"
585 | source: hosted
586 | version: "1.4.1"
587 | shelf_web_socket:
588 | dependency: transitive
589 | description:
590 | name: shelf_web_socket
591 | sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
592 | url: "https://pub.dev"
593 | source: hosted
594 | version: "1.0.4"
595 | sky_engine:
596 | dependency: transitive
597 | description: flutter
598 | source: sdk
599 | version: "0.0.99"
600 | source_gen:
601 | dependency: transitive
602 | description:
603 | name: source_gen
604 | sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16
605 | url: "https://pub.dev"
606 | source: hosted
607 | version: "1.4.0"
608 | source_span:
609 | dependency: transitive
610 | description:
611 | name: source_span
612 | sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
613 | url: "https://pub.dev"
614 | source: hosted
615 | version: "1.10.0"
616 | sprintf:
617 | dependency: transitive
618 | description:
619 | name: sprintf
620 | sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
621 | url: "https://pub.dev"
622 | source: hosted
623 | version: "7.0.0"
624 | stack_trace:
625 | dependency: transitive
626 | description:
627 | name: stack_trace
628 | sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
629 | url: "https://pub.dev"
630 | source: hosted
631 | version: "1.11.1"
632 | state_notifier:
633 | dependency: transitive
634 | description:
635 | name: state_notifier
636 | sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb
637 | url: "https://pub.dev"
638 | source: hosted
639 | version: "1.0.0"
640 | stream_channel:
641 | dependency: transitive
642 | description:
643 | name: stream_channel
644 | sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
645 | url: "https://pub.dev"
646 | source: hosted
647 | version: "2.1.2"
648 | stream_transform:
649 | dependency: transitive
650 | description:
651 | name: stream_transform
652 | sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
653 | url: "https://pub.dev"
654 | source: hosted
655 | version: "2.1.0"
656 | string_scanner:
657 | dependency: transitive
658 | description:
659 | name: string_scanner
660 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
661 | url: "https://pub.dev"
662 | source: hosted
663 | version: "1.2.0"
664 | term_glyph:
665 | dependency: transitive
666 | description:
667 | name: term_glyph
668 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
669 | url: "https://pub.dev"
670 | source: hosted
671 | version: "1.2.1"
672 | test_api:
673 | dependency: transitive
674 | description:
675 | name: test_api
676 | sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
677 | url: "https://pub.dev"
678 | source: hosted
679 | version: "0.6.1"
680 | time:
681 | dependency: transitive
682 | description:
683 | name: time
684 | sha256: "83427e11d9072e038364a5e4da559e85869b227cf699a541be0da74f14140124"
685 | url: "https://pub.dev"
686 | source: hosted
687 | version: "2.1.3"
688 | timing:
689 | dependency: transitive
690 | description:
691 | name: timing
692 | sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
693 | url: "https://pub.dev"
694 | source: hosted
695 | version: "1.0.1"
696 | typed_data:
697 | dependency: transitive
698 | description:
699 | name: typed_data
700 | sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
701 | url: "https://pub.dev"
702 | source: hosted
703 | version: "1.3.2"
704 | uuid:
705 | dependency: transitive
706 | description:
707 | name: uuid
708 | sha256: df5a4d8f22ee4ccd77f8839ac7cb274ebc11ef9adcce8b92be14b797fe889921
709 | url: "https://pub.dev"
710 | source: hosted
711 | version: "4.2.1"
712 | vector_math:
713 | dependency: transitive
714 | description:
715 | name: vector_math
716 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
717 | url: "https://pub.dev"
718 | source: hosted
719 | version: "2.1.4"
720 | vm_service:
721 | dependency: transitive
722 | description:
723 | name: vm_service
724 | sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
725 | url: "https://pub.dev"
726 | source: hosted
727 | version: "13.0.0"
728 | watcher:
729 | dependency: transitive
730 | description:
731 | name: watcher
732 | sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
733 | url: "https://pub.dev"
734 | source: hosted
735 | version: "1.1.0"
736 | web:
737 | dependency: transitive
738 | description:
739 | name: web
740 | sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
741 | url: "https://pub.dev"
742 | source: hosted
743 | version: "0.3.0"
744 | web_socket_channel:
745 | dependency: transitive
746 | description:
747 | name: web_socket_channel
748 | sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
749 | url: "https://pub.dev"
750 | source: hosted
751 | version: "2.4.0"
752 | xml:
753 | dependency: transitive
754 | description:
755 | name: xml
756 | sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
757 | url: "https://pub.dev"
758 | source: hosted
759 | version: "6.3.0"
760 | yaml:
761 | dependency: transitive
762 | description:
763 | name: yaml
764 | sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
765 | url: "https://pub.dev"
766 | source: hosted
767 | version: "3.1.2"
768 | sdks:
769 | dart: ">=3.2.0-194.0.dev <4.0.0"
770 | flutter: ">=3.7.0"
771 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_traffic_light
2 | description: A new Flutter project.
3 | publish_to: 'none'
4 | version: 1.0.0+1
5 |
6 | environment:
7 | sdk: '>=3.1.5 <4.0.0'
8 |
9 | dependencies:
10 | collection:
11 | cupertino_icons:
12 | flutter:
13 | sdk: flutter
14 | flutter_riverpod:
15 | flutter_web_plugins:
16 | sdk: flutter
17 | freezed_annotation:
18 | gap:
19 | riverpod_annotation:
20 | roggle:
21 |
22 | dev_dependencies:
23 | build_runner:
24 | custom_lint:
25 | flutter_gen_runner:
26 | flutter_test:
27 | sdk: flutter
28 | freezed:
29 | pedantic_mono:
30 | riverpod_generator:
31 | riverpod_lint:
32 |
33 | flutter:
34 | uses-material-design: true
35 |
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/susatthi/flutter-traffic-light/724e93b9461b4fc5594b9791b3d9874bcbb50d4b/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/susatthi/flutter-traffic-light/724e93b9461b4fc5594b9791b3d9874bcbb50d4b/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/susatthi/flutter-traffic-light/724e93b9461b4fc5594b9791b3d9874bcbb50d4b/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/susatthi/flutter-traffic-light/724e93b9461b4fc5594b9791b3d9874bcbb50d4b/web/icons/Icon-maskable-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/susatthi/flutter-traffic-light/724e93b9461b4fc5594b9791b3d9874bcbb50d4b/web/icons/Icon-maskable-512.png
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | 信号機シミュレーター
33 |
34 |
35 |
39 |
40 |
41 |
42 |
43 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "信号機シミュレーター",
3 | "short_name": "信号機シミュレーター",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "Flutter における「状態」を解説するためのサンプル。Riverpod を利用しています。",
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 | }
36 |
--------------------------------------------------------------------------------