Compare commits
541 Commits
290948e50d
...
developmen
| Author | SHA1 | Date | |
|---|---|---|---|
| 048fb0ef43 | |||
| a4bc03111d | |||
| 00abc4d1c0 | |||
| d4fcc8106f | |||
| 487efb4d61 | |||
| 3f790cfbb1 | |||
| ee1962ef9c | |||
| a4d4703069 | |||
| fabb7bae19 | |||
| d1458443eb | |||
| 9c00b48de5 | |||
| 03ce304a0a | |||
| dde617d429 | |||
| 03a2df4fdf | |||
| 96ef70b209 | |||
| 4ae59ec881 | |||
| c162e245bd | |||
| 481afd7533 | |||
| af42ebbf92 | |||
| 34e442dbe9 | |||
| 8783d0ac44 | |||
| 7f356b0c86 | |||
| e4a2ac6b47 | |||
| 6065b53ce9 | |||
| c644ccfb06 | |||
| 2dd7d0285d | |||
| cf5883b430 | |||
| 7af2b43193 | |||
| 90cc4d4c2a | |||
| db2ba2571f | |||
| 3b01c4623c | |||
| c5c9a43459 | |||
| b2e58f2539 | |||
| 58dc5d8c2e | |||
| fd7dbd1155 | |||
| 61b72cf595 | |||
| 81c6c377d4 | |||
| 92f2b4db95 | |||
| 5178adf71c | |||
| 4a6d639f1c | |||
| e9cf707fca | |||
| 2b7941202a | |||
| 92317bcbdf | |||
| ceade5cafd | |||
| 6060afc543 | |||
| ac6399d707 | |||
| 8ee2b6cb06 | |||
| b14b7733ca | |||
| bc51b23563 | |||
| 057f8c1d58 | |||
| 4c1c22123e | |||
| e9929426e0 | |||
| eb404f3ef2 | |||
| c7b4623198 | |||
| ccd0c62e3c | |||
| 9f71c22a56 | |||
| 87d7fbebcd | |||
| c625174017 | |||
| 53a33ca2e1 | |||
| e1dd40a1c3 | |||
| 45b11359b3 | |||
| 57fb8dbcc8 | |||
| 5a30538aa5 | |||
| 1e18105ce0 | |||
| 9ce2ca0ceb | |||
| 39e6e485ac | |||
| e9633a898c | |||
| 94c3bad02b | |||
| ed2d672dee | |||
| 449639df0e | |||
| a713ccb59c | |||
| f5924c4758 | |||
| 5c9f44e947 | |||
| 5f987806d6 | |||
| 92c62000af | |||
| babe74f2be | |||
| 8a38b9c3ea | |||
| ddd0a5d8bd | |||
| be9d1b52d2 | |||
| 514e0f8064 | |||
| ff47ef38c1 | |||
| fa2706395c | |||
| 2d1ac3a17c | |||
| 4fd8d2129b | |||
| db41f40a52 | |||
| 0e747710ab | |||
| 9f44f02a35 | |||
| 3addaa0f9d | |||
| abb0fcbbd6 | |||
| fc6eb2b9cf | |||
| 6a0896d818 | |||
| a8129eb134 | |||
| 783f772da1 | |||
| b7930d5e2e | |||
| 1b709707b5 | |||
| cef02956b1 | |||
| a479cea5be | |||
| bbd41a65df | |||
| 2cadab004d | |||
| 6a3e184a95 | |||
| 5350113ee1 | |||
| bb79eecdfd | |||
| db51990695 | |||
| e483fc38f3 | |||
| 4019ed083f | |||
| 7be0b96491 | |||
| efdb5e0361 | |||
| 82ad2b74f8 | |||
| 4161e1e88b | |||
| d662680a34 | |||
| b69d2784df | |||
| d7f4b1c227 | |||
| 7a1752f773 | |||
| 57357f8aad | |||
| 806ed200f7 | |||
| d5bd0bca5f | |||
| 5da12939cb | |||
| 0d20b5847f | |||
| 973e327232 | |||
| 8c41f6a255 | |||
| 70f570489a | |||
| fa7740101b | |||
| 5aa2a335e3 | |||
| 80e601c10e | |||
| 2124c523bc | |||
| 7d0da81cf5 | |||
| cd3a5c2a49 | |||
| 4628e96456 | |||
| da61f45e8e | |||
| 9344f8212c | |||
| 6d42d59bad | |||
| 46118c274c | |||
| ab06662397 | |||
| 679f4c94d9 | |||
| 8bf2b9e3dd | |||
| cde40ef293 | |||
| 0fb6208345 | |||
| ec5a686f90 | |||
| f0c6dd8401 | |||
| 7bdad57cc8 | |||
| 5da1b6eecb | |||
| cdafd4bb6f | |||
| 6aee055df2 | |||
| 6d9871a5f0 | |||
| 4bbbcdd93f | |||
| fed5c55dd4 | |||
| c157644b44 | |||
| 5a5898787f | |||
| 9d3a45c01d | |||
| 485ac87fdb | |||
| 1ebcfc9e57 | |||
| 758f1e6c3a | |||
| 22ce742d43 | |||
| 7fc4bbfb13 | |||
| 857e05127d | |||
| 86982ada0f | |||
| e51bf3eabb | |||
| d7f08c5f50 | |||
| 9248284292 | |||
| 9a00e543d7 | |||
| 5ea7797b3e | |||
| c8b76ae0ea | |||
| c5fa540c5f | |||
| 3ceae8341b | |||
| 76ce3af643 | |||
| ab20bd764b | |||
| 8ca4e3210e | |||
| e384230a0b | |||
| 1e4fd2a164 | |||
| a491427a1d | |||
| a480530919 | |||
| 906c8d8450 | |||
| 000bdc8cbc | |||
| 497f30421d | |||
| adedb85eb2 | |||
| 2a72332bcd | |||
| 7aa41abe61 | |||
| e1263d51ad | |||
| 8791b5296e | |||
| f2a4327166 | |||
| d34990ed50 | |||
| 2ef671884d | |||
| 2ef8eb6534 | |||
| 6f0e5ba5c2 | |||
| 1c07346aaf | |||
| 830a64b5dd | |||
| 9221f64fa5 | |||
| c4f6749882 | |||
| 14a043785e | |||
| 9eb9c0eb7f | |||
| 54ec865f04 | |||
| d5e7a17127 | |||
| 275f64b296 | |||
| 97ca62b083 | |||
| 32fb1550ff | |||
| d67972624e | |||
| 595cf6ead0 | |||
| 6faafe9fab | |||
| 66b90aac25 | |||
| d22855fc1a | |||
| 1be86bc3c5 | |||
| db3e8215fa | |||
| 2c4cef76d8 | |||
| a4ef9705f9 | |||
| 799c849570 | |||
| 799b7d8403 | |||
| 644728a9df | |||
| afb7a5f1d4 | |||
| 3d510d5b3d | |||
| a9d2325eee | |||
| 349ff948de | |||
| c2394c3733 | |||
| 88766652b9 | |||
| 2a1573ee2d | |||
| cfb07bfe28 | |||
| d741990f2f | |||
| 76121eb4fb | |||
| d5ee6449b0 | |||
| 7d9757abb6 | |||
| d94d51c6ea | |||
|
|
803cf8a972 | ||
|
|
13be75a65b | ||
| aef12bd65a | |||
| 02d79574dd | |||
| fdd0e7579a | |||
| cd2770be26 | |||
| e196d6e5ef | |||
| bc3beac866 | |||
| aa936a938d | |||
| 2811ea892e | |||
| 4b1d3923a0 | |||
| 0f824bb30a | |||
| 21c74b74bc | |||
| 6e45e9435b | |||
| a78614851b | |||
| 8df9a27dc7 | |||
| 52180eeb6d | |||
| 0893667e41 | |||
| 1dc5286c6b | |||
|
|
f140ebae2e | ||
| a487e4071f | |||
|
|
99044c0ea0 | ||
| 69effa2b7d | |||
| 5db008c274 | |||
| feaa0709a7 | |||
|
|
2fea3597fe | ||
|
|
7b2314a25e | ||
|
|
7f6c1cb9a6 | ||
| dcfed75a93 | |||
| 7fa434782c | |||
| bdcee85eb9 | |||
| 072dba1cde | |||
| 3c7c4598ff | |||
| 1a20d7b64c | |||
| ec94e12ed7 | |||
| 9fc308554c | |||
| 42cef337aa | |||
|
|
d9980edf0e | ||
|
|
4c084cae4a | ||
|
|
cecfd5da4e | ||
| 5289660327 | |||
| 16e1f542f5 | |||
| e4ae526d93 | |||
| 2f65316a51 | |||
| 31abb7f1e4 | |||
| 132966f3d2 | |||
| 77095725de | |||
| d081a597db | |||
| bdc3453d7f | |||
| 678ab90af3 | |||
| a038c22ba6 | |||
| 22fcff73bd | |||
|
|
4a67dae456 | ||
| 3c22b084d6 | |||
| 7f923f6dff | |||
| 87856e6548 | |||
| cb7804cf55 | |||
| 304fa82a93 | |||
| f84a645e61 | |||
| b0073addf8 | |||
| b5c17ac5a9 | |||
| 4451f9e2a9 | |||
| 1d4fdae84b | |||
| 60862de4c4 | |||
| 6899bb0c3c | |||
| 55a22b292f | |||
| db30b0fd5a | |||
| 5ee0d59377 | |||
| f22595e678 | |||
| 25fe10eb9a | |||
| 5a318f9760 | |||
| 0051990168 | |||
| 7e21c65026 | |||
| cc23c03f6b | |||
| d77b5f20f9 | |||
| 3c3bf506cb | |||
| 8afba5680b | |||
| 7103765054 | |||
| bc01a6de9a | |||
| ad87dca674 | |||
| 633a21d829 | |||
| 81f63c1c07 | |||
| fc6c74b377 | |||
| 15d09f381a | |||
| f97c341b81 | |||
| 7bf03ec388 | |||
| 0bfaba4225 | |||
| bbb7914fc5 | |||
| 86dbc9afb0 | |||
| 73aea0d0f5 | |||
| ed9e3af768 | |||
| d93ead40b6 | |||
| 3374a80c27 | |||
| 534d19efc3 | |||
| d9a26a8cf7 | |||
| 8e05e9d61b | |||
| 179ac2fe21 | |||
| 2b78617924 | |||
| 175a9cb349 | |||
| 18f0626e95 | |||
| d99a04549a | |||
| cc1ecc4c86 | |||
| 16cdf9db3e | |||
| da494ed146 | |||
| af0242c44f | |||
| cd63f5cf06 | |||
| 8c3282b954 | |||
| 1c0fb9f3ab | |||
| bfca41bd36 | |||
| 92b8ef0877 | |||
| 5428064c53 | |||
| 27916456db | |||
| 58fe38fd72 | |||
| ecd03dfd9d | |||
| 05c6625bf3 | |||
| 9821af39fe | |||
| c1789458e0 | |||
| e19f696714 | |||
| 9cb35dc4a1 | |||
| b8b65c4ca1 | |||
| 356cb1fb43 | |||
| 4c8896d2d9 | |||
| 31c8598222 | |||
| 884680d329 | |||
| 5ae569f2e7 | |||
| 37d6ad81fd | |||
| cea6c36407 | |||
| 1b300faea9 | |||
| dac5cc8a89 | |||
| bafbde7d03 | |||
| fdea594a1e | |||
| 856ce43c49 | |||
| 5c8b93072f | |||
| 94fdd7026d | |||
| 966f7caa54 | |||
| 88bea48956 | |||
| a2e66b9c80 | |||
| d7a006dd87 | |||
| 12856342a8 | |||
| b0a5145490 | |||
| 7a80c1a792 | |||
| c73f37507f | |||
| 1e730cebe6 | |||
| 7eb25221d7 | |||
| f9722bc762 | |||
| f2917a6813 | |||
| b29cd6dff4 | |||
| 1d92084da6 | |||
| 7732c6ceb9 | |||
| a747d91c5d | |||
| 06a9c0cd84 | |||
| 9ad5c4ad6f | |||
| 9b3d61e5b0 | |||
| df0a5207c2 | |||
| 4f0a1eec6d | |||
| 24b60bb18b | |||
| c8532adfde | |||
| 76186787e7 | |||
| f05114a99e | |||
| d96494f608 | |||
| 0eaf3d251b | |||
| 0567fce02b | |||
| 74ea540b39 | |||
| d578a7f9bd | |||
| 0e5ad1c3d9 | |||
| c4b249b199 | |||
| 99cea1e703 | |||
| 7b7c41b96c | |||
| d0059b44a8 | |||
| 3b3d298ff5 | |||
| e1626225ac | |||
| 93ced81e7e | |||
| 23cdddfbd9 | |||
| 5d2fed74ac | |||
| 0d0806dfbb | |||
| 27ff599a88 | |||
| c4094a547e | |||
| 701500c7e2 | |||
| 062c2681bf | |||
| 7cff48ebc0 | |||
| 708157df54 | |||
| f1f3fd7b6e | |||
| 7bc75d60a7 | |||
| a1ed17355a | |||
| 45abc79f95 | |||
| c214a26c54 | |||
| 6c0cb92e56 | |||
| b4ba4f8d74 | |||
| f60c11fc08 | |||
| d2d0a82c9b | |||
| 1044ee9bea | |||
| 32e812127d | |||
| 4500d85f78 | |||
| c8bf03f462 | |||
| 7ecccb13c2 | |||
| 4fc1959704 | |||
| 1e03507f75 | |||
| e37a98fdcc | |||
| 6ae0471fa2 | |||
| a1a995777b | |||
| 3d12f0c160 | |||
| 10aad47124 | |||
| 75b62d0854 | |||
| 527f163346 | |||
| 0f79495775 | |||
| 6ae7166d34 | |||
| dcd8b460c1 | |||
| dbbe04d4cc | |||
| 1ed6290628 | |||
| 91a7273964 | |||
| b1bb8b919f | |||
| 697767f0de | |||
| 306a783d67 | |||
| 03035138ac | |||
| 7323f52153 | |||
| f5842f9c4a | |||
| e3ac91bf48 | |||
| dba448b9c1 | |||
| d8551b3a27 | |||
| 8f2c7493d0 | |||
| f7f97fcdcb | |||
| 9ac6b6e04c | |||
| e77896c1d4 | |||
| dd2024e96e | |||
| cd9780871f | |||
| 3169eebd14 | |||
| ec902c6196 | |||
| b719a6662b | |||
| 09b407eba8 | |||
| 877c2921d9 | |||
|
|
5ce4964c32 | ||
| b4ccb567b5 | |||
| bcd7bf751b | |||
| 4dbc106e38 | |||
|
|
fb28de5772 | ||
| 236a737fd1 | |||
|
|
f713bd6fb7 | ||
| 94b113eb95 | |||
| 71b2f30d29 | |||
| d2d6852f31 | |||
| 126dc7ed97 | |||
| 40a3c1b82e | |||
|
|
da722c5277 | ||
|
|
516c2afd1e | ||
|
|
9ee9da2ac8 | ||
|
|
aa208bb2ef | ||
|
|
a29123c964 | ||
|
|
8c005d6e5e | ||
|
|
cc50e497c9 | ||
|
|
ae348499d4 | ||
|
|
b443230285 | ||
|
|
099e587d45 | ||
| dc0e536221 | |||
| 2a34243e69 | |||
| 499415e0c5 | |||
| 397c5c1550 | |||
| 738f242eee | |||
| 745aaef978 | |||
| b5234c765c | |||
| 919c9f57ac | |||
| 27424694ce | |||
| 84338f8f66 | |||
| 733df2dcb5 | |||
| 9ba3dd7909 | |||
| 2838376434 | |||
| 86ec4de5c0 | |||
| 479e9a2575 | |||
| d97871d15b | |||
| 00fd6880e9 | |||
| 649330f358 | |||
| 07d81d687b | |||
| b291673899 | |||
| 5fbf2ccb45 | |||
| e489d16c51 | |||
| 7cfffadb86 | |||
| ae529effd2 | |||
| 4c3b2152eb | |||
| 51e3c04e72 | |||
| 2b9f038b0d | |||
| 0653700f9c | |||
| 7be80e6f91 | |||
| a4b934388d | |||
| f8c0dbba5a | |||
| ebb531d825 | |||
| fc9779153d | |||
| a2522cef13 | |||
| 442e1d64a3 | |||
| 54b54796e8 | |||
| 686463720a | |||
| 6a77028171 | |||
| f1bd9c18e0 | |||
| 6c9b742bdf | |||
| 744a402602 | |||
| 2d9148788e | |||
| 18f635e6ef | |||
| 9efbc12909 | |||
| 7c7676abee | |||
| 1faa74f026 | |||
| 3afae89234 | |||
| 093c527591 | |||
| 2ba710ca2d | |||
| 9054b163ce | |||
| e182c815a1 | |||
| c284d10943 | |||
| 72e48ada94 | |||
|
|
4591a6857d | ||
|
|
44279bc148 | ||
|
|
32c7d45809 | ||
|
|
4341c2509e | ||
| a3fa499662 | |||
| f25737cdc5 | |||
| 0b500b5248 | |||
| e71cb11295 | |||
| b102ec4c1c | |||
| 974d6e9b56 | |||
| 694cac7f26 | |||
| bd616c510a | |||
| 424a258df1 | |||
| 6dc74ca82e | |||
| 937f1e3ac8 | |||
| 46d1c25bb5 |
@@ -1,35 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Erstelle eine Meldung für etwas, das nicht Funktioniert, wie es soll.
|
|
||||||
title: ''
|
|
||||||
labels: 'Task/Bug'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Bug Report
|
|
||||||
|
|
||||||
## Beschreibung
|
|
||||||
[Eine klare und prägnante Beschreibung des Bugs]
|
|
||||||
|
|
||||||
## Schritte zur Reproduktion
|
|
||||||
1. Schritt 1
|
|
||||||
2. Schritt 2
|
|
||||||
3. ...
|
|
||||||
|
|
||||||
## Erwartetes Verhalten
|
|
||||||
[Was hätte passieren sollen]
|
|
||||||
|
|
||||||
## Tatsächliches Verhalten
|
|
||||||
[Was tatsächlich passiert ist]
|
|
||||||
|
|
||||||
## Screenshots/Protokolle
|
|
||||||
[Falls zutreffend, füge Screenshots, Error Logs oder Stack Traces hinzu]
|
|
||||||
|
|
||||||
## Umgebung
|
|
||||||
- Plattform: Android, iOS, Web
|
|
||||||
- OS: [z. B. iOS 18.5, Android 14]
|
|
||||||
- Flutter Version: [z.B. 3.35.6]
|
|
||||||
|
|
||||||
## Verwandte Issues
|
|
||||||
[Verweisen Sie auf ähnliche Issues oder PRs]
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
---
|
|
||||||
name: Enhancement
|
|
||||||
about: Enhancements for current features
|
|
||||||
title: ''
|
|
||||||
labels: 'Task\Enhancement'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Enhancement
|
|
||||||
|
|
||||||
## Aktuelles Verhalten
|
|
||||||
[Beschreibe die bestehende Funktionalität]
|
|
||||||
|
|
||||||
## Einschränkungen/Probleme
|
|
||||||
[Was sind die aktuellen Mängel?]
|
|
||||||
|
|
||||||
## Vorgeschlagene Verbesserung
|
|
||||||
[Wie kann das Problem bzw. die Einschränkung verbessert werden?]
|
|
||||||
|
|
||||||
## Zugehörige Issues
|
|
||||||
[Links zu verwandten oder blockierenden Issues]
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature
|
|
||||||
about: Neues Feature für die App
|
|
||||||
title: ''
|
|
||||||
labels: 'Task\Feature'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Feature
|
|
||||||
|
|
||||||
## Beschreibung
|
|
||||||
[Ausführliche Erläuterung der vorgeschlagenen Funktion]
|
|
||||||
|
|
||||||
## Vorgeschlagene Lösung
|
|
||||||
[Beschreibe, wie die Feature funktionieren soll]
|
|
||||||
|
|
||||||
## Zugehörige Issues
|
|
||||||
[Links zu verwandten oder blockierenden Issues]
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# [PR Titel]
|
|
||||||
|
|
||||||
**Zugehörige Issue(s):**
|
|
||||||
Closes `<issue-no>`
|
|
||||||
|
|
||||||
## Beschreibung
|
|
||||||
*Eine klare und prägnante Übersicht über die vorgenommenen Änderungen. Erläutere nicht nur das was gemacht wurde, sondern auch warum.*
|
|
||||||
|
|
||||||
## Änderungen
|
|
||||||
- [ ] Neue Funktion X hinzugefügt
|
|
||||||
- [ ] Bug in Komponente Y behoben
|
|
||||||
- [ ] Modul Z für bessere Leistung refactored
|
|
||||||
- [ ] Dependencies aktualisiert
|
|
||||||
|
|
||||||
## Zusätzliche Anmerkungen
|
|
||||||
*Gibt es zusätzlichen Kontext, Einschränkungen oder Informationen, die Reviewer wissen sollten?*
|
|
||||||
53
.gitea/issue_template/bug.yaml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
name: Bug Report
|
||||||
|
about: Erstelle eine Bug Report
|
||||||
|
labels: 'Task/Bug'
|
||||||
|
title: ''
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Beschreibung
|
||||||
|
description: Beschreibe klar und pregnant das Fehlerverhalten
|
||||||
|
placeholder: |
|
||||||
|
- Was genau ist das unerwünschte Verhalten?
|
||||||
|
- Welche Auswirkungen hat der Fehler?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: reproduce
|
||||||
|
attributes:
|
||||||
|
label: Schritte zur Reproduktion
|
||||||
|
description: Beschreibe, wie der Fehler reproduziert werden kann
|
||||||
|
placeholder: |
|
||||||
|
- 1. Schritt 1
|
||||||
|
- 2. Schritt 2
|
||||||
|
- 3. ...
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: enviroment
|
||||||
|
attributes:
|
||||||
|
label: Umgebung
|
||||||
|
description: Gebe an, auf welchen Platformen dieser Fehler auftritt
|
||||||
|
list: false
|
||||||
|
multiple: true
|
||||||
|
options: ['Android', 'iOS']
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: solution
|
||||||
|
attributes:
|
||||||
|
label: Lösungsidee
|
||||||
|
description: Beschreibe, wie das Problem bzw. gelöst werden kann
|
||||||
|
placeholder: |
|
||||||
|
- Button X ändern, sodass ...
|
||||||
|
- Funktion X so erweitern, dass ...
|
||||||
|
- Design anpassen, sodass ...
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Verwandte Issues
|
||||||
|
description: Verweise auf ähnliche Issues oder PRs
|
||||||
|
placeholder: |
|
||||||
|
- Knüpft an Issue #35 an
|
||||||
|
- Ersetzt Issue #12
|
||||||
|
- Brauch Implementierung von #43
|
||||||
36
.gitea/issue_template/enhancement.yaml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
name: Enhancement
|
||||||
|
about: Erstelle ein Enhancement-Ticket
|
||||||
|
labels: 'Task/Enhancement'
|
||||||
|
title: ''
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Aktuelles Verhalten
|
||||||
|
description: Beschreibe, wie die Funktionalität aktuell gestaltet ist
|
||||||
|
placeholder: |
|
||||||
|
- Aktuell macht Button X folgendes ...
|
||||||
|
- Das Problem ist, dass ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: solution
|
||||||
|
attributes:
|
||||||
|
label: Vorgeschlagene Verbesserung
|
||||||
|
description: Beschreibe, wie das Problem bzw. die Einschränkung verbessert werden kann
|
||||||
|
placeholder: |
|
||||||
|
- Button X ändern, sodass ...
|
||||||
|
- Funktion X so erweitern, dass ...
|
||||||
|
- Design anpassen, sodass ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Zugehörige Issues
|
||||||
|
description: Links zu verwandten oder blockierenden Issues
|
||||||
|
placeholder: |
|
||||||
|
- Knüpft an Issue #35 an
|
||||||
|
- Ersetzt Issue #12
|
||||||
|
- Brauch Implementierung von #43
|
||||||
36
.gitea/issue_template/feature.yaml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
name: Feature
|
||||||
|
about: Erstelle ein Feature-Ticket
|
||||||
|
labels: 'Task/Feature'
|
||||||
|
title: ''
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Beschreibung
|
||||||
|
description: Ausführliche Erläuterung der vorgeschlagenen Funktion
|
||||||
|
placeholder: |
|
||||||
|
- Welchen Zweck erfüllt das Feature?
|
||||||
|
- Welches Problem löst das Feature?
|
||||||
|
- Wer profitiert davon?
|
||||||
|
- Warum ist es wichtig?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: solution
|
||||||
|
attributes:
|
||||||
|
label: Vorgeschlagene Lösung
|
||||||
|
description: Beschreibe, wie das Feature funktionieren soll
|
||||||
|
placeholder: |
|
||||||
|
- Neues Widget, das folgendermaßen aussieht ...
|
||||||
|
- Neue Ansicht, die folgende Inhalte hat
|
||||||
|
- Neue Funktionsweise von Komponente XY
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Zugehörige Issues
|
||||||
|
description: Links zu verwandten oder blockierenden Issues
|
||||||
|
placeholder: |
|
||||||
|
- Knüpft an Issue #35 an
|
||||||
|
- Ersetzt Issue #12
|
||||||
|
- Brauch Implementierung von #43
|
||||||
47
.gitea/pull_request_template.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: Pull Request
|
||||||
|
about: Vorlage für Pull Requests
|
||||||
|
title: "WIP: [Name des Issues]"
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: input
|
||||||
|
id: related_issue
|
||||||
|
attributes:
|
||||||
|
label: Zugehörige Issue(s)
|
||||||
|
description: Issues welche mit diesem Pull Request geschlossen werden sollen
|
||||||
|
placeholder: "Closes #123"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Beschreibung
|
||||||
|
description: |
|
||||||
|
Eine klare und prägnante Zusammenfassung aller vorgenommenen Änderungen.
|
||||||
|
placeholder: |
|
||||||
|
Was wurde geändert?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: changes
|
||||||
|
attributes:
|
||||||
|
label: Änderungen
|
||||||
|
description: Liste alle Änderungen detailiert auf, die in diesem Pull Request vorgenommen wurden.
|
||||||
|
placeholder: |
|
||||||
|
- Neue Funktion X hinzugefügt
|
||||||
|
- Bug in Komponente X behoben
|
||||||
|
- Modul X für bessere Leistung refactored
|
||||||
|
- Dependencies aktualisiert
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: additional_notes
|
||||||
|
attributes:
|
||||||
|
label: Zusätzliche Anmerkungen
|
||||||
|
description: |
|
||||||
|
Gibt es zusätzlichen Kontext, Einschränkungen oder Informationen,
|
||||||
|
die Reviewer wissen sollten?
|
||||||
|
placeholder: |
|
||||||
|
- Bekannte Einschränkungen
|
||||||
|
- Offene TODOs
|
||||||
|
- Hinweise für Reviewer
|
||||||
@@ -10,22 +10,22 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# Required for Flutter action
|
||||||
- name: Install jq
|
- name: Install jq
|
||||||
run: |
|
run: |
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y jq
|
apt-get install -y jq
|
||||||
|
|
||||||
- name: Install Flutter (wget)
|
- name: Set up Flutter
|
||||||
run: |
|
uses: subosito/flutter-action@v2
|
||||||
wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
|
with:
|
||||||
tar xf flutter_linux_3.38.2-stable.tar.xz
|
channel: stable
|
||||||
# Set Git safe directory for Flutter path
|
flutter-version: 3.38.6
|
||||||
git config --global --add safe.directory "$(pwd)/flutter"
|
|
||||||
# Set Flutter path
|
|
||||||
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Get dependencies
|
- 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
|
- name: Analyze Formatting
|
||||||
run: flutter analyze lib test
|
run: flutter analyze lib test
|
||||||
@@ -36,22 +36,22 @@ jobs:
|
|||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install dependencies
|
# Required for Flutter action
|
||||||
|
- name: Install jq
|
||||||
run: |
|
run: |
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y jq
|
apt-get install -y jq
|
||||||
|
|
||||||
- name: Install Flutter (wget)
|
- name: Set up Flutter
|
||||||
run: |
|
uses: subosito/flutter-action@v2
|
||||||
wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
|
with:
|
||||||
tar xf flutter_linux_3.38.2-stable.tar.xz
|
channel: stable
|
||||||
# Set Git safe directory for Flutter path
|
flutter-version: 3.38.6
|
||||||
git config --global --add safe.directory "$(pwd)/flutter"
|
|
||||||
# Set Flutter path
|
|
||||||
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Get dependencies
|
- 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
|
- name: Run tests
|
||||||
run: flutter test
|
run: flutter test
|
||||||
@@ -7,44 +7,194 @@ on:
|
|||||||
- "main"
|
- "main"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
format:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: false # Needs bot user
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
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: |
|
run: |
|
||||||
apt-get update
|
apt-get update
|
||||||
apt-get install -y jq
|
apt-get install -y jq
|
||||||
|
|
||||||
- name: Install Flutter (wget)
|
- name: Set up Flutter
|
||||||
run: |
|
uses: subosito/flutter-action@v2
|
||||||
wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
|
with:
|
||||||
tar xf flutter_linux_3.38.2-stable.tar.xz
|
channel: stable
|
||||||
# Set Git safe directory for Flutter path
|
flutter-version: 3.38.6
|
||||||
git config --global --add safe.directory "$(pwd)/flutter"
|
|
||||||
# Set Flutter path
|
|
||||||
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Get & upgrade dependencies
|
- name: Get dependencies
|
||||||
run: |
|
run: |
|
||||||
|
git config --global --add safe.directory /opt/hostedtoolcache/flutter/stable-3.38.6-x64
|
||||||
flutter pub get
|
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: |
|
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 lib
|
||||||
|
dart fix --apply test
|
||||||
|
|
||||||
# Needs credentials, push access and the right files need to be staged
|
if [ -n "$(git status --porcelain lib test)" ]; then
|
||||||
- name: Commit Changes
|
git config --global user.name "Gitea Actions [bot]"
|
||||||
run: |
|
git config --global user.email "actions@yannick-weigert.de"
|
||||||
git config --global user.name "Gitea Actions"
|
git config pull.rebase false
|
||||||
git config --global user.email "actions@gitea.com"
|
git pull origin ${{ gitea.ref_name }}
|
||||||
git status
|
git add lib test
|
||||||
git add lib/
|
git commit -m "Auto-format code [skip ci]"
|
||||||
git status
|
git push origin HEAD:${{ gitea.ref_name }}
|
||||||
git commit -m "Actions: Auto-formatting [skip ci]"
|
else
|
||||||
git push
|
echo "No changes to commit"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Verify format
|
||||||
|
run: flutter analyze lib test
|
||||||
28
.gitignore
vendored
@@ -150,25 +150,9 @@ app.*.symbols
|
|||||||
.gclient_previous_custom_vars
|
.gclient_previous_custom_vars
|
||||||
.gclient_previous_sync_commits
|
.gclient_previous_sync_commits
|
||||||
|
|
||||||
# Miscellaneous
|
|
||||||
*.class
|
|
||||||
*.log
|
|
||||||
*.pyc
|
|
||||||
*.swp
|
|
||||||
.DS_Store
|
|
||||||
.atom/
|
|
||||||
.build/
|
|
||||||
.buildlog/
|
|
||||||
.history
|
|
||||||
.svn/
|
|
||||||
.swiftpm/
|
.swiftpm/
|
||||||
migrate_working_dir/
|
migrate_working_dir/
|
||||||
|
|
||||||
# IntelliJ related
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
*.iws
|
|
||||||
.idea/
|
|
||||||
|
|
||||||
# The .vscode folder contains launch configuration and tasks you configure in
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
# VS Code which you may wish to be included in version control, so this line
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
@@ -176,17 +160,8 @@ migrate_working_dir/
|
|||||||
#.vscode/
|
#.vscode/
|
||||||
|
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
**/doc/api/
|
|
||||||
**/ios/Flutter/.last_build_id
|
|
||||||
.dart_tool/
|
|
||||||
.flutter-plugins
|
|
||||||
.flutter-plugins-dependencies
|
|
||||||
.pub-cache/
|
|
||||||
.pub/
|
|
||||||
/build/
|
/build/
|
||||||
|
|
||||||
# Symbolication related
|
|
||||||
app.*.symbols
|
|
||||||
|
|
||||||
# Obfuscation related
|
# Obfuscation related
|
||||||
app.*.map.json
|
app.*.map.json
|
||||||
@@ -195,3 +170,6 @@ app.*.map.json
|
|||||||
/android/app/debug
|
/android/app/debug
|
||||||
/android/app/profile
|
/android/app/profile
|
||||||
/android/app/release
|
/android/app/release
|
||||||
|
/devtools_options.yaml
|
||||||
|
|
||||||
|
untranslated_messages.json
|
||||||
13
CONTRIBUTING.md
Normal 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
@@ -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.
|
||||||
66
README.md
@@ -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>
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## 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).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
|
|
||||||
A all-in-one app to track card- and board games, manage players and groups and get statistics about your played games.
|
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ linter:
|
|||||||
prefer_const_literals_to_create_immutables: true
|
prefer_const_literals_to_create_immutables: true
|
||||||
unnecessary_const: true
|
unnecessary_const: true
|
||||||
lines_longer_than_80_chars: false
|
lines_longer_than_80_chars: false
|
||||||
|
constant_identifier_names: false
|
||||||
@@ -6,7 +6,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.example.game_tracker"
|
namespace = "de.liquid.tallee"
|
||||||
compileSdk = flutter.compileSdkVersion
|
compileSdk = flutter.compileSdkVersion
|
||||||
ndkVersion = flutter.ndkVersion
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// 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.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||||
minSdk = flutter.minSdkVersion
|
minSdk = flutter.minSdkVersion
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<application
|
<application
|
||||||
android:label="game_tracker"
|
android:label="Tallee"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
android:screenOrientation="portrait"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:taskAffinity=""
|
android:taskAffinity=""
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
@@ -41,5 +43,14 @@
|
|||||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||||
<data android:mimeType="text/plain"/>
|
<data android:mimeType="text/plain"/>
|
||||||
</intent>
|
</intent>
|
||||||
|
<!-- Required for url_launcher to open URLs in external browser -->
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="http" />
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 17 KiB |
@@ -1,4 +1,4 @@
|
|||||||
package com.example.game_tracker
|
package de.liquid.tallee
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 828 B After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 448 B After Width: | Height: | Size: 884 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 656 B After Width: | Height: | Size: 938 B |
|
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 596 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 508 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 704 B After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 824 B After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 9.0 KiB |
@@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="app_icon_background">#E6F1E4</color>
|
<color name="launch_background">#ef681f</color>
|
||||||
<color name="launch_background">#0B0B0B</color>
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Referenz unbedingt als @color/launch_background (nicht @colors/...) -->
|
<color name="ic_launcher_background">#EF681F</color>
|
||||||
<color name="ic_launcher_background">@color/app_icon_background</color>
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -18,7 +18,7 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||||
id("com.android.application") version "8.7.3" apply false
|
id("com.android.application") version "8.9.1" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
|
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
artefacts/app-logo.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
artefacts/screenshot-1.png
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
artefacts/screenshot-2.png
Normal file
|
After Width: | Height: | Size: 279 KiB |
BIN
artefacts/screenshot-3.png
Normal file
|
After Width: | Height: | Size: 354 KiB |
BIN
artefacts/screenshot-4.png
Normal file
|
After Width: | Height: | Size: 294 KiB |
@@ -2,178 +2,103 @@
|
|||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"games": {
|
"players": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": [
|
"items": {
|
||||||
{
|
"type": "object",
|
||||||
"type": "object",
|
"properties": {
|
||||||
"properties": {
|
"id": {
|
||||||
"id": {
|
"type": "string"
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"players": {
|
|
||||||
"type": [
|
|
||||||
"array",
|
|
||||||
"null"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"createdAt",
|
|
||||||
"name"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"group": {
|
"createdAt": {
|
||||||
"type": [
|
"type": "string"
|
||||||
"object",
|
|
||||||
"null"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"members": {
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"createdAt",
|
|
||||||
"name"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"createdAt",
|
|
||||||
"name",
|
|
||||||
"members"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"winner": {
|
"name": {
|
||||||
"type": ["object","null"]
|
"type": "string"
|
||||||
},
|
}
|
||||||
"required": [
|
},
|
||||||
"id",
|
"required": [
|
||||||
"createdAt",
|
"id",
|
||||||
"name"
|
"createdAt",
|
||||||
]
|
"name"
|
||||||
}
|
]
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"groups": {
|
"groups": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": [
|
"items": {
|
||||||
{
|
"type": "object",
|
||||||
"type": "object",
|
"properties": {
|
||||||
"properties": {
|
"id": {
|
||||||
"id": {
|
"type": "string"
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"members": {
|
|
||||||
"type": "array",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"createdAt",
|
|
||||||
"name"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"required": [
|
"name": {
|
||||||
"id",
|
"type": "string"
|
||||||
"createdAt",
|
},
|
||||||
"name",
|
"createdAt": {
|
||||||
"members"
|
"type": "string"
|
||||||
]
|
},
|
||||||
}
|
"memberIds": {
|
||||||
]
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"createdAt",
|
||||||
|
"memberIds"
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"players": {
|
"matches": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": [
|
"items": {
|
||||||
{
|
"type": "object",
|
||||||
"type": [
|
"properties": {
|
||||||
"object",
|
"id": {
|
||||||
"null"
|
"type": "string"
|
||||||
],
|
},
|
||||||
"properties": {
|
"name": {
|
||||||
"id": {
|
"type": "string"
|
||||||
"type": "string"
|
},
|
||||||
},
|
"createdAt": {
|
||||||
"createdAt": {
|
"type": "string"
|
||||||
"type": "string"
|
},
|
||||||
},
|
"groupId": {
|
||||||
"name": {
|
"anyOf": [
|
||||||
|
{"type": "string"},
|
||||||
|
{"type": "null"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"playerIds": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"winnerId": {
|
||||||
"id",
|
"anyOf": [
|
||||||
"createdAt",
|
{"type": "string"},
|
||||||
"name"
|
{"type": "null"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"createdAt",
|
||||||
|
"groupId",
|
||||||
|
"playerIds"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"required": [
|
||||||
|
"players",
|
||||||
|
"groups",
|
||||||
|
"matches"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,7 +152,6 @@
|
|||||||
B68CF4A64F0B5E45B43D6900 /* Pods-RunnerTests.release.xcconfig */,
|
B68CF4A64F0B5E45B43D6900 /* Pods-RunnerTests.release.xcconfig */,
|
||||||
E754D1191B3E54E52B6DCC49 /* Pods-RunnerTests.profile.xcconfig */,
|
E754D1191B3E54E52B6DCC49 /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
name = Pods;
|
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -478,7 +477,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker;
|
PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -661,7 +660,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker;
|
PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
@@ -684,7 +683,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker;
|
PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
|||||||
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
@@ -1,14 +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"}]}
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "icon_x1024.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"platform" : "ios",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 8.8 KiB |
@@ -5,9 +5,9 @@
|
|||||||
"color-space" : "srgb",
|
"color-space" : "srgb",
|
||||||
"components" : {
|
"components" : {
|
||||||
"alpha" : "1.000",
|
"alpha" : "1.000",
|
||||||
"blue" : "0.043",
|
"blue" : "0.122",
|
||||||
"green" : "0.043",
|
"green" : "0.408",
|
||||||
"red" : "0.043"
|
"red" : "0.937"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"idiom" : "universal"
|
"idiom" : "universal"
|
||||||
@@ -1,17 +1,8 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename" : "icon.png",
|
"filename" : "icon-transparent.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal"
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
BIN
ios/Runner/Assets.xcassets/LauncherIcon.imageset/icon-transparent.png
vendored
Normal file
|
After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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"/>
|
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<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="Named colors" minToolsVersion="9.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -20,12 +20,19 @@
|
|||||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<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">
|
<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"/>
|
<rect key="frame" x="46" y="334" width="301" height="184"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" name="LauncherBackgroundColor"/>
|
<color key="backgroundColor" name="LauncherColor"/>
|
||||||
</view>
|
</view>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<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"/>
|
<color key="tintColor" red="0.90196078431372551" green="0.94509803921568625" blue="0.89411764705882346" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="LauncherIcon" width="1000" height="1000"/>
|
<image name="LauncherIcon" width="1000" height="1000"/>
|
||||||
<namedColor name="LauncherBackgroundColor">
|
<namedColor name="LauncherColor">
|
||||||
<color red="0.90196078431372551" green="0.94509803921568625" blue="0.89411764705882346" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color red="0.93699997663497925" green="0.40799999237060547" blue="0.12200000137090683" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</namedColor>
|
</namedColor>
|
||||||
</resources>
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
|
<true/>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Game Tracker</string>
|
<string>Tallee</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@@ -13,7 +15,7 @@
|
|||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>game_tracker</string>
|
<string>tallee</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
@@ -22,8 +24,15 @@
|
|||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
|
<key>LSApplicationQueriesSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>https</string>
|
||||||
|
<string>http</string>
|
||||||
|
</array>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
|
<true/>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
<key>UIMainStoryboardFile</key>
|
<key>UIMainStoryboardFile</key>
|
||||||
@@ -31,8 +40,6 @@
|
|||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
</array>
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
<array>
|
<array>
|
||||||
@@ -41,9 +48,5 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
|
||||||
<true/>
|
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
6
l10n.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
arb-dir: lib/l10n/arb
|
||||||
|
template-arb-file: app_en.arb
|
||||||
|
output-localization-file: app_localizations.dart
|
||||||
|
output-dir: lib/l10n/generated
|
||||||
|
nullable-getter: false
|
||||||
|
untranslated-messages-file: lib/l10n/untranslated_messages.json
|
||||||
23
lib/core/adaptive_page_route.dart
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Returns a platform-adaptive page route based on the current platform.
|
||||||
|
/// - On iOS, it returns a [CupertinoPageRoute].
|
||||||
|
/// - On other platforms, it returns a [MaterialPageRoute].
|
||||||
|
Route<T> adaptivePageRoute<T>({
|
||||||
|
required Widget Function(BuildContext) builder,
|
||||||
|
bool fullscreenDialog = false,
|
||||||
|
}) {
|
||||||
|
if (Platform.isIOS) {
|
||||||
|
return CupertinoPageRoute<T>(
|
||||||
|
builder: builder,
|
||||||
|
fullscreenDialog: fullscreenDialog,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return MaterialPageRoute<T>(
|
||||||
|
builder: builder,
|
||||||
|
fullscreenDialog: fullscreenDialog,
|
||||||
|
);
|
||||||
|
}
|
||||||
22
lib/core/constants.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/// Application-wide constants
|
||||||
|
class Constants {
|
||||||
|
Constants._(); // Private constructor to prevent instantiation
|
||||||
|
|
||||||
|
/// Minimum duration of all app skeletons
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -1,22 +1,83 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Theme class that defines colors, border radius, padding, and decorations
|
||||||
class CustomTheme {
|
class CustomTheme {
|
||||||
static Color primaryColor = const Color(0xFF7505E4);
|
CustomTheme._(); // Private constructor to prevent instantiation
|
||||||
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 AppBarTheme appBarTheme = AppBarTheme(
|
// ==================== Colors ====================
|
||||||
|
|
||||||
|
/// 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 Color 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 boxBorderColor = 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);
|
||||||
|
|
||||||
|
/// Background color for the navigation bar
|
||||||
|
static const Color navBarBackgroundColor = Color(0xFF131313);
|
||||||
|
|
||||||
|
/// Selected color for the [NavbarItem]
|
||||||
|
static Color navBarItemSelectedColor = primaryColor.withGreen(100);
|
||||||
|
|
||||||
|
/// Unselected color for the [NavbarItem]
|
||||||
|
static Color navBarItemUnselectedColor = Colors.grey.shade400;
|
||||||
|
|
||||||
|
// ==================== Border Radius ====================
|
||||||
|
static const double standardBorderRadius = 12.0;
|
||||||
|
static BorderRadius get standardBorderRadiusAll =>
|
||||||
|
BorderRadius.circular(standardBorderRadius);
|
||||||
|
|
||||||
|
// ==================== Padding & Margins ====================
|
||||||
|
static const EdgeInsets standardMargin = EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 10,
|
||||||
|
);
|
||||||
|
static const EdgeInsets tileMargin = EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 5,
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================== Decorations ====================
|
||||||
|
static BoxDecoration standardBoxDecoration = BoxDecoration(
|
||||||
|
color: boxColor,
|
||||||
|
border: Border.all(color: boxBorderColor),
|
||||||
|
borderRadius: standardBorderRadiusAll,
|
||||||
|
);
|
||||||
|
|
||||||
|
static BoxDecoration highlightedBoxDecoration = BoxDecoration(
|
||||||
|
color: boxColor,
|
||||||
|
border: Border.all(color: primaryColor),
|
||||||
|
borderRadius: standardBorderRadiusAll,
|
||||||
|
boxShadow: [BoxShadow(color: primaryColor.withAlpha(120), blurRadius: 12)],
|
||||||
|
);
|
||||||
|
|
||||||
|
// ==================== App Bar Theme ====================
|
||||||
|
static const AppBarTheme appBarTheme = AppBarTheme(
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: textColor,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
titleTextStyle: const TextStyle(
|
scrolledUnderElevation: 0,
|
||||||
color: Colors.white,
|
centerTitle: true,
|
||||||
|
titleTextStyle: TextStyle(
|
||||||
|
color: textColor,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
iconTheme: const IconThemeData(color: Colors.white),
|
iconTheme: IconThemeData(color: textColor),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
|
||||||
/// Button types used for styling the [CustomWidthButton]
|
/// Button types used for styling the [CustomWidthButton]
|
||||||
|
/// - [ButtonType.primary]: Primary button style.
|
||||||
|
/// - [ButtonType.secondary]: Secondary button style.
|
||||||
|
/// - [ButtonType.tertiary]: Tertiary button style.
|
||||||
enum ButtonType { primary, secondary, tertiary }
|
enum ButtonType { primary, secondary, tertiary }
|
||||||
|
|
||||||
/// Result types for import operations in the [SettingsView]
|
/// Result types for import operations in the [SettingsView]
|
||||||
@@ -22,3 +28,25 @@ enum ImportResult {
|
|||||||
/// - [ExportResult.canceled]: The export operation was canceled by the user.
|
/// - [ExportResult.canceled]: The export operation was canceled by the user.
|
||||||
/// - [ExportResult.unknownException]: An exception occurred during export.
|
/// - [ExportResult.unknownException]: An exception occurred during export.
|
||||||
enum ExportResult { success, canceled, unknownException }
|
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 }
|
||||||
|
|
||||||
|
/// 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.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,256 +0,0 @@
|
|||||||
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:game_tracker/data/dto/group.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
|
|
||||||
part 'game_dao.g.dart';
|
|
||||||
|
|
||||||
@DriftAccessor(tables: [GameTable])
|
|
||||||
class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
|
|
||||||
GameDao(super.db);
|
|
||||||
|
|
||||||
/// Retrieves all games from the database.
|
|
||||||
Future<List<Game>> getAllGames() async {
|
|
||||||
final query = select(gameTable);
|
|
||||||
final result = await query.get();
|
|
||||||
|
|
||||||
return Future.wait(
|
|
||||||
result.map((row) async {
|
|
||||||
final group = await db.groupGameDao.getGroupOfGame(gameId: row.id);
|
|
||||||
final players = await db.playerGameDao.getPlayersOfGame(gameId: row.id);
|
|
||||||
final winner = row.winnerId != null
|
|
||||||
? await db.playerDao.getPlayerById(playerId: row.winnerId!)
|
|
||||||
: null;
|
|
||||||
return Game(
|
|
||||||
id: row.id,
|
|
||||||
name: row.name,
|
|
||||||
group: group,
|
|
||||||
players: players,
|
|
||||||
createdAt: row.createdAt,
|
|
||||||
winner: winner,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves a [Game] by its [gameId].
|
|
||||||
Future<Game> getGameById({required String gameId}) async {
|
|
||||||
final query = select(gameTable)..where((g) => g.id.equals(gameId));
|
|
||||||
final result = await query.getSingle();
|
|
||||||
|
|
||||||
List<Player>? players;
|
|
||||||
if (await db.playerGameDao.gameHasPlayers(gameId: gameId)) {
|
|
||||||
players = await db.playerGameDao.getPlayersOfGame(gameId: gameId);
|
|
||||||
}
|
|
||||||
Group? group;
|
|
||||||
if (await db.groupGameDao.gameHasGroup(gameId: gameId)) {
|
|
||||||
group = await db.groupGameDao.getGroupOfGame(gameId: gameId);
|
|
||||||
}
|
|
||||||
Player? winner;
|
|
||||||
if (result.winnerId != null) {
|
|
||||||
winner = await db.playerDao.getPlayerById(playerId: result.winnerId!);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Game(
|
|
||||||
id: result.id,
|
|
||||||
name: result.name,
|
|
||||||
players: players,
|
|
||||||
group: group,
|
|
||||||
winner: winner,
|
|
||||||
createdAt: result.createdAt,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a new [Game] to the database.
|
|
||||||
/// Also adds associated players and group if they exist.
|
|
||||||
Future<void> addGame({required Game game}) async {
|
|
||||||
await db.transaction(() async {
|
|
||||||
await into(gameTable).insert(
|
|
||||||
GameTableCompanion.insert(
|
|
||||||
id: game.id,
|
|
||||||
name: game.name,
|
|
||||||
winnerId: Value(game.winner?.id),
|
|
||||||
createdAt: game.createdAt,
|
|
||||||
),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (game.players != null) {
|
|
||||||
await db.playerDao.addPlayers(players: game.players!);
|
|
||||||
for (final p in game.players ?? []) {
|
|
||||||
await db.playerGameDao.addPlayerToGame(
|
|
||||||
gameId: game.id,
|
|
||||||
playerId: p.id,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (game.group != null) {
|
|
||||||
await db.groupDao.addGroup(group: game.group!);
|
|
||||||
await db.groupGameDao.addGroupToGame(game.id, game.group!.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> addGames({required List<Game> games}) async {
|
|
||||||
if (games.isEmpty) return;
|
|
||||||
await db.transaction(() async {
|
|
||||||
// Add all games in batch
|
|
||||||
await db.batch(
|
|
||||||
(b) => b.insertAll(
|
|
||||||
gameTable,
|
|
||||||
games
|
|
||||||
.map(
|
|
||||||
(game) => GameTableCompanion.insert(
|
|
||||||
id: game.id,
|
|
||||||
name: game.name,
|
|
||||||
createdAt: game.createdAt,
|
|
||||||
winnerId: Value(game.winner?.id),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add all groups of the games in batch
|
|
||||||
await db.batch(
|
|
||||||
(b) => b.insertAll(
|
|
||||||
db.groupTable,
|
|
||||||
games
|
|
||||||
.where((game) => game.group != null)
|
|
||||||
.map(
|
|
||||||
(game) => GroupTableCompanion.insert(
|
|
||||||
id: game.group!.id,
|
|
||||||
name: game.group!.name,
|
|
||||||
createdAt: game.group!.createdAt,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add all players of the games in batch (unique)
|
|
||||||
final uniquePlayers = <String, Player>{};
|
|
||||||
for (final game in games) {
|
|
||||||
if (game.players != null) {
|
|
||||||
for (final p in game.players!) {
|
|
||||||
uniquePlayers[p.id] = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Also include members of groups
|
|
||||||
if (game.group != null) {
|
|
||||||
for (final m in game.group!.members) {
|
|
||||||
uniquePlayers[m.id] = m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uniquePlayers.isNotEmpty) {
|
|
||||||
await db.batch(
|
|
||||||
(b) => b.insertAll(
|
|
||||||
db.playerTable,
|
|
||||||
uniquePlayers.values
|
|
||||||
.map(
|
|
||||||
(p) => PlayerTableCompanion.insert(
|
|
||||||
id: p.id,
|
|
||||||
name: p.name,
|
|
||||||
createdAt: p.createdAt,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add all player-game associations in batch
|
|
||||||
await db.batch((b) {
|
|
||||||
for (final game in games) {
|
|
||||||
if (game.players != null) {
|
|
||||||
for (final p in game.players ?? []) {
|
|
||||||
b.insert(
|
|
||||||
db.playerGameTable,
|
|
||||||
PlayerGameTableCompanion.insert(
|
|
||||||
gameId: game.id,
|
|
||||||
playerId: p.id,
|
|
||||||
),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add all player-group associations in batch
|
|
||||||
await db.batch((b) {
|
|
||||||
for (final game in games) {
|
|
||||||
if (game.group != null) {
|
|
||||||
for (final m in game.group!.members) {
|
|
||||||
b.insert(
|
|
||||||
db.playerGroupTable,
|
|
||||||
PlayerGroupTableCompanion.insert(
|
|
||||||
playerId: m.id,
|
|
||||||
groupId: game.group!.id,
|
|
||||||
),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add all group-game associations in batch
|
|
||||||
await db.batch((b) {
|
|
||||||
for (final game in games) {
|
|
||||||
if (game.group != null) {
|
|
||||||
b.insert(
|
|
||||||
db.groupGameTable,
|
|
||||||
GroupGameTableCompanion.insert(
|
|
||||||
gameId: game.id,
|
|
||||||
groupId: game.group!.id,
|
|
||||||
),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes the game with the given [gameId] from the database.
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> deleteGame({required String gameId}) async {
|
|
||||||
final query = delete(gameTable)..where((g) => g.id.equals(gameId));
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the number 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();
|
|
||||||
return count ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if a game with the given [gameId] exists in the database.
|
|
||||||
/// Returns `true` if the game exists, otherwise `false`.
|
|
||||||
Future<bool> gameExists({required String gameId}) async {
|
|
||||||
final query = select(gameTable)..where((g) => g.id.equals(gameId));
|
|
||||||
final result = await query.getSingleOrNull();
|
|
||||||
return result != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes all games from the database.
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> deleteAllGames() async {
|
|
||||||
final query = delete(gameTable);
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'game_dao.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
mixin _$GameDaoMixin on DatabaseAccessor<AppDatabase> {
|
|
||||||
$GameTableTable get gameTable => attachedDatabase.gameTable;
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
import 'package:tallee/data/db/database.dart';
|
||||||
import 'package:game_tracker/data/db/tables/group_table.dart';
|
import 'package:tallee/data/db/tables/group_table.dart';
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
import 'package:tallee/data/db/tables/player_group_table.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:tallee/data/dto/group.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
|
||||||
part 'group_dao.g.dart';
|
part 'group_dao.g.dart';
|
||||||
|
|
||||||
@DriftAccessor(tables: [GroupTable])
|
@DriftAccessor(tables: [GroupTable, PlayerGroupTable])
|
||||||
class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
||||||
GroupDao(super.db);
|
GroupDao(super.db);
|
||||||
|
|
||||||
@@ -84,7 +85,7 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
|||||||
|
|
||||||
/// Adds multiple groups to the database.
|
/// Adds multiple groups to the database.
|
||||||
/// Also adds the group's members to the [PlayerGroupTable].
|
/// Also adds the group's members to the [PlayerGroupTable].
|
||||||
Future<void> addGroups({required List<Group> groups}) async {
|
Future<void> addGroupsAsList({required List<Group> groups}) async {
|
||||||
if (groups.isEmpty) return;
|
if (groups.isEmpty) return;
|
||||||
await db.transaction(() async {
|
await db.transaction(() async {
|
||||||
// Deduplicate groups by id - keep first occurrence
|
// Deduplicate groups by id - keep first occurrence
|
||||||
@@ -94,6 +95,8 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Insert unique groups in batch
|
// Insert unique groups in batch
|
||||||
|
// Using insertOrIgnore to avoid triggering cascade deletes on
|
||||||
|
// player_group associations when groups already exist
|
||||||
await db.batch(
|
await db.batch(
|
||||||
(b) => b.insertAll(
|
(b) => b.insertAll(
|
||||||
groupTable,
|
groupTable,
|
||||||
@@ -106,7 +109,7 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
mode: InsertMode.insertOrReplace,
|
mode: InsertMode.insertOrIgnore,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -119,6 +122,8 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (uniquePlayers.isNotEmpty) {
|
if (uniquePlayers.isNotEmpty) {
|
||||||
|
// Using insertOrIgnore to avoid triggering cascade deletes on
|
||||||
|
// player_group associations when players already exist
|
||||||
await db.batch(
|
await db.batch(
|
||||||
(b) => b.insertAll(
|
(b) => b.insertAll(
|
||||||
db.playerTable,
|
db.playerTable,
|
||||||
@@ -131,7 +136,7 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
mode: InsertMode.insertOrReplace,
|
mode: InsertMode.insertOrIgnore,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,4 +5,7 @@ part of 'group_dao.dart';
|
|||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
mixin _$GroupDaoMixin on DatabaseAccessor<AppDatabase> {
|
mixin _$GroupDaoMixin on DatabaseAccessor<AppDatabase> {
|
||||||
$GroupTableTable get groupTable => attachedDatabase.groupTable;
|
$GroupTableTable get groupTable => attachedDatabase.groupTable;
|
||||||
|
$PlayerTableTable get playerTable => attachedDatabase.playerTable;
|
||||||
|
$PlayerGroupTableTable get playerGroupTable =>
|
||||||
|
attachedDatabase.playerGroupTable;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/group_game_table.dart';
|
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
|
||||||
|
|
||||||
part 'group_game_dao.g.dart';
|
|
||||||
|
|
||||||
@DriftAccessor(tables: [GroupGameTable])
|
|
||||||
class GroupGameDao extends DatabaseAccessor<AppDatabase>
|
|
||||||
with _$GroupGameDaoMixin {
|
|
||||||
GroupGameDao(super.db);
|
|
||||||
|
|
||||||
/// Associates a group with a game by inserting a record into the
|
|
||||||
/// [GroupGameTable].
|
|
||||||
Future<void> addGroupToGame(String gameId, String groupId) async {
|
|
||||||
await into(groupGameTable).insert(
|
|
||||||
GroupGameTableCompanion.insert(groupId: groupId, gameId: gameId),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the [Group] associated with the given [gameId].
|
|
||||||
/// Returns `null` if no group is found.
|
|
||||||
Future<Group?> getGroupOfGame({required String gameId}) async {
|
|
||||||
final result = await (select(
|
|
||||||
groupGameTable,
|
|
||||||
)..where((g) => g.gameId.equals(gameId))).getSingleOrNull();
|
|
||||||
|
|
||||||
if (result == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final group = await db.groupDao.getGroupById(groupId: result.groupId);
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if there is a group associated with the given [gameId].
|
|
||||||
/// Returns `true` if there is a group, otherwise `false`.
|
|
||||||
Future<bool> gameHasGroup({required String gameId}) async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(groupGameTable)
|
|
||||||
..where(groupGameTable.gameId.equals(gameId))
|
|
||||||
..addColumns([groupGameTable.groupId.count()]))
|
|
||||||
.map((row) => row.read(groupGameTable.groupId.count()))
|
|
||||||
.getSingle();
|
|
||||||
return (count ?? 0) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if a specific group is associated with a specific game.
|
|
||||||
/// Returns `true` if the group is in the game, otherwise `false`.
|
|
||||||
Future<bool> isGroupInGame({
|
|
||||||
required String gameId,
|
|
||||||
required String groupId,
|
|
||||||
}) async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(groupGameTable)
|
|
||||||
..where(
|
|
||||||
groupGameTable.gameId.equals(gameId) &
|
|
||||||
groupGameTable.groupId.equals(groupId),
|
|
||||||
)
|
|
||||||
..addColumns([groupGameTable.groupId.count()]))
|
|
||||||
.map((row) => row.read(groupGameTable.groupId.count()))
|
|
||||||
.getSingle();
|
|
||||||
return (count ?? 0) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes the association of a group from a game based on [groupId] and
|
|
||||||
/// [gameId].
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> removeGroupFromGame({
|
|
||||||
required String gameId,
|
|
||||||
required String groupId,
|
|
||||||
}) async {
|
|
||||||
final query = delete(groupGameTable)
|
|
||||||
..where((g) => g.gameId.equals(gameId) & g.groupId.equals(groupId));
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'group_game_dao.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
mixin _$GroupGameDaoMixin on DatabaseAccessor<AppDatabase> {
|
|
||||||
$GroupTableTable get groupTable => attachedDatabase.groupTable;
|
|
||||||
$GameTableTable get gameTable => attachedDatabase.gameTable;
|
|
||||||
$GroupGameTableTable get groupGameTable => attachedDatabase.groupGameTable;
|
|
||||||
}
|
|
||||||
98
lib/data/dao/group_match_dao.dart
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/db/tables/group_match_table.dart';
|
||||||
|
import 'package:tallee/data/dto/group.dart';
|
||||||
|
|
||||||
|
part 'group_match_dao.g.dart';
|
||||||
|
|
||||||
|
@DriftAccessor(tables: [GroupMatchTable])
|
||||||
|
class GroupMatchDao extends DatabaseAccessor<AppDatabase>
|
||||||
|
with _$GroupMatchDaoMixin {
|
||||||
|
GroupMatchDao(super.db);
|
||||||
|
|
||||||
|
/// Associates a group with a match by inserting a record into the
|
||||||
|
/// [GroupMatchTable].
|
||||||
|
Future<void> addGroupToMatch({
|
||||||
|
required String matchId,
|
||||||
|
required String groupId,
|
||||||
|
}) async {
|
||||||
|
if (await matchHasGroup(matchId: matchId)) {
|
||||||
|
throw Exception('Match already has a group');
|
||||||
|
}
|
||||||
|
await into(groupMatchTable).insert(
|
||||||
|
GroupMatchTableCompanion.insert(groupId: groupId, matchId: matchId),
|
||||||
|
mode: InsertMode.insertOrIgnore,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the [Group] associated with the given [matchId].
|
||||||
|
/// Returns `null` if no group is found.
|
||||||
|
Future<Group?> getGroupOfMatch({required String matchId}) async {
|
||||||
|
final result = await (select(
|
||||||
|
groupMatchTable,
|
||||||
|
)..where((g) => g.matchId.equals(matchId))).getSingleOrNull();
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final group = await db.groupDao.getGroupById(groupId: result.groupId);
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if there is a group associated with the given [matchId].
|
||||||
|
/// Returns `true` if there is a group, otherwise `false`.
|
||||||
|
Future<bool> matchHasGroup({required String matchId}) async {
|
||||||
|
final count =
|
||||||
|
await (selectOnly(groupMatchTable)
|
||||||
|
..where(groupMatchTable.matchId.equals(matchId))
|
||||||
|
..addColumns([groupMatchTable.groupId.count()]))
|
||||||
|
.map((row) => row.read(groupMatchTable.groupId.count()))
|
||||||
|
.getSingle();
|
||||||
|
return (count ?? 0) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a specific group is associated with a specific match.
|
||||||
|
/// Returns `true` if the group is in the match, otherwise `false`.
|
||||||
|
Future<bool> isGroupInMatch({
|
||||||
|
required String matchId,
|
||||||
|
required String groupId,
|
||||||
|
}) async {
|
||||||
|
final count =
|
||||||
|
await (selectOnly(groupMatchTable)
|
||||||
|
..where(
|
||||||
|
groupMatchTable.matchId.equals(matchId) &
|
||||||
|
groupMatchTable.groupId.equals(groupId),
|
||||||
|
)
|
||||||
|
..addColumns([groupMatchTable.groupId.count()]))
|
||||||
|
.map((row) => row.read(groupMatchTable.groupId.count()))
|
||||||
|
.getSingle();
|
||||||
|
return (count ?? 0) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the association of a group from a match based on [groupId] and
|
||||||
|
/// [matchId].
|
||||||
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
|
Future<bool> removeGroupFromMatch({
|
||||||
|
required String matchId,
|
||||||
|
required String groupId,
|
||||||
|
}) async {
|
||||||
|
final query = delete(groupMatchTable)
|
||||||
|
..where((g) => g.matchId.equals(matchId) & g.groupId.equals(groupId));
|
||||||
|
final rowsAffected = await query.go();
|
||||||
|
return rowsAffected > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates the group associated with a match to [newGroupId] based on
|
||||||
|
/// [matchId].
|
||||||
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
|
Future<bool> updateGroupOfMatch({
|
||||||
|
required String matchId,
|
||||||
|
required String newGroupId,
|
||||||
|
}) async {
|
||||||
|
final updatedRows =
|
||||||
|
await (update(groupMatchTable)..where((g) => g.matchId.equals(matchId)))
|
||||||
|
.write(GroupMatchTableCompanion(groupId: Value(newGroupId)));
|
||||||
|
return updatedRows > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
lib/data/dao/group_match_dao.g.dart
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'group_match_dao.dart';
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
mixin _$GroupMatchDaoMixin on DatabaseAccessor<AppDatabase> {
|
||||||
|
$GroupTableTable get groupTable => attachedDatabase.groupTable;
|
||||||
|
$MatchTableTable get matchTable => attachedDatabase.matchTable;
|
||||||
|
$GroupMatchTableTable get groupMatchTable => attachedDatabase.groupMatchTable;
|
||||||
|
}
|
||||||
326
lib/data/dao/match_dao.dart
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/db/tables/match_table.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';
|
||||||
|
|
||||||
|
@DriftAccessor(tables: [MatchTable])
|
||||||
|
class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
||||||
|
MatchDao(super.db);
|
||||||
|
|
||||||
|
/// Retrieves all matches from the database.
|
||||||
|
Future<List<Match>> getAllMatches() async {
|
||||||
|
final query = select(matchTable);
|
||||||
|
final result = await query.get();
|
||||||
|
|
||||||
|
return Future.wait(
|
||||||
|
result.map((row) async {
|
||||||
|
final group = await db.groupMatchDao.getGroupOfMatch(matchId: row.id);
|
||||||
|
final players = await db.playerMatchDao.getPlayersOfMatch(
|
||||||
|
matchId: row.id,
|
||||||
|
);
|
||||||
|
final winner = row.winnerId != null
|
||||||
|
? await db.playerDao.getPlayerById(playerId: row.winnerId!)
|
||||||
|
: null;
|
||||||
|
return Match(
|
||||||
|
id: row.id,
|
||||||
|
name: row.name,
|
||||||
|
group: group,
|
||||||
|
players: players,
|
||||||
|
createdAt: row.createdAt,
|
||||||
|
winner: winner,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves a [Match] by its [matchId].
|
||||||
|
Future<Match> getMatchById({required String matchId}) async {
|
||||||
|
final query = select(matchTable)..where((g) => g.id.equals(matchId));
|
||||||
|
final result = await query.getSingle();
|
||||||
|
|
||||||
|
List<Player>? players;
|
||||||
|
if (await db.playerMatchDao.matchHasPlayers(matchId: matchId)) {
|
||||||
|
players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId);
|
||||||
|
}
|
||||||
|
Group? group;
|
||||||
|
if (await db.groupMatchDao.matchHasGroup(matchId: matchId)) {
|
||||||
|
group = await db.groupMatchDao.getGroupOfMatch(matchId: matchId);
|
||||||
|
}
|
||||||
|
Player? winner;
|
||||||
|
if (result.winnerId != null) {
|
||||||
|
winner = await db.playerDao.getPlayerById(playerId: result.winnerId!);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Match(
|
||||||
|
id: result.id,
|
||||||
|
name: result.name,
|
||||||
|
players: players,
|
||||||
|
group: group,
|
||||||
|
winner: winner,
|
||||||
|
createdAt: result.createdAt,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a new [Match] to the database. Also adds players and group
|
||||||
|
/// associations. This method assumes that the players and groups added to
|
||||||
|
/// this match are already present in the database.
|
||||||
|
Future<void> addMatch({required Match match}) async {
|
||||||
|
await db.transaction(() async {
|
||||||
|
await into(matchTable).insert(
|
||||||
|
MatchTableCompanion.insert(
|
||||||
|
id: match.id,
|
||||||
|
name: match.name,
|
||||||
|
winnerId: Value(match.winner?.id),
|
||||||
|
createdAt: match.createdAt,
|
||||||
|
),
|
||||||
|
mode: InsertMode.insertOrReplace,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (match.players != null) {
|
||||||
|
for (final p in match.players ?? []) {
|
||||||
|
await db.playerMatchDao.addPlayerToMatch(
|
||||||
|
matchId: match.id,
|
||||||
|
playerId: p.id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match.group != null) {
|
||||||
|
await db.groupMatchDao.addGroupToMatch(
|
||||||
|
matchId: match.id,
|
||||||
|
groupId: match.group!.id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds multiple [Match]s to the database in a batch operation.
|
||||||
|
/// Also adds associated players and groups if they exist.
|
||||||
|
/// If the [matches] list is empty, the method returns immediately.
|
||||||
|
/// This Method should only be used to import matches from a different device.
|
||||||
|
Future<void> addMatchAsList({required List<Match> matches}) async {
|
||||||
|
if (matches.isEmpty) return;
|
||||||
|
await db.transaction(() async {
|
||||||
|
// Add all matches in batch
|
||||||
|
await db.batch(
|
||||||
|
(b) => b.insertAll(
|
||||||
|
matchTable,
|
||||||
|
matches
|
||||||
|
.map(
|
||||||
|
(match) => MatchTableCompanion.insert(
|
||||||
|
id: match.id,
|
||||||
|
name: match.name,
|
||||||
|
createdAt: match.createdAt,
|
||||||
|
winnerId: Value(match.winner?.id),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
mode: InsertMode.insertOrReplace,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add all groups of the matches in batch
|
||||||
|
// Using insertOrIgnore to avoid overwriting existing groups (which would
|
||||||
|
// trigger cascade deletes on player_group associations)
|
||||||
|
await db.batch(
|
||||||
|
(b) => b.insertAll(
|
||||||
|
db.groupTable,
|
||||||
|
matches
|
||||||
|
.where((match) => match.group != null)
|
||||||
|
.map(
|
||||||
|
(matches) => GroupTableCompanion.insert(
|
||||||
|
id: matches.group!.id,
|
||||||
|
name: matches.group!.name,
|
||||||
|
createdAt: matches.group!.createdAt,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
mode: InsertMode.insertOrIgnore,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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!) {
|
||||||
|
uniquePlayers[p.id] = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Also include members of groups
|
||||||
|
if (match.group != null) {
|
||||||
|
for (final m in match.group!.members) {
|
||||||
|
uniquePlayers[m.id] = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uniquePlayers.isNotEmpty) {
|
||||||
|
// Using insertOrIgnore to avoid triggering cascade deletes on
|
||||||
|
// player_group/player_match associations when players already exist
|
||||||
|
await db.batch(
|
||||||
|
(b) => b.insertAll(
|
||||||
|
db.playerTable,
|
||||||
|
uniquePlayers.values
|
||||||
|
.map(
|
||||||
|
(p) => PlayerTableCompanion.insert(
|
||||||
|
id: p.id,
|
||||||
|
name: p.name,
|
||||||
|
createdAt: p.createdAt,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
mode: InsertMode.insertOrIgnore,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 ?? []) {
|
||||||
|
b.insert(
|
||||||
|
db.playerMatchTable,
|
||||||
|
PlayerMatchTableCompanion.insert(
|
||||||
|
matchId: match.id,
|
||||||
|
playerId: p.id,
|
||||||
|
),
|
||||||
|
mode: InsertMode.insertOrIgnore,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add all player-group associations in batch
|
||||||
|
await db.batch((b) {
|
||||||
|
for (final match in matches) {
|
||||||
|
if (match.group != null) {
|
||||||
|
for (final m in match.group!.members) {
|
||||||
|
b.insert(
|
||||||
|
db.playerGroupTable,
|
||||||
|
PlayerGroupTableCompanion.insert(
|
||||||
|
playerId: m.id,
|
||||||
|
groupId: match.group!.id,
|
||||||
|
),
|
||||||
|
mode: InsertMode.insertOrIgnore,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add all group-match associations in batch
|
||||||
|
await db.batch((b) {
|
||||||
|
for (final match in matches) {
|
||||||
|
if (match.group != null) {
|
||||||
|
b.insert(
|
||||||
|
db.groupMatchTable,
|
||||||
|
GroupMatchTableCompanion.insert(
|
||||||
|
matchId: match.id,
|
||||||
|
groupId: match.group!.id,
|
||||||
|
),
|
||||||
|
mode: InsertMode.insertOrIgnore,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes the match with the given [matchId] from the database.
|
||||||
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
|
Future<bool> deleteMatch({required String matchId}) async {
|
||||||
|
final query = delete(matchTable)..where((g) => g.id.equals(matchId));
|
||||||
|
final rowsAffected = await query.go();
|
||||||
|
return rowsAffected > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the number of matches in the database.
|
||||||
|
Future<int> getMatchCount() async {
|
||||||
|
final count =
|
||||||
|
await (selectOnly(matchTable)..addColumns([matchTable.id.count()]))
|
||||||
|
.map((row) => row.read(matchTable.id.count()))
|
||||||
|
.getSingle();
|
||||||
|
return count ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a match with the given [matchId] exists in the database.
|
||||||
|
/// Returns `true` if the match exists, otherwise `false`.
|
||||||
|
Future<bool> matchExists({required String matchId}) async {
|
||||||
|
final query = select(matchTable)..where((g) => g.id.equals(matchId));
|
||||||
|
final result = await query.getSingleOrNull();
|
||||||
|
return result != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes all matches from the database.
|
||||||
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
|
Future<bool> deleteAllMatches() async {
|
||||||
|
final query = delete(matchTable);
|
||||||
|
final rowsAffected = await query.go();
|
||||||
|
return rowsAffected > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the winner of the match with the given [matchId] to the player with
|
||||||
|
/// the given [winnerId].
|
||||||
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
|
Future<bool> setWinner({
|
||||||
|
required String matchId,
|
||||||
|
required String winnerId,
|
||||||
|
}) async {
|
||||||
|
final query = update(matchTable)..where((g) => g.id.equals(matchId));
|
||||||
|
final rowsAffected = await query.write(
|
||||||
|
MatchTableCompanion(winnerId: Value(winnerId)),
|
||||||
|
);
|
||||||
|
return rowsAffected > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves the winner of the match with the given [matchId].
|
||||||
|
/// Returns the [Player] who won the match, or `null` if no winner is set.
|
||||||
|
Future<Player?> getWinner({required String matchId}) async {
|
||||||
|
final query = select(matchTable)..where((g) => g.id.equals(matchId));
|
||||||
|
final result = await query.getSingleOrNull();
|
||||||
|
if (result == null || result.winnerId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final winner = await db.playerDao.getPlayerById(playerId: result.winnerId!);
|
||||||
|
return winner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the winner of the match with the given [matchId].
|
||||||
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
|
Future<bool> removeWinner({required String matchId}) async {
|
||||||
|
final query = update(matchTable)..where((g) => g.id.equals(matchId));
|
||||||
|
final rowsAffected = await query.write(
|
||||||
|
const MatchTableCompanion(winnerId: Value(null)),
|
||||||
|
);
|
||||||
|
return rowsAffected > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the match with the given [matchId] has a winner set.
|
||||||
|
/// Returns `true` if a winner is set, otherwise `false`.
|
||||||
|
Future<bool> hasWinner({required String matchId}) async {
|
||||||
|
final query = select(matchTable)
|
||||||
|
..where((g) => g.id.equals(matchId) & g.winnerId.isNotNull());
|
||||||
|
final result = await query.getSingleOrNull();
|
||||||
|
return result != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Changes the title of the match with the given [matchId] to [newName].
|
||||||
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
|
Future<bool> updateMatchName({
|
||||||
|
required String matchId,
|
||||||
|
required String newName,
|
||||||
|
}) async {
|
||||||
|
final query = update(matchTable)..where((g) => g.id.equals(matchId));
|
||||||
|
final rowsAffected = await query.write(
|
||||||
|
MatchTableCompanion(name: Value(newName)),
|
||||||
|
);
|
||||||
|
return rowsAffected > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
lib/data/dao/match_dao.g.dart
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'match_dao.dart';
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
mixin _$MatchDaoMixin on DatabaseAccessor<AppDatabase> {
|
||||||
|
$MatchTableTable get matchTable => attachedDatabase.matchTable;
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
import 'package:tallee/data/db/database.dart';
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
import 'package:tallee/data/db/tables/player_table.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
|
||||||
part 'player_dao.g.dart';
|
part 'player_dao.g.dart';
|
||||||
|
|
||||||
@@ -50,7 +50,9 @@ class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Adds multiple [players] to the database in a batch operation.
|
/// Adds multiple [players] to the database in a batch operation.
|
||||||
Future<bool> addPlayers({required List<Player> players}) async {
|
/// Uses insertOrIgnore to avoid triggering cascade deletes on
|
||||||
|
/// player_group associations when players already exist.
|
||||||
|
Future<bool> addPlayersAsList({required List<Player> players}) async {
|
||||||
if (players.isEmpty) return false;
|
if (players.isEmpty) return false;
|
||||||
|
|
||||||
await db.batch(
|
await db.batch(
|
||||||
@@ -65,7 +67,7 @@ class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
mode: InsertMode.insertOrReplace,
|
mode: InsertMode.insertOrIgnore,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_game_table.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
|
|
||||||
part 'player_game_dao.g.dart';
|
|
||||||
|
|
||||||
@DriftAccessor(tables: [PlayerGameTable])
|
|
||||||
class PlayerGameDao extends DatabaseAccessor<AppDatabase>
|
|
||||||
with _$PlayerGameDaoMixin {
|
|
||||||
PlayerGameDao(super.db);
|
|
||||||
|
|
||||||
/// Associates a player with a game by inserting a record into the
|
|
||||||
/// [PlayerGameTable].
|
|
||||||
Future<void> addPlayerToGame({
|
|
||||||
required String gameId,
|
|
||||||
required String playerId,
|
|
||||||
}) async {
|
|
||||||
await into(playerGameTable).insert(
|
|
||||||
PlayerGameTableCompanion.insert(playerId: playerId, gameId: gameId),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves a list of [Player]s associated with the given [gameId].
|
|
||||||
/// Returns null if no players are found.
|
|
||||||
Future<List<Player>?> getPlayersOfGame({required String gameId}) async {
|
|
||||||
final result = await (select(
|
|
||||||
playerGameTable,
|
|
||||||
)..where((p) => p.gameId.equals(gameId))).get();
|
|
||||||
|
|
||||||
if (result.isEmpty) return null;
|
|
||||||
|
|
||||||
final futures = result.map(
|
|
||||||
(row) => db.playerDao.getPlayerById(playerId: row.playerId),
|
|
||||||
);
|
|
||||||
final players = await Future.wait(futures);
|
|
||||||
return players;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if there are any players associated with the given [gameId].
|
|
||||||
/// Returns `true` if there are players, otherwise `false`.
|
|
||||||
Future<bool> gameHasPlayers({required String gameId}) async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(playerGameTable)
|
|
||||||
..where(playerGameTable.gameId.equals(gameId))
|
|
||||||
..addColumns([playerGameTable.playerId.count()]))
|
|
||||||
.map((row) => row.read(playerGameTable.playerId.count()))
|
|
||||||
.getSingle();
|
|
||||||
return (count ?? 0) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if a specific player is associated with a specific game.
|
|
||||||
/// Returns `true` if the player is in the game, otherwise `false`.
|
|
||||||
Future<bool> isPlayerInGame({
|
|
||||||
required String gameId,
|
|
||||||
required String playerId,
|
|
||||||
}) async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(playerGameTable)
|
|
||||||
..where(playerGameTable.gameId.equals(gameId))
|
|
||||||
..where(playerGameTable.playerId.equals(playerId))
|
|
||||||
..addColumns([playerGameTable.playerId.count()]))
|
|
||||||
.map((row) => row.read(playerGameTable.playerId.count()))
|
|
||||||
.getSingle();
|
|
||||||
return (count ?? 0) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes the association of a player with a game by deleting the record
|
|
||||||
/// from the [PlayerGameTable].
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> removePlayerFromGame({
|
|
||||||
required String gameId,
|
|
||||||
required String playerId,
|
|
||||||
}) async {
|
|
||||||
final query = delete(playerGameTable)
|
|
||||||
..where((pg) => pg.gameId.equals(gameId))
|
|
||||||
..where((pg) => pg.playerId.equals(playerId));
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'player_game_dao.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
mixin _$PlayerGameDaoMixin on DatabaseAccessor<AppDatabase> {
|
|
||||||
$PlayerTableTable get playerTable => attachedDatabase.playerTable;
|
|
||||||
$GameTableTable get gameTable => attachedDatabase.gameTable;
|
|
||||||
$PlayerGameTableTable get playerGameTable => attachedDatabase.playerGameTable;
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
import 'package:tallee/data/db/database.dart';
|
||||||
import 'package:game_tracker/data/db/tables/player_group_table.dart';
|
import 'package:tallee/data/db/tables/player_group_table.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:tallee/data/db/tables/player_table.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
|
||||||
part 'player_group_dao.g.dart';
|
part 'player_group_dao.g.dart';
|
||||||
|
|
||||||
@DriftAccessor(tables: [PlayerGroupTable])
|
@DriftAccessor(tables: [PlayerGroupTable, PlayerTable])
|
||||||
class PlayerGroupDao extends DatabaseAccessor<AppDatabase>
|
class PlayerGroupDao extends DatabaseAccessor<AppDatabase>
|
||||||
with _$PlayerGroupDaoMixin {
|
with _$PlayerGroupDaoMixin {
|
||||||
PlayerGroupDao(super.db);
|
PlayerGroupDao(super.db);
|
||||||
|
|||||||
130
lib/data/dao/player_match_dao.dart
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/db/tables/player_match_table.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
|
||||||
|
part 'player_match_dao.g.dart';
|
||||||
|
|
||||||
|
@DriftAccessor(tables: [PlayerMatchTable])
|
||||||
|
class PlayerMatchDao extends DatabaseAccessor<AppDatabase>
|
||||||
|
with _$PlayerMatchDaoMixin {
|
||||||
|
PlayerMatchDao(super.db);
|
||||||
|
|
||||||
|
/// Associates a player with a match by inserting a record into the
|
||||||
|
/// [PlayerMatchTable].
|
||||||
|
Future<void> addPlayerToMatch({
|
||||||
|
required String matchId,
|
||||||
|
required String playerId,
|
||||||
|
}) async {
|
||||||
|
await into(playerMatchTable).insert(
|
||||||
|
PlayerMatchTableCompanion.insert(playerId: playerId, matchId: matchId),
|
||||||
|
mode: InsertMode.insertOrIgnore,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieves a list of [Player]s associated with the given [matchId].
|
||||||
|
/// Returns null if no players are found.
|
||||||
|
Future<List<Player>?> getPlayersOfMatch({required String matchId}) async {
|
||||||
|
final result = await (select(
|
||||||
|
playerMatchTable,
|
||||||
|
)..where((p) => p.matchId.equals(matchId))).get();
|
||||||
|
|
||||||
|
if (result.isEmpty) return null;
|
||||||
|
|
||||||
|
final futures = result.map(
|
||||||
|
(row) => db.playerDao.getPlayerById(playerId: row.playerId),
|
||||||
|
);
|
||||||
|
final players = await Future.wait(futures);
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if there are any players associated with the given [matchId].
|
||||||
|
/// Returns `true` if there are players, otherwise `false`.
|
||||||
|
Future<bool> matchHasPlayers({required String matchId}) async {
|
||||||
|
final count =
|
||||||
|
await (selectOnly(playerMatchTable)
|
||||||
|
..where(playerMatchTable.matchId.equals(matchId))
|
||||||
|
..addColumns([playerMatchTable.playerId.count()]))
|
||||||
|
.map((row) => row.read(playerMatchTable.playerId.count()))
|
||||||
|
.getSingle();
|
||||||
|
return (count ?? 0) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if a specific player is associated with a specific match.
|
||||||
|
/// Returns `true` if the player is in the match, otherwise `false`.
|
||||||
|
Future<bool> isPlayerInMatch({
|
||||||
|
required String matchId,
|
||||||
|
required String playerId,
|
||||||
|
}) async {
|
||||||
|
final count =
|
||||||
|
await (selectOnly(playerMatchTable)
|
||||||
|
..where(playerMatchTable.matchId.equals(matchId))
|
||||||
|
..where(playerMatchTable.playerId.equals(playerId))
|
||||||
|
..addColumns([playerMatchTable.playerId.count()]))
|
||||||
|
.map((row) => row.read(playerMatchTable.playerId.count()))
|
||||||
|
.getSingle();
|
||||||
|
return (count ?? 0) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes the association of a player with a match by deleting the record
|
||||||
|
/// from the [PlayerMatchTable].
|
||||||
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
|
Future<bool> removePlayerFromMatch({
|
||||||
|
required String matchId,
|
||||||
|
required String playerId,
|
||||||
|
}) async {
|
||||||
|
final query = delete(playerMatchTable)
|
||||||
|
..where((pg) => pg.matchId.equals(matchId))
|
||||||
|
..where((pg) => pg.playerId.equals(playerId));
|
||||||
|
final rowsAffected = await query.go();
|
||||||
|
return rowsAffected > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates the players associated with a match based on the provided
|
||||||
|
/// [newPlayer] list. It adds new players and removes players that are no
|
||||||
|
/// longer associated with the match.
|
||||||
|
Future<void> updatePlayersFromMatch({
|
||||||
|
required String matchId,
|
||||||
|
required List<Player> newPlayer,
|
||||||
|
}) async {
|
||||||
|
final currentPlayers = await getPlayersOfMatch(matchId: matchId);
|
||||||
|
// Create sets of player IDs for easy comparison
|
||||||
|
final currentPlayerIds = currentPlayers?.map((p) => p.id).toSet() ?? {};
|
||||||
|
final newPlayerIdsSet = newPlayer.map((p) => p.id).toSet();
|
||||||
|
|
||||||
|
// Determine players to add and remove
|
||||||
|
final playersToAdd = newPlayerIdsSet.difference(currentPlayerIds);
|
||||||
|
final playersToRemove = currentPlayerIds.difference(newPlayerIdsSet);
|
||||||
|
|
||||||
|
db.transaction(() async {
|
||||||
|
// Remove old players
|
||||||
|
if (playersToRemove.isNotEmpty) {
|
||||||
|
await (delete(playerMatchTable)..where(
|
||||||
|
(pg) =>
|
||||||
|
pg.matchId.equals(matchId) &
|
||||||
|
pg.playerId.isIn(playersToRemove.toList()),
|
||||||
|
))
|
||||||
|
.go();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new players
|
||||||
|
if (playersToAdd.isNotEmpty) {
|
||||||
|
final inserts = playersToAdd
|
||||||
|
.map(
|
||||||
|
(id) => PlayerMatchTableCompanion.insert(
|
||||||
|
playerId: id,
|
||||||
|
matchId: matchId,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList();
|
||||||
|
await Future.wait(
|
||||||
|
inserts.map(
|
||||||
|
(c) => into(
|
||||||
|
playerMatchTable,
|
||||||
|
).insert(c, mode: InsertMode.insertOrIgnore),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
11
lib/data/dao/player_match_dao.g.dart
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'player_match_dao.dart';
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
mixin _$PlayerMatchDaoMixin on DatabaseAccessor<AppDatabase> {
|
||||||
|
$PlayerTableTable get playerTable => attachedDatabase.playerTable;
|
||||||
|
$MatchTableTable get matchTable => attachedDatabase.matchTable;
|
||||||
|
$PlayerMatchTableTable get playerMatchTable =>
|
||||||
|
attachedDatabase.playerMatchTable;
|
||||||
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:drift_flutter/drift_flutter.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/group_game_dao.dart';
|
|
||||||
import 'package:game_tracker/data/dao/player_dao.dart';
|
|
||||||
import 'package:game_tracker/data/dao/player_game_dao.dart';
|
|
||||||
import 'package:game_tracker/data/dao/player_group_dao.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/game_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/group_game_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/group_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_game_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_group_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:tallee/data/dao/group_dao.dart';
|
||||||
|
import 'package:tallee/data/dao/group_match_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/db/tables/group_match_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';
|
||||||
|
|
||||||
part 'database.g.dart';
|
part 'database.g.dart';
|
||||||
|
|
||||||
@@ -20,18 +20,18 @@ part 'database.g.dart';
|
|||||||
tables: [
|
tables: [
|
||||||
PlayerTable,
|
PlayerTable,
|
||||||
GroupTable,
|
GroupTable,
|
||||||
GameTable,
|
MatchTable,
|
||||||
PlayerGroupTable,
|
PlayerGroupTable,
|
||||||
PlayerGameTable,
|
PlayerMatchTable,
|
||||||
GroupGameTable,
|
GroupMatchTable,
|
||||||
],
|
],
|
||||||
daos: [
|
daos: [
|
||||||
PlayerDao,
|
PlayerDao,
|
||||||
GroupDao,
|
GroupDao,
|
||||||
GameDao,
|
MatchDao,
|
||||||
PlayerGroupDao,
|
PlayerGroupDao,
|
||||||
PlayerGameDao,
|
PlayerMatchDao,
|
||||||
GroupGameDao,
|
GroupMatchDao,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
class AppDatabase extends _$AppDatabase {
|
class AppDatabase extends _$AppDatabase {
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
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';
|
|
||||||
|
|
||||||
class GroupGameTable extends Table {
|
|
||||||
TextColumn get groupId =>
|
|
||||||
text().references(GroupTable, #id, onDelete: KeyAction.cascade)();
|
|
||||||
TextColumn get gameId =>
|
|
||||||
text().references(GameTable, #id, onDelete: KeyAction.cascade)();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<Column<Object>> get primaryKey => {groupId, gameId};
|
|
||||||
}
|
|
||||||
13
lib/data/db/tables/group_match_table.dart
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:tallee/data/db/tables/group_table.dart';
|
||||||
|
import 'package:tallee/data/db/tables/match_table.dart';
|
||||||
|
|
||||||
|
class GroupMatchTable extends Table {
|
||||||
|
TextColumn get groupId =>
|
||||||
|
text().references(GroupTable, #id, onDelete: KeyAction.cascade)();
|
||||||
|
TextColumn get matchId =>
|
||||||
|
text().references(MatchTable, #id, onDelete: KeyAction.cascade)();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column<Object>> get primaryKey => {groupId, matchId};
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
|
|
||||||
class GameTable extends Table {
|
class MatchTable extends Table {
|
||||||
TextColumn get id => text()();
|
TextColumn get id => text()();
|
||||||
TextColumn get name => text()();
|
TextColumn get name => text()();
|
||||||
late final winnerId = text().nullable()();
|
late final winnerId = text().nullable()();
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/game_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
|
||||||
|
|
||||||
class PlayerGameTable extends Table {
|
|
||||||
TextColumn get playerId =>
|
|
||||||
text().references(PlayerTable, #id, onDelete: KeyAction.cascade)();
|
|
||||||
TextColumn get gameId =>
|
|
||||||
text().references(GameTable, #id, onDelete: KeyAction.cascade)();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<Column<Object>> get primaryKey => {playerId, gameId};
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/tables/group_table.dart';
|
import 'package:tallee/data/db/tables/group_table.dart';
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
import 'package:tallee/data/db/tables/player_table.dart';
|
||||||
|
|
||||||
class PlayerGroupTable extends Table {
|
class PlayerGroupTable extends Table {
|
||||||
TextColumn get playerId =>
|
TextColumn get playerId =>
|
||||||
|
|||||||
13
lib/data/db/tables/player_match_table.dart
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:tallee/data/db/tables/match_table.dart';
|
||||||
|
import 'package:tallee/data/db/tables/player_table.dart';
|
||||||
|
|
||||||
|
class PlayerMatchTable extends Table {
|
||||||
|
TextColumn get playerId =>
|
||||||
|
text().references(PlayerTable, #id, onDelete: KeyAction.cascade)();
|
||||||
|
TextColumn get matchId =>
|
||||||
|
text().references(MatchTable, #id, onDelete: KeyAction.cascade)();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column<Object>> get primaryKey => {playerId, matchId};
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:clock/clock.dart';
|
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';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class Group {
|
class Group {
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import 'package:clock/clock.dart';
|
import 'package:clock/clock.dart';
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
import 'package:tallee/data/dto/group.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:tallee/data/dto/player.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class Game {
|
class Match {
|
||||||
final String id;
|
final String id;
|
||||||
final DateTime createdAt;
|
final DateTime createdAt;
|
||||||
final String name;
|
final String name;
|
||||||
final List<Player>? players;
|
final List<Player>? players;
|
||||||
final Group? group;
|
final Group? group;
|
||||||
final Player? winner;
|
Player? winner;
|
||||||
|
|
||||||
Game({
|
Match({
|
||||||
String? id,
|
String? id,
|
||||||
DateTime? createdAt,
|
DateTime? createdAt,
|
||||||
required this.name,
|
required this.name,
|
||||||
@@ -23,11 +23,11 @@ class Game {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'Game{\n\tid: $id,\n\tname: $name,\n\tplayers: $players,\n\tgroup: $group,\n\twinner: $winner\n}';
|
return 'Match{\n\tid: $id,\n\tname: $name,\n\tplayers: $players,\n\tgroup: $group,\n\twinner: $winner\n}';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a Game instance from a JSON object.
|
/// Creates a Match instance from a JSON object.
|
||||||
Game.fromJson(Map<String, dynamic> json)
|
Match.fromJson(Map<String, dynamic> json)
|
||||||
: id = json['id'],
|
: id = json['id'],
|
||||||
name = json['name'],
|
name = json['name'],
|
||||||
createdAt = DateTime.parse(json['createdAt']),
|
createdAt = DateTime.parse(json['createdAt']),
|
||||||
@@ -39,7 +39,7 @@ class Game {
|
|||||||
group = json['group'] != null ? Group.fromJson(json['group']) : null,
|
group = json['group'] != null ? Group.fromJson(json['group']) : null,
|
||||||
winner = json['winner'] != null ? Player.fromJson(json['winner']) : null;
|
winner = json['winner'] != null ? Player.fromJson(json['winner']) : null;
|
||||||
|
|
||||||
/// Converts the Game instance to a JSON object.
|
/// Converts the Match instance to a JSON object.
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
'id': id,
|
'id': id,
|
||||||
'createdAt': createdAt.toIso8601String(),
|
'createdAt': createdAt.toIso8601String(),
|
||||||
97
lib/l10n/arb/app_de.arb
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
{
|
||||||
|
"@@locale": "de",
|
||||||
|
"all_players": "Alle Spieler:innen",
|
||||||
|
"all_players_selected": "Alle Spieler:innen ausgewählt",
|
||||||
|
"amount_of_matches": "Anzahl der Spiele",
|
||||||
|
"app_name": "Tallee",
|
||||||
|
"best_player": "Beste:r Spieler:in",
|
||||||
|
"cancel": "Abbrechen",
|
||||||
|
"choose_game": "Spielvorlage wählen",
|
||||||
|
"choose_group": "Gruppe wählen",
|
||||||
|
"choose_ruleset": "Regelwerk wählen",
|
||||||
|
"could_not_add_player": "Spieler:in {playerName} konnte nicht hinzugefügt werden",
|
||||||
|
"create_group": "Gruppe erstellen",
|
||||||
|
"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",
|
||||||
|
"data_successfully_imported": "Daten erfolgreich importiert",
|
||||||
|
"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",
|
||||||
|
"export_data": "Daten exportieren",
|
||||||
|
"format_exception": "Formatfehler (siehe Konsole)",
|
||||||
|
"game": "Spielvorlage",
|
||||||
|
"game_name": "Spielvorlagenname",
|
||||||
|
"group": "Gruppe",
|
||||||
|
"group_name": "Gruppenname",
|
||||||
|
"group_profile": "Gruppenprofil",
|
||||||
|
"groups": "Gruppen",
|
||||||
|
"home": "Startseite",
|
||||||
|
"import_canceled": "Import abgebrochen",
|
||||||
|
"import_data": "Daten importieren",
|
||||||
|
"info": "Info",
|
||||||
|
"invalid_schema": "Ungültiges Schema",
|
||||||
|
"least_points": "Niedrigste Punkte",
|
||||||
|
"legal": "Rechtliches",
|
||||||
|
"legal_notice": "Impressum",
|
||||||
|
"licenses": "Lizenzen",
|
||||||
|
"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",
|
||||||
|
"no_licenses_found": "Keine Lizenzen gefunden",
|
||||||
|
"no_license_text_available": "Kein Lizenztext verfügbar",
|
||||||
|
"no_matches_created_yet": "Noch keine Spiele erstellt",
|
||||||
|
"no_players_created_yet": "Noch keine Spieler:in erstellt",
|
||||||
|
"no_players_found_with_that_name": "Keine Spieler:in mit diesem Namen gefunden",
|
||||||
|
"no_players_selected": "Keine Spieler:innen ausgewählt",
|
||||||
|
"no_recent_matches_available": "Keine letzten Spiele verfügbar",
|
||||||
|
"no_second_match_available": "Kein zweites Spiel verfügbar",
|
||||||
|
"no_statistics_available": "Keine Statistiken verfügbar",
|
||||||
|
"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",
|
||||||
|
"privacy_policy": "Datenschutzerklärung",
|
||||||
|
"quick_create": "Schnellzugriff",
|
||||||
|
"recent_matches": "Letzte Spiele",
|
||||||
|
"ruleset": "Regelwerk",
|
||||||
|
"ruleset_least_points": "Umgekehrte Wertung: Der/die Spieler:in mit den wenigsten Punkten gewinnt.",
|
||||||
|
"ruleset_most_points": "Traditionelles Regelwerk: Der/die Spieler:in mit den meisten Punkten gewinnt.",
|
||||||
|
"ruleset_single_loser": "Genau ein:e Verlierer:in wird bestimmt; der letzte Platz erhält die Strafe oder Konsequenz.",
|
||||||
|
"ruleset_single_winner": "Genau ein:e Gewinner:in wird gewählt; Unentschieden werden durch einen vordefinierten Tie-Breaker aufgelöst.",
|
||||||
|
"search_for_groups": "Nach Gruppen suchen",
|
||||||
|
"search_for_players": "Nach Spieler:innen suchen",
|
||||||
|
"select_winner": "Gewinner:in wählen:",
|
||||||
|
"selected_players": "Ausgewählte Spieler:innen",
|
||||||
|
"settings": "Einstellungen",
|
||||||
|
"single_loser": "Ein:e Verlierer:in",
|
||||||
|
"single_winner": "Ein:e Gewinner:in",
|
||||||
|
"statistics": "Statistiken",
|
||||||
|
"stats": "Statistiken",
|
||||||
|
"successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt",
|
||||||
|
"there_is_no_group_matching_your_search": "Es gibt keine Gruppe, die deiner Suche entspricht",
|
||||||
|
"this_cannot_be_undone": "Dies kann nicht rückgängig gemacht werden.",
|
||||||
|
"today_at": "Heute um",
|
||||||
|
"undo": "Rückgängig",
|
||||||
|
"unknown_exception": "Unbekannter Fehler (siehe Konsole)",
|
||||||
|
"winner": "Gewinner:in",
|
||||||
|
"winrate": "Siegquote",
|
||||||
|
"wins": "Siege",
|
||||||
|
"yesterday_at": "Gestern um"
|
||||||
|
}
|
||||||
395
lib/l10n/arb/app_en.arb
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
{
|
||||||
|
"@@locale": "en",
|
||||||
|
"@all_players": {
|
||||||
|
"description": "Label for all players list"
|
||||||
|
},
|
||||||
|
"@all_players_selected": {
|
||||||
|
"description": "Message when all players are added to selection"
|
||||||
|
},
|
||||||
|
"@amount_of_matches": {
|
||||||
|
"description": "Label for amount of matches statistic"
|
||||||
|
},
|
||||||
|
"@app_name": {
|
||||||
|
"description": "The name of the App"
|
||||||
|
},
|
||||||
|
"@best_player": {
|
||||||
|
"description": "Label for best player statistic"
|
||||||
|
},
|
||||||
|
"@cancel": {
|
||||||
|
"description": "Cancel button text"
|
||||||
|
},
|
||||||
|
"@choose_game": {
|
||||||
|
"description": "Label for choosing a game"
|
||||||
|
},
|
||||||
|
"@choose_group": {
|
||||||
|
"description": "Label for choosing a group"
|
||||||
|
},
|
||||||
|
"@choose_ruleset": {
|
||||||
|
"description": "Label for choosing a ruleset"
|
||||||
|
},
|
||||||
|
"@could_not_add_player": {
|
||||||
|
"description": "Error message when adding a player fails"
|
||||||
|
},
|
||||||
|
"@create_group": {
|
||||||
|
"description": "Button text to create a group"
|
||||||
|
},
|
||||||
|
"@create_match": {
|
||||||
|
"description": "Button text to create a match"
|
||||||
|
},
|
||||||
|
"@create_new_group": {
|
||||||
|
"description": "Button text to create a new group"
|
||||||
|
},
|
||||||
|
"@create_new_match": {
|
||||||
|
"description": "Button text to create a new match"
|
||||||
|
},
|
||||||
|
"@created_on": {
|
||||||
|
"description": "Label for creation date"
|
||||||
|
},
|
||||||
|
"@data": {
|
||||||
|
"description": "Data label"
|
||||||
|
},
|
||||||
|
"@data_successfully_deleted": {
|
||||||
|
"description": "Success message after deleting data"
|
||||||
|
},
|
||||||
|
"@data_successfully_exported": {
|
||||||
|
"description": "Success message after exporting data"
|
||||||
|
},
|
||||||
|
"@data_successfully_imported": {
|
||||||
|
"description": "Success message after importing data"
|
||||||
|
},
|
||||||
|
"@days_ago": {
|
||||||
|
"description": "Date format for days ago",
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"type": "int"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@delete": {
|
||||||
|
"description": "Delete button text"
|
||||||
|
},
|
||||||
|
"@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"
|
||||||
|
},
|
||||||
|
"@error_reading_file": {
|
||||||
|
"description": "Error message when file cannot be read"
|
||||||
|
},
|
||||||
|
"@export_canceled": {
|
||||||
|
"description": "Message when export is canceled"
|
||||||
|
},
|
||||||
|
"@export_data": {
|
||||||
|
"description": "Export data menu item"
|
||||||
|
},
|
||||||
|
"@format_exception": {
|
||||||
|
"description": "Error message for format exceptions"
|
||||||
|
},
|
||||||
|
"@game": {
|
||||||
|
"description": "Game label"
|
||||||
|
},
|
||||||
|
"@game_name": {
|
||||||
|
"description": "Placeholder for game name search"
|
||||||
|
},
|
||||||
|
"@group": {
|
||||||
|
"description": "Group label"
|
||||||
|
},
|
||||||
|
"@group_name": {
|
||||||
|
"description": "Placeholder for group name input"
|
||||||
|
},
|
||||||
|
"@group_profile": {
|
||||||
|
"description": "Title for group profile view"
|
||||||
|
},
|
||||||
|
"@groups": {
|
||||||
|
"description": "Label for groups"
|
||||||
|
},
|
||||||
|
"@home": {
|
||||||
|
"description": "Home tab label"
|
||||||
|
},
|
||||||
|
"@import_canceled": {
|
||||||
|
"description": "Message when import is canceled"
|
||||||
|
},
|
||||||
|
"@import_data": {
|
||||||
|
"description": "Import data menu item"
|
||||||
|
},
|
||||||
|
"@info": {
|
||||||
|
"description": "Info label"
|
||||||
|
},
|
||||||
|
"@invalid_schema": {
|
||||||
|
"description": "Error message for invalid schema"
|
||||||
|
},
|
||||||
|
"@least_points": {
|
||||||
|
"description": "Title for least points ruleset"
|
||||||
|
},
|
||||||
|
"@legal": {
|
||||||
|
"description": "Legal section header"
|
||||||
|
},
|
||||||
|
"@legal_notice": {
|
||||||
|
"description": "Legal notice menu item"
|
||||||
|
},
|
||||||
|
"@licenses": {
|
||||||
|
"description": "Licenses menu item"
|
||||||
|
},
|
||||||
|
"@match_in_progress": {
|
||||||
|
"description": "Message when match is in progress"
|
||||||
|
},
|
||||||
|
"@match_name": {
|
||||||
|
"description": "Placeholder for match name input"
|
||||||
|
},
|
||||||
|
"@matches": {
|
||||||
|
"description": "Label for matches"
|
||||||
|
},
|
||||||
|
"@members": {
|
||||||
|
"description": "Label for group members"
|
||||||
|
},
|
||||||
|
"@most_points": {
|
||||||
|
"description": "Title for most points ruleset"
|
||||||
|
},
|
||||||
|
"@no_data_available": {
|
||||||
|
"description": "Message when no data in the statistic tiles is given"
|
||||||
|
},
|
||||||
|
"@no_groups_created_yet": {
|
||||||
|
"description": "Message when no groups exist"
|
||||||
|
},
|
||||||
|
"@no_licenses_found": {
|
||||||
|
"description": "Message when no licenses are found"
|
||||||
|
},
|
||||||
|
"@no_license_text_available": {
|
||||||
|
"description": "Message when no license text is available"
|
||||||
|
},
|
||||||
|
"@no_matches_created_yet": {
|
||||||
|
"description": "Message when no matches exist"
|
||||||
|
},
|
||||||
|
"@no_players_created_yet": {
|
||||||
|
"description": "Message when no players exist"
|
||||||
|
},
|
||||||
|
"@no_players_found_with_that_name": {
|
||||||
|
"description": "Message when search returns no results"
|
||||||
|
},
|
||||||
|
"@no_players_selected": {
|
||||||
|
"description": "Message when no players are selected"
|
||||||
|
},
|
||||||
|
"@no_recent_matches_available": {
|
||||||
|
"description": "Message when no recent matches exist"
|
||||||
|
},
|
||||||
|
"@no_second_match_available": {
|
||||||
|
"description": "Message when no second match exists"
|
||||||
|
},
|
||||||
|
"@no_statistics_available": {
|
||||||
|
"description": "Message when no statistics are available, because no matches were played yet"
|
||||||
|
},
|
||||||
|
"@none": {
|
||||||
|
"description": "None option label"
|
||||||
|
},
|
||||||
|
"@none_group": {
|
||||||
|
"description": "None group option label"
|
||||||
|
},
|
||||||
|
"@not_available": {
|
||||||
|
"description": "Abbreviation for not available"
|
||||||
|
},
|
||||||
|
"@played_matches": {
|
||||||
|
"description": "Label for played matches statistic"
|
||||||
|
},
|
||||||
|
"@player_name": {
|
||||||
|
"description": "Placeholder for player name input"
|
||||||
|
},
|
||||||
|
"@players": {
|
||||||
|
"description": "Players label"
|
||||||
|
},
|
||||||
|
"@players_count": {
|
||||||
|
"description": "Shows the number of players",
|
||||||
|
"placeholders": {
|
||||||
|
"count": {
|
||||||
|
"type": "int"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@privacy_policy": {
|
||||||
|
"description": "Privacy policy menu item"
|
||||||
|
},
|
||||||
|
"@quick_create": {
|
||||||
|
"description": "Title for quick create section"
|
||||||
|
},
|
||||||
|
"@recent_matches": {
|
||||||
|
"description": "Title for recent matches section"
|
||||||
|
},
|
||||||
|
"@ruleset": {
|
||||||
|
"description": "Ruleset label"
|
||||||
|
},
|
||||||
|
"@ruleset_least_points": {
|
||||||
|
"description": "Description for least points ruleset"
|
||||||
|
},
|
||||||
|
"@ruleset_most_points": {
|
||||||
|
"description": "Description for most points ruleset"
|
||||||
|
},
|
||||||
|
"@ruleset_single_loser": {
|
||||||
|
"description": "Description for single loser ruleset"
|
||||||
|
},
|
||||||
|
"@ruleset_single_winner": {
|
||||||
|
"description": "Description for single winner ruleset"
|
||||||
|
},
|
||||||
|
"@search_for_groups": {
|
||||||
|
"description": "Hint text for group search input field"
|
||||||
|
},
|
||||||
|
"@search_for_players": {
|
||||||
|
"description": "Hint text for player search input field"
|
||||||
|
},
|
||||||
|
"@select_winner": {
|
||||||
|
"description": "Label to select the winner"
|
||||||
|
},
|
||||||
|
"@selected_players": {
|
||||||
|
"description": "Shows the number of selected players"
|
||||||
|
},
|
||||||
|
"@settings": {
|
||||||
|
"description": "Label for the App Settings"
|
||||||
|
},
|
||||||
|
"@single_loser": {
|
||||||
|
"description": "Title for single loser ruleset"
|
||||||
|
},
|
||||||
|
"@single_winner": {
|
||||||
|
"description": "Title for single winner ruleset"
|
||||||
|
},
|
||||||
|
"@statistics": {
|
||||||
|
"description": "Statistics tab label"
|
||||||
|
},
|
||||||
|
"@stats": {
|
||||||
|
"description": "Stats tab label (short)"
|
||||||
|
},
|
||||||
|
"@successfully_added_player": {
|
||||||
|
"description": "Success message when adding a player",
|
||||||
|
"placeholders": {
|
||||||
|
"playerName": {
|
||||||
|
"type": "String",
|
||||||
|
"example": "John"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@there_is_no_group_matching_your_search": {
|
||||||
|
"description": "Message when search returns no groups"
|
||||||
|
},
|
||||||
|
"@this_cannot_be_undone": {
|
||||||
|
"description": "Warning message for irreversible actions"
|
||||||
|
},
|
||||||
|
"@today_at": {
|
||||||
|
"description": "Date format for today"
|
||||||
|
},
|
||||||
|
"@undo": {
|
||||||
|
"description": "Undo button text"
|
||||||
|
},
|
||||||
|
"@unknown_exception": {
|
||||||
|
"description": "Error message for unknown exceptions"
|
||||||
|
},
|
||||||
|
"@winner": {
|
||||||
|
"description": "Winner label"
|
||||||
|
},
|
||||||
|
"@winrate": {
|
||||||
|
"description": "Label for winrate statistic"
|
||||||
|
},
|
||||||
|
"@wins": {
|
||||||
|
"description": "Label for wins statistic"
|
||||||
|
},
|
||||||
|
"@yesterday_at": {
|
||||||
|
"description": "Date format for yesterday"
|
||||||
|
},
|
||||||
|
"all_players": "All players",
|
||||||
|
"all_players_selected": "All players selected",
|
||||||
|
"amount_of_matches": "Amount of Matches",
|
||||||
|
"app_name": "Tallee",
|
||||||
|
"best_player": "Best Player",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"choose_game": "Choose Game",
|
||||||
|
"choose_group": "Choose Group",
|
||||||
|
"choose_ruleset": "Choose Ruleset",
|
||||||
|
"could_not_add_player": "Could not add player",
|
||||||
|
"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",
|
||||||
|
"data_successfully_exported": "Data successfully exported",
|
||||||
|
"data_successfully_imported": "Data successfully imported",
|
||||||
|
"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",
|
||||||
|
"export_data": "Export data",
|
||||||
|
"format_exception": "Format Exception (see console)",
|
||||||
|
"game": "Game",
|
||||||
|
"game_name": "Game Name",
|
||||||
|
"group": "Group",
|
||||||
|
"group_name": "Group name",
|
||||||
|
"group_profile": "Group Profile",
|
||||||
|
"groups": "Groups",
|
||||||
|
"home": "Home",
|
||||||
|
"import_canceled": "Import canceled",
|
||||||
|
"import_data": "Import data",
|
||||||
|
"info": "Info",
|
||||||
|
"invalid_schema": "Invalid Schema",
|
||||||
|
"least_points": "Least Points",
|
||||||
|
"legal": "Legal",
|
||||||
|
"legal_notice": "Legal Notice",
|
||||||
|
"licenses": "Licenses",
|
||||||
|
"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",
|
||||||
|
"no_licenses_found": "No licenses found",
|
||||||
|
"no_license_text_available": "No license text available",
|
||||||
|
"no_matches_created_yet": "No matches created yet",
|
||||||
|
"no_players_created_yet": "No players created yet",
|
||||||
|
"no_players_found_with_that_name": "No players found with that name",
|
||||||
|
"no_players_selected": "No players selected",
|
||||||
|
"no_recent_matches_available": "No recent matches available",
|
||||||
|
"no_second_match_available": "No second match available",
|
||||||
|
"no_statistics_available": "No statistics available",
|
||||||
|
"none": "None",
|
||||||
|
"none_group": "None",
|
||||||
|
"not_available": "Not available",
|
||||||
|
"played_matches": "Played Matches",
|
||||||
|
"player_name": "Player name",
|
||||||
|
"players": "Players",
|
||||||
|
"players_count": "{count} Players",
|
||||||
|
"privacy_policy": "Privacy Policy",
|
||||||
|
"quick_create": "Quick Create",
|
||||||
|
"recent_matches": "Recent Matches",
|
||||||
|
"ruleset": "Ruleset",
|
||||||
|
"ruleset_least_points": "Inverse scoring: the player with the fewest points wins.",
|
||||||
|
"ruleset_most_points": "Traditional ruleset: the player with the most points wins.",
|
||||||
|
"ruleset_single_loser": "Exactly one loser is determined; last place receives the penalty or consequence.",
|
||||||
|
"ruleset_single_winner": "Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.",
|
||||||
|
"search_for_groups": "Search for groups",
|
||||||
|
"search_for_players": "Search for players",
|
||||||
|
"select_winner": "Select Winner:",
|
||||||
|
"selected_players": "Selected players",
|
||||||
|
"settings": "Settings",
|
||||||
|
"single_loser": "Single Loser",
|
||||||
|
"single_winner": "Single Winner",
|
||||||
|
"statistics": "Statistics",
|
||||||
|
"stats": "Stats",
|
||||||
|
"successfully_added_player": "Successfully added player {playerName}",
|
||||||
|
"there_is_no_group_matching_your_search": "There is no group matching your search",
|
||||||
|
"this_cannot_be_undone": "This can't be undone.",
|
||||||
|
"today_at": "Today at",
|
||||||
|
"undo": "Undo",
|
||||||
|
"unknown_exception": "Unknown Exception (see console)",
|
||||||
|
"winner": "Winner",
|
||||||
|
"winrate": "Winrate",
|
||||||
|
"wins": "Wins",
|
||||||
|
"yesterday_at": "Yesterday at"
|
||||||
|
}
|
||||||
698
lib/l10n/generated/app_localizations.dart
Normal file
@@ -0,0 +1,698 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
|
import 'package:intl/intl.dart' as intl;
|
||||||
|
|
||||||
|
import 'app_localizations_de.dart';
|
||||||
|
import 'app_localizations_en.dart';
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
|
||||||
|
/// Callers can lookup localized strings with an instance of AppLocalizations
|
||||||
|
/// returned by `AppLocalizations.of(context)`.
|
||||||
|
///
|
||||||
|
/// Applications need to include `AppLocalizations.delegate()` in their app's
|
||||||
|
/// `localizationDelegates` list, and the locales they support in the app's
|
||||||
|
/// `supportedLocales` list. For example:
|
||||||
|
///
|
||||||
|
/// ```dart
|
||||||
|
/// import 'generated/app_localizations.dart';
|
||||||
|
///
|
||||||
|
/// return MaterialApp(
|
||||||
|
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
|
/// supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
/// home: MyApplicationHome(),
|
||||||
|
/// );
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Update pubspec.yaml
|
||||||
|
///
|
||||||
|
/// Please make sure to update your pubspec.yaml to include the following
|
||||||
|
/// packages:
|
||||||
|
///
|
||||||
|
/// ```yaml
|
||||||
|
/// dependencies:
|
||||||
|
/// # Internationalization support.
|
||||||
|
/// flutter_localizations:
|
||||||
|
/// sdk: flutter
|
||||||
|
/// intl: any # Use the pinned version from flutter_localizations
|
||||||
|
///
|
||||||
|
/// # Rest of dependencies
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## iOS Applications
|
||||||
|
///
|
||||||
|
/// iOS applications define key application metadata, including supported
|
||||||
|
/// locales, in an Info.plist file that is built into the application bundle.
|
||||||
|
/// To configure the locales supported by your app, you’ll need to edit this
|
||||||
|
/// file.
|
||||||
|
///
|
||||||
|
/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
|
||||||
|
/// Then, in the Project Navigator, open the Info.plist file under the Runner
|
||||||
|
/// project’s Runner folder.
|
||||||
|
///
|
||||||
|
/// Next, select the Information Property List item, select Add Item from the
|
||||||
|
/// Editor menu, then select Localizations from the pop-up menu.
|
||||||
|
///
|
||||||
|
/// Select and expand the newly-created Localizations item then, for each
|
||||||
|
/// locale your application supports, add a new item and select the locale
|
||||||
|
/// you wish to add from the pop-up menu in the Value field. This list should
|
||||||
|
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
|
||||||
|
/// property.
|
||||||
|
abstract class AppLocalizations {
|
||||||
|
AppLocalizations(String locale)
|
||||||
|
: localeName = intl.Intl.canonicalizedLocale(locale.toString());
|
||||||
|
|
||||||
|
final String localeName;
|
||||||
|
|
||||||
|
static AppLocalizations of(BuildContext context) {
|
||||||
|
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const LocalizationsDelegate<AppLocalizations> delegate =
|
||||||
|
_AppLocalizationsDelegate();
|
||||||
|
|
||||||
|
/// A list of this localizations delegate along with the default localizations
|
||||||
|
/// delegates.
|
||||||
|
///
|
||||||
|
/// Returns a list of localizations delegates containing this delegate along with
|
||||||
|
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
|
||||||
|
/// and GlobalWidgetsLocalizations.delegate.
|
||||||
|
///
|
||||||
|
/// Additional delegates can be added by appending to this list in
|
||||||
|
/// MaterialApp. This list does not have to be used at all if a custom list
|
||||||
|
/// of delegates is preferred or required.
|
||||||
|
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates =
|
||||||
|
<LocalizationsDelegate<dynamic>>[
|
||||||
|
delegate,
|
||||||
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
GlobalCupertinoLocalizations.delegate,
|
||||||
|
GlobalWidgetsLocalizations.delegate,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// A list of this localizations delegate's supported locales.
|
||||||
|
static const List<Locale> supportedLocales = <Locale>[
|
||||||
|
Locale('de'),
|
||||||
|
Locale('en'),
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Label for all players list
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'All players'**
|
||||||
|
String get all_players;
|
||||||
|
|
||||||
|
/// Message when all players are added to selection
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'All players selected'**
|
||||||
|
String get all_players_selected;
|
||||||
|
|
||||||
|
/// Label for amount of matches statistic
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Amount of Matches'**
|
||||||
|
String get amount_of_matches;
|
||||||
|
|
||||||
|
/// The name of the App
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'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:
|
||||||
|
/// **'Cancel'**
|
||||||
|
String get cancel;
|
||||||
|
|
||||||
|
/// Label for choosing a game
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Choose Game'**
|
||||||
|
String get choose_game;
|
||||||
|
|
||||||
|
/// Label for choosing a group
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Choose Group'**
|
||||||
|
String get choose_group;
|
||||||
|
|
||||||
|
/// Label for choosing a ruleset
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Choose Ruleset'**
|
||||||
|
String get choose_ruleset;
|
||||||
|
|
||||||
|
/// Error message when adding a player fails
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Could not add player'**
|
||||||
|
String could_not_add_player(Object playerName);
|
||||||
|
|
||||||
|
/// Button text to create a group
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Create Group'**
|
||||||
|
String get create_group;
|
||||||
|
|
||||||
|
/// Button text to create a match
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Create match'**
|
||||||
|
String get create_match;
|
||||||
|
|
||||||
|
/// Button text to create a new group
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'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:
|
||||||
|
/// **'Create new match'**
|
||||||
|
String get create_new_match;
|
||||||
|
|
||||||
|
/// Data label
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Data'**
|
||||||
|
String get data;
|
||||||
|
|
||||||
|
/// Success message after deleting data
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Data successfully deleted'**
|
||||||
|
String get data_successfully_deleted;
|
||||||
|
|
||||||
|
/// Success message after exporting data
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Data successfully exported'**
|
||||||
|
String get data_successfully_exported;
|
||||||
|
|
||||||
|
/// Success message after importing data
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Data successfully imported'**
|
||||||
|
String get data_successfully_imported;
|
||||||
|
|
||||||
|
/// Date format for days ago
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'{count} days ago'**
|
||||||
|
String days_ago(int count);
|
||||||
|
|
||||||
|
/// Delete button text
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Delete'**
|
||||||
|
String get delete;
|
||||||
|
|
||||||
|
/// Confirmation dialog for deleting all data
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'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:
|
||||||
|
/// **'Error while creating group, please try again'**
|
||||||
|
String get error_creating_group;
|
||||||
|
|
||||||
|
/// Error message when file cannot be read
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Error reading file'**
|
||||||
|
String get error_reading_file;
|
||||||
|
|
||||||
|
/// Message when export is canceled
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Export canceled'**
|
||||||
|
String get export_canceled;
|
||||||
|
|
||||||
|
/// Export data menu item
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Export data'**
|
||||||
|
String get export_data;
|
||||||
|
|
||||||
|
/// Error message for format exceptions
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Format Exception (see console)'**
|
||||||
|
String get format_exception;
|
||||||
|
|
||||||
|
/// Game label
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Game'**
|
||||||
|
String get game;
|
||||||
|
|
||||||
|
/// Placeholder for game name search
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Game Name'**
|
||||||
|
String get game_name;
|
||||||
|
|
||||||
|
/// Group label
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Group'**
|
||||||
|
String get group;
|
||||||
|
|
||||||
|
/// Placeholder for group name input
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'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:
|
||||||
|
/// **'Groups'**
|
||||||
|
String get groups;
|
||||||
|
|
||||||
|
/// Home tab label
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Home'**
|
||||||
|
String get home;
|
||||||
|
|
||||||
|
/// Message when import is canceled
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Import canceled'**
|
||||||
|
String get import_canceled;
|
||||||
|
|
||||||
|
/// Import data menu item
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Import data'**
|
||||||
|
String get import_data;
|
||||||
|
|
||||||
|
/// Info label
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Info'**
|
||||||
|
String get info;
|
||||||
|
|
||||||
|
/// Error message for invalid schema
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Invalid Schema'**
|
||||||
|
String get invalid_schema;
|
||||||
|
|
||||||
|
/// Title for least points ruleset
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Least Points'**
|
||||||
|
String get least_points;
|
||||||
|
|
||||||
|
/// Legal section header
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Legal'**
|
||||||
|
String get legal;
|
||||||
|
|
||||||
|
/// Legal notice menu item
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Legal Notice'**
|
||||||
|
String get legal_notice;
|
||||||
|
|
||||||
|
/// Licenses menu item
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Licenses'**
|
||||||
|
String get licenses;
|
||||||
|
|
||||||
|
/// Message when match is in progress
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Match in progress...'**
|
||||||
|
String get match_in_progress;
|
||||||
|
|
||||||
|
/// Placeholder for match name input
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Match name'**
|
||||||
|
String get match_name;
|
||||||
|
|
||||||
|
/// Label for matches
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'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:
|
||||||
|
/// **'Most Points'**
|
||||||
|
String get most_points;
|
||||||
|
|
||||||
|
/// Message when no data in the statistic tiles is given
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No data available'**
|
||||||
|
String get no_data_available;
|
||||||
|
|
||||||
|
/// Message when no groups exist
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No groups created yet'**
|
||||||
|
String get no_groups_created_yet;
|
||||||
|
|
||||||
|
/// Message when no licenses are found
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No licenses found'**
|
||||||
|
String get no_licenses_found;
|
||||||
|
|
||||||
|
/// Message when no license text is available
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No license text available'**
|
||||||
|
String get no_license_text_available;
|
||||||
|
|
||||||
|
/// Message when no matches exist
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No matches created yet'**
|
||||||
|
String get no_matches_created_yet;
|
||||||
|
|
||||||
|
/// Message when no players exist
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No players created yet'**
|
||||||
|
String get no_players_created_yet;
|
||||||
|
|
||||||
|
/// Message when search returns no results
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No players found with that name'**
|
||||||
|
String get no_players_found_with_that_name;
|
||||||
|
|
||||||
|
/// Message when no players are selected
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No players selected'**
|
||||||
|
String get no_players_selected;
|
||||||
|
|
||||||
|
/// Message when no recent matches exist
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No recent matches available'**
|
||||||
|
String get no_recent_matches_available;
|
||||||
|
|
||||||
|
/// Message when no second match exists
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No second match available'**
|
||||||
|
String get no_second_match_available;
|
||||||
|
|
||||||
|
/// Message when no statistics are available, because no matches were played yet
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'No statistics available'**
|
||||||
|
String get no_statistics_available;
|
||||||
|
|
||||||
|
/// None option label
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'None'**
|
||||||
|
String get none;
|
||||||
|
|
||||||
|
/// None group option label
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'None'**
|
||||||
|
String get none_group;
|
||||||
|
|
||||||
|
/// Abbreviation for not available
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'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:
|
||||||
|
/// **'Player name'**
|
||||||
|
String get player_name;
|
||||||
|
|
||||||
|
/// Players label
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Players'**
|
||||||
|
String get players;
|
||||||
|
|
||||||
|
/// Shows the number of players
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'{count} Players'**
|
||||||
|
String players_count(int count);
|
||||||
|
|
||||||
|
/// Privacy policy menu item
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Privacy Policy'**
|
||||||
|
String get privacy_policy;
|
||||||
|
|
||||||
|
/// Title for quick create section
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Quick Create'**
|
||||||
|
String get quick_create;
|
||||||
|
|
||||||
|
/// Title for recent matches section
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Recent Matches'**
|
||||||
|
String get recent_matches;
|
||||||
|
|
||||||
|
/// Ruleset label
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Ruleset'**
|
||||||
|
String get ruleset;
|
||||||
|
|
||||||
|
/// Description for least points ruleset
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Inverse scoring: the player with the fewest points wins.'**
|
||||||
|
String get ruleset_least_points;
|
||||||
|
|
||||||
|
/// Description for most points ruleset
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Traditional ruleset: the player with the most points wins.'**
|
||||||
|
String get ruleset_most_points;
|
||||||
|
|
||||||
|
/// Description for single loser ruleset
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Exactly one loser is determined; last place receives the penalty or consequence.'**
|
||||||
|
String get ruleset_single_loser;
|
||||||
|
|
||||||
|
/// Description for single winner ruleset
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.'**
|
||||||
|
String get ruleset_single_winner;
|
||||||
|
|
||||||
|
/// Hint text for group search input field
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Search for groups'**
|
||||||
|
String get search_for_groups;
|
||||||
|
|
||||||
|
/// Hint text for player search input field
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Search for players'**
|
||||||
|
String get search_for_players;
|
||||||
|
|
||||||
|
/// Label to select the winner
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Select Winner:'**
|
||||||
|
String get select_winner;
|
||||||
|
|
||||||
|
/// Shows the number of selected players
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Selected players'**
|
||||||
|
String get selected_players;
|
||||||
|
|
||||||
|
/// Label for the App Settings
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Settings'**
|
||||||
|
String get settings;
|
||||||
|
|
||||||
|
/// Title for single loser ruleset
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Single Loser'**
|
||||||
|
String get single_loser;
|
||||||
|
|
||||||
|
/// Title for single winner ruleset
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Single Winner'**
|
||||||
|
String get single_winner;
|
||||||
|
|
||||||
|
/// Statistics tab label
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Statistics'**
|
||||||
|
String get statistics;
|
||||||
|
|
||||||
|
/// Stats tab label (short)
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Stats'**
|
||||||
|
String get stats;
|
||||||
|
|
||||||
|
/// Success message when adding a player
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Successfully added player {playerName}'**
|
||||||
|
String successfully_added_player(String playerName);
|
||||||
|
|
||||||
|
/// Message when search returns no groups
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'There is no group matching your search'**
|
||||||
|
String get there_is_no_group_matching_your_search;
|
||||||
|
|
||||||
|
/// Warning message for irreversible actions
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'This can\'t be undone.'**
|
||||||
|
String get this_cannot_be_undone;
|
||||||
|
|
||||||
|
/// Date format for today
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Today at'**
|
||||||
|
String get today_at;
|
||||||
|
|
||||||
|
/// Undo button text
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Undo'**
|
||||||
|
String get undo;
|
||||||
|
|
||||||
|
/// Error message for unknown exceptions
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Unknown Exception (see console)'**
|
||||||
|
String get unknown_exception;
|
||||||
|
|
||||||
|
/// Winner label
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Winner'**
|
||||||
|
String get winner;
|
||||||
|
|
||||||
|
/// Label for winrate statistic
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Winrate'**
|
||||||
|
String get winrate;
|
||||||
|
|
||||||
|
/// Label for wins statistic
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Wins'**
|
||||||
|
String get wins;
|
||||||
|
|
||||||
|
/// Date format for yesterday
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Yesterday at'**
|
||||||
|
String get yesterday_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AppLocalizationsDelegate
|
||||||
|
extends LocalizationsDelegate<AppLocalizations> {
|
||||||
|
const _AppLocalizationsDelegate();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<AppLocalizations> load(Locale locale) {
|
||||||
|
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool isSupported(Locale locale) =>
|
||||||
|
<String>['de', 'en'].contains(locale.languageCode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppLocalizations lookupAppLocalizations(Locale locale) {
|
||||||
|
// Lookup logic when only language code is specified.
|
||||||
|
switch (locale.languageCode) {
|
||||||
|
case 'de':
|
||||||
|
return AppLocalizationsDe();
|
||||||
|
case 'en':
|
||||||
|
return AppLocalizationsEn();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw FlutterError(
|
||||||
|
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
|
||||||
|
'an issue with the localizations generation tool. Please file an issue '
|
||||||
|
'on GitHub with a reproducible sample app and the gen-l10n configuration '
|
||||||
|
'that was used.',
|
||||||
|
);
|
||||||
|
}
|
||||||
308
lib/l10n/generated/app_localizations_de.dart
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
// ignore: unused_import
|
||||||
|
import 'package:intl/intl.dart' as intl;
|
||||||
|
import 'app_localizations.dart';
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
|
||||||
|
/// The translations for German (`de`).
|
||||||
|
class AppLocalizationsDe extends AppLocalizations {
|
||||||
|
AppLocalizationsDe([String locale = 'de']) : super(locale);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get all_players => 'Alle Spieler:innen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get all_players_selected => 'Alle Spieler:innen ausgewählt';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get amount_of_matches => 'Anzahl der Spiele';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get app_name => 'Tallee';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get best_player => 'Beste:r Spieler:in';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get cancel => 'Abbrechen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get choose_game => 'Spielvorlage wählen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get choose_group => 'Gruppe wählen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get choose_ruleset => 'Regelwerk wählen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String could_not_add_player(Object playerName) {
|
||||||
|
return 'Spieler:in $playerName konnte nicht hinzugefügt werden';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get create_group => 'Gruppe erstellen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get create_match => 'Spiel erstellen';
|
||||||
|
|
||||||
|
@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';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get data => 'Daten';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get data_successfully_deleted => 'Daten erfolgreich gelöscht';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get data_successfully_exported => 'Daten erfolgreich exportiert';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get data_successfully_imported => 'Daten erfolgreich importiert';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String days_ago(int count) {
|
||||||
|
return 'vor $count Tagen';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get delete => 'Löschen';
|
||||||
|
|
||||||
|
@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';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get error_reading_file => 'Fehler beim Lesen der Datei';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get export_canceled => 'Export abgebrochen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get export_data => 'Daten exportieren';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get format_exception => 'Formatfehler (siehe Konsole)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get game => 'Spielvorlage';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get game_name => 'Spielvorlagenname';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get group => 'Gruppe';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get group_name => 'Gruppenname';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get group_profile => 'Gruppenprofil';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groups => 'Gruppen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get home => 'Startseite';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_canceled => 'Import abgebrochen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_data => 'Daten importieren';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get info => 'Info';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get invalid_schema => 'Ungültiges Schema';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get least_points => 'Niedrigste Punkte';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get legal => 'Rechtliches';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get legal_notice => 'Impressum';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get licenses => 'Lizenzen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get match_in_progress => 'Spiel läuft...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get match_name => 'Spieltitel';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get matches => 'Spiele';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get members => 'Mitglieder';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get most_points => 'Höchste Punkte';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_data_available => 'Keine Daten verfügbar';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_groups_created_yet => 'Noch keine Gruppen erstellt';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_licenses_found => 'Keine Lizenzen gefunden';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_license_text_available => 'Kein Lizenztext verfügbar';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_matches_created_yet => 'Noch keine Spiele erstellt';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_players_created_yet => 'Noch keine Spieler:in erstellt';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_players_found_with_that_name =>
|
||||||
|
'Keine Spieler:in mit diesem Namen gefunden';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_players_selected => 'Keine Spieler:innen ausgewählt';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_recent_matches_available => 'Keine letzten Spiele verfügbar';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_second_match_available => 'Kein zweites Spiel verfügbar';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_statistics_available => 'Keine Statistiken verfügbar';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get none => 'Kein';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get none_group => 'Keine';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get not_available => 'Nicht verfügbar';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get played_matches => 'Gespielte Spiele';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get player_name => 'Spieler:innenname';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get players => 'Spieler:innen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String players_count(int count) {
|
||||||
|
return '$count Spieler';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get privacy_policy => 'Datenschutzerklärung';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get quick_create => 'Schnellzugriff';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get recent_matches => 'Letzte Spiele';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ruleset => 'Regelwerk';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ruleset_least_points =>
|
||||||
|
'Umgekehrte Wertung: Der/die Spieler:in mit den wenigsten Punkten gewinnt.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ruleset_most_points =>
|
||||||
|
'Traditionelles Regelwerk: Der/die Spieler:in mit den meisten Punkten gewinnt.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ruleset_single_loser =>
|
||||||
|
'Genau ein:e Verlierer:in wird bestimmt; der letzte Platz erhält die Strafe oder Konsequenz.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ruleset_single_winner =>
|
||||||
|
'Genau ein:e Gewinner:in wird gewählt; Unentschieden werden durch einen vordefinierten Tie-Breaker aufgelöst.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get search_for_groups => 'Nach Gruppen suchen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get search_for_players => 'Nach Spieler:innen suchen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get select_winner => 'Gewinner:in wählen:';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get selected_players => 'Ausgewählte Spieler:innen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settings => 'Einstellungen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get single_loser => 'Ein:e Verlierer:in';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get single_winner => 'Ein:e Gewinner:in';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get statistics => 'Statistiken';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stats => 'Statistiken';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String successfully_added_player(String playerName) {
|
||||||
|
return 'Spieler:in $playerName erfolgreich hinzugefügt';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get there_is_no_group_matching_your_search =>
|
||||||
|
'Es gibt keine Gruppe, die deiner Suche entspricht';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get this_cannot_be_undone =>
|
||||||
|
'Dies kann nicht rückgängig gemacht werden.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get today_at => 'Heute um';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get undo => 'Rückgängig';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get unknown_exception => 'Unbekannter Fehler (siehe Konsole)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get winner => 'Gewinner:in';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get winrate => 'Siegquote';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get wins => 'Siege';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get yesterday_at => 'Gestern um';
|
||||||
|
}
|
||||||
307
lib/l10n/generated/app_localizations_en.dart
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
// ignore: unused_import
|
||||||
|
import 'package:intl/intl.dart' as intl;
|
||||||
|
import 'app_localizations.dart';
|
||||||
|
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
|
||||||
|
/// The translations for English (`en`).
|
||||||
|
class AppLocalizationsEn extends AppLocalizations {
|
||||||
|
AppLocalizationsEn([String locale = 'en']) : super(locale);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get all_players => 'All players';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get all_players_selected => 'All players selected';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get amount_of_matches => 'Amount of Matches';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get app_name => 'Tallee';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get best_player => 'Best Player';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get cancel => 'Cancel';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get choose_game => 'Choose Game';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get choose_group => 'Choose Group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get choose_ruleset => 'Choose Ruleset';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String could_not_add_player(Object playerName) {
|
||||||
|
return 'Could not add player';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get create_group => 'Create Group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get create_match => 'Create match';
|
||||||
|
|
||||||
|
@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';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get data => 'Data';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get data_successfully_deleted => 'Data successfully deleted';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get data_successfully_exported => 'Data successfully exported';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get data_successfully_imported => 'Data successfully imported';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String days_ago(int count) {
|
||||||
|
return '$count days ago';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get delete => 'Delete';
|
||||||
|
|
||||||
|
@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';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get error_reading_file => 'Error reading file';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get export_canceled => 'Export canceled';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get export_data => 'Export data';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get format_exception => 'Format Exception (see console)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get game => 'Game';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get game_name => 'Game Name';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get group => 'Group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get group_name => 'Group name';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get group_profile => 'Group Profile';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get groups => 'Groups';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get home => 'Home';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_canceled => 'Import canceled';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get import_data => 'Import data';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get info => 'Info';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get invalid_schema => 'Invalid Schema';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get least_points => 'Least Points';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get legal => 'Legal';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get legal_notice => 'Legal Notice';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get licenses => 'Licenses';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get match_in_progress => 'Match in progress...';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get match_name => 'Match name';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get matches => 'Matches';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get members => 'Members';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get most_points => 'Most Points';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_data_available => 'No data available';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_groups_created_yet => 'No groups created yet';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_licenses_found => 'No licenses found';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_license_text_available => 'No license text available';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_matches_created_yet => 'No matches created yet';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_players_created_yet => 'No players created yet';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_players_found_with_that_name =>
|
||||||
|
'No players found with that name';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_players_selected => 'No players selected';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_recent_matches_available => 'No recent matches available';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_second_match_available => 'No second match available';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get no_statistics_available => 'No statistics available';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get none => 'None';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get none_group => 'None';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get not_available => 'Not available';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get played_matches => 'Played Matches';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get player_name => 'Player name';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get players => 'Players';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String players_count(int count) {
|
||||||
|
return '$count Players';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get privacy_policy => 'Privacy Policy';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get quick_create => 'Quick Create';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get recent_matches => 'Recent Matches';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ruleset => 'Ruleset';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ruleset_least_points =>
|
||||||
|
'Inverse scoring: the player with the fewest points wins.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ruleset_most_points =>
|
||||||
|
'Traditional ruleset: the player with the most points wins.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ruleset_single_loser =>
|
||||||
|
'Exactly one loser is determined; last place receives the penalty or consequence.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get ruleset_single_winner =>
|
||||||
|
'Exactly one winner is chosen; ties are resolved by a predefined tiebreaker.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get search_for_groups => 'Search for groups';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get search_for_players => 'Search for players';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get select_winner => 'Select Winner:';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get selected_players => 'Selected players';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get settings => 'Settings';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get single_loser => 'Single Loser';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get single_winner => 'Single Winner';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get statistics => 'Statistics';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get stats => 'Stats';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String successfully_added_player(String playerName) {
|
||||||
|
return 'Successfully added player $playerName';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get there_is_no_group_matching_your_search =>
|
||||||
|
'There is no group matching your search';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get this_cannot_be_undone => 'This can\'t be undone.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get today_at => 'Today at';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get undo => 'Undo';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get unknown_exception => 'Unknown Exception (see console)';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get winner => 'Winner';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get winrate => 'Winrate';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get wins => 'Wins';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get yesterday_at => 'Yesterday at';
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/presentation/views/main_menu/custom_navigation_bar.dart';
|
|
||||||
import 'package:provider/provider.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() {
|
void main() {
|
||||||
runApp(
|
runApp(
|
||||||
@@ -20,22 +21,36 @@ class GameTracker extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||||
|
supportedLocales: AppLocalizations.supportedLocales,
|
||||||
|
localeResolutionCallback: (locale, supportedLocales) {
|
||||||
|
for (final supportedLocale in supportedLocales) {
|
||||||
|
if (supportedLocale.languageCode == locale?.languageCode) {
|
||||||
|
return supportedLocale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return supportedLocales.firstWhere(
|
||||||
|
(locale) => locale.languageCode == 'en',
|
||||||
|
);
|
||||||
|
},
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
title: 'Game Tracker',
|
onGenerateTitle: (context) => AppLocalizations.of(context).app_name,
|
||||||
darkTheme: ThemeData.dark(),
|
|
||||||
|
|
||||||
themeMode: ThemeMode.dark, // forces dark mode
|
themeMode: ThemeMode.dark, // forces dark mode
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
primaryColor: CustomTheme.primaryColor,
|
primaryColor: CustomTheme.primaryColor,
|
||||||
scaffoldBackgroundColor: CustomTheme.backgroundColor,
|
scaffoldBackgroundColor: CustomTheme.backgroundColor,
|
||||||
appBarTheme: CustomTheme.appBarTheme,
|
appBarTheme: CustomTheme.appBarTheme,
|
||||||
|
|
||||||
colorScheme: ColorScheme.fromSeed(
|
colorScheme: ColorScheme.fromSeed(
|
||||||
seedColor: CustomTheme.primaryColor,
|
seedColor: CustomTheme.primaryColor,
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
).copyWith(surface: CustomTheme.backgroundColor),
|
).copyWith(surface: CustomTheme.backgroundColor),
|
||||||
|
pageTransitionsTheme: const PageTransitionsTheme(
|
||||||
|
builders: {
|
||||||
|
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
|
||||||
|
TargetPlatform.android: PredictiveBackPageTransitionsBuilder(),
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
home: const CustomNavigationBar(),
|
home: const CustomNavigationBar(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||