146 Commits

Author SHA1 Message Date
gelbeinhalb
e4ea46c6cd Merge remote-tracking branch 'origin/development' into feature/88-neue-datenbank-struktur
All checks were successful
Pull Request Pipeline / lint (pull_request) Successful in 40s
Pull Request Pipeline / test (pull_request) Successful in 36s
2026-02-07 20:11:51 +01:00
gelbeinhalb
e881cf0555 fix expected null when empty string is correct
All checks were successful
Pull Request Pipeline / lint (pull_request) Successful in 40s
Pull Request Pipeline / test (pull_request) Successful in 35s
2026-02-07 18:17:08 +01:00
gelbeinhalb
278544788e fix formatting
Some checks failed
Pull Request Pipeline / lint (pull_request) Successful in 1m25s
Pull Request Pipeline / test (pull_request) Failing after 36s
2026-02-07 17:40:27 +01:00
gelbeinhalb
a12f4eb1c1 implement winner methods
Some checks failed
Pull Request Pipeline / test (pull_request) Failing after 28s
Pull Request Pipeline / lint (pull_request) Failing after 40s
2026-02-07 17:35:43 +01:00
gelbeinhalb
0eb8e2683c add replace players in a match test 2026-02-07 17:31:23 +01:00
gelbeinhalb
07b9b78252 add replace players in a match method 2026-02-07 17:31:19 +01:00
gelbeinhalb
fa9ad9dbae add test for replacing group players 2026-02-07 17:26:07 +01:00
gelbeinhalb
25699dffc0 add replaceGroupPlayers method 2026-02-07 17:25:49 +01:00
a4d4703069 Updated licenses [skip ci] 2026-02-06 12:32:19 +00:00
fabb7bae19 Updated version number [skip ci] 2026-02-06 12:31:47 +00:00
gelbeinhalb
70d6178829 restructure tests 2026-02-01 19:51:57 +01:00
gelbeinhalb
7aba8554c0 players cant be null
Some checks failed
Pull Request Pipeline / test (pull_request) Failing after 40s
Pull Request Pipeline / lint (pull_request) Failing after 44s
2026-02-01 18:23:58 +01:00
gelbeinhalb
dbef735a82 add color enum 2026-02-01 18:13:03 +01:00
gelbeinhalb
ccfea71a35 reduce line length 2026-02-01 17:56:24 +01:00
gelbeinhalb
415cae18cd added endedAt to matches 2026-02-01 17:55:42 +01:00
gelbeinhalb
2a3ea32193 change how optional parameters are defined 2026-02-01 17:31:40 +01:00
gelbeinhalb
2ea68dcc89 fix errors after merging 2026-02-01 17:29:19 +01:00
gelbeinhalb
acf3a7b003 Merge remote-tracking branch 'origin/development' into feature/88-neue-datenbank-struktur
# Conflicts:
#	lib/data/dao/group_match_dao.dart
#	lib/data/dao/match_dao.dart
#	lib/data/dao/player_match_dao.dart
#	lib/data/db/database.dart
#	lib/data/db/database.g.dart
#	lib/data/db/tables/group_match_table.dart
#	lib/data/db/tables/player_match_table.dart
#	lib/data/dto/match.dart
#	lib/presentation/views/main_menu/home_view.dart
#	lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart
#	lib/presentation/views/main_menu/match_view/match_view.dart
#	lib/services/data_transfer_service.dart
#	test/db_tests/game_test.dart
#	test/db_tests/group_match_test.dart
#	test/db_tests/player_match_test.dart
2026-02-01 15:55:06 +01:00
gelbeinhalb
1d352821fc all parameters are now required 2026-01-30 13:13:06 +01:00
d1458443eb Added ref again
Some checks failed
Push Pipeline / update_version (push) Successful in 6s
Push Pipeline / build (push) Failing after 31s
Push Pipeline / generate_licenses (push) Successful in 30s
Push Pipeline / test (push) Successful in 38s
Push Pipeline / format (push) Successful in 41s
2026-01-26 14:47:26 +01:00
9c00b48de5 Updated licenses [skip ci] 2026-01-26 13:38:35 +00:00
03ce304a0a Updated version number [skip ci] 2026-01-26 13:38:01 +00:00
dde617d429 Tried new workflow fix
Some checks failed
Push Pipeline / update_version (push) Successful in 4s
Push Pipeline / generate_licenses (push) Successful in 33s
Push Pipeline / test (push) Successful in 39s
Push Pipeline / format (push) Successful in 47s
Push Pipeline / build (push) Failing after 1m42s
2026-01-26 14:37:23 +01:00
03a2df4fdf Updated version number [skip ci] 2026-01-26 08:55:12 +00:00
96ef70b209 Updated version number [skip ci] 2026-01-26 08:45:49 +00:00
4ae59ec881 Merge pull request 'README vervollständigen' (#150) from enhancement/81-readme-vervollstaendigen into development
Some checks failed
Push Pipeline / update_version (push) Successful in 5s
Push Pipeline / generate_licenses (push) Failing after 30s
Push Pipeline / format (push) Has been skipped
Push Pipeline / test (push) Successful in 38s
Push Pipeline / build (push) Successful in 5m5s
Reviewed-on: #150
2026-01-26 08:45:42 +00:00
gelbeinhalb
3bd6dd4189 fix typo 2026-01-25 10:15:50 +01:00
c162e245bd Updated license name in Readme
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 37s
Pull Request Pipeline / lint (pull_request) Successful in 42s
2026-01-24 22:35:11 +01:00
481afd7533 Added example CONTRIBUTING.md
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 37s
Pull Request Pipeline / lint (pull_request) Successful in 43s
2026-01-24 19:17:33 +01:00
af42ebbf92 Merge remote-tracking branch 'origin/development' into enhancement/81-readme-vervollstaendigen
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 37s
Pull Request Pipeline / lint (pull_request) Successful in 45s
2026-01-24 17:48:25 +01:00
34e442dbe9 added white space
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m3s
Pull Request Pipeline / lint (pull_request) Successful in 2m7s
2026-01-24 17:47:32 +01:00
8783d0ac44 Version badges in one row
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m6s
Pull Request Pipeline / lint (pull_request) Successful in 2m9s
2026-01-24 17:30:56 +01:00
7f356b0c86 Updated licenses [skip ci] 2026-01-24 13:55:49 +00:00
e4a2ac6b47 Updated version number [skip ci] 2026-01-24 13:55:18 +00:00
6065b53ce9 Updated workflow
All checks were successful
Push Pipeline / test (push) Successful in 36s
Push Pipeline / update_version (push) Successful in 5s
Push Pipeline / generate_licenses (push) Successful in 30s
Push Pipeline / format (push) Successful in 50s
Push Pipeline / build (push) Successful in 5m21s
2026-01-24 14:53:31 +01:00
c644ccfb06 Updated version number [skip ci] 2026-01-24 12:21:35 +00:00
2dd7d0285d Pipeline Push Error (again) (#187)
Some checks failed
Push Pipeline / test (push) Successful in 34s
Push Pipeline / update_version (push) Successful in 5s
Push Pipeline / generate_licenses (push) Failing after 30s
Push Pipeline / format (push) Has been skipped
Push Pipeline / build (push) Successful in 5m23s
Pipeline Push Error (again) (#187)
Co-authored-by: Gitea Actions [bot] <actions@yannick-weigert.de>
Reviewed-on: #187
2026-01-24 12:20:55 +00:00
cf5883b430 Updated version number [skip ci] 2026-01-24 12:03:27 +00:00
7af2b43193 Merge pull request 'Hotfix: Pipeline Push Error' (#186) from hotifx/pipeline-push-error into development
Some checks failed
Push Pipeline / test (push) Successful in 36s
Push Pipeline / update_version (push) Successful in 5s
Push Pipeline / generate_licenses (push) Failing after 28s
Push Pipeline / format (push) Has been skipped
Push Pipeline / build (push) Successful in 5m15s
Reviewed-on: #186
2026-01-24 12:02:46 +00:00
90cc4d4c2a Added missing flutter step
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 36s
Pull Request Pipeline / lint (pull_request) Successful in 42s
2026-01-24 12:49:40 +01:00
db2ba2571f Added pull 2026-01-24 12:49:21 +01:00
3b01c4623c Updated version number [skip ci] 2026-01-24 11:41:50 +00:00
c5c9a43459 Update licenses in push pipeline (#184)
Some checks failed
Push Pipeline / test (push) Successful in 35s
Push Pipeline / update_version (push) Successful in 4s
Push Pipeline / generate_licenses (push) Failing after 2m1s
Push Pipeline / format (push) Has been skipped
Push Pipeline / build (push) Successful in 5m22s
Update licenses in push pipeline (#184)
Co-authored-by: Gitea Actions [bot] <actions@yannick-weigert.de>
Reviewed-on: #184
2026-01-24 11:41:07 +00:00
b2e58f2539 Updated version number [skip ci] 2026-01-24 10:33:32 +00:00
58dc5d8c2e Extend workflow to include build stage (#185)
All checks were successful
Push Pipeline / test (push) Successful in 35s
Push Pipeline / format (push) Successful in 50s
Push Pipeline / update_version (push) Successful in 4s
Push Pipeline / build (push) Successful in 5m22s
Extend workflow to include build stage (#185)
Reviewed-on: #185
Reviewed-by: Mathis Kirchner <mathis.kirchner.mk@gmail.com>
2026-01-24 10:32:00 +00:00
fd7dbd1155 Added gnu license
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m2s
Pull Request Pipeline / lint (pull_request) Successful in 2m5s
2026-01-23 22:30:54 +01:00
61b72cf595 Merge remote-tracking branch 'origin/enhancement/81-readme-vervollstaendigen' into enhancement/81-readme-vervollstaendigen
# Conflicts:
#	LICENSE
2026-01-23 22:15:01 +01:00
81c6c377d4 Added placeholder LICENSE and CONTRIBUTING.md 2026-01-23 22:14:51 +01:00
92f2b4db95 Added placeholder LICENSE and CONTRIBUTING.md
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m2s
Pull Request Pipeline / lint (pull_request) Successful in 2m7s
2026-01-23 22:14:12 +01:00
5178adf71c Changed screenshot order
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m5s
Pull Request Pipeline / lint (pull_request) Successful in 2m14s
2026-01-23 22:11:33 +01:00
4a6d639f1c Updated readme
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 1m59s
Pull Request Pipeline / lint (pull_request) Successful in 2m8s
2026-01-23 22:10:30 +01:00
e9cf707fca Merge branch 'refs/heads/development' into enhancement/81-readme-vervollstaendigen 2026-01-23 20:56:56 +01:00
2b7941202a Updated version number [skip ci] 2026-01-23 12:31:09 +00:00
92317bcbdf Merge pull request 'App-Name, Icon und Design' (#179) from documentation/131-app-name-icon-und-design into development
All checks were successful
Push Pipeline / test (push) Successful in 1m56s
Push Pipeline / format (push) Successful in 2m4s
Push Pipeline / update_version (push) Successful in 4s
Reviewed-on: #179
Reviewed-by: gelbeinhalb <spam@yannick-weigert.de>
Reviewed-by: Mathis Kirchner <mathis.kirchner.mk@gmail.com>
2026-01-23 12:28:56 +00:00
gelbeinhalb
b0cb385756 ruleset is now a required game enum parameter
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m1s
Pull Request Pipeline / lint (pull_request) Successful in 2m7s
2026-01-23 11:54:37 +01:00
gelbeinhalb
118b316a35 description is now a required game parameter 2026-01-23 11:25:20 +01:00
gelbeinhalb
55f5aac4e2 color is now a required game parameter 2026-01-23 11:08:11 +01:00
ceade5cafd Fixed ios laucn screen
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m0s
Pull Request Pipeline / lint (pull_request) Successful in 2m7s
2026-01-22 22:34:36 +01:00
6060afc543 Renamed package & bundle identifier
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 1m58s
Pull Request Pipeline / lint (pull_request) Successful in 2m18s
2026-01-22 22:13:12 +01:00
ac6399d707 Merge branch 'development' into documentation/131-app-name-icon-und-design 2026-01-22 21:46:11 +01:00
gelbeinhalb
6006c6d3f7 Merge remote-tracking branch 'origin/development' into feature/88-neue-datenbank-struktur
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 1m58s
Pull Request Pipeline / lint (pull_request) Successful in 2m17s
2026-01-21 16:10:47 +01:00
gelbeinhalb
0ddb4edbc9 remove unused variable
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m4s
Pull Request Pipeline / lint (pull_request) Successful in 2m11s
2026-01-21 16:08:21 +01:00
gelbeinhalb
7339194ba0 fix data import and export
Some checks failed
Pull Request Pipeline / test (pull_request) Successful in 2m8s
Pull Request Pipeline / lint (pull_request) Failing after 2m18s
2026-01-21 15:43:56 +01:00
gelbeinhalb
bd5e38a3ca save game to database on create 2026-01-21 15:42:47 +01:00
gelbeinhalb
12b713bb70 remove skip from test
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m0s
Pull Request Pipeline / lint (pull_request) Successful in 2m8s
2026-01-21 12:04:13 +01:00
gelbeinhalb
e55cea0dcc fix missing await 2026-01-21 12:04:00 +01:00
gelbeinhalb
b2a3a0cf75 fix getting non-existent team throws exception test
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m4s
Pull Request Pipeline / lint (pull_request) Successful in 2m19s
2026-01-21 11:55:15 +01:00
gelbeinhalb
f142169371 fix overlapping members in teams test 2026-01-21 11:54:00 +01:00
gelbeinhalb
0b778210ef add new team tests
Some checks failed
Pull Request Pipeline / test (pull_request) Failing after 2m4s
Pull Request Pipeline / lint (pull_request) Successful in 2m9s
2026-01-21 11:36:23 +01:00
gelbeinhalb
748361d04f add new score tests 2026-01-21 11:33:37 +01:00
gelbeinhalb
2e6a2b8e55 add more player_match tests 2026-01-21 11:26:46 +01:00
gelbeinhalb
15894096f3 fix missing await error 2026-01-21 11:11:46 +01:00
gelbeinhalb
d488eac3ae add more group tests 2026-01-21 11:11:37 +01:00
gelbeinhalb
19b2685714 add more player tests 2026-01-21 11:03:09 +01:00
gelbeinhalb
068ca95afc Merge branch 'feature/88-neue-datenbank-struktur' of git.yannick-weigert.de:liquid-development/game-tracker into feature/88-neue-datenbank-struktur
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m6s
Pull Request Pipeline / lint (pull_request) Successful in 2m16s
2026-01-20 16:34:43 +01:00
gelbeinhalb
0d28f4b87c remove winner test again 2026-01-20 16:34:38 +01:00
gelbeinhalb
2e454a530a remove winner test again 2026-01-20 16:33:12 +01:00
gelbeinhalb
6c39e1e574 remove winner check
Some checks failed
Pull Request Pipeline / test (pull_request) Failing after 2m2s
Pull Request Pipeline / lint (pull_request) Successful in 2m9s
2026-01-20 16:31:52 +01:00
gelbeinhalb
b33260ec23 fix match missing game 2026-01-20 16:31:43 +01:00
gelbeinhalb
b108375ad5 remove winner tests
Some checks failed
Pull Request Pipeline / test (pull_request) Failing after 2m2s
Pull Request Pipeline / lint (pull_request) Successful in 2m15s
2026-01-20 16:03:37 +01:00
gelbeinhalb
e09ccf9356 add comments to all tests
Some checks failed
Pull Request Pipeline / test (pull_request) Failing after 2m2s
Pull Request Pipeline / lint (pull_request) Successful in 2m9s
2026-01-20 15:58:16 +01:00
8ee2b6cb06 Updated version number [skip ci] 2026-01-20 14:55:05 +00:00
b14b7733ca Merge pull request 'Push Pipeline Error' (#181) from hotfix/push-pipeline-error into development
All checks were successful
Push Pipeline / test (push) Successful in 2m7s
Push Pipeline / format (push) Successful in 2m8s
Push Pipeline / update_version (push) Successful in 5s
Reviewed-on: #181
Reviewed-by: gelbeinhalb <spam@yannick-weigert.de>
2026-01-20 14:52:47 +00:00
gelbeinhalb
b0b21bcba6 add new group tests 2026-01-20 15:48:40 +01:00
gelbeinhalb
dec74e9b62 add game tests 2026-01-20 15:41:05 +01:00
gelbeinhalb
4e73babb71 rename game_test to match_test 2026-01-20 15:28:26 +01:00
bc51b23563 Updated ref names
All checks were successful
Pull Request Pipeline / lint (pull_request) Successful in 2m13s
Pull Request Pipeline / test (pull_request) Successful in 2m22s
2026-01-20 12:03:31 +01:00
057f8c1d58 Changed workflow back to prod mode 2026-01-20 12:00:33 +01:00
4c1c22123e Updated version number [skip ci] 2026-01-20 10:59:27 +00:00
e9929426e0 Removed development restriction
All checks were successful
Push Pipeline / test (push) Successful in 1m57s
Push Pipeline / update_version (push) Successful in 6s
Push Pipeline / format (push) Successful in 2m6s
2026-01-20 11:57:17 +01:00
eb404f3ef2 Fixed push pipeline
All checks were successful
Push Pipeline / test (push) Successful in 1m57s
Push Pipeline / update_version (push) Has been skipped
Push Pipeline / format (push) Successful in 2m17s
2026-01-20 11:54:15 +01:00
c7b4623198 Workflows um Format Stage erweitern (#175)
Some checks failed
Push Pipeline / test (push) Successful in 1m58s
Push Pipeline / update_version (push) Failing after 4s
Push Pipeline / format (push) Successful in 2m8s
Extend workflows with format stage

Co-authored-by: Gitea Actions [bot] <>
Reviewed-on: #175
Reviewed-by: gelbeinhalb <spam@yannick-weigert.de>
2026-01-20 10:48:49 +00:00
ccd0c62e3c Added launchscreen
All checks were successful
Pull Request Pipeline / lint (pull_request) Successful in 2m3s
Pull Request Pipeline / test (pull_request) Successful in 1m56s
2026-01-19 20:04:58 +01:00
gelbeinhalb
25e0c75dc6 add team_test.dart.dart
Some checks failed
Pull Request Pipeline / lint (pull_request) Successful in 2m8s
Pull Request Pipeline / test (pull_request) Failing after 1m56s
2026-01-19 19:52:00 +01:00
gelbeinhalb
fb59372c97 add score_test.dart 2026-01-19 19:51:48 +01:00
9f71c22a56 Fixed pipeline
All checks were successful
Pull Request Pipeline / lint (pull_request) Successful in 2m4s
Pull Request Pipeline / test (pull_request) Successful in 2m5s
2026-01-19 16:14:26 +01:00
87d7fbebcd Updated quick create button color
Some checks failed
Pull Request Pipeline / lint (pull_request) Failing after 2m6s
Pull Request Pipeline / test (pull_request) Successful in 2m25s
2026-01-19 16:07:20 +01:00
c625174017 Updated text color 2026-01-19 16:07:12 +01:00
gelbeinhalb
8dd2f5f8b8 add name to team
Some checks failed
Pull Request Pipeline / lint (pull_request) Successful in 2m8s
Pull Request Pipeline / test (pull_request) Failing after 1m56s
2026-01-19 15:46:25 +01:00
gelbeinhalb
c97fdc2b5f add match method to change created at
Some checks failed
Pull Request Pipeline / lint (pull_request) Successful in 2m4s
Pull Request Pipeline / test (pull_request) Failing after 1m59s
2026-01-19 14:58:33 +01:00
gelbeinhalb
764ce13240 fix felix typos :) 2026-01-19 14:57:19 +01:00
gelbeinhalb
715b3debbb add updateGroupDescription 2026-01-19 14:18:59 +01:00
gelbeinhalb
bb11c86816 Merge remote-tracking branch 'origin/development' into feature/88-neue-datenbank-struktur
# Conflicts:
#	lib/presentation/views/main_menu/match_view/create_match/create_match_view.dart
2026-01-19 14:05:32 +01:00
53a33ca2e1 Updated app name
All checks were successful
Pull Request Pipeline / lint (pull_request) Successful in 2m7s
Pull Request Pipeline / test (pull_request) Successful in 1m56s
2026-01-18 22:58:28 +01:00
e1dd40a1c3 first app icon and theme update 2026-01-18 22:53:54 +01:00
45b11359b3 Merge pull request 'Maximale Input in Textfelder gefixtx' (#176) from hotifx/fix-input-length into development
Reviewed-on: #176
Reviewed-by: Mathis Kirchner <mathis.kirchner.mk@gmail.com>
2026-01-18 13:49:53 +00:00
57fb8dbcc8 Merge branch 'development' into hotifx/fix-input-length
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m5s
Pull Request Pipeline / lint (pull_request) Successful in 2m11s
2026-01-18 13:46:25 +00:00
5a30538aa5 Merge pull request 'Text Overflows durch Tastatur' (#173) from bug/162-text-overflows-durch-tastatur into development
Reviewed-on: #173
2026-01-18 11:23:04 +00:00
1e18105ce0 Merge remote-tracking branch 'origin/development' into bug/162-text-overflows-durch-tastatur
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m5s
Pull Request Pipeline / lint (pull_request) Successful in 2m9s
# Conflicts:
#	pubspec.yaml
2026-01-18 11:45:50 +01:00
9ce2ca0ceb Merge pull request 'Match braucht Game' (#174) from enhancement/103-match-braucht-game into development
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m15s
Pull Request Pipeline / lint (pull_request) Successful in 2m15s
Reviewed-on: #174
2026-01-17 22:03:55 +00:00
39e6e485ac remove newline
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m6s
Pull Request Pipeline / lint (pull_request) Successful in 2m8s
2026-01-17 22:54:22 +01:00
e9633a898c bump version 2026-01-17 22:54:18 +01:00
94c3bad02b Removed counter
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m6s
Pull Request Pipeline / lint (pull_request) Successful in 2m11s
2026-01-17 22:41:02 +01:00
ed2d672dee Implemented maxLength attribute 2026-01-17 22:40:56 +01:00
449639df0e Merge remote-tracking branch 'origin/development' into enhancement/103-match-braucht-game
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m6s
Pull Request Pipeline / lint (pull_request) Successful in 2m10s
# Conflicts:
#	pubspec.yaml
2026-01-17 21:35:42 +01:00
a713ccb59c Merge pull request 'Gruppenprofile implementieren' (#172) from feature/169-gruppenprofile-implementieren into development
Reviewed-on: #172
2026-01-17 20:34:26 +00:00
f5924c4758 adjusted spacing & changed runAlignment to alignment
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m8s
Pull Request Pipeline / lint (pull_request) Successful in 2m20s
2026-01-17 21:27:22 +01:00
5c9f44e947 bump build nr
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m6s
Pull Request Pipeline / lint (pull_request) Successful in 2m9s
2026-01-17 21:12:53 +01:00
5f987806d6 remove ruleset 2026-01-17 21:12:43 +01:00
92c62000af remove margin from title_description_list_tile.dart 2026-01-17 21:12:17 +01:00
babe74f2be Merge remote-tracking branch 'origin/feature/169-gruppenprofile-implementieren' into feature/169-gruppenprofile-implementieren
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m15s
Pull Request Pipeline / lint (pull_request) Successful in 2m16s
2026-01-17 15:21:13 +01:00
8a38b9c3ea Updated dateformat to localize 2026-01-17 15:18:56 +01:00
ddd0a5d8bd Updated dateformat to localize
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m11s
Pull Request Pipeline / lint (pull_request) Successful in 2m12s
2026-01-17 15:17:33 +01:00
be9d1b52d2 Merge branch 'development' into feature/169-gruppenprofile-implementieren
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m19s
Pull Request Pipeline / lint (pull_request) Successful in 2m21s
# Conflicts:
#	pubspec.yaml
2026-01-17 14:56:26 +01:00
514e0f8064 Changed date format
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m21s
Pull Request Pipeline / lint (pull_request) Successful in 2m26s
2026-01-17 14:54:06 +01:00
ff47ef38c1 Changed alignment 2026-01-17 14:51:12 +01:00
fa2706395c Merge remote-tracking branch 'origin/development' into bug/162-text-overflows-durch-tastatur
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m6s
Pull Request Pipeline / lint (pull_request) Successful in 2m9s
# Conflicts:
#	pubspec.yaml
2026-01-17 14:44:49 +01:00
2d1ac3a17c Merge pull request 'Konstanten für Länge von Namen' (#170) from enhancement/158-konstanten-für-länge-von-namen into development
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m6s
Pull Request Pipeline / lint (pull_request) Successful in 2m9s
Reviewed-on: #170
Reviewed-by: Mathis Kirchner <mathis.kirchner.mk@gmail.com>
2026-01-17 13:42:50 +00:00
4fd8d2129b Merge remote-tracking branch 'origin/enhancement/158-konstanten-für-länge-von-namen' into enhancement/158-konstanten-für-länge-von-namen
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m14s
Pull Request Pipeline / lint (pull_request) Successful in 2m18s
2026-01-17 14:35:44 +01:00
db41f40a52 Edited comment 2026-01-17 14:35:21 +01:00
0e747710ab Edited comment
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m5s
Pull Request Pipeline / lint (pull_request) Successful in 2m10s
2026-01-17 14:33:24 +01:00
9f44f02a35 Changed length to 32 2026-01-17 14:32:25 +01:00
3addaa0f9d Disable resizing when using keyboard
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m7s
Pull Request Pipeline / lint (pull_request) Successful in 2m9s
2026-01-17 14:22:45 +01:00
abb0fcbbd6 Updated file name
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m3s
Pull Request Pipeline / lint (pull_request) Successful in 2m10s
2026-01-17 00:57:28 +01:00
fc6eb2b9cf Added comments
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m7s
Pull Request Pipeline / lint (pull_request) Successful in 2m10s
2026-01-17 00:52:13 +01:00
6a0896d818 Implemented ColoredIconContainer 2026-01-17 00:52:09 +01:00
a8129eb134 Implemented first version of group profile 2026-01-16 23:34:47 +01:00
783f772da1 Implemented constants
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m41s
Pull Request Pipeline / lint (pull_request) Successful in 2m45s
2026-01-16 21:52:58 +01:00
b7930d5e2e Adjusted constant name 2026-01-16 21:41:42 +01:00
1b709707b5 Added constants 2026-01-16 21:41:20 +01:00
gelbeinhalb
6a6e36ed7c remove pair
Some checks failed
Pull Request Pipeline / test (pull_request) Failing after 2m5s
Pull Request Pipeline / lint (pull_request) Successful in 2m11s
2026-01-16 15:55:17 +01:00
gelbeinhalb
d21c37966e tests create testGame now
Some checks failed
Pull Request Pipeline / test (pull_request) Failing after 2m6s
Pull Request Pipeline / lint (pull_request) Successful in 2m8s
2026-01-16 14:15:55 +01:00
5da12939cb Updated Dart version
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m12s
Pull Request Pipeline / lint (pull_request) Successful in 2m18s
2026-01-12 20:30:57 +01:00
0d20b5847f Updated versions
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 2m6s
Pull Request Pipeline / lint (pull_request) Successful in 2m19s
2026-01-12 20:29:18 +01:00
973e327232 Merge remote-tracking branch 'origin/development' into enhancement/81-readme-vervollstaendigen 2026-01-12 20:29:06 +01:00
0f79495775 Implemented badges
All checks were successful
Pull Request Pipeline / lint (pull_request) Successful in 2m25s
Pull Request Pipeline / test (pull_request) Successful in 2m27s
2025-12-06 15:42:02 +01:00
136 changed files with 7468 additions and 2894 deletions

View File

@@ -10,22 +10,22 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
# Required for Flutter action
- name: Install jq
run: |
apt-get update
apt-get install -y jq
- name: Install Flutter (wget)
run: |
wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
tar xf flutter_linux_3.38.2-stable.tar.xz
# Set Git safe directory for Flutter path
git config --global --add safe.directory "$(pwd)/flutter"
# Set Flutter path
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: 3.38.6
- name: Get dependencies
run: flutter pub get
run: |
git config --global --add safe.directory /opt/hostedtoolcache/flutter/stable-3.38.6-x64
flutter pub get
- name: Analyze Formatting
run: flutter analyze lib test
@@ -36,22 +36,22 @@ jobs:
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
# Required for Flutter action
- name: Install jq
run: |
apt-get update
apt-get install -y jq
- name: Install Flutter (wget)
run: |
wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
tar xf flutter_linux_3.38.2-stable.tar.xz
# Set Git safe directory for Flutter path
git config --global --add safe.directory "$(pwd)/flutter"
# Set Flutter path
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: 3.38.6
- name: Get dependencies
run: flutter pub get
run: |
git config --global --add safe.directory /opt/hostedtoolcache/flutter/stable-3.38.6-x64
flutter pub get
- name: Run tests
run: flutter test

View File

@@ -7,44 +7,194 @@ on:
- "main"
jobs:
format:
build:
runs-on: ubuntu-latest
if: false # Needs bot user
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install dependencies
- name: Setup Java (Temurin 17)
uses: actions/setup-java@v3
with:
distribution: temurin
java-version: '17'
- name: Setup Android SDK
uses: android-actions/setup-android@v3
# Required for Flutter action
- name: Install jq
run: |
apt-get update
apt-get install -y jq
- name: Install Flutter (wget)
run: |
wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
tar xf flutter_linux_3.38.2-stable.tar.xz
# Set Git safe directory for Flutter path
git config --global --add safe.directory "$(pwd)/flutter"
# Set Flutter path
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: 3.38.6
- name: Get & upgrade dependencies
- name: Get dependencies
run: |
git config --global --add safe.directory /opt/hostedtoolcache/flutter/stable-3.38.6-x64
flutter pub get
flutter pub upgrade --major-versions
- name: Auto-format
- name: Build APK
run: flutter build apk --release
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
# Required for Flutter action
- name: Install jq
run: |
dart format lib
apt-get update
apt-get install -y jq
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: 3.38.6
- name: Get dependencies
run: |
git config --global --add safe.directory /opt/hostedtoolcache/flutter/stable-3.38.6-x64
flutter pub get
- name: Run tests
run: flutter test
update_version:
runs-on: ubuntu-latest
if: gitea.ref == 'refs/heads/development'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.BOT_TOKEN }}
ref: ${{ gitea.ref_name }}
- name: Increment version number
uses: stikkyapp/update-pubspec-version@v2
with:
strategy: 'patch'
path: './pubspec.yaml'
- name: Commit version update
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
run: |
git config --global user.name "Gitea Actions [bot]"
git config --global user.email "actions@yannick-weigert.de"
git config pull.rebase false
git pull origin ${{ gitea.ref_name }}
git add pubspec.yaml
git commit -m "Updated version number [skip ci]"
git push origin HEAD:${{ gitea.ref_name }}
generate_licenses:
runs-on: ubuntu-latest
needs: update_version
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.BOT_TOKEN }}
ref: ${{ gitea.ref_name }}
# Required for Flutter action
- name: Install jq
run: |
apt-get update
apt-get install -y jq
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: 3.38.6
- name: Get dependencies
run: |
git config --global --add safe.directory /opt/hostedtoolcache/flutter/stable-3.38.6-x64
flutter pub get
- name: Generate oss_licenses.dart
run: flutter pub run dart_pubspec_licenses:generate -o lib/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart
- name: Commit license update
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
run: |
if [ -n "$(git status --porcelain lib test)" ]; then
git config --global user.name "Gitea Actions [bot]"
git config --global user.email "actions@yannick-weigert.de"
git config pull.rebase false
git pull origin ${{ gitea.ref_name }}
git add lib test
git commit -m "Updated licenses [skip ci]"
git push origin HEAD:${{ gitea.ref_name }}
else
echo "No changes to commit"
fi
format:
runs-on: ubuntu-latest
needs: [update_version, generate_licenses]
steps:
- name: Checkout code
uses: actions/checkout@v4
# Required for Flutter action
- name: Install jq
run: |
apt-get update
apt-get install -y jq
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: 3.38.6
- name: Get dependencies
run: |
git config --global --add safe.directory /opt/hostedtoolcache/flutter/stable-3.38.6-x64
flutter pub get
- name: Check code format
id: check_format
continue-on-error: true
run: flutter analyze lib test
- name: Format code
if: steps.check_format.outcome == 'failure'
env:
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
run: |
git fetch origin ${{ gitea.ref_name }}
git checkout ${{ gitea.ref_name }}
dart fix --apply lib
dart fix --apply test
# Needs credentials, push access and the right files need to be staged
- name: Commit Changes
run: |
git config --global user.name "Gitea Actions"
git config --global user.email "actions@gitea.com"
git status
git add lib/
git status
git commit -m "Actions: Auto-formatting [skip ci]"
git push
if [ -n "$(git status --porcelain lib test)" ]; then
git config --global user.name "Gitea Actions [bot]"
git config --global user.email "actions@yannick-weigert.de"
git config pull.rebase false
git pull origin ${{ gitea.ref_name }}
git add lib test
git commit -m "Auto-format code [skip ci]"
git push origin HEAD:${{ gitea.ref_name }}
else
echo "No changes to commit"
fi
- name: Verify format
run: flutter analyze lib test

13
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,13 @@
# Contributing
## Code of Conduct
`<insert link to code of conduct here>`
## Code Style
`<insert styling guidelines here>`
## Repository structure
`<insert folder structure and explanation here>`

165
LICENSE Normal file
View File

@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

View File

@@ -1,7 +1,63 @@
# Game Tracker
<p align="center">
<img alt="Tallee Logo" src="/artefacts/app-logo.png" width="200"/>
<h2 align="center">Tallee</h2>
</p>
<p align="center">
An open-source app to track card- and board games, manage players & groups and get statistics about your played games.
</p>
<p align="center">
<a href="https://apps.apple.com/">
<img src="https://tools.applemediaservices.com/api/badges/download-on-the-app-store/black/en-US"
alt="Download on the App Store"
height="48"
/>
</a>
<a href="https://play.google.com/">
<img alt="Get it on Google Play"
title="Google Play"
src="https://raw.githubusercontent.com/pd4d10/git-touch/main/assets/google-play-badge.png"
height="48"
/>
</a>
</p>
![Version](https://img.shields.io/badge/App--Version-0.0.1_Alpha-orange)
![Flutter](https://img.shields.io/badge/Flutter-3.38.6-027DFD?logo=flutter)
![iOS26](https://img.shields.io/badge/iOS-26-white?logo=apple)
![Android16](https://img.shields.io/badge/Android-16-3DDC84?logo=android)
## Screenshots
<table align="center" cellspacing="8">
<tr>
<td><img src="/artefacts/screenshot-1.png" alt="Screenshot 1" width="240" /></td>
<td><img src="/artefacts/screenshot-2.png" alt="Screenshot 2" width="240" /></td>
<td><img src="/artefacts/screenshot-3.png" alt="Screenshot 3" width="240" /></td>
<td><img src="/artefacts/screenshot-4.png" alt="Screenshot 4" width="240" /></td>
</tr>
</table>
## Contributing
Contributions are welcome! If you find a bug or have a feature request, please open an issue on GitHub. If you'd like to
contribute code, feel free to fork the repository and submit a pull request. For contribution guidelines, please refer
to [CONTRIBUTING.md](CONTRIBUTING.md).
## License
This project is licensed under the GNU LGPLv3 License. See the [LICENSE](LICENSE) file for details.
## Contributors
<a href="https://github.com/liquiddevelopmentde/game-tracker/graphs/contributors">
<img src="https://contrib.rocks/image?repo=liquiddevelopmentde/game-tracker" />
</a>
## Credits
Tallee is developed and maintained by [Liquid Development](https://liquid-dev.de). For more information or support regarding Tallee, contact us through our website or [hello@liquid-dev.de](mailto:hello@liquid-dev.de).
![Created by Liquid Development](https://img.shields.io/badge/Created_by-Liquid_Development-027DFD?logo=data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iRWJlbmVfMSIgZGF0YS1uYW1lPSJFYmVuZSAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3MjUuNDggODk3LjMiPgogIDxkZWZzPgogICAgPHN0eWxlPgogICAgICAuY2xzLTEgewogICAgICAgIGZpbGw6ICNmZmY7CiAgICAgIH0KICAgIDwvc3R5bGU+CiAgPC9kZWZzPgogIDxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTcwNS4yNiw3MDEuOTJsNi40LDExLjA4Yy0xLjk1LTMuODEtNC4wOS03LjUxLTYuNC0xMS4wOFoiLz4KICA8cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik02MDIuMzksODk3LjI1aC03LjIxYzEuMi4wMywyLjQuMDUsMy42MS4wNXMyLjQxLS4wMiwzLjYxLS4wNVoiLz4KICA8cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0wLDY5NS4zOGwyLjY4LTQuNjRjLS45MywxLjUyLTEuODIsMy4wNy0yLjY4LDQuNjRaIi8+CiAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNNjgyLjU1LDcyMy40NWw2LjA1LDEwLjQ5Yy0xLjc5LTMuNjQtMy44MS03LjE1LTYuMDUtMTAuNDlaIi8+CiAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMzcuNzIsNzMzLjI4bDUuMy05LjE4Yy0xLjk0LDIuOTQtMy43MSw2LjAxLTUuMyw5LjE4WiIvPgogIDxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTcxMS42Niw3MTMuMDFsLTYuNC0xMS4wOC0yMjAuNDYtMzgxLjg0aDBWMTAxLjg0YzIwLjY3LTYuOTgsMzUuNTYtMjYuNTIsMzUuNTYtNDkuNTQsMC0yOC44OC0yMy40MS01Mi4zLTUyLjMtNTIuM2gtMjA5LjQ4Yy0yOC44OCwwLTUyLjMsMjMuNDEtNTIuMyw1Mi4zLDAsMjIuNzEsMTQuNDgsNDIuMDMsMzQuNyw0OS4yNXYyMTguNTRsLS4zMy41OEwxOC44OSw3MDQuNzlsLTIuNjgsNC42NGMtOS45OSwxOC4xMi0xNS42OCwzOC45Ni0xNS42OCw2MS4xMiwwLDY5Ljk3LDU2LjY0LDEyNi43LDEyNi41MSwxMjYuN2g0NzUuMzVjNjguMy0xLjkxLDEyMy4wOS01Ny44OCwxMjMuMDktMTI2LjY0LDAtMjAuNzQtNC45OS00MC4zMi0xMy44Mi01Ny42Wk02MDguNTYsODYyLjUzSDExNy40M2MtNDkuMzcsMC04OS4zOS00MC4wMi04OS4zOS04OS4zOSwwLTE0LjM2LDMuMzktMjcuOTMsOS40MS0zOS45Nmw1LjMtOS4xOCwyMzMuMi00MDMuOTJoLS4wOFYxMDQuNTloMTcuODFjOS40NywwLDE3LjE1LTcuNjgsMTcuMTUtMTcuMTVzLTcuNjgtMTcuMTUtMTcuMTUtMTcuMTVoLTM1LjU5di0uMDJjLTkuNzItLjI2LTE3LjUyLTguMi0xNy41Mi0xNy45OHM3LjgtMTcuNzIsMTcuNTItMTcuOTh2LS4wMmgyMDkuMjZjOS45NCwwLDE4LDguMDYsMTgsMThzLTguMDYsMTgtMTgsMThoLTM0LjQ4Yy05LjQ3LDAtMTcuMTUsNy42OC0xNy4xNSwxNy4xNXM3LjY4LDE3LjE1LDE3LjE1LDE3LjE1aDE3LjA0djIxNS40OWguMDdsMjMyLjgyLDQwMy4yNiw2LjA2LDEwLjVjNS44MiwxMS44Niw5LjA5LDI1LjIsOS4wOSwzOS4zLDAsNDkuMzctNDAuMDIsODkuMzktODkuMzksODkuMzlaIi8+CiAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMzgxLjY4LDU0NS4zOGMtMy4wOCwxLjY4LTYuMTgsMy4zLTkuMzIsNC44NiwzLjA3LTEuNjcsNi4xOC0zLjI5LDkuMzItNC44NloiLz4KICA8cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik01ODMuNDIsNTUxLjE5bC0yMC42Ny0zNS44Yy0xMy42OS0xLjg0LTI3LjY3LTIuNzktNDEuODYtMi43OS0xNy45OSwwLTM1LjYyLDEuNTMtNTIuNzgsNC40Ni0zMC41Niw1LjIxLTU5LjYsMTQuODktODYuNDIsMjguMzMtMy4wOCwxLjY4LTYuMTgsMy4zLTkuMzIsNC44Ni00MS44OCwyMC45OS04OS4xNiwzMi43OS0xMzkuMTksMzIuNzktMzQuODUsMC02OC4zNS01Ljc0LTk5LjYzLTE2LjMxLDAsMCwwLC4wMiwwLC4wMmwtMTYuNTIsMjguNjFjMzcuMDEsMTUuNTMsNzcuNjUsMjQuMTIsMTIwLjMsMjQuMTIsMTcuOTgsMCwzNS42MS0xLjUzLDUyLjc2LTQuNDYsMzIuNzctNS41OSw2My43OC0xNi4zMSw5Mi4yLTMxLjI5Ljg3LS40NiwxLjczLS45MiwyLjYtMS40LDQzLjI5LTIyLjgyLDkyLjYyLTM1Ljc0LDE0NC45Ni0zNS43NCwxOC4yOCwwLDM2LjE4LDEuNTksNTMuNTksNC42MWwtLjAyLS4wMloiLz4KICA8Zz4KICAgIDxjaXJjbGUgY2xhc3M9ImNscy0xIiBjeD0iNTg3LjY0IiBjeT0iODAzLjQiIHI9IjE4Ljk2Ii8+CiAgICA8cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik01MTUuNTIsNzg0LjQzSDEwMy41NWMtMTAuOTIsMC0xOS43Niw4LjQ5LTE5Ljc2LDE4Ljk2czguODUsMTguOTYsMTkuNzYsMTguOTZoNDExLjk3YzEwLjkyLDAsMTkuNzYtOC40OSwxOS43Ni0xOC45NnMtOC44NS0xOC45Ni0xOS43Ni0xOC45NloiLz4KICA8L2c+CiAgPGNpcmNsZSBjbGFzcz0iY2xzLTEiIGN4PSIyODMuMzIiIGN5PSI0NjcuNTkiIHI9IjE4Ljk2Ii8+CiAgPGNpcmNsZSBjbGFzcz0iY2xzLTEiIGN4PSIzMjYuMjMiIGN5PSIzNjYuMjUiIHI9IjE4Ljk2Ii8+CiAgPHBhdGggY2xhc3M9ImNscy0xIiBkPSJNNDA2LjU2LDM4NS4yMmMtMjQuMDYsMC00My41NiwxOS41LTQzLjU2LDQzLjU2czE5LjUsNDMuNTYsNDMuNTYsNDMuNTYsNDMuNTYtMTkuNSw0My41Ni00My41Ni0xOS41LTQzLjU2LTQzLjU2LTQzLjU2Wk00MDYuNTYsNDQ3Ljc0Yy0xMC40NywwLTE4Ljk2LTguNDktMTguOTYtMTguOTZzOC40OS0xOC45NiwxOC45Ni0xOC45NiwxOC45Niw4LjQ5LDE4Ljk2LDE4Ljk2LTguNDksMTguOTYtMTguOTYsMTguOTZaIi8+Cjwvc3ZnPg==)
![Version](https://img.shields.io/badge/Version-0.3.0-orange)
![Flutter](https://img.shields.io/badge/Flutter-3.32.1-blue?logo=flutter)
![Dart](https://img.shields.io/badge/Dart-3.8.1-blue?logo=dart)
A all-in-one app to track card- and board games, manage players and groups and get statistics about your played games.

View File

@@ -11,3 +11,4 @@ linter:
prefer_const_literals_to_create_immutables: true
unnecessary_const: true
lines_longer_than_80_chars: false
constant_identifier_names: false

View File

@@ -6,7 +6,7 @@ plugins {
}
android {
namespace = "com.example.game_tracker"
namespace = "de.liquid.tallee"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
@@ -21,7 +21,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.game_tracker"
applicationId = "de.liquid.tallee"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion

View File

@@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:label="game_tracker"
android:label="Tallee"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,4 +1,4 @@
package com.example.game_tracker
package de.liquid.tallee
import io.flutter.embedding.android.FlutterActivity

Binary file not shown.

Before

Width:  |  Height:  |  Size: 828 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 B

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 656 B

After

Width:  |  Height:  |  Size: 938 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 B

After

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 824 B

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="app_icon_background">#E6F1E4</color>
<color name="launch_background">#0B0B0B</color>
<color name="launch_background">#ef681f</color>
</resources>

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Referenz unbedingt als @color/launch_background (nicht @colors/...) -->
<color name="ic_launcher_background">@color/app_icon_background</color>
<color name="ic_launcher_background">#EF681F</color>
</resources>

BIN
artefacts/app-logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
artefacts/screenshot-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

BIN
artefacts/screenshot-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 KiB

BIN
artefacts/screenshot-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

BIN
artefacts/screenshot-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

View File

@@ -15,16 +15,91 @@
},
"name": {
"type": "string"
},
"description": {
"type": "string"
}
},
"required": [
"id",
"createdAt",
"name"
"name",
"description"
]
}
},
"games": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"name": {
"type": "string"
},
"ruleset": {
"type": "string"
},
"description": {
"type": "string"
},
"color": {
"type": "string"
},
"icon": {
"type": "string"
}
},
"required": [
"id",
"createdAt",
"name",
"ruleset",
"description",
"color",
"icon"
]
}
},
"groups": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"createdAt": {
"type": "string"
},
"description": {
"type": "string"
},
"memberIds": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"id",
"name",
"createdAt",
"description",
"memberIds"
]
}
},
"teams": {
"type": "array",
"items": {
"type": "object",
@@ -67,11 +142,14 @@
"createdAt": {
"type": "string"
},
"endedAt": {
"type": ["string", "null"]
},
"gameId": {
"type": "string"
},
"groupId": {
"anyOf": [
{"type": "string"},
{"type": "null"}
]
"type": ["string", "null"]
},
"playerIds": {
"type": "array",
@@ -79,26 +157,26 @@
"type": "string"
}
},
"winnerId": {
"anyOf": [
{"type": "string"},
{"type": "null"}
]
"notes": {
"type": "string"
}
},
"required": [
"id",
"name",
"createdAt",
"groupId",
"playerIds"
"gameId",
"playerIds",
"notes"
]
}
}
},
"required": [
"players",
"games",
"groups",
"teams",
"matches"
]
}

View File

@@ -152,7 +152,6 @@
B68CF4A64F0B5E45B43D6900 /* Pods-RunnerTests.release.xcconfig */,
E754D1191B3E54E52B6DCC49 /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
@@ -478,7 +477,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker;
PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@@ -661,7 +660,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker;
PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -684,7 +683,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker;
PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1,14 +1 @@
{
"images" : [
{
"filename" : "icon_x1024.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"}]}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

View File

@@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.043",
"green" : "0.043",
"red" : "0.043"
"blue" : "0.122",
"green" : "0.408",
"red" : "0.937"
}
},
"idiom" : "universal"

View File

@@ -1,17 +1,8 @@
{
"images" : [
{
"filename" : "icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
"filename" : "icon-transparent.png",
"idiom" : "universal"
}
],
"info" : {

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

View File

@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24412" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24405"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -20,12 +20,19 @@
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Tallee" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="m4u-iU-Cmv">
<rect key="frame" x="153" y="747" width="87" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" name="Futura-Bold" family="Futura" pointSize="28"/>
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="LauncherIcon" translatesAutoresizingMaskIntoConstraints="NO" id="ygV-Op-Bu5">
<rect key="frame" x="46" y="334" width="301" height="184"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
</subviews>
<color key="backgroundColor" name="LauncherBackgroundColor"/>
<color key="backgroundColor" name="LauncherColor"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -36,8 +43,8 @@
<color key="tintColor" red="0.90196078431372551" green="0.94509803921568625" blue="0.89411764705882346" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<resources>
<image name="LauncherIcon" width="1000" height="1000"/>
<namedColor name="LauncherBackgroundColor">
<color red="0.90196078431372551" green="0.94509803921568625" blue="0.89411764705882346" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<namedColor name="LauncherColor">
<color red="0.93699997663497925" green="0.40799999237060547" blue="0.12200000137090683" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
</resources>
</document>

View File

@@ -2,10 +2,12 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Game Tracker</string>
<string>Tallee</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -13,7 +15,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>game_tracker</string>
<string>tallee</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
@@ -22,13 +24,15 @@
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
<string>http</string>
</array>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
@@ -44,9 +48,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View File

@@ -3,5 +3,20 @@ class Constants {
Constants._(); // Private constructor to prevent instantiation
/// Minimum duration of all app skeletons
static Duration minimumSkeletonDuration = const Duration(milliseconds: 250);
static const Duration MINIMUM_SKELETON_DURATION = Duration(milliseconds: 250);
/// Maximum length for player names
static const int MAX_PLAYER_NAME_LENGTH = 32;
/// Maximum length for group names
static const int MAX_GROUP_NAME_LENGTH = 32;
/// Maximum length for match names
static const int MAX_MATCH_NAME_LENGTH = 32;
/// Maximum length for game names
static const int MAX_GAME_NAME_LENGTH = 32;
/// Maximum length for team names
static const int MAX_TEAM_NAME_LENGTH = 32;
}

View File

@@ -5,14 +5,32 @@ class CustomTheme {
CustomTheme._(); // Private constructor to prevent instantiation
// ==================== Colors ====================
static Color primaryColor = const Color(0xFF7505E4);
static Color secondaryColor = const Color(0xFFAFA2FF);
static Color backgroundColor = const Color(0xFF0B0B0B);
static Color boxColor = const Color(0xFF101010);
static Color onBoxColor = const Color(0xFF181818);
static Color boxBorder = const Color(0xFF272727);
static const Color textColor = Colors.white;
/// Primary color of the app theme
static const Color primaryColor = Color(0xFFef681f);
/// Secondary color of the app theme
static const Color secondaryColor = Color(0xFFf2a981);
/// Background color of the app theme
static const backgroundColor = Color(0xFF0B0B0B);
/// Default color for boxes and containers
static const Color boxColor = Color(0xFF101010);
/// Default border color for boxes and containers
static const Color boxBorder = Color(0xFF272727);
/// Color for boxes and containers displayed on boxes
static const Color onBoxColor = Color(0xFF181818);
/// Text color used throughout the app
static const Color textColor = Color(0xFFFFFFFF);
/// Selected color for the [NavbarItem]
static Color navBarItemSelectedColor = primaryColor.withGreen(100);
/// Unselected color for the [NavbarItem]
static Color navBarItemUnselectedColor = Colors.grey.shade400;
// ==================== Border Radius ====================
@@ -45,18 +63,18 @@ class CustomTheme {
);
// ==================== App Bar Theme ====================
static AppBarTheme appBarTheme = AppBarTheme(
static const AppBarTheme appBarTheme = AppBarTheme(
backgroundColor: backgroundColor,
foregroundColor: textColor,
elevation: 0,
scrolledUnderElevation: 0,
centerTitle: true,
titleTextStyle: const TextStyle(
titleTextStyle: TextStyle(
color: textColor,
fontSize: 20,
fontWeight: FontWeight.bold,
overflow: TextOverflow.ellipsis,
),
iconTheme: const IconThemeData(color: textColor),
iconTheme: IconThemeData(color: textColor),
);
}

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
/// Button types used for styling the [CustomWidthButton]
/// - [ButtonType.primary]: Primary button style.
@@ -29,24 +29,38 @@ enum ImportResult {
/// - [ExportResult.unknownException]: An exception occurred during export.
enum ExportResult { success, canceled, unknownException }
/// Different rulesets available for matches
/// - [Ruleset.singleWinner]: The match is won by a single player
/// - [Ruleset.singleLoser]: The match is lost by a single player
/// - [Ruleset.mostPoints]: The player with the most points wins.
/// - [Ruleset.leastPoints]: The player with the fewest points wins.
enum Ruleset { singleWinner, singleLoser, mostPoints, leastPoints }
/// Different rulesets available for games
/// - [Ruleset.highestScore]: The player with the highest score wins.
/// - [Ruleset.lowestScore]: The player with the lowest score wins.
/// - [Ruleset.singleWinner]: The match is won by a single player.
/// - [Ruleset.singleLoser]: The match has a single loser.
/// - [Ruleset.multipleWinners]: Multiple players can be winners.
enum Ruleset { highestScore, lowestScore, singleWinner, singleLoser, multipleWinners }
/// Different colors available for games
/// - [GameColor.red]: Red color
/// - [GameColor.blue]: Blue color
/// - [GameColor.green]: Green color
/// - [GameColor.yellow]: Yellow color
/// - [GameColor.purple]: Purple color
/// - [GameColor.orange]: Orange color
/// - [GameColor.pink]: Pink color
/// - [GameColor.teal]: Teal color
enum GameColor { red, blue, green, yellow, purple, orange, pink, teal }
/// Translates a [Ruleset] enum value to its corresponding localized string.
String translateRulesetToString(Ruleset ruleset, BuildContext context) {
final loc = AppLocalizations.of(context);
switch (ruleset) {
case Ruleset.highestScore:
return loc.highest_score;
case Ruleset.lowestScore:
return loc.lowest_score;
case Ruleset.singleWinner:
return loc.single_winner;
case Ruleset.singleLoser:
return loc.single_loser;
case Ruleset.mostPoints:
return loc.most_points;
case Ruleset.leastPoints:
return loc.least_points;
case Ruleset.multipleWinners:
return loc.multiple_winners;
}
}

View File

@@ -1,7 +1,8 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/db/tables/game_table.dart';
import 'package:game_tracker/data/dto/game.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/db/tables/game_table.dart';
import 'package:tallee/data/dto/game.dart';
import 'package:tallee/core/enums.dart';
part 'game_dao.g.dart';
@@ -18,9 +19,9 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
(row) => Game(
id: row.id,
name: row.name,
ruleset: row.ruleset,
ruleset: Ruleset.values.firstWhere((e) => e.name == row.ruleset),
description: row.description,
color: row.color != null ? int.tryParse(row.color!) : null,
color: GameColor.values.firstWhere((e) => e.name == row.color),
icon: row.icon,
createdAt: row.createdAt,
),
@@ -35,9 +36,9 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
return Game(
id: result.id,
name: result.name,
ruleset: result.ruleset,
ruleset: Ruleset.values.firstWhere((e) => e.name == result.ruleset),
description: result.description,
color: result.color != null ? int.tryParse(result.color!) : null,
color: GameColor.values.firstWhere((e) => e.name == result.color),
icon: result.icon,
createdAt: result.createdAt,
);
@@ -52,10 +53,10 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
GameTableCompanion.insert(
id: game.id,
name: game.name,
ruleset: game.ruleset ?? '',
description: Value(game.description),
color: Value(game.color?.toString()),
icon: Value(game.icon),
ruleset: game.ruleset.name,
description: game.description,
color: game.color.name,
icon: game.icon,
createdAt: game.createdAt,
),
mode: InsertMode.insertOrReplace,
@@ -78,10 +79,10 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
(game) => GameTableCompanion.insert(
id: game.id,
name: game.name,
ruleset: game.ruleset ?? '',
description: Value(game.description),
color: Value(game.color?.toString()),
icon: Value(game.icon),
ruleset: game.ruleset.name,
description: game.description,
color: game.color.name,
icon: game.icon,
createdAt: game.createdAt,
),
)
@@ -110,29 +111,23 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
}
/// Updates the name of the game with the given [gameId] to [newName].
Future<void> updateGameName({
required String gameId,
required String newName,
}) async {
await (update(gameTable)..where((g) => g.id.equals(gameId))).write(
GameTableCompanion(name: Value(newName)),
);
Future<void> updateGameName({required String gameId, required String newName}) async {
await (update(
gameTable,
)..where((g) => g.id.equals(gameId))).write(GameTableCompanion(name: Value(newName)));
}
/// Updates the ruleset of the game with the given [gameId].
Future<void> updateGameRuleset({
required String gameId,
required String newRuleset,
}) async {
Future<void> updateGameRuleset({required String gameId, required Ruleset newRuleset}) async {
await (update(gameTable)..where((g) => g.id.equals(gameId))).write(
GameTableCompanion(ruleset: Value(newRuleset)),
GameTableCompanion(ruleset: Value(newRuleset.name)),
);
}
/// Updates the description of the game with the given [gameId].
Future<void> updateGameDescription({
required String gameId,
required String? newDescription,
required String newDescription,
}) async {
await (update(gameTable)..where((g) => g.id.equals(gameId))).write(
GameTableCompanion(description: Value(newDescription)),
@@ -140,31 +135,24 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
}
/// Updates the color of the game with the given [gameId].
Future<void> updateGameColor({
required String gameId,
required int? newColor,
}) async {
await (update(gameTable)..where((g) => g.id.equals(gameId))).write(
GameTableCompanion(color: Value(newColor?.toString())),
);
Future<void> updateGameColor({required String gameId, required GameColor newColor}) async {
await (update(
gameTable,
)..where((g) => g.id.equals(gameId))).write(GameTableCompanion(color: Value(newColor.name)));
}
/// Updates the icon of the game with the given [gameId].
Future<void> updateGameIcon({
required String gameId,
required String? newIcon,
}) async {
await (update(gameTable)..where((g) => g.id.equals(gameId))).write(
GameTableCompanion(icon: Value(newIcon)),
);
Future<void> updateGameIcon({required String gameId, required String newIcon}) async {
await (update(
gameTable,
)..where((g) => g.id.equals(gameId))).write(GameTableCompanion(icon: Value(newIcon)));
}
/// Retrieves the total count of games in the database.
Future<int> getGameCount() async {
final count =
await (selectOnly(gameTable)..addColumns([gameTable.id.count()]))
.map((row) => row.read(gameTable.id.count()))
.getSingle();
final count = await (selectOnly(
gameTable,
)..addColumns([gameTable.id.count()])).map((row) => row.read(gameTable.id.count())).getSingle();
return count ?? 0;
}
@@ -176,4 +164,3 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
return rowsAffected > 0;
}
}

View File

@@ -1,9 +1,9 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/db/tables/group_table.dart';
import 'package:game_tracker/data/db/tables/player_group_table.dart';
import 'package:game_tracker/data/dto/group.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/db/tables/group_table.dart';
import 'package:tallee/data/db/tables/player_group_table.dart';
import 'package:tallee/data/dto/group.dart';
import 'package:tallee/data/dto/player.dart';
part 'group_dao.g.dart';
@@ -58,7 +58,7 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
GroupTableCompanion.insert(
id: group.id,
name: group.name,
description: Value(group.description),
description: group.description,
createdAt: group.createdAt,
),
mode: InsertMode.insertOrReplace,
@@ -108,7 +108,7 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
(group) => GroupTableCompanion.insert(
id: group.id,
name: group.name,
description: Value(group.description),
description: group.description,
createdAt: group.createdAt,
),
)
@@ -136,7 +136,7 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
(p) => PlayerTableCompanion.insert(
id: p.id,
name: p.name,
description: Value(p.description),
description: p.description,
createdAt: p.createdAt,
),
)
@@ -181,7 +181,7 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
/// Updates the name of the group with the given [id] to [newName].
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
Future<bool> updateGroupname({
Future<bool> updateGroupName({
required String groupId,
required String newName,
}) async {
@@ -192,6 +192,21 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
return rowsAffected > 0;
}
/// Updates the description of the group with the given [groupId] to [newDescription].
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
Future<bool> updateGroupDescription({
required String groupId,
required String newDescription,
}) async {
final rowsAffected =
await (update(groupTable)..where((g) => g.id.equals(groupId))).write(
GroupTableCompanion(description: Value(newDescription)),
);
return rowsAffected > 0;
}
/// Retrieves the number of groups in the database.
Future<int> getGroupCount() async {
final count =
@@ -216,4 +231,44 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
final rowsAffected = await query.go();
return rowsAffected > 0;
}
/// Replaces all players in a group with the provided list of players.
/// Removes all existing players from the group and adds the new players.
/// Also adds any new players to the player table if they don't exist.
Future<void> replaceGroupPlayers({
required String groupId,
required List<Player> newPlayers,
}) async {
await db.transaction(() async {
// Remove all existing players from the group
final deleteQuery = delete(db.playerGroupTable)
..where((p) => p.groupId.equals(groupId));
await deleteQuery.go();
// Add new players to the player table if they don't exist
await Future.wait(
newPlayers.map((player) async {
if (!await db.playerDao.playerExists(playerId: player.id)) {
await db.playerDao.addPlayer(player: player);
}
}),
);
// Add the new players to the group
await db.batch(
(b) => b.insertAll(
db.playerGroupTable,
newPlayers
.map(
(player) => PlayerGroupTableCompanion.insert(
playerId: player.id,
groupId: groupId,
),
)
.toList(),
mode: InsertMode.insertOrReplace,
),
);
});
}
}

View File

@@ -1,13 +1,13 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/db/tables/game_table.dart';
import 'package:game_tracker/data/db/tables/group_table.dart';
import 'package:game_tracker/data/db/tables/match_table.dart';
import 'package:game_tracker/data/db/tables/player_match_table.dart';
import 'package:game_tracker/data/dto/game.dart';
import 'package:game_tracker/data/dto/group.dart';
import 'package:game_tracker/data/dto/match.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/db/tables/game_table.dart';
import 'package:tallee/data/db/tables/group_table.dart';
import 'package:tallee/data/db/tables/match_table.dart';
import 'package:tallee/data/db/tables/player_match_table.dart';
import 'package:tallee/data/dto/game.dart';
import 'package:tallee/data/dto/group.dart';
import 'package:tallee/data/dto/match.dart';
import 'package:tallee/data/dto/player.dart';
part 'match_dao.g.dart';
@@ -29,15 +29,16 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
}
final players = await db.playerMatchDao.getPlayersOfMatch(
matchId: row.id,
);
) ?? [];
return Match(
id: row.id,
name: row.name ?? '',
game: game,
group: group,
players: players,
notes: row.notes,
notes: row.notes ?? '',
createdAt: row.createdAt,
endedAt: row.endedAt,
);
}),
);
@@ -55,10 +56,7 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
group = await db.groupDao.getGroupById(groupId: result.groupId!);
}
List<Player>? players;
if (await db.playerMatchDao.matchHasPlayers(matchId: matchId)) {
players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId);
}
final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? [];
return Match(
id: result.id,
@@ -66,8 +64,9 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
game: game,
group: group,
players: players,
notes: result.notes,
notes: result.notes ?? '',
createdAt: result.createdAt,
endedAt: result.endedAt,
);
}
@@ -75,31 +74,26 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
/// This method assumes that the game and group (if any) are already present
/// in the database.
Future<void> addMatch({required Match match}) async {
if (match.game == null) {
throw ArgumentError('Match must have a game associated with it');
}
await db.transaction(() async {
await into(matchTable).insert(
MatchTableCompanion.insert(
id: match.id,
gameId: match.game!.id,
gameId: match.game.id,
groupId: Value(match.group?.id),
name: Value(match.name),
notes: Value(match.notes),
createdAt: match.createdAt,
endedAt: Value(match.endedAt),
),
mode: InsertMode.insertOrReplace,
);
if (match.players != null) {
for (final p in match.players!) {
for (final p in match.players) {
await db.playerMatchDao.addPlayerToMatch(
matchId: match.id,
playerId: p.id,
);
}
}
});
}
@@ -113,9 +107,7 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
// Add all games first (deduplicated)
final uniqueGames = <String, Game>{};
for (final match in matches) {
if (match.game != null) {
uniqueGames[match.game!.id] = match.game!;
}
uniqueGames[match.game.id] = match.game;
}
if (uniqueGames.isNotEmpty) {
@@ -127,10 +119,10 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
(game) => GameTableCompanion.insert(
id: game.id,
name: game.name,
ruleset: game.ruleset ?? '',
description: Value(game.description),
color: Value(game.color?.toString()),
icon: Value(game.icon),
ruleset: game.ruleset.name,
description: game.description,
color: game.color.name,
icon: game.icon,
createdAt: game.createdAt,
),
)
@@ -150,7 +142,7 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
(match) => GroupTableCompanion.insert(
id: match.group!.id,
name: match.group!.name,
description: Value(match.group!.description),
description: match.group!.description,
createdAt: match.group!.createdAt,
),
)
@@ -164,15 +156,15 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
(b) => b.insertAll(
matchTable,
matches
.where((match) => match.game != null)
.map(
(match) => MatchTableCompanion.insert(
id: match.id,
gameId: match.game!.id,
gameId: match.game.id,
groupId: Value(match.group?.id),
name: Value(match.name),
notes: Value(match.notes),
createdAt: match.createdAt,
endedAt: Value(match.endedAt),
),
)
.toList(),
@@ -183,11 +175,9 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
// Add all players of the matches in batch (unique)
final uniquePlayers = <String, Player>{};
for (final match in matches) {
if (match.players != null) {
for (final p in match.players!) {
for (final p in match.players) {
uniquePlayers[p.id] = p;
}
}
// Also include members of groups
if (match.group != null) {
for (final m in match.group!.members) {
@@ -205,7 +195,7 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
(p) => PlayerTableCompanion.insert(
id: p.id,
name: p.name,
description: Value(p.description),
description: p.description,
createdAt: p.createdAt,
),
)
@@ -218,8 +208,7 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
// Add all player-match associations in batch
await db.batch((b) {
for (final match in matches) {
if (match.players != null) {
for (final p in match.players!) {
for (final p in match.players) {
b.insert(
db.playerMatchTable,
PlayerMatchTableCompanion.insert(
@@ -231,7 +220,6 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
);
}
}
}
});
// Add all player-group associations in batch
@@ -340,39 +328,146 @@ class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
return rowsAffected > 0;
}
/// Updates the createdAt timestamp of the match with the given [matchId].
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
Future<bool> updateMatchCreatedAt({
required String matchId,
required DateTime createdAt,
}) async {
final query = update(matchTable)..where((g) => g.id.equals(matchId));
final rowsAffected = await query.write(
MatchTableCompanion(createdAt: Value(createdAt)),
);
return rowsAffected > 0;
}
/// Updates the endedAt timestamp of the match with the given [matchId].
/// Pass null to remove the ended time (mark match as ongoing).
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
Future<bool> updateMatchEndedAt({
required String matchId,
required DateTime? endedAt,
}) async {
final query = update(matchTable)..where((g) => g.id.equals(matchId));
final rowsAffected = await query.write(
MatchTableCompanion(endedAt: Value(endedAt)),
);
return rowsAffected > 0;
}
/// Replaces all players in a match with the provided list of players.
/// Removes all existing players from the match and adds the new players.
/// Also adds any new players to the player table if they don't exist.
Future<void> replaceMatchPlayers({
required String matchId,
required List<Player> newPlayers,
}) async {
await db.transaction(() async {
// Remove all existing players from the match
final deleteQuery = delete(db.playerMatchTable)
..where((p) => p.matchId.equals(matchId));
await deleteQuery.go();
// Add new players to the player table if they don't exist
await Future.wait(
newPlayers.map((player) async {
if (!await db.playerDao.playerExists(playerId: player.id)) {
await db.playerDao.addPlayer(player: player);
}
}),
);
// Add the new players to the match
await Future.wait(
newPlayers.map((player) => db.playerMatchDao.addPlayerToMatch(
matchId: matchId,
playerId: player.id,
)),
);
});
}
// ============================================================
// TEMPORARY: Winner methods - these are stubs and do not persist data
// TODO: Implement proper winner handling
// Winner methods - handle winner logic via player scores
// ============================================================
/// TEMPORARY: Checks if a match has a winner.
/// Currently returns true if the match has any players.
/// Checks if a match has a winner.
/// Returns true if any player in the match has their score set to 1.
Future<bool> hasWinner({required String matchId}) async {
final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId);
return players?.isNotEmpty ?? false;
final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? [];
for (final player in players) {
final score = await db.playerMatchDao.getPlayerScore(
matchId: matchId,
playerId: player.id,
);
if (score == 1) {
return true;
}
}
return false;
}
/// TEMPORARY: Gets the winner of a match.
/// Currently returns the first player in the match's player list.
/// Gets the winner of a match.
/// Returns the player with score 1, or null if no winner is set.
Future<Player?> getWinner({required String matchId}) async {
final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId);
return (players?.isNotEmpty ?? false) ? players!.first : null;
final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? [];
for (final player in players) {
final score = await db.playerMatchDao.getPlayerScore(
matchId: matchId,
playerId: player.id,
);
if (score == 1) {
return player;
}
}
return null;
}
/// TEMPORARY: Sets the winner of a match.
/// Currently does nothing - winner is not persisted.
/// Sets the winner of a match.
/// Sets all players' scores to 0, then sets the specified player's score to 1.
/// Returns `true` if the operation was successful, otherwise `false`.
Future<bool> setWinner({
required String matchId,
required String winnerId,
}) async {
// TODO: Implement winner persistence
await db.transaction(() async {
final players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId) ?? [];
// Set all players' scores to 0
for (final player in players) {
await db.playerMatchDao.updatePlayerScore(
matchId: matchId,
playerId: player.id,
newScore: 0,
);
}
// Set the winner's score to 1
await db.playerMatchDao.updatePlayerScore(
matchId: matchId,
playerId: winnerId,
newScore: 1,
);
});
return true;
}
/// TEMPORARY: Removes the winner of a match.
/// Currently does nothing - winner is not persisted.
/// Removes the winner of a match.
/// Sets the current winner's score to 0 (no winner).
/// Returns `true` if a winner was removed, otherwise `false`.
Future<bool> removeWinner({required String matchId}) async {
// TODO: Implement winner persistence
return true;
final winner = await getWinner(matchId: matchId);
if (winner == null) {
return false;
}
final success = await db.playerMatchDao.updatePlayerScore(
matchId: matchId,
playerId: winner.id,
newScore: 0,
);
return success;
}
}

View File

@@ -1,7 +1,7 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/db/tables/player_table.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/db/tables/player_table.dart';
import 'package:tallee/data/dto/player.dart';
part 'player_dao.g.dart';
@@ -46,7 +46,7 @@ class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
PlayerTableCompanion.insert(
id: player.id,
name: player.name,
description: Value(player.description),
description: player.description,
createdAt: player.createdAt,
),
mode: InsertMode.insertOrReplace,
@@ -70,7 +70,7 @@ class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
(player) => PlayerTableCompanion.insert(
id: player.id,
name: player.name,
description: Value(player.description),
description: player.description,
createdAt: player.createdAt,
),
)
@@ -99,7 +99,7 @@ class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
}
/// Updates the name of the player with the given [playerId] to [newName].
Future<void> updatePlayername({
Future<void> updatePlayerName({
required String playerId,
required String newName,
}) async {

View File

@@ -1,8 +1,8 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/db/tables/player_group_table.dart';
import 'package:game_tracker/data/db/tables/player_table.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/db/tables/player_group_table.dart';
import 'package:tallee/data/db/tables/player_table.dart';
import 'package:tallee/data/dto/player.dart';
part 'player_group_dao.g.dart';
@@ -27,7 +27,7 @@ class PlayerGroupDao extends DatabaseAccessor<AppDatabase>
}
if (!await db.playerDao.playerExists(playerId: player.id)) {
db.playerDao.addPlayer(player: player);
await db.playerDao.addPlayer(player: player);
}
await into(playerGroupTable).insert(

View File

@@ -1,8 +1,8 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/db/tables/player_match_table.dart';
import 'package:game_tracker/data/db/tables/team_table.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/db/tables/player_match_table.dart';
import 'package:tallee/data/db/tables/team_table.dart';
import 'package:tallee/data/dto/player.dart';
part 'player_match_dao.g.dart';
@@ -148,7 +148,7 @@ class PlayerMatchDao extends DatabaseAccessor<AppDatabase>
final playersToAdd = newPlayerIdsSet.difference(currentPlayerIds);
final playersToRemove = currentPlayerIds.difference(newPlayerIdsSet);
db.transaction(() async {
await db.transaction(() async {
// Remove old players
if (playersToRemove.isNotEmpty) {
await (delete(playerMatchTable)..where(

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/db/tables/score_table.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/db/tables/score_table.dart';
part 'score_dao.g.dart';

View File

@@ -1,8 +1,8 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/db/tables/team_table.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:game_tracker/data/dto/team.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/db/tables/team_table.dart';
import 'package:tallee/data/dto/player.dart';
import 'package:tallee/data/dto/team.dart';
part 'team_dao.g.dart';
@@ -20,6 +20,7 @@ class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
final members = await _getTeamMembers(teamId: row.id);
return Team(
id: row.id,
name: row.name,
createdAt: row.createdAt,
members: members,
);
@@ -34,6 +35,7 @@ class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
final members = await _getTeamMembers(teamId: teamId);
return Team(
id: result.id,
name: result.name,
createdAt: result.createdAt,
members: members,
);
@@ -66,7 +68,7 @@ class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
await into(teamTable).insert(
TeamTableCompanion.insert(
id: team.id,
name: '', // Team name from table (not in DTO currently)
name: team.name,
createdAt: team.createdAt,
),
mode: InsertMode.insertOrReplace,
@@ -87,7 +89,7 @@ class TeamDao extends DatabaseAccessor<AppDatabase> with _$TeamDaoMixin {
.map(
(team) => TeamTableCompanion.insert(
id: team.id,
name: '',
name: team.name,
createdAt: team.createdAt,
),
)

View File

@@ -1,22 +1,22 @@
import 'package:drift/drift.dart';
import 'package:drift_flutter/drift_flutter.dart';
import 'package:game_tracker/data/dao/game_dao.dart';
import 'package:game_tracker/data/dao/group_dao.dart';
import 'package:game_tracker/data/dao/match_dao.dart';
import 'package:game_tracker/data/dao/player_dao.dart';
import 'package:game_tracker/data/dao/player_group_dao.dart';
import 'package:game_tracker/data/dao/player_match_dao.dart';
import 'package:game_tracker/data/dao/score_dao.dart';
import 'package:game_tracker/data/dao/team_dao.dart';
import 'package:game_tracker/data/db/tables/game_table.dart';
import 'package:game_tracker/data/db/tables/group_table.dart';
import 'package:game_tracker/data/db/tables/match_table.dart';
import 'package:game_tracker/data/db/tables/player_group_table.dart';
import 'package:game_tracker/data/db/tables/player_match_table.dart';
import 'package:game_tracker/data/db/tables/player_table.dart';
import 'package:game_tracker/data/db/tables/score_table.dart';
import 'package:game_tracker/data/db/tables/team_table.dart';
import 'package:path_provider/path_provider.dart';
import 'package:tallee/data/dao/game_dao.dart';
import 'package:tallee/data/dao/group_dao.dart';
import 'package:tallee/data/dao/match_dao.dart';
import 'package:tallee/data/dao/player_dao.dart';
import 'package:tallee/data/dao/player_group_dao.dart';
import 'package:tallee/data/dao/player_match_dao.dart';
import 'package:tallee/data/dao/score_dao.dart';
import 'package:tallee/data/dao/team_dao.dart';
import 'package:tallee/data/db/tables/game_table.dart';
import 'package:tallee/data/db/tables/group_table.dart';
import 'package:tallee/data/db/tables/match_table.dart';
import 'package:tallee/data/db/tables/player_group_table.dart';
import 'package:tallee/data/db/tables/player_match_table.dart';
import 'package:tallee/data/db/tables/player_table.dart';
import 'package:tallee/data/db/tables/score_table.dart';
import 'package:tallee/data/db/tables/team_table.dart';
part 'database.g.dart';
@@ -24,29 +24,29 @@ part 'database.g.dart';
tables: [
PlayerTable,
GroupTable,
GameTable,
TeamTable,
MatchTable,
PlayerGroupTable,
PlayerMatchTable,
GameTable,
TeamTable,
ScoreTable,
],
daos: [
PlayerDao,
GroupDao,
GameDao,
TeamDao,
MatchDao,
PlayerGroupDao,
PlayerMatchDao,
GameDao,
ScoreDao,
TeamDao
],
)
class AppDatabase extends _$AppDatabase {
AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());
@override
int get schemaVersion => 2;
int get schemaVersion => 1;
@override
MigrationStrategy get migration {
@@ -60,9 +60,7 @@ class AppDatabase extends _$AppDatabase {
static QueryExecutor _openConnection() {
return driftDatabase(
name: 'gametracker_db',
native: const DriftNativeOptions(
databaseDirectory: getApplicationSupportDirectory,
),
native: const DriftNativeOptions(databaseDirectory: getApplicationSupportDirectory),
);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,9 +4,9 @@ class GameTable extends Table {
TextColumn get id => text()();
TextColumn get name => text()();
TextColumn get ruleset => text()();
TextColumn get description => text().nullable()();
TextColumn get color => text().nullable()();
TextColumn get icon => text().nullable()();
TextColumn get description => text()();
TextColumn get color => text()();
TextColumn get icon => text()();
DateTimeColumn get createdAt => dateTime()();
@override

View File

@@ -3,7 +3,7 @@ import 'package:drift/drift.dart';
class GroupTable extends Table {
TextColumn get id => text()();
TextColumn get name => text()();
TextColumn get description => text().nullable()();
TextColumn get description => text()();
DateTimeColumn get createdAt => dateTime()();
@override

View File

@@ -1,16 +1,18 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/tables/game_table.dart';
import 'package:game_tracker/data/db/tables/group_table.dart';
import 'package:tallee/data/db/tables/game_table.dart';
import 'package:tallee/data/db/tables/group_table.dart';
class MatchTable extends Table {
TextColumn get id => text()();
TextColumn get gameId =>
text().references(GameTable, #id, onDelete: KeyAction.cascade)();
// Nullable if not part of a group
TextColumn get groupId =>
text().references(GroupTable, #id, onDelete: KeyAction.cascade).nullable()(); // Nullable if not part of a group
text().references(GroupTable, #id, onDelete: KeyAction.cascade).nullable()();
TextColumn get name => text().nullable()();
TextColumn get notes => text().nullable()();
DateTimeColumn get createdAt => dateTime()();
DateTimeColumn get endedAt => dateTime().nullable()();
@override
Set<Column<Object>> get primaryKey => {id};

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/tables/group_table.dart';
import 'package:game_tracker/data/db/tables/player_table.dart';
import 'package:tallee/data/db/tables/group_table.dart';
import 'package:tallee/data/db/tables/player_table.dart';
class PlayerGroupTable extends Table {
TextColumn get playerId =>

View File

@@ -1,7 +1,7 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/tables/match_table.dart';
import 'package:game_tracker/data/db/tables/player_table.dart';
import 'package:game_tracker/data/db/tables/team_table.dart';
import 'package:tallee/data/db/tables/match_table.dart';
import 'package:tallee/data/db/tables/player_table.dart';
import 'package:tallee/data/db/tables/team_table.dart';
class PlayerMatchTable extends Table {
TextColumn get playerId =>

View File

@@ -3,7 +3,7 @@ import 'package:drift/drift.dart';
class PlayerTable extends Table {
TextColumn get id => text()();
TextColumn get name => text()();
TextColumn get description => text().nullable()();
TextColumn get description => text()();
DateTimeColumn get createdAt => dateTime()();
@override

View File

@@ -1,6 +1,6 @@
import 'package:drift/drift.dart';
import 'package:game_tracker/data/db/tables/match_table.dart';
import 'package:game_tracker/data/db/tables/player_table.dart';
import 'package:tallee/data/db/tables/match_table.dart';
import 'package:tallee/data/db/tables/player_table.dart';
class ScoreTable extends Table {
TextColumn get playerId =>

View File

@@ -1,23 +1,24 @@
import 'package:clock/clock.dart';
import 'package:uuid/uuid.dart';
import 'package:tallee/core/enums.dart';
class Game {
final String id;
final DateTime createdAt;
final String name;
final String? ruleset;
final String? description;
final int? color;
final String? icon;
final Ruleset ruleset;
final String description;
final GameColor color;
final String icon;
Game({
String? id,
DateTime? createdAt,
required this.name,
this.ruleset,
this.description,
this.color,
this.icon,
required this.ruleset,
required this.description,
required this.color,
required this.icon,
}) : id = id ?? const Uuid().v4(),
createdAt = createdAt ?? clock.now();
@@ -31,9 +32,9 @@ class Game {
: id = json['id'],
createdAt = DateTime.parse(json['createdAt']),
name = json['name'],
ruleset = json['ruleset'],
ruleset = Ruleset.values.firstWhere((e) => e.name == json['ruleset']),
description = json['description'],
color = json['color'],
color = GameColor.values.firstWhere((e) => e.name == json['color']),
icon = json['icon'];
/// Converts the Game instance to a JSON object.
@@ -41,9 +42,9 @@ class Game {
'id': id,
'createdAt': createdAt.toIso8601String(),
'name': name,
'ruleset': ruleset,
'ruleset': ruleset.name,
'description': description,
'color': color,
'color': color.name,
'icon': icon,
};
}

View File

@@ -1,11 +1,11 @@
import 'package:clock/clock.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:tallee/data/dto/player.dart';
import 'package:uuid/uuid.dart';
class Group {
final String id;
final String name;
final String? description;
final String description;
final DateTime createdAt;
final List<Player> members;
@@ -13,7 +13,7 @@ class Group {
String? id,
DateTime? createdAt,
required this.name,
this.description,
required this.description,
required this.members,
}) : id = id ?? const Uuid().v4(),
createdAt = createdAt ?? clock.now();
@@ -23,22 +23,21 @@ class Group {
return 'Group{id: $id, name: $name, description: $description, members: $members}';
}
/// Creates a Group instance from a JSON object.
/// Creates a Group instance from a JSON object (memberIds format).
/// Player objects are reconstructed from memberIds by the DataTransferService.
Group.fromJson(Map<String, dynamic> json)
: id = json['id'],
createdAt = DateTime.parse(json['createdAt']),
name = json['name'],
description = json['description'],
members = (json['members'] as List)
.map((memberJson) => Player.fromJson(memberJson))
.toList();
members = []; // Populated during import via DataTransferService
/// Converts the Group instance to a JSON object.
/// Converts the Group instance to a JSON object using normalized format (memberIds only).
Map<String, dynamic> toJson() => {
'id': id,
'createdAt': createdAt.toIso8601String(),
'name': name,
'description': description,
'members': members.map((member) => member.toJson()).toList(),
'memberIds': members.map((member) => member.id).toList(),
};
}

View File

@@ -1,58 +1,60 @@
import 'package:clock/clock.dart';
import 'package:game_tracker/data/dto/game.dart';
import 'package:game_tracker/data/dto/group.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:tallee/core/enums.dart';
import 'package:tallee/data/dto/game.dart';
import 'package:tallee/data/dto/group.dart';
import 'package:tallee/data/dto/player.dart';
import 'package:uuid/uuid.dart';
class Match {
final String id;
final DateTime createdAt;
final DateTime? endedAt;
final String name;
final Game? game;
final Game game;
final Group? group;
final List<Player>? players;
final String? notes;
final List<Player> players;
final String notes;
Player? winner;
Match({
String? id,
DateTime? createdAt,
this.endedAt,
required this.name,
this.game,
required this.game,
this.group,
this.players,
this.notes,
this.players = const [],
required this.notes,
this.winner,
}) : id = id ?? const Uuid().v4(),
createdAt = createdAt ?? clock.now();
@override
String toString() {
return 'Match{id: $id, name: $name, game: $game, group: $group, players: $players, notes: $notes, winner: $winner}';
return 'Match{id: $id, name: $name, game: $game, group: $group, players: $players, notes: $notes, endedAt: $endedAt}';
}
/// Creates a Match instance from a JSON object.
/// Creates a Match instance from a JSON object (ID references format).
/// Related objects are reconstructed from IDs by the DataTransferService.
Match.fromJson(Map<String, dynamic> json)
: id = json['id'],
createdAt = DateTime.parse(json['createdAt']),
endedAt = json['endedAt'] != null ? DateTime.parse(json['endedAt']) : null,
name = json['name'],
game = json['game'] != null ? Game.fromJson(json['game']) : null,
group = json['group'] != null ? Group.fromJson(json['group']) : null,
players = json['players'] != null
? (json['players'] as List)
.map((playerJson) => Player.fromJson(playerJson))
.toList()
: null,
notes = json['notes'];
game = Game(name: '', ruleset: Ruleset.singleWinner, description: '', color: GameColor.blue, icon: ''), // Populated during import via DataTransferService
group = null, // Populated during import via DataTransferService
players = [], // Populated during import via DataTransferService
notes = json['notes'] ?? '';
/// Converts the Match instance to a JSON object.
/// Converts the Match instance to a JSON object using normalized format (ID references only).
Map<String, dynamic> toJson() => {
'id': id,
'createdAt': createdAt.toIso8601String(),
'endedAt': endedAt?.toIso8601String(),
'name': name,
'game': game?.toJson(),
'group': group?.toJson(),
'players': players?.map((player) => player.toJson()).toList(),
'gameId': game.id,
'groupId': group?.id,
'playerIds': players.map((player) => player.id).toList(),
'notes': notes,
};
}

View File

@@ -1,16 +0,0 @@
import 'package:game_tracker/data/dto/team.dart';
class Pair extends Team {
Pair({
super.id,
super.createdAt,
required super.members,
});
@override
String toString() {
return 'Pair{id: $id, members: $members}';
}
}

View File

@@ -5,13 +5,13 @@ class Player {
final String id;
final DateTime createdAt;
final String name;
final String? description;
final String description;
Player({
String? id,
DateTime? createdAt,
required this.name,
this.description,
required this.description,
}) : id = id ?? const Uuid().v4(),
createdAt = createdAt ?? clock.now();

View File

@@ -1,14 +1,16 @@
import 'package:clock/clock.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:tallee/data/dto/player.dart';
import 'package:uuid/uuid.dart';
class Team {
final String id;
final String name;
final DateTime createdAt;
final List<Player> members;
Team({
String? id,
required this.name,
DateTime? createdAt,
required this.members,
}) : id = id ?? const Uuid().v4(),
@@ -16,22 +18,23 @@ class Team {
@override
String toString() {
return 'Team{id: $id, members: $members}';
return 'Team{id: $id, name: $name, members: $members}';
}
/// Creates a Team instance from a JSON object.
/// Creates a Team instance from a JSON object (memberIds format).
/// Player objects are reconstructed from memberIds by the DataTransferService.
Team.fromJson(Map<String, dynamic> json)
: id = json['id'],
name = json['name'],
createdAt = DateTime.parse(json['createdAt']),
members = (json['members'] as List)
.map((memberJson) => Player.fromJson(memberJson))
.toList();
members = []; // Populated during import via DataTransferService
/// Converts the Team instance to a JSON object.
/// Converts the Team instance to a JSON object using normalized format (memberIds only).
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'createdAt': createdAt.toIso8601String(),
'members': members.map((member) => member.toJson()).toList(),
'memberIds': members.map((member) => member.id).toList(),
};
}

View File

@@ -3,7 +3,8 @@
"all_players": "Alle Spieler:innen",
"all_players_selected": "Alle Spieler:innen ausgewählt",
"amount_of_matches": "Anzahl der Spiele",
"app_name": "Game Tracker",
"app_name": "Tallee",
"best_player": "Beste:r Spieler:in",
"cancel": "Abbrechen",
"choose_game": "Spielvorlage wählen",
"choose_group": "Gruppe wählen",
@@ -13,6 +14,7 @@
"create_match": "Spiel erstellen",
"create_new_group": "Neue Gruppe erstellen",
"create_new_match": "Neues Spiel erstellen",
"created_on": "Erstellt am",
"data": "Daten",
"data_successfully_deleted": "Daten erfolgreich gelöscht",
"data_successfully_exported": "Daten erfolgreich exportiert",
@@ -20,6 +22,8 @@
"days_ago": "vor {count} Tagen",
"delete": "Löschen",
"delete_all_data": "Alle Daten löschen",
"delete_group": "Gruppe löschen",
"edit_group": "Gruppe bearbeiten",
"error_creating_group": "Fehler beim Erstellen der Gruppe, bitte erneut versuchen",
"error_reading_file": "Fehler beim Lesen der Datei",
"export_canceled": "Export abgebrochen",
@@ -29,6 +33,7 @@
"game_name": "Spielvorlagenname",
"group": "Gruppe",
"group_name": "Gruppenname",
"group_profile": "Gruppenprofil",
"groups": "Gruppen",
"home": "Startseite",
"import_canceled": "Import abgebrochen",
@@ -42,6 +47,7 @@
"match_in_progress": "Spiel läuft...",
"match_name": "Spieltitel",
"matches": "Spiele",
"members": "Mitglieder",
"most_points": "Höchste Punkte",
"no_data_available": "Keine Daten verfügbar",
"no_groups_created_yet": "Noch keine Gruppen erstellt",
@@ -57,6 +63,7 @@
"none": "Kein",
"none_group": "Keine",
"not_available": "Nicht verfügbar",
"played_matches": "Gespielte Spiele",
"player_name": "Spieler:innenname",
"players": "Spieler:innen",
"players_count": "{count} Spieler",
@@ -75,6 +82,9 @@
"settings": "Einstellungen",
"single_loser": "Ein:e Verlierer:in",
"single_winner": "Ein:e Gewinner:in",
"highest_score": "Höchste Punkte",
"lowest_score": "Niedrigste Punkte",
"multiple_winners": "Mehrere Gewinner:innen",
"statistics": "Statistiken",
"stats": "Statistiken",
"successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt",

View File

@@ -12,6 +12,9 @@
"@app_name": {
"description": "The name of the App"
},
"@best_player": {
"description": "Label for best player statistic"
},
"@cancel": {
"description": "Cancel button text"
},
@@ -39,6 +42,9 @@
"@create_new_match": {
"description": "Button text to create a new match"
},
"@created_on": {
"description": "Label for creation date"
},
"@data": {
"description": "Data label"
},
@@ -65,6 +71,12 @@
"@delete_all_data": {
"description": "Confirmation dialog for deleting all data"
},
"@delete_group": {
"description": "Button text to delete a group"
},
"@edit_group": {
"description": "Button text to edit a group"
},
"@error_creating_group": {
"description": "Error message when group creation fails"
},
@@ -92,6 +104,9 @@
"@group_name": {
"description": "Placeholder for group name input"
},
"@group_profile": {
"description": "Title for group profile view"
},
"@groups": {
"description": "Label for groups"
},
@@ -131,6 +146,9 @@
"@matches": {
"description": "Label for matches"
},
"@members": {
"description": "Label for group members"
},
"@most_points": {
"description": "Title for most points ruleset"
},
@@ -176,6 +194,9 @@
"@not_available": {
"description": "Abbreviation for not available"
},
"@played_matches": {
"description": "Label for played matches statistic"
},
"@player_name": {
"description": "Placeholder for player name input"
},
@@ -280,7 +301,8 @@
"all_players": "All players",
"all_players_selected": "All players selected",
"amount_of_matches": "Amount of Matches",
"app_name": "Game Tracker",
"app_name": "Tallee",
"best_player": "Best Player",
"cancel": "Cancel",
"choose_game": "Choose Game",
"choose_group": "Choose Group",
@@ -289,6 +311,7 @@
"create_group": "Create Group",
"create_match": "Create match",
"create_new_group": "Create new group",
"created_on": "Created on",
"create_new_match": "Create new match",
"data": "Data",
"data_successfully_deleted": "Data successfully deleted",
@@ -297,6 +320,8 @@
"days_ago": "{count} days ago",
"delete": "Delete",
"delete_all_data": "Delete all data",
"delete_group": "Delete Group",
"edit_group": "Edit Group",
"error_creating_group": "Error while creating group, please try again",
"error_reading_file": "Error reading file",
"export_canceled": "Export canceled",
@@ -306,6 +331,7 @@
"game_name": "Game Name",
"group": "Group",
"group_name": "Group name",
"group_profile": "Group Profile",
"groups": "Groups",
"home": "Home",
"import_canceled": "Import canceled",
@@ -319,6 +345,7 @@
"match_in_progress": "Match in progress...",
"match_name": "Match name",
"matches": "Matches",
"members": "Members",
"most_points": "Most Points",
"no_data_available": "No data available",
"no_groups_created_yet": "No groups created yet",
@@ -334,6 +361,7 @@
"none": "None",
"none_group": "None",
"not_available": "Not available",
"played_matches": "Played Matches",
"player_name": "Player name",
"players": "Players",
"players_count": "{count} Players",
@@ -352,6 +380,9 @@
"settings": "Settings",
"single_loser": "Single Loser",
"single_winner": "Single Winner",
"highest_score": "Highest Score",
"lowest_score": "Lowest Score",
"multiple_winners": "Multiple Winners",
"statistics": "Statistics",
"stats": "Stats",
"successfully_added_player": "Successfully added player {playerName}",

View File

@@ -119,9 +119,15 @@ abstract class AppLocalizations {
/// The name of the App
///
/// In en, this message translates to:
/// **'Game Tracker'**
/// **'Tallee'**
String get app_name;
/// Label for best player statistic
///
/// In en, this message translates to:
/// **'Best Player'**
String get best_player;
/// Cancel button text
///
/// In en, this message translates to:
@@ -170,6 +176,12 @@ abstract class AppLocalizations {
/// **'Create new group'**
String get create_new_group;
/// Label for creation date
///
/// In en, this message translates to:
/// **'Created on'**
String get created_on;
/// Button text to create a new match
///
/// In en, this message translates to:
@@ -218,6 +230,18 @@ abstract class AppLocalizations {
/// **'Delete all data'**
String get delete_all_data;
/// Button text to delete a group
///
/// In en, this message translates to:
/// **'Delete Group'**
String get delete_group;
/// Button text to edit a group
///
/// In en, this message translates to:
/// **'Edit Group'**
String get edit_group;
/// Error message when group creation fails
///
/// In en, this message translates to:
@@ -272,6 +296,12 @@ abstract class AppLocalizations {
/// **'Group name'**
String get group_name;
/// Title for group profile view
///
/// In en, this message translates to:
/// **'Group Profile'**
String get group_profile;
/// Label for groups
///
/// In en, this message translates to:
@@ -350,6 +380,12 @@ abstract class AppLocalizations {
/// **'Matches'**
String get matches;
/// Label for group members
///
/// In en, this message translates to:
/// **'Members'**
String get members;
/// Title for most points ruleset
///
/// In en, this message translates to:
@@ -440,6 +476,12 @@ abstract class AppLocalizations {
/// **'Not available'**
String get not_available;
/// Label for played matches statistic
///
/// In en, this message translates to:
/// **'Played Matches'**
String get played_matches;
/// Placeholder for player name input
///
/// In en, this message translates to:
@@ -548,6 +590,24 @@ abstract class AppLocalizations {
/// **'Single Winner'**
String get single_winner;
/// No description provided for @highest_score.
///
/// In en, this message translates to:
/// **'Highest Score'**
String get highest_score;
/// No description provided for @lowest_score.
///
/// In en, this message translates to:
/// **'Lowest Score'**
String get lowest_score;
/// No description provided for @multiple_winners.
///
/// In en, this message translates to:
/// **'Multiple Winners'**
String get multiple_winners;
/// Statistics tab label
///
/// In en, this message translates to:

View File

@@ -18,7 +18,10 @@ class AppLocalizationsDe extends AppLocalizations {
String get amount_of_matches => 'Anzahl der Spiele';
@override
String get app_name => 'Game Tracker';
String get app_name => 'Tallee';
@override
String get best_player => 'Beste:r Spieler:in';
@override
String get cancel => 'Abbrechen';
@@ -46,6 +49,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get create_new_group => 'Neue Gruppe erstellen';
@override
String get created_on => 'Erstellt am';
@override
String get create_new_match => 'Neues Spiel erstellen';
@@ -72,6 +78,12 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get delete_all_data => 'Alle Daten löschen';
@override
String get delete_group => 'Gruppe löschen';
@override
String get edit_group => 'Gruppe bearbeiten';
@override
String get error_creating_group =>
'Fehler beim Erstellen der Gruppe, bitte erneut versuchen';
@@ -100,6 +112,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get group_name => 'Gruppenname';
@override
String get group_profile => 'Gruppenprofil';
@override
String get groups => 'Gruppen';
@@ -139,6 +154,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get matches => 'Spiele';
@override
String get members => 'Mitglieder';
@override
String get most_points => 'Höchste Punkte';
@@ -185,6 +203,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get not_available => 'Nicht verfügbar';
@override
String get played_matches => 'Gespielte Spiele';
@override
String get player_name => 'Spieler:innenname';
@@ -245,6 +266,15 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get single_winner => 'Ein:e Gewinner:in';
@override
String get highest_score => 'Höchste Punkte';
@override
String get lowest_score => 'Niedrigste Punkte';
@override
String get multiple_winners => 'Mehrere Gewinner:innen';
@override
String get statistics => 'Statistiken';

View File

@@ -18,7 +18,10 @@ class AppLocalizationsEn extends AppLocalizations {
String get amount_of_matches => 'Amount of Matches';
@override
String get app_name => 'Game Tracker';
String get app_name => 'Tallee';
@override
String get best_player => 'Best Player';
@override
String get cancel => 'Cancel';
@@ -46,6 +49,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get create_new_group => 'Create new group';
@override
String get created_on => 'Created on';
@override
String get create_new_match => 'Create new match';
@@ -72,6 +78,12 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get delete_all_data => 'Delete all data';
@override
String get delete_group => 'Delete Group';
@override
String get edit_group => 'Edit Group';
@override
String get error_creating_group =>
'Error while creating group, please try again';
@@ -100,6 +112,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get group_name => 'Group name';
@override
String get group_profile => 'Group Profile';
@override
String get groups => 'Groups';
@@ -139,6 +154,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get matches => 'Matches';
@override
String get members => 'Members';
@override
String get most_points => 'Most Points';
@@ -185,6 +203,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get not_available => 'Not available';
@override
String get played_matches => 'Played Matches';
@override
String get player_name => 'Player name';
@@ -245,6 +266,15 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get single_winner => 'Single Winner';
@override
String get highest_score => 'Highest Score';
@override
String get lowest_score => 'Lowest Score';
@override
String get multiple_winners => 'Multiple Winners';
@override
String get statistics => 'Statistics';

View File

@@ -1,9 +1,9 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/views/main_menu/custom_navigation_bar.dart';
import 'package:provider/provider.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/views/main_menu/custom_navigation_bar.dart';
void main() {
runApp(
@@ -29,9 +29,7 @@ class GameTracker extends StatelessWidget {
return supportedLocale;
}
}
return supportedLocales.firstWhere(
(locale) => locale.languageCode == 'en',
);
return supportedLocales.firstWhere((locale) => locale.languageCode == 'en');
},
debugShowCheckedModeBanner: false,
onGenerateTitle: (context) => AppLocalizations.of(context).app_name,

View File

@@ -1,15 +1,15 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:game_tracker/core/adaptive_page_route.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/views/main_menu/group_view/groups_view.dart';
import 'package:game_tracker/presentation/views/main_menu/home_view.dart';
import 'package:game_tracker/presentation/views/main_menu/match_view/match_view.dart';
import 'package:game_tracker/presentation/views/main_menu/settings_view/settings_view.dart';
import 'package:game_tracker/presentation/views/main_menu/statistics_view.dart';
import 'package:game_tracker/presentation/widgets/navbar_item.dart';
import 'package:tallee/core/adaptive_page_route.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/views/main_menu/group_view/groups_view.dart';
import 'package:tallee/presentation/views/main_menu/home_view.dart';
import 'package:tallee/presentation/views/main_menu/match_view/match_view.dart';
import 'package:tallee/presentation/views/main_menu/settings_view/settings_view.dart';
import 'package:tallee/presentation/views/main_menu/statistics_view.dart';
import 'package:tallee/presentation/widgets/navbar_item.dart';
class CustomNavigationBar extends StatefulWidget {
/// A custom navigation bar widget that provides tabbed navigation

View File

@@ -1,14 +1,15 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/core/enums.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/dto/group.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart';
import 'package:game_tracker/presentation/widgets/player_selection.dart';
import 'package:game_tracker/presentation/widgets/text_input/text_input_field.dart';
import 'package:provider/provider.dart';
import 'package:tallee/core/constants.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/core/enums.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/dto/group.dart';
import 'package:tallee/data/dto/player.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
import 'package:tallee/presentation/widgets/player_selection.dart';
import 'package:tallee/presentation/widgets/text_input/text_input_field.dart';
class CreateGroupView extends StatefulWidget {
/// A view that allows the user to create a new group
@@ -47,6 +48,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
final loc = AppLocalizations.of(context);
return ScaffoldMessenger(
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: CustomTheme.backgroundColor,
appBar: AppBar(title: Text(loc.create_new_group)),
body: SafeArea(
@@ -58,6 +60,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
child: TextInputField(
controller: _groupNameController,
hintText: loc.group_name,
maxLength: Constants.MAX_GROUP_NAME_LENGTH,
),
),
Expanded(
@@ -81,6 +84,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
bool success = await db.groupDao.addGroup(
group: Group(
name: _groupNameController.text.trim(),
description: '',
members: selectedPlayers,
),
);

View File

@@ -0,0 +1,273 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/dto/group.dart';
import 'package:tallee/data/dto/match.dart';
import 'package:tallee/data/dto/player.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/widgets/app_skeleton.dart';
import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart';
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
import 'package:tallee/presentation/widgets/custom_alert_dialog.dart';
import 'package:tallee/presentation/widgets/tiles/info_tile.dart';
import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart';
class GroupProfileView extends StatefulWidget {
/// A view that displays the profile of a group
/// - [group]: The group to display
const GroupProfileView({
super.key,
required this.group,
required this.callback,
});
/// The group to display
final Group group;
final VoidCallback callback;
@override
State<GroupProfileView> createState() => _GroupProfileViewState();
}
class _GroupProfileViewState extends State<GroupProfileView> {
late final AppDatabase db;
bool isLoading = true;
/// Total matches played in this group
int totalMatches = 0;
String bestPlayer = '';
@override
void initState() {
super.initState();
db = Provider.of<AppDatabase>(context, listen: false);
_loadStatistics();
}
@override
Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return Scaffold(
backgroundColor: CustomTheme.backgroundColor,
appBar: AppBar(
title: Text(loc.group_profile),
actions: [
IconButton(
icon: const Icon(Icons.delete),
onPressed: () async {
showDialog<bool>(
context: context,
builder: (context) => CustomAlertDialog(
title: '${loc.delete_group}?',
content: loc.this_cannot_be_undone,
actions: [
AnimatedDialogButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text(
loc.cancel,
style: const TextStyle(color: CustomTheme.textColor),
),
),
AnimatedDialogButton(
onPressed: () => Navigator.of(context).pop(true),
child: Text(
loc.delete,
style: const TextStyle(
color: CustomTheme.secondaryColor,
),
),
),
],
),
).then((confirmed) async {
if (confirmed! && context.mounted) {
await db.groupDao.deleteGroup(groupId: widget.group.id);
if (!context.mounted) return;
Navigator.pop(context);
widget.callback.call();
}
});
},
),
],
),
body: SafeArea(
child: Stack(
alignment: Alignment.center,
children: [
ListView(
padding: const EdgeInsets.only(
left: 12,
right: 12,
top: 20,
bottom: 100,
),
children: [
const Center(
child: ColoredIconContainer(
icon: Icons.group,
containerSize: 55,
iconSize: 38,
),
),
const SizedBox(height: 10),
Text(
widget.group.name,
style: const TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
color: CustomTheme.textColor,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 5),
Text(
'${loc.created_on} ${DateFormat.yMMMd(Localizations.localeOf(context).toString()).format(widget.group.createdAt)}',
style: const TextStyle(
fontSize: 12,
color: CustomTheme.textColor,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
InfoTile(
title: loc.members,
icon: Icons.people,
horizontalAlignment: CrossAxisAlignment.start,
content: Wrap(
alignment: WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.start,
spacing: 12,
runSpacing: 8,
children: widget.group.members.map((member) {
return TextIconTile(
text: member.name,
iconEnabled: false,
);
}).toList(),
),
),
const SizedBox(height: 15),
InfoTile(
title: loc.statistics,
icon: Icons.bar_chart,
content: AppSkeleton(
enabled: isLoading,
child: Column(
children: [
_buildStatRow(
loc.members,
widget.group.members.length.toString(),
),
_buildStatRow(
loc.played_matches,
totalMatches.toString(),
),
_buildStatRow(loc.best_player, bestPlayer),
],
),
),
),
],
),
Positioned(
bottom: MediaQuery.paddingOf(context).bottom,
child: MainMenuButton(
text: loc.edit_group,
icon: Icons.edit,
onPressed: () {
// TODO: Uncomment when GroupDetailView is implemented
/*
await Navigator.push(
context,
adaptivePageRoute(
builder: (context) {
return const GroupDetailView();
},
),
);*/
print('Edit Group pressed');
},
),
),
],
),
),
);
}
/// Builds a single statistic row with a label and value
/// - [label]: The label of the statistic
/// - [value]: The value of the statistic
Widget _buildStatRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text(
label,
style: const TextStyle(
fontSize: 16,
color: CustomTheme.textColor,
),
),
],
),
Text(
value,
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
],
),
);
}
/// Loads statistics for this group
Future<void> _loadStatistics() async {
final matches = await db.matchDao.getAllMatches();
final groupMatches = matches
.where((match) => match.group?.id == widget.group.id)
.toList();
setState(() {
totalMatches = groupMatches.length;
bestPlayer = _getBestPlayer(groupMatches);
isLoading = false;
});
}
/// Determines the best player in the group based on match wins
String _getBestPlayer(List<Match> matches) {
final bestPlayerCounts = <Player, int>{};
// Count wins for each player
for (var match in matches) {
if (match.winner != null) {
bestPlayerCounts.update(
match.winner!,
(value) => value + 1,
ifAbsent: () => 1,
);
}
}
// Sort players by win count
final sortedPlayers = bestPlayerCounts.entries.toList()
..sort((a, b) => b.value.compareTo(a.value));
// Get the best player
bestPlayer = sortedPlayers.isNotEmpty ? sortedPlayers.first.key.name : '-';
return bestPlayer;
}
}

View File

@@ -1,17 +1,18 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/adaptive_page_route.dart';
import 'package:game_tracker/core/constants.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/dto/group.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/views/main_menu/group_view/create_group_view.dart';
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart';
import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart';
import 'package:game_tracker/presentation/widgets/top_centered_message.dart';
import 'package:provider/provider.dart';
import 'package:tallee/core/adaptive_page_route.dart';
import 'package:tallee/core/constants.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/dto/group.dart';
import 'package:tallee/data/dto/player.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/views/main_menu/group_view/create_group_view.dart';
import 'package:tallee/presentation/views/main_menu/group_view/group_profile_view.dart';
import 'package:tallee/presentation/widgets/app_skeleton.dart';
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
import 'package:tallee/presentation/widgets/tiles/group_tile.dart';
import 'package:tallee/presentation/widgets/top_centered_message.dart';
class GroupsView extends StatefulWidget {
/// A view that displays a list of groups
@@ -34,7 +35,8 @@ class _GroupsViewState extends State<GroupsView> {
7,
Group(
name: 'Skeleton Group',
members: List.filled(6, Player(name: 'Skeleton Player')),
description: '',
members: List.filled(6, Player(name: 'Skeleton Player', description: '')),
),
);
@@ -74,7 +76,22 @@ class _GroupsViewState extends State<GroupsView> {
height: MediaQuery.paddingOf(context).bottom - 20,
);
}
return GroupTile(group: groups[index]);
return GroupTile(
group: groups[index],
onTap: () async {
await Navigator.push(
context,
adaptivePageRoute(
builder: (context) {
return GroupProfileView(
group: groups[index],
callback: loadGroups,
);
},
),
);
},
);
},
),
),
@@ -105,9 +122,12 @@ class _GroupsViewState extends State<GroupsView> {
}
void loadGroups() {
setState(() {
isLoading = true;
});
Future.wait([
db.groupDao.getAllGroups(),
Future.delayed(Constants.minimumSkeletonDuration),
Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
]).then((results) {
loadedGroups = results[0] as List<Group>;
setState(() {

View File

@@ -1,18 +1,20 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/adaptive_page_route.dart';
import 'package:game_tracker/core/constants.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/dto/group.dart';
import 'package:game_tracker/data/dto/match.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart';
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
import 'package:game_tracker/presentation/widgets/buttons/quick_create_button.dart';
import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart';
import 'package:game_tracker/presentation/widgets/tiles/match_tile.dart';
import 'package:game_tracker/presentation/widgets/tiles/quick_info_tile.dart';
import 'package:provider/provider.dart';
import 'package:tallee/core/adaptive_page_route.dart';
import 'package:tallee/core/constants.dart';
import 'package:tallee/core/enums.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/dto/game.dart';
import 'package:tallee/data/dto/group.dart';
import 'package:tallee/data/dto/match.dart';
import 'package:tallee/data/dto/player.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
import 'package:tallee/presentation/widgets/app_skeleton.dart';
import 'package:tallee/presentation/widgets/buttons/quick_create_button.dart';
import 'package:tallee/presentation/widgets/tiles/info_tile.dart';
import 'package:tallee/presentation/widgets/tiles/match_tile.dart';
import 'package:tallee/presentation/widgets/tiles/quick_info_tile.dart';
class HomeView extends StatefulWidget {
/// The main home view of the application, displaying quick info,
@@ -40,13 +42,16 @@ class _HomeViewState extends State<HomeView> {
2,
Match(
name: 'Skeleton Match',
game: Game(name: '', ruleset: Ruleset.singleWinner, description: '', color: GameColor.blue, icon: ''),
group: Group(
name: 'Skeleton Group',
description: '',
members: [
Player(name: 'Skeleton Player 1'),
Player(name: 'Skeleton Player 2'),
Player(name: 'Skeleton Player 1', description: ''),
Player(name: 'Skeleton Player 2', description: ''),
],
),
notes: '',
),
);
@@ -99,9 +104,7 @@ class _HomeViewState extends State<HomeView> {
if (recentMatches.isNotEmpty)
for (Match match in recentMatches)
Padding(
padding: const EdgeInsets.symmetric(
vertical: 6.0,
),
padding: const EdgeInsets.symmetric(vertical: 6.0),
child: MatchTile(
compact: true,
width: constraints.maxWidth * 0.9,
@@ -110,19 +113,15 @@ class _HomeViewState extends State<HomeView> {
await Navigator.of(context).push(
adaptivePageRoute(
fullscreenDialog: true,
builder: (context) =>
MatchResultView(match: match),
builder: (context) => MatchResultView(match: match),
),
);
await updatedWinnerinRecentMatches(match.id);
await updatedWinnerInRecentMatches(match.id);
},
),
)
else
Center(
heightFactor: 5,
child: Text(loc.no_recent_matches_available),
),
Center(heightFactor: 5, child: Text(loc.no_recent_matches_available)),
],
),
),
@@ -138,40 +137,22 @@ class _HomeViewState extends State<HomeView> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
QuickCreateButton(
text: 'Category 1',
onPressed: () {},
),
QuickCreateButton(
text: 'Category 2',
onPressed: () {},
),
QuickCreateButton(text: 'Category 1', onPressed: () {}),
QuickCreateButton(text: 'Category 2', onPressed: () {}),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
QuickCreateButton(
text: 'Category 3',
onPressed: () {},
),
QuickCreateButton(
text: 'Category 4',
onPressed: () {},
),
QuickCreateButton(text: 'Category 3', onPressed: () {}),
QuickCreateButton(text: 'Category 4', onPressed: () {}),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
QuickCreateButton(
text: 'Category 5',
onPressed: () {},
),
QuickCreateButton(
text: 'Category 6',
onPressed: () {},
),
QuickCreateButton(text: 'Category 5', onPressed: () {}),
QuickCreateButton(text: 'Category 6', onPressed: () {}),
],
),
],
@@ -195,14 +176,12 @@ class _HomeViewState extends State<HomeView> {
db.matchDao.getMatchCount(),
db.groupDao.getGroupCount(),
db.matchDao.getAllMatches(),
Future.delayed(Constants.minimumSkeletonDuration),
Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
]).then((results) {
matchCount = results[0] as int;
groupCount = results[1] as int;
loadedRecentMatches = results[2] as List<Match>;
recentMatches =
(loadedRecentMatches
..sort((a, b) => b.createdAt.compareTo(a.createdAt)))
recentMatches = (loadedRecentMatches..sort((a, b) => b.createdAt.compareTo(a.createdAt)))
.take(2)
.toList();
if (mounted) {
@@ -214,7 +193,7 @@ class _HomeViewState extends State<HomeView> {
}
/// Updates the winner information for a specific match in the recent matches list.
Future<void> updatedWinnerinRecentMatches(String matchId) async {
Future<void> updatedWinnerInRecentMatches(String matchId) async {
final db = Provider.of<AppDatabase>(context, listen: false);
final winner = await db.matchDao.getWinner(matchId: matchId);
final matchIndex = recentMatches.indexWhere((match) => match.id == matchId);

View File

@@ -1,9 +1,9 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/core/enums.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart';
import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/core/enums.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
import 'package:tallee/presentation/widgets/tiles/title_description_list_tile.dart';
class ChooseGameView extends StatefulWidget {
/// A view that allows the user to choose a game from a list of available games
@@ -43,6 +43,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
final loc = AppLocalizations.of(context);
return Scaffold(
backgroundColor: CustomTheme.backgroundColor,
resizeToAvoidBottomInset: false,
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios),

View File

@@ -1,10 +1,10 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/data/dto/group.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart';
import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart';
import 'package:game_tracker/presentation/widgets/top_centered_message.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/data/dto/group.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
import 'package:tallee/presentation/widgets/tiles/group_tile.dart';
import 'package:tallee/presentation/widgets/top_centered_message.dart';
class ChooseGroupView extends StatefulWidget {
/// A view that allows the user to choose a group from a list of groups.
@@ -43,6 +43,7 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
final loc = AppLocalizations.of(context);
return Scaffold(
backgroundColor: CustomTheme.backgroundColor,
resizeToAvoidBottomInset: false,
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios),

View File

@@ -1,99 +0,0 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/core/enums.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart';
class ChooseRulesetView extends StatefulWidget {
/// A view that allows the user to choose a ruleset from a list of available rulesets
/// - [rulesets]: A list of tuples containing the ruleset and its description
/// - [initialRulesetIndex]: The index of the initially selected ruleset
const ChooseRulesetView({
super.key,
required this.rulesets,
required this.initialRulesetIndex,
});
/// A list of tuples containing the ruleset and its description
final List<(Ruleset, String)> rulesets;
/// The index of the initially selected ruleset
final int initialRulesetIndex;
@override
State<ChooseRulesetView> createState() => _ChooseRulesetViewState();
}
class _ChooseRulesetViewState extends State<ChooseRulesetView> {
/// Currently selected ruleset index
late int selectedRulesetIndex;
@override
void initState() {
selectedRulesetIndex = widget.initialRulesetIndex;
super.initState();
}
@override
Widget build(BuildContext context) {
final loc = AppLocalizations.of(context);
return DefaultTabController(
length: 2,
initialIndex: 0,
child: Scaffold(
backgroundColor: CustomTheme.backgroundColor,
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back_ios),
onPressed: () {
Navigator.of(context).pop(
selectedRulesetIndex == -1
? null
: widget.rulesets[selectedRulesetIndex].$1,
);
},
),
title: Text(loc.choose_ruleset),
),
body: PopScope(
// This fixes that the Android Back Gesture didn't return the
// selectedRulesetIndex and therefore the selected Ruleset wasn't saved
canPop: false,
onPopInvokedWithResult: (bool didPop, Object? result) {
if (didPop) {
return;
}
Navigator.of(context).pop(
selectedRulesetIndex == -1
? null
: widget.rulesets[selectedRulesetIndex].$1,
);
},
child: ListView.builder(
padding: const EdgeInsets.only(bottom: 85),
itemCount: widget.rulesets.length,
itemBuilder: (BuildContext context, int index) {
return TitleDescriptionListTile(
onPressed: () async {
setState(() {
if (selectedRulesetIndex == index) {
selectedRulesetIndex = -1;
} else {
selectedRulesetIndex = index;
}
});
},
title: translateRulesetToString(
widget.rulesets[index].$1,
context,
),
description: widget.rulesets[index].$2,
isHighlighted: selectedRulesetIndex == index,
);
},
),
),
),
);
}
}

View File

@@ -1,22 +1,22 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/adaptive_page_route.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/core/enums.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/dto/game.dart';
import 'package:game_tracker/data/dto/group.dart';
import 'package:game_tracker/data/dto/match.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_game_view.dart';
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_group_view.dart';
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart';
import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart';
import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart';
import 'package:game_tracker/presentation/widgets/player_selection.dart';
import 'package:game_tracker/presentation/widgets/text_input/text_input_field.dart';
import 'package:game_tracker/presentation/widgets/tiles/choose_tile.dart';
import 'package:provider/provider.dart';
import 'package:tallee/core/adaptive_page_route.dart';
import 'package:tallee/core/constants.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/core/enums.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/dto/game.dart';
import 'package:tallee/data/dto/group.dart';
import 'package:tallee/data/dto/match.dart';
import 'package:tallee/data/dto/player.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/views/main_menu/match_view/create_match/choose_game_view.dart';
import 'package:tallee/presentation/views/main_menu/match_view/create_match/choose_group_view.dart';
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
import 'package:tallee/presentation/widgets/player_selection.dart';
import 'package:tallee/presentation/widgets/text_input/text_input_field.dart';
import 'package:tallee/presentation/widgets/tiles/choose_tile.dart';
class CreateMatchView extends StatefulWidget {
/// A view that allows creating a new match
@@ -58,22 +58,12 @@ class _CreateMatchViewState extends State<CreateMatchView> {
/// the [ChooseGroupView]
String selectedGroupId = '';
/// The currently selected ruleset
Ruleset? selectedRuleset;
/// The index of the currently selected ruleset in [rulesets] to mark it in
/// the [ChooseRulesetView]
int selectedRulesetIndex = -1;
/// The index of the currently selected game in [games] to mark it in
/// the [ChooseGameView]
int selectedGameIndex = -1;
/// The currently selected players
List<Player>? selectedPlayers;
/// List of available rulesets with their localized string representations
late final List<(Ruleset, String)> _rulesets;
List<Player> selectedPlayers = [];
@override
void initState() {
@@ -107,17 +97,10 @@ class _CreateMatchViewState extends State<CreateMatchView> {
super.didChangeDependencies();
final loc = AppLocalizations.of(context);
hintText ??= loc.match_name;
_rulesets = [
(Ruleset.singleWinner, loc.ruleset_single_winner),
(Ruleset.singleLoser, loc.ruleset_single_loser),
(Ruleset.mostPoints, loc.ruleset_most_points),
(Ruleset.leastPoints, loc.ruleset_least_points),
];
}
// TODO: Replace when games are implemented
List<(String, String, Ruleset)> games = [
('Example Game 1', 'This is a description', Ruleset.leastPoints),
('Example Game 1', 'This is a description', Ruleset.lowestScore),
('Example Game 2', '', Ruleset.singleWinner),
];
@@ -126,6 +109,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
final loc = AppLocalizations.of(context);
return ScaffoldMessenger(
child: Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: CustomTheme.backgroundColor,
appBar: AppBar(title: Text(loc.create_new_match)),
body: SafeArea(
@@ -137,6 +121,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
child: TextInputField(
controller: _matchNameController,
hintText: hintText ?? '',
maxLength: Constants.MAX_MATCH_NAME_LENGTH,
),
),
ChooseTile(
@@ -156,39 +141,12 @@ class _CreateMatchViewState extends State<CreateMatchView> {
setState(() {
if (selectedGameIndex != -1) {
hintText = games[selectedGameIndex].$1;
selectedRuleset = games[selectedGameIndex].$3;
selectedRulesetIndex = _rulesets.indexWhere(
(r) => r.$1 == selectedRuleset,
);
} else {
hintText = loc.match_name;
selectedRuleset = null;
}
});
},
),
ChooseTile(
title: loc.ruleset,
trailingText: selectedRuleset == null
? loc.none
: translateRulesetToString(selectedRuleset!, context),
onPressed: () async {
selectedRuleset = await Navigator.of(context).push(
adaptivePageRoute(
builder: (context) => ChooseRulesetView(
rulesets: _rulesets,
initialRulesetIndex: selectedRulesetIndex,
),
),
);
if (!mounted) return;
selectedRulesetIndex = _rulesets.indexWhere(
(r) => r.$1 == selectedRuleset,
);
selectedGameIndex = -1;
setState(() {});
},
),
ChooseTile(
title: loc.group,
trailingText: selectedGroup == null
@@ -220,7 +178,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
Expanded(
child: PlayerSelection(
key: ValueKey(selectedGroup?.id ?? 'no_group'),
initialSelectedPlayers: selectedPlayers ?? [],
initialSelectedPlayers: selectedPlayers,
availablePlayers: filteredPlayerList,
onChanged: (value) {
setState(() {
@@ -235,22 +193,41 @@ class _CreateMatchViewState extends State<CreateMatchView> {
buttonType: ButtonType.primary,
onPressed: _enableCreateGameButton()
? () async {
final selectedGame = games[selectedGameIndex];
final game = Game(
// Use a game from the games list
Game? gameToUse;
if (selectedGameIndex == -1) {
// Use the first game as default if none selected
final selectedGame = games[0];
gameToUse = Game(
name: selectedGame.$1,
description: selectedGame.$2.isEmpty ? null : selectedGame.$2,
ruleset: selectedGame.$3.name,
description: selectedGame.$2,
ruleset: selectedGame.$3,
color: GameColor.blue,
icon: '',
);
// Ensure the game exists in the database before creating the match
await db.gameDao.addGame(game: game);
} else {
// Use the selected game from the list
final selectedGame = games[selectedGameIndex];
gameToUse = Game(
name: selectedGame.$1,
description: selectedGame.$2,
ruleset: selectedGame.$3,
color: GameColor.blue,
icon: '',
);
}
// Add the game to the database if it doesn't exist
await db.gameDao.addGame(game: gameToUse);
Match match = Match(
name: _matchNameController.text.isEmpty
? (hintText ?? '')
: _matchNameController.text.trim(),
createdAt: DateTime.now(),
game: game,
game: gameToUse,
group: selectedGroup,
players: selectedPlayers,
notes: '',
);
await db.matchDao.addMatch(match: match);
if (context.mounted) {
@@ -278,13 +255,10 @@ class _CreateMatchViewState extends State<CreateMatchView> {
/// Determines whether the "Create Match" button should be enabled.
///
/// Returns `true` if:
/// - A game is selected AND
/// - A ruleset is selected AND
/// - Either a group is selected OR at least 2 players are selected
bool _enableCreateGameButton() {
return selectedGameIndex != -1 &&
(selectedGroup != null ||
(selectedPlayers != null && selectedPlayers!.length > 1)) &&
selectedRuleset != null;
return (selectedGroup != null ||
(selectedPlayers.length > 1));
}
}

View File

@@ -1,11 +1,11 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/dto/match.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/widgets/tiles/custom_radio_list_tile.dart';
import 'package:provider/provider.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/dto/match.dart';
import 'package:tallee/data/dto/player.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/widgets/tiles/custom_radio_list_tile.dart';
class MatchResultView extends StatefulWidget {
/// A view that allows selecting and saving the winner of a match
@@ -153,12 +153,10 @@ class _MatchResultViewState extends State<MatchResultView> {
List<Player> getAllPlayers(Match match) {
List<Player> players = [];
if (match.group == null && match.players != null) {
players = [...match.players!];
} else if (match.group != null && match.players != null) {
players = [...match.players!, ...match.group!.members];
if (match.group == null) {
players = [...match.players];
} else {
players = [...match.group!.members];
players = [...match.players, ...match.group!.members];
}
players.sort((a, b) => a.name.compareTo(b.name));

View File

@@ -2,21 +2,23 @@ import 'dart:core' hide Match;
import 'package:flutter/material.dart';
import 'package:fluttericon/rpg_awesome_icons.dart';
import 'package:game_tracker/core/adaptive_page_route.dart';
import 'package:game_tracker/core/constants.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/data/db/database.dart';
import 'package:game_tracker/data/dto/group.dart';
import 'package:game_tracker/data/dto/match.dart';
import 'package:game_tracker/data/dto/player.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/create_match_view.dart';
import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart';
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
import 'package:game_tracker/presentation/widgets/buttons/main_menu_button.dart';
import 'package:game_tracker/presentation/widgets/tiles/match_tile.dart';
import 'package:game_tracker/presentation/widgets/top_centered_message.dart';
import 'package:provider/provider.dart';
import 'package:tallee/core/adaptive_page_route.dart';
import 'package:tallee/core/constants.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/core/enums.dart';
import 'package:tallee/data/db/database.dart';
import 'package:tallee/data/dto/game.dart';
import 'package:tallee/data/dto/group.dart';
import 'package:tallee/data/dto/match.dart';
import 'package:tallee/data/dto/player.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_match_view.dart';
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
import 'package:tallee/presentation/widgets/app_skeleton.dart';
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
import 'package:tallee/presentation/widgets/tiles/match_tile.dart';
import 'package:tallee/presentation/widgets/top_centered_message.dart';
class MatchView extends StatefulWidget {
/// A view that displays a list of matches
@@ -36,12 +38,15 @@ class _MatchViewState extends State<MatchView> {
4,
Match(
name: 'Skeleton match name',
game: Game(name: '', ruleset: Ruleset.singleWinner, description: '', color: GameColor.blue, icon: ''),
group: Group(
name: 'Group name',
members: List.filled(5, Player(name: 'Player')),
description: '',
members: List.filled(5, Player(name: 'Player', description: '')),
),
winner: Player(name: 'Player'),
players: [Player(name: 'Player')],
winner: Player(name: 'Player', description: ''),
players: [Player(name: 'Player', description: '')],
notes: '',
),
);
@@ -130,7 +135,7 @@ class _MatchViewState extends State<MatchView> {
void loadGames() {
Future.wait([
db.matchDao.getAllMatches(),
Future.delayed(Constants.minimumSkeletonDuration),
Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
]).then((results) {
if (mounted) {
setState(() {

View File

@@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
import 'package:url_launcher/url_launcher.dart';
class LicenseDetailView extends StatelessWidget {
@@ -29,19 +30,11 @@ class LicenseDetailView extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: const EdgeInsetsGeometry.only(right: 15),
width: 60,
height: 60,
decoration: BoxDecoration(
color: CustomTheme.primaryColor.withAlpha(40),
borderRadius: BorderRadius.circular(10),
),
child: Icon(
Icons.description,
color: CustomTheme.primaryColor,
size: 30,
),
const ColoredIconContainer(
icon: Icons.description,
margin: EdgeInsetsGeometry.only(right: 15),
containerSize: 60,
iconSize: 30,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -96,7 +89,7 @@ class LicenseDetailView extends StatelessWidget {
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: TextStyle(
style: const TextStyle(
fontSize: 12,
color: CustomTheme.secondaryColor,
decoration: TextDecoration.underline,

View File

@@ -8,7 +8,7 @@
// https://pub.dev/packages/dart_pubspec_licenses
/// This package.
const thisPackage = _game_tracker;
const thisPackage = _tallee;
/// All dependencies including transitive dependencies.
const allDependencies = <Package>[
@@ -31,6 +31,7 @@ const allDependencies = <Package>[
_cli_config,
_cli_util,
_clock,
_code_assets,
_code_builder,
_collection,
_convert,
@@ -57,10 +58,12 @@ const allDependencies = <Package>[
_flutter_lints,
_flutter_plugin_android_lifecycle,
_flutter_web_plugins,
_fluttericon,
_font_awesome_flutter,
_frontend_server_client,
_glob,
_graphs,
_hooks,
_html,
_http,
_http_multi_server,
@@ -80,8 +83,10 @@ const allDependencies = <Package>[
_material_color_utilities,
_meta,
_mime,
_native_toolchain_c,
_nested,
_node_preamble,
_objective_c,
_package_config,
_package_info_plus,
_package_info_plus_platform_interface,
@@ -160,6 +165,7 @@ const dependencies = <Package>[
_drift_flutter,
_file_picker,
_file_saver,
_fluttericon,
_font_awesome_flutter,
_intl,
_json_schema,
@@ -517,13 +523,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// build_daemon 4.1.0
/// build_daemon 4.1.1
const _build_daemon = Package(
name: 'build_daemon',
description: 'A daemon for running Dart builds.',
repository: 'https://github.com/dart-lang/build/tree/master/build_daemon',
authors: [],
version: '4.1.0',
version: '4.1.1',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
@@ -724,14 +730,14 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// built_value 8.12.0
/// built_value 8.12.3
const _built_value = Package(
name: 'built_value',
description: '''Value types with builders, Dart classes as enums, and serialization. This library is the runtime dependency.
''',
repository: 'https://github.com/google/built_value.dart/tree/master/built_value',
authors: [],
version: '8.12.0',
version: '8.12.3',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
@@ -1185,13 +1191,54 @@ const _clock = Package(
limitations under the License.''',
);
/// code_builder 4.11.0
/// code_assets 1.0.0
const _code_assets = Package(
name: 'code_assets',
description: 'This library contains the hook protocol specification for bundling native code with Dart packages.',
repository: 'https://github.com/dart-lang/native/tree/main/pkgs/code_assets',
authors: [],
version: '1.0.0',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
dependencies: [PackageRef('collection'), PackageRef('hooks')],
devDependencies: [PackageRef('json_schema'), PackageRef('test')],
license: '''Copyright 2025, the Dart project authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// code_builder 4.11.1
const _code_builder = Package(
name: 'code_builder',
description: 'A fluent, builder-based library for generating valid Dart code.',
repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/code_builder',
authors: [],
version: '4.11.0',
version: '4.11.1',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
@@ -1349,13 +1396,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// cross_file 0.3.5+1
/// cross_file 0.3.5+2
const _cross_file = Package(
name: 'cross_file',
description: 'An abstraction to allow working with files across multiple platforms.',
repository: 'https://github.com/flutter/packages/tree/main/packages/cross_file',
authors: [],
version: '0.3.5+1',
version: '0.3.5+2',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
@@ -1581,13 +1628,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// dbus 0.7.11
/// dbus 0.7.12
const _dbus = Package(
name: 'dbus',
description: 'A native Dart implementation of the D-Bus message bus client. This package allows Dart applications to directly access services on the Linux desktop.',
homepage: 'https://github.com/canonical/dbus.dart',
authors: [],
version: '0.7.11',
version: '0.7.12',
spdxIdentifiers: ['MPL-2.0'],
isMarkdown: false,
isSdk: false,
@@ -1968,7 +2015,7 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice
defined by the Mozilla Public License, v. 2.0.''',
);
/// dio 5.9.0
/// dio 5.9.1
const _dio = Package(
name: 'dio',
description: '''A powerful HTTP networking package,
@@ -1979,7 +2026,7 @@ Custom adapters, Transformers, etc.
homepage: 'https://github.com/cfug/dio',
repository: 'https://github.com/cfug/dio/blob/main/dio',
authors: [],
version: '5.9.0',
version: '5.9.1',
spdxIdentifiers: ['MIT'],
isMarkdown: false,
isSdk: false,
@@ -2369,13 +2416,13 @@ const _fake_async = Package(
limitations under the License.''',
);
/// ffi 2.1.4
/// ffi 2.1.5
const _ffi = Package(
name: 'ffi',
description: 'Utilities for working with Foreign Function Interface (FFI) code.',
repository: 'https://github.com/dart-lang/native/tree/main/pkgs/ffi',
authors: [],
version: '2.1.4',
version: '2.1.5',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
@@ -2450,14 +2497,14 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// file_picker 10.3.7
/// file_picker 10.3.10
const _file_picker = Package(
name: 'file_picker',
description: 'A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support.',
homepage: 'https://github.com/miguelpruivo/plugins_flutter_file_picker',
repository: 'https://github.com/miguelpruivo/flutter_file_picker',
authors: [],
version: '10.3.7',
version: '10.3.10',
spdxIdentifiers: ['MIT'],
isMarkdown: false,
isSdk: false,
@@ -2571,13 +2618,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// flutter 3.38.4
/// flutter 3.38.6
const _flutter = Package(
name: 'flutter',
description: 'A framework for writing Flutter applications',
homepage: 'https://flutter.dev',
authors: [],
version: '3.38.4',
version: '3.38.6',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: true,
@@ -2701,6 +2748,44 @@ const _flutter_web_plugins = Package(
devDependencies: [],
);
/// fluttericon 2.0.0
const _fluttericon = Package(
name: 'fluttericon',
description: 'Flutter icons from popular web icon fonts. Customize your final icon package using fluttericon.com.',
homepage: 'https://github.com/ilikerobots/fluttericon_pkg',
authors: [],
version: '2.0.0',
spdxIdentifiers: [],
isMarkdown: false,
isSdk: false,
dependencies: [PackageRef('flutter')],
devDependencies: [PackageRef('test'), PackageRef('recase')],
license: '''Copyright (c) 2020, Mike Hoolehan, StarHeight Media
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the StarHeight Media nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL HOOLEHAN OR STARHEIGHT MEDIA BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// font_awesome_flutter 10.12.0
const _font_awesome_flutter = Package(
name: 'font_awesome_flutter',
@@ -2862,6 +2947,47 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// hooks 1.0.1
const _hooks = Package(
name: 'hooks',
description: 'A library that contains a Dart API for the JSON-based protocol for `hook/build.dart` and `hook/link.dart`.',
repository: 'https://github.com/dart-lang/native/tree/main/pkgs/hooks',
authors: [],
version: '1.0.1',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
dependencies: [PackageRef('collection'), PackageRef('crypto'), PackageRef('logging'), PackageRef('meta'), PackageRef('pub_semver'), PackageRef('yaml')],
devDependencies: [PackageRef('args'), PackageRef('code_assets'), PackageRef('glob'), PackageRef('json_schema'), PackageRef('path'), PackageRef('test')],
license: '''Copyright 2025, the Dart project authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// html 0.15.6
const _html = Package(
name: 'html',
@@ -3145,13 +3271,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// json_annotation 4.9.0
/// json_annotation 4.10.0
const _json_annotation = Package(
name: 'json_annotation',
description: 'Classes and helper functions that support JSON code generation via the `json_serializable` package.',
repository: 'https://github.com/google/json_serializable.dart/tree/master/json_annotation',
authors: [],
version: '4.9.0',
version: '4.10.0',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
@@ -3821,6 +3947,47 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// native_toolchain_c 0.17.4
const _native_toolchain_c = Package(
name: 'native_toolchain_c',
description: 'A library to invoke the native C compiler installed on the host machine.',
repository: 'https://github.com/dart-lang/native/tree/main/pkgs/native_toolchain_c',
authors: [],
version: '0.17.4',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
dependencies: [PackageRef('code_assets'), PackageRef('glob'), PackageRef('hooks'), PackageRef('logging'), PackageRef('meta'), PackageRef('pub_semver')],
devDependencies: [PackageRef('collection'), PackageRef('test')],
license: '''Copyright 2023, the Dart project authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// nested 1.0.0
const _nested = Package(
name: 'nested',
@@ -3918,6 +4085,47 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// objective_c 9.3.0
const _objective_c = Package(
name: 'objective_c',
description: 'A library to access Objective C from Flutter that acts as a support library for package:ffigen.',
repository: 'https://github.com/dart-lang/native/tree/main/pkgs/objective_c',
authors: [],
version: '9.3.0',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
dependencies: [PackageRef('code_assets'), PackageRef('collection'), PackageRef('ffi'), PackageRef('hooks'), PackageRef('logging'), PackageRef('native_toolchain_c'), PackageRef('pub_semver')],
devDependencies: [PackageRef('args'), PackageRef('path'), PackageRef('test'), PackageRef('yaml')],
license: '''Copyright 2024, the Dart project authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// package_config 2.2.0
const _package_config = Package(
name: 'package_config',
@@ -4164,13 +4372,13 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// path_provider_android 2.2.20
/// path_provider_android 2.2.22
const _path_provider_android = Package(
name: 'path_provider_android',
description: 'Android implementation of the path_provider plugin.',
repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_android',
authors: [],
version: '2.2.20',
version: '2.2.22',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
@@ -4203,18 +4411,18 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// path_provider_foundation 2.4.3
/// path_provider_foundation 2.6.0
const _path_provider_foundation = Package(
name: 'path_provider_foundation',
description: 'iOS and macOS implementation of the path_provider plugin',
repository: 'https://github.com/flutter/packages/tree/main/packages/path_provider/path_provider_foundation',
authors: [],
version: '2.4.3',
version: '2.6.0',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
dependencies: [PackageRef('flutter'), PackageRef('path_provider_platform_interface')],
devDependencies: [PackageRef('build_runner'), PackageRef('path')],
dependencies: [PackageRef('ffi'), PackageRef('flutter'), PackageRef('objective_c'), PackageRef('path_provider_platform_interface')],
devDependencies: [],
license: '''Copyright 2013 The Flutter Authors
Redistribution and use in source and binary forms, with or without modification,
@@ -5503,18 +5711,18 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// skeletonizer 2.1.1
/// skeletonizer 2.1.2
const _skeletonizer = Package(
name: 'skeletonizer',
description: 'Converts already built widgets into skeleton loaders with no extra effort.',
homepage: 'https://github.com/Milad-Akarie/skeletonizer',
authors: [],
version: '2.1.1',
version: '2.1.2',
spdxIdentifiers: ['MIT'],
isMarkdown: false,
isSdk: false,
dependencies: [PackageRef('flutter')],
devDependencies: [PackageRef('flutter_lints')],
devDependencies: [PackageRef('flutter_lints'), PackageRef('coverage')],
license: '''MIT License
Copyright (c) 2023 Milad Akarie
@@ -5661,13 +5869,13 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// source_span 1.10.1
/// source_span 1.10.2
const _source_span = Package(
name: 'source_span',
description: 'Provides a standard representation for source code locations and spans.',
repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/source_span',
authors: [],
version: '1.10.1',
version: '1.10.2',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
@@ -5737,13 +5945,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.''',
);
/// sqlite3_flutter_libs 0.5.40
/// sqlite3_flutter_libs 0.5.41
const _sqlite3_flutter_libs = Package(
name: 'sqlite3_flutter_libs',
description: 'Flutter plugin to include native sqlite3 libraries with your app',
homepage: 'https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3_flutter_libs',
homepage: 'https://github.com/simolus3/sqlite3.dart/tree/v2/sqlite3_flutter_libs',
authors: [],
version: '0.5.40',
version: '0.5.41',
spdxIdentifiers: ['MIT'],
isMarkdown: false,
isSdk: false,
@@ -5772,14 +5980,14 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.''',
);
/// sqlparser 0.42.0
/// sqlparser 0.42.1
const _sqlparser = Package(
name: 'sqlparser',
description: 'Parses sqlite statements and performs static analysis on them',
homepage: 'https://github.com/simolus3/drift/tree/develop/sqlparser',
repository: 'https://github.com/simolus3/drift',
authors: [],
version: '0.42.0',
version: '0.42.1',
spdxIdentifiers: ['MIT'],
isMarkdown: false,
isSdk: false,
@@ -6525,13 +6733,13 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// url_launcher_web 2.4.1
/// url_launcher_web 2.4.2
const _url_launcher_web = Package(
name: 'url_launcher_web',
description: 'Web platform implementation of url_launcher',
repository: 'https://github.com/flutter/packages/tree/main/packages/url_launcher/url_launcher_web',
authors: [],
version: '2.4.1',
version: '2.4.2',
spdxIdentifiers: ['Apache-2.0', 'BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
@@ -6539,7 +6747,7 @@ const _url_launcher_web = Package(
devDependencies: [],
license: '''url_launcher_web
Copyright 2013 The Flutter Authors. All rights reserved.
Copyright 2013 The Flutter Authors
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
@@ -6932,18 +7140,18 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
);
/// watcher 1.1.4
/// watcher 1.2.1
const _watcher = Package(
name: 'watcher',
description: 'A file system watcher. It monitors changes to contents of directories and sends notifications when files have been added, removed, or modified.',
repository: 'https://github.com/dart-lang/tools/tree/main/pkgs/watcher',
authors: [],
version: '1.1.4',
version: '1.2.1',
spdxIdentifiers: ['BSD-3-Clause'],
isMarkdown: false,
isSdk: false,
dependencies: [PackageRef('async'), PackageRef('path')],
devDependencies: [PackageRef('test')],
devDependencies: [PackageRef('clock'), PackageRef('fake_async'), PackageRef('test')],
license: '''Copyright 2014, the Dart project authors.
Redistribution and use in source and binary forms, with or without
@@ -7151,7 +7359,7 @@ const _win32 = Package(
isMarkdown: false,
isSdk: false,
dependencies: [PackageRef('ffi')],
devDependencies: [PackageRef('args'), PackageRef('path'), PackageRef('test')],
devDependencies: [PackageRef('args'), PackageRef('hooks'), PackageRef('path'), PackageRef('test')],
license: '''BSD 3-Clause License
Copyright (c) 2024, Halil Durmus
@@ -7291,16 +7499,181 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.''',
);
/// game_tracker 0.0.5+127
const _game_tracker = Package(
name: 'game_tracker',
description: 'Game Tracking App for Card Games',
/// tallee 0.0.15+249
const _tallee = Package(
name: 'tallee',
description: 'Tracking App for Card Games',
authors: [],
version: '0.0.5+127',
spdxIdentifiers: [],
version: '0.0.15+249',
spdxIdentifiers: ['LGPL-3.0'],
isMarkdown: false,
isSdk: false,
dependencies: [PackageRef('flutter'), PackageRef('clock'), PackageRef('cupertino_icons'), PackageRef('drift'), PackageRef('drift_flutter'), PackageRef('file_picker'), PackageRef('file_saver'), PackageRef('font_awesome_flutter'), PackageRef('intl'), PackageRef('json_schema'), PackageRef('package_info_plus'), PackageRef('path_provider'), PackageRef('provider'), PackageRef('skeletonizer'), PackageRef('url_launcher'), PackageRef('uuid')],
dependencies: [PackageRef('flutter'), PackageRef('clock'), PackageRef('cupertino_icons'), PackageRef('drift'), PackageRef('drift_flutter'), PackageRef('file_picker'), PackageRef('file_saver'), PackageRef('fluttericon'), PackageRef('font_awesome_flutter'), PackageRef('intl'), PackageRef('json_schema'), PackageRef('package_info_plus'), PackageRef('path_provider'), PackageRef('provider'), PackageRef('skeletonizer'), PackageRef('url_launcher'), PackageRef('uuid')],
devDependencies: [PackageRef('build_runner'), PackageRef('dart_pubspec_licenses'), PackageRef('drift_dev'), PackageRef('flutter_lints')],
license: '''GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.''',
);

View File

@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
import 'package:game_tracker/presentation/widgets/tiles/license_tile.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
import 'package:tallee/presentation/widgets/tiles/license_tile.dart';
class LicensesView extends StatelessWidget {
/// A view that displays a list of open source licenses used in the app

View File

@@ -3,16 +3,16 @@ import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:game_tracker/core/enums.dart';
import 'package:game_tracker/l10n/generated/app_localizations.dart';
import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses_view.dart';
import 'package:game_tracker/presentation/widgets/buttons/animated_dialog_button.dart';
import 'package:game_tracker/presentation/widgets/custom_alert_dialog.dart';
import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart';
import 'package:game_tracker/services/data_transfer_service.dart';
import 'package:intl/intl.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:tallee/core/custom_theme.dart';
import 'package:tallee/core/enums.dart';
import 'package:tallee/l10n/generated/app_localizations.dart';
import 'package:tallee/presentation/views/main_menu/settings_view/licenses_view.dart';
import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart';
import 'package:tallee/presentation/widgets/custom_alert_dialog.dart';
import 'package:tallee/presentation/widgets/tiles/settings_list_tile.dart';
import 'package:tallee/services/data_transfer_service.dart';
import 'package:url_launcher/url_launcher.dart';
class SettingsView extends StatefulWidget {
@@ -88,7 +88,7 @@ class _SettingsViewState extends State<SettingsView> {
);
final result = await DataTransferService.exportData(
json,
'game_tracker-data',
'tallee-data',
);
if (!scaffoldMessengerContext.mounted) return;
showExportSnackBar(
@@ -136,7 +136,7 @@ class _SettingsViewState extends State<SettingsView> {
onPressed: () => Navigator.of(context).pop(true),
child: Text(
loc.delete,
style: TextStyle(
style: const TextStyle(
color: CustomTheme.secondaryColor,
),
),

Some files were not shown because too many files have changed in this diff Show More