Compare commits

...

135 commits
0.1.0 ... main

Author SHA1 Message Date
Matyáš Caras cddeaafde7 feat: přidat zobrazení alergenů, opravit věci po upgradu závislostí (#52)
Reviewed-on: #52
2023-11-28 20:10:34 +01:00
Matyáš Caras 69074c7d28 ci: změnit RenovateBot base branch 2023-11-28 19:17:06 +01:00
Renovate Bot a6ab0525e1 fix(deps): update dependency flutter_local_notifications to v16 (#46)
Reviewed-on: #46
Co-authored-by: Renovate Bot <kontakt+renovator@caras.cafe>
Co-committed-by: Renovate Bot <kontakt+renovator@caras.cafe>
2023-11-28 19:12:58 +01:00
Renovate Bot 346ea5bb43 fix(deps): update dependency flutter_secure_storage to v9 (#45)
Reviewed-on: #45
Co-authored-by: Renovate Bot <kontakt+renovator@caras.cafe>
Co-committed-by: Renovate Bot <kontakt+renovator@caras.cafe>
2023-11-28 19:12:37 +01:00
Renovate Bot 855f4caf04 chore(deps): update dependency flutter_lints to v3 (#49)
Reviewed-on: #49
Co-authored-by: Renovate Bot <kontakt+renovator@caras.cafe>
Co-committed-by: Renovate Bot <kontakt+renovator@caras.cafe>
2023-11-28 19:12:19 +01:00
Renovate Bot 64cc85e195 fix(deps): update dependency package_info_plus to v5 (#50)
Reviewed-on: #50
Co-authored-by: Renovate Bot <kontakt+renovator@caras.cafe>
Co-committed-by: Renovate Bot <kontakt+renovator@caras.cafe>
2023-11-28 19:09:42 +01:00
Matyáš Caras 5b06e5708c
fix: opravit chybu s propisováním HTML 2023-10-06 13:28:13 +02:00
Matyáš Caras 1950d850b8
chore: bump 2023-09-12 22:40:17 +02:00
Matyáš Caras 3c918e7e41
docs: aktualizovat changelog 2023-09-12 22:39:57 +02:00
Matyáš Caras 21f69975e6 fix: opravit iOS vzhled + burzu (#41)
Reviewed-on: #41
2023-09-12 22:38:56 +02:00
Matyáš Caras 0b5967271a
fix: opravit nesoulad závislostí 2023-09-12 21:00:54 +02:00
Matyáš Caras 0232694142
chore: ⬆️ aktualizace dalších závislostí 2023-09-12 20:37:03 +02:00
Matyáš Caras 3423aa0368 Merge pull request 'chore(deps): update dependency flutter_launcher_icons to ^0.13.0' (#39) from renovate/flutter_launcher_icons-0.x into main
Reviewed-on: #39
2023-09-12 20:31:26 +02:00
Renovate Bot 7bfc8412d9 chore(deps): update dependency flutter_launcher_icons to ^0.13.0 2023-09-12 20:30:30 +02:00
Matyáš Caras 0f9de6080f Merge pull request 'fix(deps): update dependency intl to ^0.18.0' (#40) from renovate/intl-0.x into main
Reviewed-on: #40
2023-09-12 20:29:59 +02:00
Renovate Bot 757b94bbd5 fix(deps): update dependency intl to ^0.18.0 2023-09-12 20:21:55 +02:00
Matyáš Caras 9da89cfd2a Merge pull request 'Configure Renovate' (#38) from renovate/configure into main
Reviewed-on: #38
2023-09-12 20:08:58 +02:00
Matyáš Caras 7782226253 Update renovate.json 2023-09-12 20:08:51 +02:00
Renovate Bot f2d794e507 Add renovate.json 2023-09-12 20:05:33 +02:00
Matyáš Caras 9b25f3b0e7
feat(nastaveni): 💄 předělat nastavení 2023-09-04 20:45:45 +02:00
Matyáš Caras 963ad1de20
chore: odstranit nepotřebné soubory 2023-09-04 19:47:42 +02:00
Matyáš Caras 6de8b85765
docs: přidat info o změně na git 2023-09-04 19:28:18 +02:00
Matyáš Caras 55a8cadf35
chore(dependencies): ⬆️ update závislostí 2023-09-04 19:17:00 +02:00
Matyáš Caras b948959e67 feat: implementovat Material 3 a upravit systém lokalizací (#37)
Reviewed-on: #37
2023-01-28 15:59:41 +01:00
Matyáš Caras 2227bb59ce chore: aktualizovat changelogy 2023-01-28 15:57:48 +01:00
Matyáš Caras 6a3d0249ab chore: aktualizovat secure_storage 2023-01-28 15:54:21 +01:00
Matyáš Caras fb737dc40f fix: locale? 2023-01-28 15:44:06 +01:00
Matyáš Caras 17d14cb175 feat: předělat jazykový systém 2023-01-28 15:41:17 +01:00
Matyáš Caras 813c8cf3da feat: Material 3 2023-01-28 15:02:44 +01:00
Matyáš Caras 2615769679 Merge pull request 'fix: přepsat Platform UI a zmenit RefreshIndicator' (#36) from better-ui into main
Reviewed-on: #36
2023-01-28 14:42:11 +01:00
Matyáš Caras 64b7f261a0 fix: přepsat Platform UI a zmenit RefreshIndicator 2023-01-28 14:30:54 +01:00
Matyáš Caras c8d1878a39 chore: update Flutter 2023-01-28 14:30:09 +01:00
Matyáš Caras 26c6e4604e fix: vratit UI zmeny 2022-12-14 20:02:32 +01:00
Matyáš Caras 44130bdc09 Merge pull request 'fix: opravit problém s burzou' (#35) from fix-burza into main
Reviewed-on: #35
2022-12-14 18:50:23 +00:00
Matyáš Caras 33ff600bbe fix: opravit problém s burzou 2022-12-14 19:44:32 +01:00
Matyáš Caras ca3d0a81c6 Merge pull request 'feat: opravit iOS bílou obrazovku a upravit UI' (#32) from ios-ui into main
Reviewed-on: #32
2022-12-12 17:36:56 +00:00
Matyáš Caras e9173a6acd fix: optimalizovat a upravit barvy 2022-12-12 17:52:33 +01:00
Matyáš Caras 365976a853 feat: opravit a rozdelit iOS 2022-12-12 16:48:19 +01:00
Matyáš Caras dfb5a091aa docs: odstranit FOSSA odznak a přidat odkazy na přispění 2022-12-08 20:20:51 +00:00
Matyáš Caras c2ea5a1a11
fix: podpora pro apk split + aktualizace knihovny
Merge pull request #35 from hernikplays/split
2022-12-08 20:34:22 +01:00
Matyáš Caras ff5ec1b7de fix: podpora pro apk split + aktualizace knihovny 2022-12-08 20:30:37 +01:00
Matyáš Caras 0dfb3c1f6a
feat: vylepšit offline užívání
Merge pull request #34 from hernikplays/lepsi-offline
2022-11-21 20:30:55 +01:00
Matyáš Caras c913e3bb95 feat: umožnit ukládat více dnů offline 2022-11-21 20:26:55 +01:00
Matyáš Caras db84284eca chore: přesunout screenshoty do správné složky 2022-11-21 20:26:37 +01:00
Matyáš Caras 881e8d7afd chore(flutter): přejít na flutter wrapper 2022-11-21 17:27:09 +01:00
Matyáš Caras e1a7de0400 chore: update gradle 2022-11-17 16:33:13 +01:00
Matyáš Caras dcc681078c
chore(metadata): vytvořit F-Droid metadata
Merge pull request #32 from hernikplays/fdroid
2022-11-17 14:38:07 +01:00
Matyáš Caras 6f73d000c4 chore(metadata): vytvořit F-Droid metadata 2022-11-17 13:59:34 +01:00
Matyáš Caras 799887eae3
fix: vylepšit podporu pro android 13
Merge pull request #31 from hernikplays/a13
2022-11-17 12:26:05 +01:00
Matyáš Caras ae5984eb4c fix: vylepšit podporu pro android 13
Adaptivní + themed ikona, zeptání na oprávnění oznámení
2022-11-17 12:19:38 +01:00
Matyáš Caras 8cbf2a22e1
docs: aktualizovat kontakt v PP 2022-10-19 11:12:22 +02:00
Matyáš Caras 1bd56edf44 fix(barmenu): opravit překlep v iTunes URL 2022-10-04 17:49:09 +02:00
Matyáš Caras 403aa5f619 fix: aktualizace, změna odkazů a bug fixy
Změněn odkaz na zpětnou vazbu na nový formulář, přidáno tlačítko na zanechání recenze, aktualizována
knihovna canteenlib, opravena chyba s vytvářením notifikací
2022-10-04 17:45:31 +02:00
Matyáš Caras 28cddffe10
docs: přidat stats a copyright 2022-10-02 16:01:24 +00:00
Matyáš Caras f49e24a840 chore: bump verze 2022-09-26 17:11:09 +02:00
Matyáš Caras d2cbebff25
fix(login): opravit vracení na přihlašovací stránku při vracení zpět
Merge pull request #29 from hernikplays/bug-login
2022-09-26 17:06:00 +02:00
Matyáš Caras d2d887e3ee fix(login): opravit vracení na přihlašovací stránku při vracení zpět 2022-09-26 17:02:45 +02:00
Matyáš Caras e5ce622473
fix: nahradit AboutPage AboutDialogem
Merge pull request #28 from hernikplays/aboutdialog
2022-09-26 16:50:44 +02:00
Matyáš Caras 5d4c94c209 fix(about): změnit about stránku na AboutDialog
closes #26
2022-09-26 16:46:22 +02:00
Matyáš Caras 04f9a24e84
chore: synchronizovat 2022-09-26 16:23:26 +02:00
Matyáš Caras a087e605c3 chore: přidat commitizen 2022-09-26 16:20:06 +02:00
Matyáš Caras acb2d91497
feat: výběr z kompatibilních instancí a lepší oznámení o chybějícím obědu
Merge pull request #24 from hernikplays/urlpicker
2022-09-12 15:22:45 +00:00
Matyáš Caras 30f08a6108 fix: odstranit print 2022-09-12 17:19:07 +02:00
Matyáš Caras ce9eb97ac9 feat: vylepšit oznámení o neobjednaném jídle 2022-09-12 17:13:12 +02:00
Matyáš Caras 28eba7d9ab feat: přidat výběr z funkčních instancí 2022-09-12 16:49:42 +02:00
Matyáš Caras c6a60744b7 fix: nastavit fixní verze a opravit offline crash 2022-09-06 20:02:37 +02:00
Matyáš Caras a51e16907d fix: upravit podle flutter_lints 2022-09-06 20:02:17 +02:00
Matyáš Caras 29e94bd612 fix: opravit odhlášení po kliknutí na ano 2022-09-02 21:02:56 +02:00
Matyáš Caras 19380a9ee8
fix: Optimalizovat kód, přidat varování před odhlášením
Merge pull request #19 from hernikplays/oznameni-qf
2022-09-02 20:22:29 +02:00
Matyáš Caras 0ea06fa73a fix: nastavit čas dopředu a zobrazovat 1. variantu 2022-09-02 20:19:17 +02:00
Matyáš Caras ae7c585ba9 fix: změnit ikonu a varování odhlášení (#18) 2022-09-02 19:51:39 +02:00
Matyáš Caras 38f5e0b331 docs: přidat komentáře 2022-09-02 19:30:55 +02:00
Matyáš Caras 49d5044834 docs: upravit CONTRIBUTING 2022-09-02 19:23:42 +02:00
Matyáš Caras daeaa19650
docs: aktualizovat FOSSA badge 2022-06-20 18:47:06 +00:00
Matyáš Caras d57b30b0bf fix: změnit ID kanálu pro android 2022-06-15 20:12:33 +02:00
Matyáš Caras c95518c557 fix: přidat info o baterii a odstranit zbytecny if 2022-06-15 20:04:30 +02:00
Matyáš Caras 6bbc9c2d0a
feat: oznámení před jídlem + tlačítko pro dnešek
PR #17
2022-06-08 19:12:00 +02:00
Matyáš Caras 84297d99a9 fix: odstranit nepoužité importy 2022-06-08 19:09:52 +02:00
Matyáš Caras b712f0e815 fix: poupravit chování nastavení + tlačítko dnes 2022-06-08 19:06:30 +02:00
Matyáš Caras 119f1000e2 fix: aktualizovat licence 2022-06-08 17:18:29 +02:00
Matyáš Caras 93a453463d feat: dokončit oznámení před obědem 2022-06-08 17:12:44 +02:00
Matyáš Caras e7c41fd124 feat: práce na odeslání oznámení před obědem 2022-06-08 09:29:53 +00:00
Matyáš Caras 93ec1e852f feat: pracovat na oznámení před obědem 2022-05-31 17:55:28 +00:00
Matyáš Caras 7ec2ded7ec
feat: implementovat oznámení o neobjednaném jídle
PR #14
2022-05-26 16:40:27 +02:00
Matyáš Caras 3ab7759981 feat: oznámení o neobjednaném jídle 2022-05-26 16:35:02 +02:00
Matyáš Caras f369239473
docs: přidat odkaz na app store 2022-05-23 16:27:16 +00:00
Matyáš Caras 67af9f7239
docs: opravit úrovně nadpisů v PP 2022-05-23 12:00:13 +02:00
Matyáš Caras a42125049a fix: opravit async v setstate 2022-05-20 08:03:53 +02:00
Matyáš Caras dfe8875356 refactor: bump version 2022-05-19 21:52:55 +02:00
Matyáš Caras a47ba9a8cb
fix: přidat licenci na introduction_screen 2022-05-19 19:49:45 +00:00
Matyáš Caras 03227a0de7
docs: upravit obrázky ke stažení 2022-05-19 19:45:28 +00:00
Matyáš Caras ce0c2d2858
fix: synchronizovat opravy z dev větve 2022-05-19 20:01:47 +02:00
Matyáš Caras 2756d8db08
docs: přidat odznáčky 2022-05-19 17:54:27 +00:00
Matyáš Caras 48947f841d
ci: kontrolovat pull requesty 2022-05-19 17:41:44 +00:00
Matyáš Caras 477c60245c
docs: přidat labeler 2022-05-19 17:31:52 +00:00
Matyáš Caras 7dd3985ab7 fix: správný jazyk kalendáře 2022-05-19 19:07:16 +02:00
Matyáš Caras 9a2f079322 fix: zobrazovat uvítání i u zapamatovaných 2022-05-19 18:46:19 +02:00
Matyáš Caras 3a35c67be4 fix: okno u jídel, které nejde objednat 2022-05-19 18:44:56 +02:00
Matyáš Caras 927f101ba1
docs: přidat stručný návod pro přispívání 2022-05-19 16:20:58 +00:00
Matyáš Caras 21e0841f0c
docs: aktualizovat předlohu chyby 2022-05-19 16:19:47 +00:00
Matyáš Caras caab6a1369 Merge branch 'main' of https://github.com/hernikplays/opencanteen 2022-05-19 17:15:14 +02:00
Matyáš Caras 0d4ba7b1a6 refactor: používat conventional commit formát 2022-05-19 17:14:58 +02:00
Matyáš Caras b5a3cf32b9
Create pull_request_template.md 2022-05-19 14:46:25 +00:00
Matyáš Caras 1c541aba70
Create CODE_OF_CONDUCT.md 2022-05-19 14:37:52 +00:00
Matyáš Caras 39caef858a Update changelog 2022-05-18 19:44:22 +02:00
Matyáš Caras 8232961c79 Opravit checkbox (closes #10) 2022-05-18 19:43:12 +02:00
Matyáš Caras 4107b96ed7 Uvítací obrazovka (Finally closes #3) 2022-05-18 19:38:11 +02:00
Matyáš Caras 4818aaba7f Připravit na nové vydání (Closes #3) 2022-05-17 18:14:14 +02:00
Matyáš Caras 1a602f0d2c Zprovoznit offline ukladani jidelnicku a nastaveni 2022-05-16 20:26:39 +02:00
Matyáš Caras 9686b259d9
Update PRIVACY.md 2022-05-15 15:24:18 +00:00
Matyáš Caras 60033b4c45 V podstate jazyky ready 2022-05-15 16:59:55 +02:00
Matyáš Caras 887900c627 Příprava nastavení 2022-05-09 16:55:20 +02:00
Matyáš Caras 7e2d735b47 Práce na vícejazyčnosti 2022-05-03 16:41:45 +02:00
Matyáš Caras 1b779b52af Odstranit nepouzity import 2022-05-02 12:10:06 +02:00
Matyáš Caras d5e9a8ec7d Merge branch 'main' of https://github.com/hernikplays/opencanteen 2022-05-02 12:07:50 +02:00
Matyáš Caras 04277effc2 Bump knihovnu + nastavení 2022-05-02 12:07:47 +02:00
Matyáš Caras 7f956f8bf8
Update README.md 2022-05-02 09:41:29 +00:00
Matyáš Caras 5b7d1e226b
Odebrat šipku na přihlašovací stránce 2022-04-26 17:50:25 +00:00
Matyáš Caras 3b7d7b0f76
Přidat action 2022-04-26 16:27:15 +00:00
Matyáš Caras 190e472eca Merge branch 'main' of https://github.com/hernikplays/opencanteen 2022-04-26 18:20:44 +02:00
Matyáš Caras 0c96776a0e Práce na #4 + pár vylepšení 2022-04-26 18:20:42 +02:00
Matyáš Caras 7b856d0591
Merge pull request #7 from fossabot/add-license-scan-badge
Add license scan report and status
2022-04-26 18:14:31 +02:00
fossabot bf6d6ad646 Add license scan report and status
Signed off by: fossabot <badges@fossa.com>
2022-04-26 11:48:56 -04:00
Matyáš Caras c08dccb2fc
Přidat návod k použití do README 2022-04-26 15:33:58 +00:00
Matyáš Caras d1c6fcc396
Update issue templates 2022-04-26 14:59:58 +00:00
Matyáš Caras de7f9a7caa Upravit CHANGELOG 2022-04-25 21:18:15 +02:00
Matyáš Caras e7db73342d Bump + changelog 2022-04-25 21:14:48 +02:00
Matyáš Caras bf183a379e UI Vylepšení (#3) 2022-04-25 20:35:57 +02:00
Matyáš Caras bf642ee9ed Merge branch 'main' of https://github.com/hernikplays/opencanteen 2022-04-25 20:09:33 +02:00
Matyáš Caras 79aa728ced Vylepšení UI
Práce na #3, closes #6
2022-04-25 20:09:13 +02:00
Matyáš Caras 1783988674
Create FUNDING.yml 2022-04-19 15:12:31 +00:00
Matyáš Caras 5a4dd5e0b6 Přidat O Aplikaci 2022-04-19 16:06:03 +02:00
Matyáš Caras 63f4d6c056 Odstranit stránku domů (#3) 2022-04-19 15:35:40 +02:00
Matyáš Caras be4f729cc0 Lepší 2022-04-12 21:20:22 +02:00
Matyáš Caras d106e78cb3 Vylepšení 2022-04-09 17:54:08 +02:00
102 changed files with 3644 additions and 932 deletions

1
.flutter Submodule

@ -0,0 +1 @@
Subproject commit 7f20e5d18ce4cb80c621533090a7c5113f5bdc52

4
.fossa.yml Normal file
View file

@ -0,0 +1,4 @@
version: 3
targets:
only:
- type: pub

View file

@ -1,28 +0,0 @@
---
name: Chybové hlášení
about: Použijte tuto předlohu, pokud se něco rozbilo
title: ''
labels: bug
assignees: hernikplays
---
**Popis chyby**
Zde popište co se stalo, mělo stát apod.
**Kroky pro replikaci**
Kroky ke spuštění chyby:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Snímky obrazovky**
Chcete-li, přiložte snímky
**Info o zařízení**
- Verze Android: [např. 12]
- Verze aplikace [např. 0.1.0]
**Ostatní**
Sem vepište doplňující informace

83
.gitignore vendored
View file

@ -1,6 +1,6 @@
# Created by https://www.toptal.com/developers/gitignore/api/flutter,visualstudiocode,windows
# Edit at https://www.toptal.com/developers/gitignore?templates=flutter,visualstudiocode,windows
# Created by https://www.toptal.com/developers/gitignore/api/flutter,linux,macos,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=flutter,linux,macos,visualstudiocode
### Flutter ###
# Flutter/Dart/Pub related
@ -66,6 +66,54 @@ lib/generated_plugin_registrant.dart
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
@ -86,31 +134,10 @@ lib/generated_plugin_registrant.dart
.ionide
# Support for Project snippet scope
.vscode/*.code-snippets
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Ignore code-workspaces
*.code-workspace
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/flutter,visualstudiocode,windows
# End of https://www.toptal.com/developers/gitignore/api/flutter,linux,macos,visualstudiocode
node_modules

4
.gitmodules vendored Normal file
View file

@ -0,0 +1,4 @@
[submodule ".flutter"]
path = .flutter
url = https://github.com/flutter/flutter.git
branch = stable

View file

@ -1,10 +1,45 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
# This file should be version controlled.
version:
revision: 097d3313d8e2c7f901932d63e537c1acefb87800
revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
channel: stable
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
- platform: android
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
- platform: ios
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
- platform: linux
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
- platform: macos
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
- platform: web
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
- platform: windows
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

7
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,7 @@
{
"dart.flutterSdkPath": ".flutter",
"conventionalCommits.scopes": [
"dependencies",
"nastaveni"
],
}

91
CHANGELOG.md Normal file
View file

@ -0,0 +1,91 @@
# 1.10.0
- Aktualizovat závislosti
- Změnit minSdk na 21
- Přidat možnost zobrazit alergeny
- Změnit fungování oznámení s aktualizací knihovny
- Žádost o oprávnění k posílání oznámení by se mělo posílat už jen v případě, že uživatel bude chtít používat funkci oznámení
# 1.9.1
- Opravit chybu s propisováním HTML do názvu obědů
# 1.9.0
- Opravit vzhled na iOS
- Opravit chybu s burzou (update canteenlib)
# 1.8.1
- aktualizace závislostí
# 1.8.0
- aktualizace závislostí
- předělání nastavení
- změna nastavení nyní nevyžaduje restart aplikace
# 1.7.0
- Implementovat Material 3 (Android)
- Upravit chování dle platformy
- Předělat jazykový systém na ARB
- Aktualizovat flutter_secure_storage
# 1.6.1
- opravit chybu s přidáváním do burzy aktualizací knihovny
# 1.6.0
- rozdělit iOS a Android UI zvlášť pro možnost využití Cupertino knihovny
- opravit chybu s FlutterLocalNotifications na iOS
- upravit vzhled
# 1.5.1
- aktualizovat knihovnu canteenlib
- přidat podporu pro splitování APK podle ABI
# 1.5.0
- umožnit ukládat více dnů offline
- chyba při ukládání offline vás nyní již nevyhodí ale zobrazí pouze zprávu
- "Přihlašování" pop-up zmizí, když není přihlášení úspěšné
# 1.4.2
- aktualizace knihovny flutter_local_notifications
- lepší podpora pro Android 13
- změna na adaptivní ikony na Androidu
# 1.4.1
- aktualizovat knihovnu canteenlib
- změnit odkaz na odeslání zpětné vazby
- přidat odkaz na hodnocení v obchodu s aplikacemi
- opravit chybu s vytvářením notifikace
# 1.4.0
- Opravit chybu, kdy po stisknutí tlačítka zpět na hlavní stránce byl uživatel vrácen na přihlašovací obrazovku
- Přidat výběr z instancí (aktuálně pouze SŠTE Olomoucká)
- Vylepšit oznámení o neobjednaném jídle
- Nahradit info stránku info dialogem
# 1.3.1
- Odstranit zbytečné podmínky
- Přidat oznámení o optimalizaci baterie
- Změnit ID kanálu pro android oznámení
- Změnit ikonu pro přesunutí na aktuální den
- Přidat varování před odhlášením
- Při prvním zapnutí nastavovat výchozí čas pro oznámení o hodinu dopředu
- V oznámení zobrazit nejdřív variantu a pak název jídla
# 1.3.0
- Odstranit connectivity_plus
- Přidat možnost oznámení s info o obědu v daný čas
- Přidat k jídelníčku tlačítko, které zobrazí dnešní jídelníček
# 1.2.0
- Přidat možnost zobrazení oznámení v případě neobjednaného jídla na příští týden
- Přidat oznámení o rozbitých uložených údajích
# 1.1.2
- Přidat chybějící knihovnu do O Aplikaci (licence)
# 1.1.1
- Přidat informaci o neobjednatelném obědě (specialitka pro apple)
- Zobrazovat uvítací obrazovku při nedokončení i když je uživatel zapamatován
- Kalendář se zobrazuje ve správném jazyce
# 1.1.0
- Přidat uvítací obrazovku při prvním spuštění
- Mírné vyčištění kódu
- Jídlo lze nyní objednat/zrušit i kliknutím na checkbox
# 1.0.0
- Ukládání dnešního jídelníčku offline
- Stránka s možnostmi nastavení aplikace
- Přidán anglický překlad
- Opravy chyb
- Přidání možnosti přeskočení víkendu
# 0.1.1
- Přidán RefreshIndicator na obrazovku s jídelníčkem
- Přidáno odsazení od okrajů u jídelníčku
- Upgrade knihovny
- Odhlášení přesunuto do textového menu
- Odstraněna stránka domů, hlavní stránka je nyní jídelníček
- Přidána stránka `O Aplikaci`
- Dialogové okno k burze se nezobrazí u jídel, která nelze přidat do burzy
- Přidán načítací dialog při objednání (#6)
# 0.1.0
- První verze

128
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
contact@hernikplays.cz.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

46
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,46 @@
# Přispívání do OpenCanteen
OpenCanteen je **aplikace** pro přístup do iCanteen. Pokud chcete přispět kód související s komunikací s iCanteen, podívejte se na [canteenlib](https://github.com/hernikplays/canteenlib).
## Jak přispět do vývoje
### Používám GitHub pod protestem
Tento projekt je aktuálně hostován i na GitHubu. To není ideální; GitHub je uzavřený systém plný obchodních tajemství. Doporučuji přečíst si o kampani
[Give up GitHub](https://GiveUpGitHub.org) od
[Software Freedom Conservancy](https://sfconservancy.org) pro pochopení proč GitHub není ideální místo pro FOSS projekty.
**Příspěvky do kódu přijímám **pouze** skrz mou Forgejo instanci na adrese https://git.mnau.xyz/hernik/opencanteen**
Jakékoli použití kódu pro učení umělých inteligencí, které neumožňuje samotná licence GNU GPL 3.0 či novější, je děláno bez mého souhlasu a vědomí.
### Nahlašování chyb
Prosté vyhledání a nahlášení chyby je asi nejjednodušší a zároveň nejpřínosnější způsob přispívání. Stačí vám běžné zařízení a stažená aplikace, pokud objevíte jakoukoliv chybu nebo nesrovnalost, nahlaste ji v [Issues](https://github.com/hernikplays/opencanteen/issues/new/choose).
Při nahlašování chyb se snažte řídit předlohou pro nahlašování chyb, informace, které se nikam nevlezly, napište úplně na konec.
### Přidání funkcí nebo oprava chyb
Pokud chcete jakkoliv přispět kódem, jste vítání. Zde následují věci, kterými byste se měli řídit.
#### Připravení projektu na vašem počítači
Budete potřebovat
- [Flutter](https://flutter.dev) (poslední stabilní verzi)
- Vývojové prostředí (Doporučuji [VS Code](https://code.visualstudio.com))
- [Git](https://git-scm.org) (není výhradně nutné, ale hodí se pro získání/přidání kódu na GitHub)
Jakmile máte všechno potřebné, [forkněte tento repozitář](https://docs.github.com/en/get-started/quickstart/fork-a-repo) na váš účet.
Poté si **váš** repozitář stáhněte, buď pomocí tlačítka `Code > Download ZIP` nebo (máte-li nainstalovaný Git) pomocí příkazu `git clone https://github.com/VASEJMENO/opencanteen`.
Následně můžete složku otevřít ve vámi preferovaném editoru a začít editovat
Budete-li chtít nahrát změny zpět do vašeho GitHub repozitáře, buďto je nahrajte na webu nebo použijte následující příkazy (jeden po druhém; může vyžadovat přihlášení):
- `git add .`
- `git commit -m 'feature: nové funkce'` (Místo "nové funkce" je dobré přidat krátký popis co přidáváte. **Tento repozitář se řídí [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) formátem, ujistěte se, že váš commit je ve stejném formátu**)
- `git push main`
#### Přidání kódu zpět do repozitáře
Jakmile máte přidáno všechno, je na čase otevřít [pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork) v našem repozitáři.
Všechny pull requesty **musí** být směřovány na **jinou větev, než `main`** a jejích název musí odpovídat [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) formátu, jinak budou automaticky zamítnuty.
Pokuste se v těle pull requestu popsat jaké funkce přidáváte nebo opravujete, případně přidejte odkaz na otevřený problém, pokud s ním souvisí.
Nějaký člověk váš kód zkontroluje a případně okomentuje co byste měl změnit. V případě, že všechno půjde hladce, vám potvrdíme pull request a váš kód se stane součástí.

View file

@ -1,20 +1,54 @@
## Zásady používání a ochrany soukromí aplikace OpenCanteen
Platí od 5. 4. 2022
Platí od 15. 5. 2022
Některé informace se mohou vztahovat pro oficiálně nevydané funkce.
[Předchozí verze](https://github.com/hernikplays/opencanteen/blob/0c96776a0e5daee1a2056ce93179b40ff06b29ca/PRIVACY.md)
### Používání
- Tato aplikace není vyvíjena nebo podporována firmou Z-WARE s.r.o. a není oficiální klient pro systém iCanteen
- Uživatel aplikace sám zodpovídá za svůj účet a údaje
- Uživatel aplikace sám zodpovídá za svůj účet, údaje a chování
- Vývojář aplikace neručí za stabilitu aplikace ani za vzniklé škody, které mohly vzniknout používáním aplikace
- Použití aplikace se řídí případnými podmínkami k používání systému iCanteen
## Ochrana soukromí
### Ochrana soukromí
- Aplikace neobsahuje žádné analytické nebo sledovací systémy
- Aplikace odesílá data pouze na URL instance systému iCanteen, kterou uživatel aplikace sám zadá
- V případě, že tato instance není zabezpečena protokolem HTTPS, neručí vývojář aplikace za vzniklá nebezpečí
- Aplikace neobsahuje reklamy
- Aplikace dlouhodobě ukládá údaje uživatele (přihlašovací jméno, heslo, URL k instanci) pouze v případě, že uživatel při přihlašování povolí možnost `Zapamatovat si mě`. V tom případě jsou data zašifrována a uložena na zařízení uživatele
- Aplikace dlouhodobě ukládá do zařízení přihlašovací údaje uživatele (tj. přihlašovací jméno, heslo, URL k instanci) pouze v případě, že uživatel při přihlašování povolí možnost `Zapamatovat si mě`. V tom případě jsou data zašifrována a uložena na zařízení uživatele
- V opačném případě jsou údaje uložené v mezipaměti jen na dobu nezbytně nutnou a následně smazány operačním systémem
- V případě, že uživatel v nastavení povolí možnost `Ukládat jídelníček na dnešní den offline`, bude jídelníček pro daný den stažen a lokálně uložen v textové podobě na zařízení uživatele
- Každý den se jídelníček přepíše na aktuální den
- V případě, že se rozhodne tuto funkci vypnout, bude soubor automaticky odstraněn
### Kontakt
Preferovaná forma komunikace je skrze Diskuze nebo Issues.
V případech nejvyšší nutnosti je můj e-mail `contact zavináč hernikplays.cz`
V případech nejvyšší nutnosti je můj e-mail `matyas zavináč caras.cafe`
## Terms of use and privacy policy of OpenCanteen
In effect from 15. 5. 2022
Some information may refer to unreleased functions of the app.
[Previous version](https://github.com/hernikplays/opencanteen/blob/0c96776a0e5daee1a2056ce93179b40ff06b29ca/PRIVACY.md)
### Usage
- This application is not developed nor endorsed by Z-WARE s.r.o. company and is not an official way to access the iCanteen system
- The user is responsible for his account, details and actions
- The application developer does not guarantee application's stability and is not responsible for any losses due to usage of this application
- In case of terms of use of the iCanteen system, you are responsible for following them when using the application
### Privacy policy
- The application does not contain any tracking, advertisment or analytics system
- The application only communicates with the iCanteen instance specified by the user
- In case the instance is not using HTTPS connection, the developer cannot be held responsible for losses or dangers
- The application stores user login details (i.e. username, password, instance URL) only if the user checks the `Remember me` checkbox when signing in. In this case the data is encrypted and stored on the user's device
- Otherwise the data is stored locally in cache
- In case the user enables `Save today's menu offline` in the settings, the menu for the day will be downloaded and saved in plaintext form on the user's device
- The menu gets overwritten on a new day
- If the user decides to disable this function, the plaintext file will be deleted
### Contact
Prefered way of communication is through the Issues system
If it is important, my e-mail address is `matyas AT caras.cafe`

View file

@ -1,15 +1,49 @@
# OpenCanteen
Open-Source **neoficiální** iCanteen klient
Open-Source **neoficiální** aplikace pro přístup do iCanteen
[![wakatime](https://wakatime.com/badge/user/17178fab-a33c-430f-a764-7b3f26c7b966/project/e3ff9994-0026-4041-a529-1cb2041bdf4b.svg)](https://wakatime.com/badge/user/17178fab-a33c-430f-a764-7b3f26c7b966/project/e3ff9994-0026-4041-a529-1cb2041bdf4b)
[![Codemagic build status](https://api.codemagic.io/apps/62863e4c96304ce0518a1694/62863e4c96304ce0518a1693/status_badge.svg)](https://codemagic.io/apps/62863e4c96304ce0518a1694/62863e4c96304ce0518a1693/latest_build) [![Commit Style: Conventional Commits](https://img.shields.io/badge/commit%20style-conventional%20commits-pink)](https://www.conventionalcommits.org/en/v1.0.0/)
### Upstream repozitář je nyní na adrese [https://git.mnau.xyz/hernik/opencanteen](https://git.mnau.xyz/hernik/opencanteen), všechny problémy hlaste tam.
## Co umí
Aplikace vás přihlásí do instance iCanteen ***pokud ji podporuje [canteenlib](https://github.com/hernikplays/canteenlib/blob/main/COMPATIBILITY.md), jinak experimentálně***, a umožní vám zobrazit, objednávat obědy, objednávat nebo přidávat jídlo na burzu<sup>beta</sup>.
Aplikace vás přihlásí do vaší iCanteen ***pokud ji podporuje [canteenlib](https://github.com/hernikplays/canteenlib/blob/main/COMPATIBILITY.md), jinak experimentálně***, a umožní vám zobrazit, objednávat obědy, objednávat nebo přidávat jídlo na burzu.
## Co se plánuje
- Offline ukládání jídelníčku a zakoupených jídel
- Burza
- Sledovač burzy
## Jak používat
Jednoduchý návod k použití naleznete [zde](https://github.com/hernikplays/opencanteen/wiki/Pou%C5%BE%C3%ADv%C3%A1n%C3%AD-aplikace)
## Stažení (BETA verze)
<a href="https://play.google.com/store/apps/details?id=cz.hernikplays.opencanteen"><img src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png" alt="Play Logo" width="300px"></a>
## Stažení
<div align="center">
<a href="https://play.google.com/store/apps/details?id=cz.hernikplays.opencanteen" target="_blank"><img src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png" alt="Play Logo" width="300px"></a><br>
<a href="https://apps.apple.com/us/app/opencanteen/id1621124445"><img src="https://developer.apple.com/assets/elements/badges/download-on-the-app-store.svg" width="200px"></a>
### Beta
<a href="https://testflight.apple.com/join/HOQhP3rW" target="_blank">App Store</a><br>
<a href="https://play.google.com/apps/testing/cz.hernikplays.opencanteen" target="_blank">Google Play</a>
</div>
## Statistiky
<div align="center">
<img src="https://repobeats.axiom.co/api/embed/ce91f6018ce5523dc8d655df771f4f504c2c6664.svg" alt="repobeats stats">
</div>
## Přispět
Přispět na vývoj můžete skrz
- Monero: `49uzFSxAsT92sXUsCEgh11VX7pmNZcoeKi4fEWbLGc2oWGMUVNcDDqGVB97ak96LqEBqsMXLS752bjgyVzbFcVwLNke4pNd`
- Bitcoin: `3NzqkBZgWgjj1NYj2JwmBBptPWw6wt7dHS`
- Kód: viz CONTRIBUTING
## Používám GitHub pod protestem
Tento projekt je aktuálně hostován i na GitHubu. To není ideální; GitHub je uzavřený systém plný obchodních tajemství. Doporučuji přečíst si o kampani
[Give up GitHub](https://GiveUpGitHub.org) od
[Software Freedom Conservancy](https://sfconservancy.org) pro pochopení proč GitHub není ideální místo pro FOSS projekty.
Příspěvky do kódu přijímám **pouze** skrz mou Forgejo instanci na adrese https://git.mnau.xyz/hernik/opencanteen
Jakékoli použití kódu pro učení umělých inteligencí, které neumožňuje samotná licence GNU GPL 3.0 či novější, je děláno bez mého souhlasu a vědomí.
## Licence
**Copyright (c) 2022 Matyáš Caras a přispěvatelé**
Tento program je svobodný software. Kde není uvedeno jinak je tento program a zdrojový kód šířen pod licencí GNU General Public License verze 3 nebo pozdější. Všechny detaily licence najdete [zde](https://github.com/hernikplays/opencanteen/blob/main/LICENSE)

View file

@ -31,9 +31,12 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
}
android {
compileSdkVersion flutter.compileSdkVersion
compileSdkVersion 33
compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 8
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
@ -47,12 +50,12 @@ android {
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "cz.hernikplays.opencanteen"
minSdkVersion 18
targetSdkVersion flutter.targetSdkVersion
minSdkVersion 21
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true
}
signingConfigs {
@ -76,4 +79,18 @@ flutter {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:multidex:1.0.3'
implementation 'androidx.appcompat:appcompat:1.3.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
}
ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3]
import com.android.build.OutputFile
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
def abiVersionCode = project.ext.abiCodes.get(output.getFilter(OutputFile.ABI))
if (abiVersionCode != null) {
output.versionCodeOverride = variant.versionCode * 10 + abiVersionCode
}
}
}

View file

@ -1,10 +1,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cz.hernikplays.opencanteen">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<application
android:label="OpenCanteen"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
android:icon="@mipmap/ic_launcher"
android:allowBackup="false"
android:fullBackupContent="false">
<activity
android:name=".MainActivity"
android:exported="true"
@ -13,7 +16,8 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"
android:screenOrientation="portrait">
android:screenOrientation="portrait"
android:showWhenLocked="true">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M8.25,42 L6.15,39.9 27.15,18.9Q26.05,16.5 26.65,13.925Q27.25,11.35 29.5,9.1Q31.75,6.9 34.95,6.275Q38.15,5.65 40.2,7.7Q42.3,9.8 41.625,12.95Q40.95,16.1 38.6,18.5Q36.55,20.6 34.025,21.25Q31.5,21.9 29.3,20.95L25.95,24.3L41.55,39.9L39.45,42L23.85,26.4ZM14.5,24.45 L8.55,18.5Q6,15.95 5.9,12.45Q5.8,8.95 8.2,6.25L20.45,18.5Z"/>
</vector>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#4f4685</color>
</resources>

View file

@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.6.10'
ext.kotlin_version = '1.9.10'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@ -26,6 +26,6 @@ subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
tasks.register("clean", Delete) {
delete rootProject.buildDir
}

View file

@ -1,6 +1,5 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip

BIN
assets/burza.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
assets/doburzy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
assets/fore.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
assets/objednavam.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

113
flutterw Executable file
View file

@ -0,0 +1,113 @@
#!/usr/bin/env sh
##############################################################################
##
## Flutter start up script for UN*X
## Version: v1.3.1
## Date: 2022-11-21 17:25:38
##
## Use this flutter wrapper to bundle Flutter within your project to make
## sure everybody builds with the same version.
##
## Read about the install and uninstall process in the README on GitHub
## https://github.com/passsy/flutter_wrapper
##
## Inspired by gradle-wrapper.
##
##############################################################################
echoerr() { echo "$@" 1>&2; }
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ]; do
ls=$(ls -ld "$PRG")
link=$(expr "$ls" : '.*-> \(.*\)$')
if expr "$link" : '/.*' >/dev/null; then
PRG="$link"
else
PRG=$(dirname "$PRG")"/$link"
fi
done
SAVED="$(pwd)"
cd "$(dirname "$PRG")/" >/dev/null
APP_HOME="$(pwd -P)"
cd "$SAVED" >/dev/null
FLUTTER_SUBMODULE_NAME='.flutter'
GIT_HOME=$(git -C "${APP_HOME}" rev-parse --show-toplevel)
FLUTTER_DIR="${GIT_HOME}/${FLUTTER_SUBMODULE_NAME}"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
# Fix not initialized flutter submodule
if [ ! -f "${FLUTTER_DIR}/bin/flutter" ]; then
echoerr "$FLUTTER_SUBMODULE_NAME submodule not initialized. Initializing..."
git submodule update --init "${FLUTTER_DIR}"
fi
# Detect detach HEAD and fix it. commands like upgrade expect a valid branch, not a detached HEAD
FLUTTER_SYMBOLIC_REF=$(git -C "${FLUTTER_DIR}" symbolic-ref -q HEAD)
if [ -z "${FLUTTER_SYMBOLIC_REF}" ]; then
FLUTTER_REV=$(git -C "${FLUTTER_DIR}" rev-parse HEAD)
FLUTTER_CHANNEL=$(git -C "${GIT_HOME}" config -f .gitmodules submodule.${FLUTTER_SUBMODULE_NAME}.branch)
if [ -z "${FLUTTER_CHANNEL}" ]; then
echoerr "Warning: Submodule '$FLUTTER_SUBMODULE_NAME' doesn't point to an official Flutter channel \
(one of stable|beta|dev|master). './flutterw upgrade' will fail without a channel."
echoerr "Fix this by adding a specific channel with:"
echoerr " - './flutterw channel <channel>' or"
echoerr " - Add 'branch = <channel>' to '$FLUTTER_SUBMODULE_NAME' submodule in .gitmodules"
else
echoerr "Fixing detached HEAD: '$FLUTTER_SUBMODULE_NAME' submodule points to a specific commit $FLUTTER_REV, not channel '$FLUTTER_CHANNEL' (as defined in .gitmodules)."
# Make sure channel is fetched
# Remove old channel branch because it might be moved to an unrelated commit where fast-forward pull isn't possible
git -C "${FLUTTER_DIR}" branch -q -D "${FLUTTER_CHANNEL}" 2> /dev/null || true
git -C "${FLUTTER_DIR}" fetch -q origin
# bind current HEAD to channel defined in .gitmodules
git -C "${FLUTTER_DIR}" checkout -q -b "${FLUTTER_CHANNEL}" "${FLUTTER_REV}"
git -C "${FLUTTER_DIR}" branch -q -u "origin/${FLUTTER_CHANNEL}" "${FLUTTER_CHANNEL}"
echoerr "Fixed! Migrated to channel '$FLUTTER_CHANNEL' while staying at commit $FLUTTER_REV. './flutterw upgrade' now works without problems!"
git -C "${FLUTTER_DIR}" status -bs
fi
fi
# Wrapper tasks done, call flutter binary with all args
set -e
"$FLUTTER_DIR/bin/flutter" "$@"
set +e
# Post flutterw tasks. exit code from /bin/flutterw will be used as final exit
FLUTTER_EXIT_STATUS=$?
if [ ${FLUTTER_EXIT_STATUS} -eq 0 ]; then
# ./flutterw channel CHANNEL
if echo "$@" | grep -q "channel"; then
if [ -n "$2" ]; then
# make sure .gitmodules is updated as well
CHANNEL=${2} # second arg
git config -f "${GIT_HOME}/.gitmodules" "submodule.${FLUTTER_SUBMODULE_NAME}.branch" "${CHANNEL}"
# makes sure nobody forgets to do commit all changed files
git add "${GIT_HOME}/.gitmodules"
git add "${FLUTTER_DIR}"
fi
fi
# ./flutterw upgrade
if echo "$@" | grep -q "upgrade"; then
# makes sure nobody forgets to do commit the changed submodule
git add "${FLUTTER_DIR}"
# flutter packages get runs automatically. Stage those changes as well
if [ -f pubspec.lock ]; then
git add pubspec.lock
fi
fi
fi
exit ${FLUTTER_EXIT_STATUS}

View file

@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
<string>11.0</string>
</dict>
</plist>

View file

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View file

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

41
ios/Podfile Normal file
View file

@ -0,0 +1,41 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '11.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

79
ios/Podfile.lock Normal file
View file

@ -0,0 +1,79 @@
PODS:
- Flutter (1.0.0)
- flutter_keyboard_visibility (0.0.1):
- Flutter
- flutter_local_notifications (0.0.1):
- Flutter
- flutter_native_timezone (0.0.1):
- Flutter
- flutter_secure_storage (6.0.0):
- Flutter
- fluttertoast (0.0.2):
- Flutter
- Toast
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- Toast (4.0.0)
- url_launcher_ios (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- flutter_native_timezone (from `.symlinks/plugins/flutter_native_timezone/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS:
trunk:
- Toast
EXTERNAL SOURCES:
Flutter:
:path: Flutter
flutter_keyboard_visibility:
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
flutter_local_notifications:
:path: ".symlinks/plugins/flutter_local_notifications/ios"
flutter_native_timezone:
:path: ".symlinks/plugins/flutter_native_timezone/ios"
flutter_secure_storage:
:path: ".symlinks/plugins/flutter_secure_storage/ios"
fluttertoast:
:path: ".symlinks/plugins/fluttertoast/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
flutter_native_timezone: 5f05b2de06c9776b4cc70e1839f03de178394d22
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
COCOAPODS: 1.12.1

View file

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@ -13,6 +13,7 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
ECEF07EFF70219039EC91A16 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7322157B64E41A54727F1B5 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@ -42,6 +43,10 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B2721B88A12E59F3457F19ED /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
BC9FB05A1DCF7C7EFD0E5EBB /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
DBABB66BE912BBC3B3B3D706 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
E7322157B64E41A54727F1B5 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -49,12 +54,32 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
ECEF07EFF70219039EC91A16 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
1CA2C3BE126DAC67B3E72712 /* Pods */ = {
isa = PBXGroup;
children = (
B2721B88A12E59F3457F19ED /* Pods-Runner.debug.xcconfig */,
DBABB66BE912BBC3B3B3D706 /* Pods-Runner.release.xcconfig */,
BC9FB05A1DCF7C7EFD0E5EBB /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
8E9103B40D6588B574AD43FA /* Frameworks */ = {
isa = PBXGroup;
children = (
E7322157B64E41A54727F1B5 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@ -72,6 +97,8 @@
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
1CA2C3BE126DAC67B3E72712 /* Pods */,
8E9103B40D6588B574AD43FA /* Frameworks */,
);
sourceTree = "<group>";
};
@ -105,12 +132,14 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
3A5C4CD1EE7C597400A4EF9C /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
C63F8C1A7AF68913C333DE72 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@ -127,7 +156,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@ -169,12 +198,36 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
3A5C4CD1EE7C597400A4EF9C /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
@ -185,6 +238,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@ -197,6 +251,23 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
C63F8C1A7AF68913C333DE72 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@ -272,7 +343,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@ -349,7 +420,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -398,7 +469,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@ -478,4 +549,4 @@
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
}

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1430"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View file

@ -4,4 +4,7 @@
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View file

@ -1,5 +1,6 @@
import UIKit
import Flutter
import flutter_local_notifications
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
@ -7,6 +8,14 @@ import Flutter
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// This is required to make any communication available in the action isolate.
FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (registry) in
GeneratedPluginRegistrant.register(with: registry)
}
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View file

@ -2,10 +2,15 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleLocalizations</key>
<array>
<string>cs</string>
<string>en</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Opencanteen</string>
<string>OpenCanteen</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@ -43,5 +48,9 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

3
l10n.yaml Normal file
View file

@ -0,0 +1,3 @@
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart

69
lib/color_schemes.g.dart Normal file
View file

@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
const lightColorScheme = ColorScheme(
brightness: Brightness.light,
primary: Color(0xFF5F52A7),
onPrimary: Color(0xFFFFFFFF),
primaryContainer: Color(0xFFE5DEFF),
onPrimaryContainer: Color(0xFF1A0261),
secondary: Color(0xFF5F5C71),
onSecondary: Color(0xFFFFFFFF),
secondaryContainer: Color(0xFFE5DFF9),
onSecondaryContainer: Color(0xFF1C192B),
tertiary: Color(0xFF763EC3),
onTertiary: Color(0xFFFFFFFF),
tertiaryContainer: Color(0xFFEDDCFF),
onTertiaryContainer: Color(0xFF290056),
error: Color(0xFFBA1A1A),
errorContainer: Color(0xFFFFDAD6),
onError: Color(0xFFFFFFFF),
onErrorContainer: Color(0xFF410002),
background: Color(0xFFFFFBFF),
onBackground: Color(0xFF1C1B1F),
surface: Color(0xFFFFFBFF),
onSurface: Color(0xFF1C1B1F),
surfaceVariant: Color(0xFFE5E0EC),
onSurfaceVariant: Color(0xFF48454E),
outline: Color(0xFF79767F),
onInverseSurface: Color(0xFFF4EFF4),
inverseSurface: Color(0xFF313033),
inversePrimary: Color(0xFFC8BFFF),
shadow: Color(0xFF000000),
surfaceTint: Color(0xFF5F52A7),
outlineVariant: Color(0xFFC9C5D0),
scrim: Color(0xFF000000),
);
const darkColorScheme = ColorScheme(
brightness: Brightness.dark,
primary: Color(0xFFC8BFFF),
onPrimary: Color(0xFF302175),
primaryContainer: Color(0xFF473A8D),
onPrimaryContainer: Color(0xFFE5DEFF),
secondary: Color(0xFFC9C3DC),
onSecondary: Color(0xFF312E41),
secondaryContainer: Color(0xFF484459),
onSecondaryContainer: Color(0xFFE5DFF9),
tertiary: Color(0xFFD7BAFF),
onTertiary: Color(0xFF440088),
tertiaryContainer: Color(0xFF5D20A9),
onTertiaryContainer: Color(0xFFEDDCFF),
error: Color(0xFFFFB4AB),
errorContainer: Color(0xFF93000A),
onError: Color(0xFF690005),
onErrorContainer: Color(0xFFFFDAD6),
background: Color(0xFF1C1B1F),
onBackground: Color(0xFFE5E1E6),
surface: Color(0xFF1C1B1F),
onSurface: Color(0xFFE5E1E6),
surfaceVariant: Color(0xFF48454E),
onSurfaceVariant: Color(0xFFC9C5D0),
outline: Color(0xFF938F99),
onInverseSurface: Color(0xFF1C1B1F),
inverseSurface: Color(0xFFE5E1E6),
inversePrimary: Color(0xFF5F52A7),
shadow: Color(0xFF000000),
surfaceTint: Color(0xFFC8BFFF),
outlineVariant: Color(0xFF48454E),
scrim: Color(0xFF000000),
);

83
lib/l10n/app_cs.arb Normal file
View file

@ -0,0 +1,83 @@
{
"about": "O Aplikaci",
"agree": "Souhlasím",
"appName": "OpenCanteen",
"balance": "Kredit: ",
"cannotOrder": "Toto jídlo není možné objednat.",
"close": "Zavřít",
"copyright": "© 2022 Matyáš Caras a přispěvatelé",
"disagree": "Nesouhlasím",
"errorContacting": "Nastala chyba při kontaktování serveru, zkontrolujte připojení",
"errorOrdering": "Jídlo se nepodařilo objednat",
"exchange": "Burza",
"exchangeError": "Nepodařilo se vložit jídlo na burzu",
"friday": "Pátek",
"home": "Domů",
"httpLogin": "Snažíte se přihlásit přes nešifrované spojení HTTP, jste si jisti, že tak chcete učinit?",
"iCanteenUrl": "iCanteen URL",
"inExchange": "V BURZE",
"license": "Vydáno pod licencí GNU GPLv3",
"loading": "Načítání...",
"logIn": "Přihlášení",
"loggingIn": "Přihlašuji vás...",
"loginFailed": "Přihlášení se nezdařilo",
"menu": "Jídelníček",
"monday": "Pondělí",
"mustLogout": "Online přejdete přetažením dolů.",
"no": "Ne",
"noChange": "Ne, změnit",
"noExchange": "Žádné jídlo v burze",
"noFood": "Žádné jídlo pro tento den",
"notOfficial": "Toto není oficiální aplikace k ovládání iCanteen. Autor neručí za ztráty nebo nefunkčnost v souvislosti s používáním této aplikace. Pokračováním souhlasíte.",
"offline": "JSTE OFFLINE",
"ok": "OK",
"order": "Objednat",
"orderSuccess": "Jídlo bylo úspěšně objednáno",
"ordered": "Objednáno",
"ordering": "Objednávám...",
"password": "Heslo",
"pullToReload": "Potáhněte zvrchu pro načtení",
"rememberMe": "Zapamatovat si mě",
"reportBugs": "Zpětná vazba",
"saturday": "Sobota",
"saveOffline": "Ukládat jídelníček offline",
"settings": "Nastavení",
"signOut": "Odhlásit se",
"skipWeekend": "Při procházení menu přeskočit víkend",
"sunday": "Neděle",
"thursday": "Čtvrtek",
"tuesday": "Úterý",
"username": "Uživatelské jméno",
"verifyExchange": "Opravdu chcete vložit jídlo na burzu?",
"warning": "Pozor!",
"wednesday": "Středa",
"yes": "Ano",
"aboutFromExch": "Žádné jídlo? Žádný problém!",
"aboutOrder": "Klepnutím objednáte",
"aboutToExch": "Nemáte chuť?",
"appDesc": "OpenCanteen je neoficiální aplikace pro přístup do obědového systému iCanteen",
"howFromExch": "Z vysunovacího menu přejděte do burzy a objednejte si z dostupných jídel",
"howOrder": "Jednoduše klepněte na jídlo s modrým políčkem a máte objednáno",
"howToExch": "Stačí dlouze podržet jméno objednaného jídla a můžete ho přesunout na nebo z burzy",
"welcome": "Vítejte v OpenCanteen",
"next": "Další",
"checkOrdered": "Kontrolovat, jestli mám objednáno na příští týden",
"noOrder": "Na přístí týden nemáte objednané žádné jídlo!",
"corrupted": "Nastal problém s dešifrováním uložených údajů, prosím zkuste vyčistit veškerá data této aplikace.",
"notifyAt": "Odeslat v",
"notifyLunch": "V určený čas odeslat notifikaci s informacemi o obědě",
"lunchNotif": "Dnes máte objednáno",
"error": "Chyba",
"needRemember": "Musíte své přihlašovací údaje uložit na přihlašovací obrazovce",
"notifyWarning": "Vaše zařízení může mít povolenou optimalizaci baterie, což může způsobovat neodesílání oznámení. Zkontrolujte nastavení ve vašem zařízení.",
"signOutWarn": "Opravdu se chcete odhlásit?",
"jump": "Přeskočit",
"source": "Zdrojový kód",
"review": "Ohodnotit aplikaci",
"saveCount": "Počet dnů dostupných offline (Akt. limit je 7)",
"errorSaving": "Při ukládání offline nastala chyba, zkuste to znovu později.",
"todayTooltip": "Přejít na dnešní jídelníček",
"settingsExperience":"Zážitek",
"settingsFunctions":"Extra funkce",
"showAllergens":"Zobrazovat alergeny, jsou-li dostupné"
}

83
lib/l10n/app_en.arb Normal file
View file

@ -0,0 +1,83 @@
{
"about": "About",
"agree": "I agree",
"appName": "OpenCanteen",
"balance": "Balance: ",
"cannotOrder": "This food cannot be ordered.",
"close": "Close",
"copyright": "© 2022 Matyáš Caras and contributors",
"disagree": "I disagree",
"errorContacting": "Failed to contact the server, check your connection.",
"errorOrdering": "Could not order food.",
"exchange": "Exchange",
"exchangeError": "Could not put food on exchange.",
"friday": "Friday",
"home": "Home",
"httpLogin": "You are trying to sign in using an insecure HTTP connection, are you sure you want to continue?",
"iCanteenUrl": "iCanteen URL",
"inExchange": "ON EXCHANGE",
"license": "Released under the GNU GPLv3",
"loading": "Loading...",
"logIn": "Sign in",
"loggingIn": "Signing you in...",
"loginFailed": "Sign in failed",
"menu": "Food Menu",
"monday": "Monday",
"mustLogout": "To go online, pull down.",
"no": "No",
"noChange": "No, change",
"noExchange": "No meal in exchange",
"noFood": "No meal for this day",
"notOfficial": "This is not an official app for accessing iCanteen. The author is not responsible for non-functionality or losses while using this app. By continuing you agree.",
"offline": "YOU ARE OFFLINE",
"ok": "OK",
"order": "Order",
"orderSuccess": "Meal ordered succesfully",
"ordered": "Ordered",
"ordering": "Ordering...",
"password": "Password",
"pullToReload": "Pull to reload",
"rememberMe": "Remember me",
"reportBugs": "Feedback",
"saturday": "Saturday",
"saveOffline": "Save menu offline",
"settings": "Settings",
"signOut": "Sign out",
"skipWeekend": "Skip weekends when browsing menu",
"sunday": "Sunday",
"thursday": "Thursday",
"tuesday": "Tuesday",
"username": "Username",
"verifyExchange": "Are you sure you want to put this meal on exchange?",
"warning": "Warning!",
"wednesday": "Wednesday",
"yes": "Yes",
"appDesc": "OpenCanteen is a mobile app for accessing iCanteen.",
"welcome": "Welcome to OpenCanteen",
"aboutOrder": "Order with a tap",
"howOrder": "Simply tap on a meal with a blue checkbox next to it and it's done!",
"aboutToExch": "Don't want your food?",
"howToExch": "If you cannot cancel your order, simply long-tap on the ordered food and put it into the exchange.",
"aboutFromExch": "No food? No problem!",
"howFromExch": "Simply check the exchange from the sidebar and order when a meal is available.",
"next": "Next",
"checkOrdered": "Check if I have ordered food for the next week",
"noOrder": "You did not order any food for the next week!",
"corrupted": "The saved credentials seem to be corrupted, please try clearing the application's data.",
"notifyAt": "Send notification at",
"notifyLunch": "Send a notification with meal info",
"lunchNotif": "Today's ordered meal",
"error": "Error",
"needRemember": "You need to save your login details on the login screen first",
"notifyWarning": "Your device may have battery optimization enabled. This may cause notifications to not be sent. Check the application info in your device's settings.",
"signOutWarn": "Do you really want to sign out?",
"jump": "Jump",
"source": "Source code",
"review": "Review the app",
"saveCount": "Number of days to save offline (Current limit is 7)",
"errorSaving": "An error occured while trying to save menu offline, try again later.",
"todayTooltip": "Go to today's meal",
"settingsExperience":"App Experience",
"settingsFunctions":"Extra Functions",
"showAllergens":"Show allergens, if available"
}

View file

@ -2,7 +2,7 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class LoginManager {
static Future<Map<String, String>?> getDetails() async {
// zkontrolovat secure storage pokud je něco uložené
// check secure storage for details
const storage = FlutterSecureStorage();
var user = await storage.read(key: "oc_user");
var pass = await storage.read(key: "oc_pass");
@ -17,4 +17,9 @@ class LoginManager {
await storage.write(key: "oc_pass", value: pass);
await storage.write(key: "oc_url", value: url);
}
static Future<bool> rememberme() async {
const storage = FlutterSecureStorage();
return await storage.containsKey(key: "oc_pass");
}
}

View file

@ -1,229 +1,170 @@
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:opencanteen/loginmanager.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:opencanteen/okna/home.dart';
import 'package:canteenlib/canteenlib.dart';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:canteenlib/canteenlib.dart';
import 'package:opencanteen/okna/login.dart';
import 'package:opencanteen/util.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:intl/intl.dart';
import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/timezone.dart' as tz;
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'color_schemes.g.dart';
import 'loginmanager.dart';
/*
Copyright (C) 2022 Matyáš Caras a přispěvatelé
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final settings = SettingsManager();
/// Used to setup notifications about ordered food
void setupNotification(SharedPreferences prefs, tz.Location l) async {
String title;
String locale = Intl.getCurrentLocale();
switch (locale) {
case "cs_CZ":
title = "Dnes máte objednáno";
break;
default:
title = "Today's ordered meal";
}
/*if (prefs.getBool("offline") ?? false) {
// TODO grab data from offline storage
} else {*/
// data from the web
var d = await LoginManager.getDetails(); // grab login
if (d != null) {
var c = Canteen(d["url"]!);
if (await c.login(d["user"]!, d["pass"]!)) {
var jidla = await c.jidelnicekDen();
try {
var jidlo = jidla.jidla
.singleWhere((element) => element.objednano); // grab ordered meal
var kdy = DateTime.parse(prefs.getString(
"oznameni_cas")!); // save the time the notif should be sent
var cas = timeToDate(
TimeOfDay(hour: kdy.hour, minute: kdy.minute),
);
if (cas.isBefore(DateTime.now())) return;
// notif data
const AndroidNotificationDetails androidSpec =
AndroidNotificationDetails('predobedem', 'Oznámení před obědem',
channelDescription: 'Oznámení o dnešním jídle',
importance: Importance.max,
priority: Priority.high,
styleInformation: BigTextStyleInformation(''),
ticker: 'today meal');
// plan through lib
await flutterLocalNotificationsPlugin.zonedSchedule(
0,
title,
"${jidlo.varianta} - ${jidlo.nazev}",
tz.TZDateTime.from(cas, l),
const NotificationDetails(android: androidSpec),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime);
} on StateError catch (_) {
// no ordered meal found
}
}
// }
}
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
tz.initializeTimeZones();
var l = tz.getLocation(await FlutterNativeTimezone.getLocalTimezone());
tz.setLocalLocation(l);
var prefs = await SharedPreferences.getInstance();
if (prefs.getBool("oznamit") ?? false) {
setupNotification(prefs, l);
}
settings.checkOrdered = prefs.getBool("tyden") ?? false;
settings.saveOffline = prefs.getBool("oznamit") ?? false;
settings.skipWeekend = prefs.getBool("skip") ?? false;
settings.allergens = prefs.getBool("allergens") ?? false;
// notif library setup
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('notif_icon');
const ios = DarwinInitializationSettings();
const InitializationSettings initializationSettings =
InitializationSettings(android: initializationSettingsAndroid, iOS: ios);
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
localizationsDelegates: GlobalMaterialLocalizations.delegates,
supportedLocales: const [Locale("cs")],
title: 'OpenCanteen',
theme: ThemeData(
primarySwatch: Colors.purple,
),
darkTheme: ThemeData(
brightness: Brightness.dark,
primarySwatch: Colors.purple,
),
home: const LoginPage(),
);
}
}
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
TextEditingController userControl = TextEditingController();
TextEditingController passControl = TextEditingController();
TextEditingController canteenControl = TextEditingController();
bool rememberMe = false;
@override
void initState() {
super.initState();
LoginManager.getDetails().then((r) async {
var connectivityResult = await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
"Nastala chyba při kontaktování serveru, zkontrolujte připojení"),
),
);
}
if (r != null) {
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => Dialog(
child: SizedBox(
height: 100,
child: Row(children: const [
CircularProgressIndicator(),
Text("Přihlašuji vás")
]),
),
));
var canteen = Canteen(r["url"]!);
var l = await canteen.login(r["user"]!, r["pass"]!);
if (!l) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("Přihlášení se nezdařilo, zkontrolujte údaje"),
return (Platform
.isAndroid) // run app based on current platform to make use of the platform's respective UI lib
? MaterialApp(
debugShowCheckedModeBanner: false,
localizationsDelegates: const [
AppLocalizations.delegate,
...GlobalMaterialLocalizations.delegates
],
supportedLocales: AppLocalizations.supportedLocales,
title: "OpenCanteen",
theme: ThemeData(useMaterial3: true, colorScheme: lightColorScheme),
darkTheme: ThemeData(
brightness: Brightness.dark,
useMaterial3: true,
colorScheme: darkColorScheme),
home: const LoginPage(),
)
: Theme(
data: ThemeData(
useMaterial3: true,
colorScheme: (MediaQuery.of(context).platformBrightness ==
Brightness.dark)
? darkColorScheme
: lightColorScheme),
child: const CupertinoApp(
debugShowCheckedModeBanner: false,
localizationsDelegates: [
AppLocalizations.delegate,
...GlobalMaterialLocalizations.delegates
],
supportedLocales: AppLocalizations.supportedLocales,
title: "OpenCanteen",
theme: CupertinoThemeData(
primaryColor: Colors.purple,
),
home: LoginPage(),
),
);
return;
}
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => HomePage(
user: r["user"]!,
canteen: canteen,
)),
);
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Přihlášení"),
),
body: Center(
child: SizedBox(
width: MediaQuery.of(context).size.width - 50,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'OpenCanteen',
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 40),
),
const Text(
'Přihlášení',
textAlign: TextAlign.center,
),
TextField(
controller: userControl,
autofillHints: const [AutofillHints.username],
decoration:
const InputDecoration(labelText: 'Uživatelské jméno'),
),
TextField(
autofillHints: const [AutofillHints.password],
decoration: const InputDecoration(labelText: 'Heslo'),
controller: passControl,
obscureText: true,
),
TextField(
autofillHints: const [AutofillHints.url],
decoration: const InputDecoration(labelText: 'iCanteen URL'),
keyboardType: TextInputType.url,
controller: canteenControl,
),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Switch(
value: rememberMe,
onChanged: (value) {
setState(() {
rememberMe = value;
});
}),
const Text("Zapamatovat si mě")
]),
TextButton(
onPressed: () async {
if (canteenControl.text.contains("http://")) {
// kontrolujeme šifrované spojení
var d = await showDialog<bool>(
context: context,
builder: (c) => AlertDialog(
title: const Text("Varování!"),
content: const SingleChildScrollView(
child: Text(
"Snažíte se přihlásit přes nešifrované spojení HTTP, jste si jisti, že tak chcete učinit?")),
actions: [
TextButton(
onPressed: () => Navigator.pop(c, true),
child: const Text("Ano")),
TextButton(
onPressed: () => Navigator.pop(c, false),
child: const Text("Ne, změnit"))
],
));
if (!d!) return;
}
// souhlas
const storage = FlutterSecureStorage();
var odsouhlasil = await storage.read(key: "oc_souhlas");
if (odsouhlasil == null || odsouhlasil != "ano") {
var d = await showDialog<bool>(
context: context,
builder: (c) => AlertDialog(
title: const Text("Pozor"),
content: const SingleChildScrollView(
child: Text(
"Toto není oficiální aplikace k ovládání iCanteen. Autor neručí za ztráty nebo nefunkčnost v souvislosti s používáním této aplikace. Tato zpráva se znovu neukáže.")),
actions: [
TextButton(
onPressed: () => Navigator.pop(c, true),
child: const Text("Souhlasím")),
TextButton(
onPressed: () => Navigator.pop(c, false),
child: const Text("Nesouhlasím"))
],
));
if (!d!) return;
await storage.write(key: "oc_souhlas", value: "ano");
}
var canteen = Canteen(canteenControl.text);
var l =
await canteen.login(userControl.text, passControl.text);
if (!l) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
"Přihlášení se nezdařilo, zkontrolujte údaje"),
),
);
return;
}
if (rememberMe) {
LoginManager.setDetails(userControl.text,
passControl.text, canteenControl.text);
}
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => HomePage(
user: userControl.text,
canteen: canteen,
)),
);
},
child: const Text("Přihlásit se")),
],
),
),
),
);
}
}

View file

@ -1,106 +1,148 @@
import 'package:canteenlib/canteenlib.dart';
import 'package:flutter/material.dart';
import 'package:opencanteen/okna/login.dart';
import 'package:opencanteen/pw/platformbutton.dart';
import 'package:opencanteen/pw/platformdialog.dart';
import 'package:opencanteen/util.dart';
import '../main.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class BurzaPage extends StatefulWidget {
const BurzaPage({Key? key, required this.canteen, required this.user})
: super(key: key);
class BurzaView extends StatefulWidget {
const BurzaView({super.key, required this.canteen});
final Canteen canteen;
final String user;
@override
State<BurzaPage> createState() => _BurzaPageState();
State<BurzaView> createState() => _BurzaViewState();
}
class _BurzaPageState extends State<BurzaPage> {
List<Widget> obsah = [];
double kredit = 0.0;
Future<void> nactiBurzu() async {
obsah = [const CircularProgressIndicator()];
widget.canteen.ziskejUzivatele().then((kr) {
kredit = kr.kredit;
widget.canteen.ziskatBurzu().then((burza) {
setState(() {
obsah = [];
if (burza.isEmpty) {
obsah = [
const Text(
"Žádné jídlo v burze.",
style: TextStyle(fontSize: 20),
),
const Text("Potáhněte zvrchu pro načtení.")
];
} else {
for (var b in burza) {
obsah.add(
Padding(
padding: const EdgeInsets.only(top: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("${b.den.day}. ${b.den.month}."),
const SizedBox(width: 10),
Flexible(
child: Text(
b.nazev,
),
),
Text("${b.pocet}x"),
TextButton(
onPressed: () {
widget.canteen.objednatZBurzy(b).then((_) {
nactiBurzu();
});
},
child: const Text("Objednat")),
],
),
),
);
}
}
});
});
}).catchError((o) {
class _BurzaViewState extends State<BurzaView> {
List<Widget> content = [];
double balance = 0.0;
Future<void> loadExchange(BuildContext context) async {
content = [const CircularProgressIndicator()];
var uzivatel = await widget.canteen.ziskejUzivatele().catchError((o) {
if (!widget.canteen.prihlasen) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (c) => const LoginPage()));
context, platformRouter((c) => const LoginPage()));
}
return Uzivatel(kredit: 0);
});
balance = uzivatel.kredit;
var burza = await widget.canteen.ziskatBurzu();
setState(() {
content = [];
if (burza.isEmpty) {
content = [
Text(
AppLocalizations.of(context)!.noExchange,
style: const TextStyle(fontSize: 20),
),
Text(AppLocalizations.of(context)!.pullToReload)
];
} else {
for (var b in burza) {
content.add(
Padding(
padding: const EdgeInsets.only(top: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("${b.den.day}. ${b.den.month}."),
const SizedBox(width: 10),
Flexible(
child: Text(
b.nazev,
),
),
Text("${b.pocet}x"),
PlatformButton(
onPressed: () {
widget.canteen.objednatZBurzy(b).then(
(a) {
if (a) {
showDialog(
context: context,
builder: (context) => PlatformDialog(
title: AppLocalizations.of(context)!.ordered,
content:
AppLocalizations.of(context)!.orderSuccess,
actions: [
PlatformButton(
text: AppLocalizations.of(context)!.ok,
onPressed: () =>
Navigator.of(context).pop(),
)
],
),
);
} else {
showDialog(
context: context,
builder: (context) => PlatformDialog(
title:
AppLocalizations.of(context)!.cannotOrder,
content:
AppLocalizations.of(context)!.errorOrdering,
actions: [
PlatformButton(
text: AppLocalizations.of(context)!.ok,
onPressed: () =>
Navigator.of(context).pop(),
)
],
),
);
}
loadExchange(context);
},
);
},
text: AppLocalizations.of(context)!.order,
),
],
),
),
);
}
}
});
return;
}
@override
void initState() {
super.initState();
nactiBurzu();
loadExchange(context);
}
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: drawerGenerator(context, widget.canteen, widget.user, 3),
drawer: drawerGenerator(context, widget.canteen, 3),
appBar: AppBar(
title: const Text('Burza'),
title: Text(AppLocalizations.of(context)!.exchange),
),
body: RefreshIndicator(
child: Center(
child: Column(
children: [
const SizedBox(height: 10),
Text("Kredit: $kredit"),
const SizedBox(height: 10),
SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: SizedBox(
height: MediaQuery.of(context).size.height - 120,
child: Column(children: obsah),
),
)
],
child: SizedBox(
width: MediaQuery.of(context).size.width - 50,
child: Column(
children: [
const SizedBox(height: 10),
Text("${AppLocalizations.of(context)!.balance}$balance"),
const SizedBox(height: 10),
SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: SizedBox(
height: MediaQuery.of(context).size.height / 1.3,
child: Column(children: content),
),
)
],
),
),
),
onRefresh: () => nactiBurzu()),
onRefresh: () => loadExchange(context)),
);
}
}

View file

@ -1,132 +0,0 @@
import 'package:canteenlib/canteenlib.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:opencanteen/main.dart';
import 'package:opencanteen/util.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key, required this.user, required this.canteen})
: super(key: key);
final String user;
final Canteen canteen;
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
double kredit = 0.0;
Jidelnicek? dnes;
Jidlo? jidloDnes;
List<Widget> obsah = [];
Future<void> nactiJidlo() async {
obsah = [];
widget.canteen.ziskejUzivatele().then((kr) {
widget.canteen.jidelnicekDen().then((jd) {
setState(() {
kredit = kr.kredit;
dnes = jd;
for (var j in jd.jidla) {
if (j.objednano) jidloDnes = j;
obsah.add(
Padding(
padding: const EdgeInsets.only(top: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(j.varianta),
const SizedBox(width: 10),
Flexible(
child: Text(
j.nazev,
),
),
Text("${j.cena}"),
Checkbox(
value: j.objednano,
fillColor: (j.lzeObjednat)
? MaterialStateProperty.all(Colors.blue)
: MaterialStateProperty.all(Colors.grey),
onChanged: (v) => setState(() {
// TODO exception handling
if (!j.lzeObjednat) return;
widget.canteen.objednat(j);
nactiJidlo();
}))
],
),
),
);
}
});
});
}).catchError((o) {
if (!widget.canteen.prihlasen) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (c) => const LoginPage()));
}
});
}
@override
void initState() {
super.initState();
nactiJidlo();
}
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: drawerGenerator(context, widget.canteen, widget.user, 1),
appBar: AppBar(
title: const Text("Domů"),
actions: [
IconButton(
onPressed: (() {
const storage = FlutterSecureStorage();
storage.deleteAll();
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (c) => const LoginPage()));
}),
icon: const Icon(Icons.logout))
],
),
body: RefreshIndicator(
onRefresh: nactiJidlo,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Center(
child: SizedBox(
child: Column(
children: [
const SizedBox(
height: 5,
),
Text(
"${widget.user} - $kredit",
style: const TextStyle(fontSize: 13),
),
const SizedBox(
height: 10,
),
Text(
"Dnes je ${DateTime.now().day}. ${DateTime.now().month}.",
style: const TextStyle(
fontSize: 20, fontWeight: FontWeight.bold),
),
Padding(
padding: const EdgeInsets.only(top: 20),
child: Column(children: obsah),
),
],
),
width: MediaQuery.of(context).size.width - 50,
),
),
),
),
);
}
}

View file

@ -1,246 +1,589 @@
import 'dart:convert';
import 'dart:io';
import 'package:canteenlib/canteenlib.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:opencanteen/main.dart';
import 'package:opencanteen/okna/login.dart';
import 'package:opencanteen/okna/nastaveni.dart';
import 'package:opencanteen/pw/platformbutton.dart';
import 'package:opencanteen/pw/platformdialog.dart';
import 'package:opencanteen/util.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
import '../main.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class JidelnicekPage extends StatefulWidget {
const JidelnicekPage({Key? key, required this.canteen, required this.user})
: super(key: key);
class MealView extends StatefulWidget {
const MealView({super.key, required this.canteen});
final Canteen canteen;
final String user;
@override
State<JidelnicekPage> createState() => _JidelnicekPageState();
State<MealView> createState() => _MealViewState();
}
class _JidelnicekPageState extends State<JidelnicekPage> {
List<Widget> obsah = [const Text("Načítám...")];
DateTime den = DateTime.now();
String denTydne = "";
double kredit = 0.0;
Future<void> nactiJidlo() async {
obsah = [const CircularProgressIndicator()];
switch (den.weekday) {
class _MealViewState extends State<MealView> {
List<Widget> content = [const CircularProgressIndicator()];
DateTime day = DateTime.now();
String dayOWeek = "";
double balance = 0.0;
void checkWeek(BuildContext context) async {
if (settings.checkOrdered) {
// Check if user has ordered a meal in the next week
var pristi = day.add(const Duration(days: 6));
for (var i = 0; i < 5; i++) {
var jidelnicek = await widget.canteen
.jidelnicekDen(den: pristi.add(Duration(days: i + 1)));
if (jidelnicek.jidla.isNotEmpty &&
!jidelnicek.jidla.any((element) => element.objednano == true)) {
if (!mounted) break;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.noOrder),
duration: const Duration(seconds: 5),
action: SnackBarAction(
onPressed: () => setState(
() {
day = pristi.add(Duration(days: i + 1));
loadMeals();
},
),
label: AppLocalizations.of(context)!.jump,
),
),
);
break;
}
}
}
}
Future<void> loadMeals() async {
content = [const CircularProgressIndicator()];
switch (day.weekday) {
case 2:
denTydne = "Úterý";
dayOWeek = AppLocalizations.of(context)!.tuesday;
break;
case 3:
denTydne = "Středa";
dayOWeek = AppLocalizations.of(context)!.wednesday;
break;
case 4:
denTydne = "Čtvrtek";
dayOWeek = AppLocalizations.of(context)!.thursday;
break;
case 5:
denTydne = "Pátek";
dayOWeek = AppLocalizations.of(context)!.friday;
break;
case 6:
denTydne = "Sobota";
dayOWeek = AppLocalizations.of(context)!.saturday;
break;
case 7:
denTydne = "Neděle";
dayOWeek = AppLocalizations.of(context)!.sunday;
break;
default:
denTydne = "Pondělí";
dayOWeek = AppLocalizations.of(context)!.monday;
}
widget.canteen.ziskejUzivatele().then((kr) {
kredit = kr.kredit;
widget.canteen.jidelnicekDen(den: den).then((jd) {
setState(() {
obsah = [];
if (jd.jidla.isEmpty) {
obsah.add(const Text(
"Žádné jídlo pro tento den",
style: TextStyle(fontSize: 15),
));
} else {
for (var j in jd.jidla) {
obsah.add(
Padding(
padding: const EdgeInsets.only(top: 15),
child: InkWell(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(j.varianta),
const SizedBox(width: 10),
Flexible(
child: Text(
j.nazev,
),
Uzivatel uzivatel;
try {
uzivatel = await widget.canteen.ziskejUzivatele();
} catch (e) {
if (!widget.canteen.prihlasen && mounted) {
Navigator.pushReplacement(
context, platformRouter((c) => const LoginPage()));
}
return;
}
balance = uzivatel.kredit;
var jd = await widget.canteen.jidelnicekDen(den: day).catchError((_) {
showInfo(context, AppLocalizations.of(context)!.errorContacting);
return Jidelnicek(DateTime.now(), []);
});
setState(
() {
content = [];
if (jd.jidla.isEmpty) {
content.add(Text(
AppLocalizations.of(context)!.noFood,
style: const TextStyle(fontSize: 15),
));
} else {
for (var j in jd.jidla) {
content.add(
Padding(
padding: const EdgeInsets.only(top: 15),
child: InkWell(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(j.varianta),
const SizedBox(width: 10),
Flexible(
child: Text(
(settings.allergens && j.alergeny.isNotEmpty)
? "${j.nazev} (${j.alergeny.map<String>((e) => (e.kod != null) ? e.kod.toString() : e.nazev).join(', ')})"
: j.nazev,
),
Text((j.naBurze) ? "V BURZE" : "${j.cena}"),
Checkbox(
value: j.objednano,
fillColor: (j.lzeObjednat)
? MaterialStateProperty.all(Colors.blue)
: MaterialStateProperty.all(Colors.grey),
onChanged: (v) async {
return;
})
],
),
onTap: () async {
if (!j.lzeObjednat) return;
widget.canteen
.objednat(j)
.then((value) => nactiJidlo())
.catchError((o) {
showDialog(
context: context,
builder: (bc) => AlertDialog(
title: const Text(
"Nepodařilo se vložit jídlo na burzu"),
content: Text(o.toString()),
),
Text((j.naBurze)
? AppLocalizations.of(context)!.inExchange
: "${j.cena}"),
Checkbox(
value: j.objednano,
side: BorderSide(
width: 2,
color: (j.lzeObjednat)
? (Colors.purple)
: (Colors.grey)),
fillColor: (j.lzeObjednat && j.objednano)
? MaterialStateProperty.all(Colors.purple)
: (j.objednano)
? MaterialStateProperty.all(Colors.grey)
: MaterialStateProperty.all(Colors.transparent),
onChanged: (v) async {
if (!j.lzeObjednat) {
showDialog(
context: context,
builder: (context) {
return PlatformDialog(
title: AppLocalizations.of(context)!
.errorOrdering,
content:
AppLocalizations.of(context)!.cannotOrder,
actions: [
TextButton(
child: const Text("Zavřít"),
PlatformButton(
text: AppLocalizations.of(context)!.ok,
onPressed: () {
Navigator.pop(bc);
Navigator.of(context).pop();
},
)
],
));
});
},
onLongPress: () async {
if (!j.objednano) return;
if (!j.naBurze) {
// pokud není na burze, radši se zeptáme
var d = await showDialog(
context: context,
builder: (bc) => SimpleDialog(
title: const Text(
"Opravdu chcete vložit jídlo na burzu?"),
children: [
SimpleDialogOption(
onPressed: () {
Navigator.pop(bc, true);
},
child: const Text("Ano"),
),
SimpleDialogOption(
onPressed: () {
Navigator.pop(bc, false);
},
child: const Text("Ne"),
),
],
));
if (d) {
widget.canteen
.doBurzy(j)
.then((_) => nactiJidlo())
.catchError((o) {
);
},
);
} else {
showDialog(
context: context,
builder: (bc) => AlertDialog(
title: const Text(
"Nepodařilo se vložit jídlo na burzu"),
content: Text(o.toString()),
actions: [
TextButton(
child: const Text("Zavřít"),
onPressed: () {
Navigator.pop(bc);
},
)
],
));
});
}
} else {
// jinak ne
widget.canteen.doBurzy(j).then((_) => nactiJidlo());
}
},
context: context,
barrierDismissible: false,
builder: (_) => Dialog(
child: SizedBox(
height: 100,
child: Row(
children: [
const Padding(
padding: EdgeInsets.all(10),
child: CircularProgressIndicator(),
),
Text(AppLocalizations.of(context)!
.ordering)
],
),
),
),
);
widget.canteen.objednat(j).then((_) {
Navigator.of(context, rootNavigator: true).pop();
loadMeals();
}).catchError(
(o) {
Navigator.of(context, rootNavigator: true)
.pop();
showDialog(
context: context,
builder: (bc) => PlatformDialog(
title: AppLocalizations.of(context)!
.errorOrdering,
content: o.toString(),
actions: [
PlatformButton(
text:
AppLocalizations.of(context)!.close,
onPressed: () {
Navigator.pop(bc);
},
)
],
),
);
},
);
}
},
)
],
),
onTap: () async {
if (!j.lzeObjednat) {
showDialog(
context: context,
builder: (context) {
return PlatformDialog(
title: AppLocalizations.of(context)!.errorOrdering,
content: AppLocalizations.of(context)!.cannotOrder,
actions: [
PlatformButton(
text: AppLocalizations.of(context)!.ok,
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
},
);
} else {
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => Dialog(
child: SizedBox(
height: 100,
child: Row(children: [
const Padding(
padding: EdgeInsets.all(10),
child: CircularProgressIndicator(),
),
Text(AppLocalizations.of(context)!.ordering)
]),
),
),
);
widget.canteen.objednat(j).then((_) {
Navigator.of(context, rootNavigator: true).pop();
loadMeals();
}).catchError(
(o) {
Navigator.of(context, rootNavigator: true).pop();
showDialog(
context: context,
builder: (bc) => PlatformDialog(
title:
AppLocalizations.of(context)!.errorOrdering,
content: o.toString(),
actions: [
PlatformButton(
text: AppLocalizations.of(context)!.close,
onPressed: () {
Navigator.pop(bc);
},
)
],
),
);
},
);
}
},
onLongPress: () async {
if (!j.objednano || j.burzaUrl == null) return;
if (!j.naBurze) {
// if not in exchange, we ask
var d = await showDialog(
context: context,
builder: (bc) => PlatformDialog(
title: AppLocalizations.of(context)!.verifyExchange,
actions: [
PlatformButton(
onPressed: () {
Navigator.pop(bc, true);
},
text: AppLocalizations.of(context)!.yes,
),
PlatformButton(
onPressed: () {
Navigator.pop(bc, false);
},
text: AppLocalizations.of(context)!.no,
),
],
),
);
if (d) {
widget.canteen
.doBurzy(j)
.then((_) => loadMeals())
.catchError((o) {
showDialog(
context: context,
builder: (bc) => PlatformDialog(
title:
AppLocalizations.of(context)!.exchangeError,
content: o.toString(),
actions: [
PlatformButton(
text: AppLocalizations.of(context)!.close,
onPressed: () {
Navigator.pop(bc);
},
)
],
),
);
});
}
} else {
// else no
widget.canteen.doBurzy(j).then((_) => loadMeals());
}
},
),
);
}
),
);
}
});
});
}).catchError((o) {
if (!widget.canteen.prihlasen) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (c) => const LoginPage()));
}
},
);
return;
}
Future<void> click(String value, BuildContext context) async {
if (value == AppLocalizations.of(context)!.signOut) {
await showDialog<bool>(
context: context,
builder: (c) => PlatformDialog(
title: AppLocalizations.of(context)!.warning,
content: AppLocalizations.of(context)!.signOutWarn,
actions: [
PlatformButton(
onPressed: () {
const storage = FlutterSecureStorage();
storage.deleteAll();
Navigator.pushAndRemoveUntil(
context,
platformRouter((c) => const LoginPage()),
(route) => false);
},
text: AppLocalizations.of(context)!.yes),
PlatformButton(
onPressed: () => Navigator.of(context).pop(),
text: AppLocalizations.of(context)!.no,
)
],
),
);
} else if (value == AppLocalizations.of(context)!.review) {
launchUrl(
Uri.parse((Platform.isAndroid)
? "market://details?id=cz.hernikplays.opencanteen"
: "https://apps.apple.com/cz/app/opencanteen/id1621124445"),
mode: LaunchMode.externalApplication);
} else if (value == AppLocalizations.of(context)!.reportBugs) {
launchUrl(Uri.parse("https://forms.gle/jKN7QeFJwpaApSbC8"),
mode: LaunchMode.externalApplication);
} else if (value == AppLocalizations.of(context)!.about) {
var packageInfo = await PackageInfo.fromPlatform();
if (!mounted) return;
showAboutDialog(
context: context,
applicationName: "OpenCanteen",
applicationLegalese:
"${AppLocalizations.of(context)!.copyright}\n${AppLocalizations.of(context)!.license}",
applicationVersion: packageInfo.version,
children: [
PlatformButton(
onPressed: (() => launchUrl(
Uri.parse("https://git.mnau.xyz/hernik/opencanteen"),
mode: LaunchMode.externalApplication)),
text: AppLocalizations.of(context)!.source,
)
]);
} else if (value == AppLocalizations.of(context)!.settings) {
Navigator.push(context, platformRouter((c) => const AndroidNastaveni()));
}
}
void loadSettings() async {
if (!mounted) return;
checkWeek(context);
}
void saveOffline() async {
if (!settings.saveOffline) return;
// clear offline storage
Directory appDocDir = await getApplicationDocumentsDirectory();
for (var f in appDocDir.listSync()) {
if (f.path.contains("jidelnicek")) {
f.deleteSync();
}
});
}
var prefs = await SharedPreferences.getInstance();
// save X meal lists
var pocet = prefs.getInt("offline_pocet") ?? 1;
if (pocet > 7) pocet = 7;
for (var i = 0; i < pocet; i++) {
var d = day.add(Duration(days: i));
Jidelnicek? j;
try {
j = await widget.canteen.jidelnicekDen(den: d);
} catch (e) {
if (!widget.canteen.prihlasen) {
if (!mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(AppLocalizations.of(context)!.errorSaving),
duration: const Duration(seconds: 5),
));
break;
}
}
var soubor = File(
"${appDocDir.path}/jidelnicek_${d.year}-${d.month}-${d.day}.json");
soubor.createSync();
var jidla = [];
for (var jidlo in j!.jidla) {
jidla.add({
"nazev": jidlo.nazev,
"varianta": jidlo.varianta,
"objednano": jidlo.objednano,
"cena": jidlo.cena,
"naBurze": jidlo.naBurze,
"den": d.toString()
});
}
await soubor.writeAsString(json.encode(jidla));
}
}
@override
void initState() {
super.initState();
nactiJidlo();
void didChangeDependencies() {
super.didChangeDependencies();
loadSettings();
saveOffline();
loadMeals();
}
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: drawerGenerator(context, widget.canteen, widget.user, 2),
drawer: drawerGenerator(context, widget.canteen, 1),
appBar: AppBar(
title: const Text('Jídelníček'),
title: Text(AppLocalizations.of(context)!.menu),
actions: [
PopupMenuButton(
onSelected: ((String value) => click(value, context)),
itemBuilder: (BuildContext context) {
return {
AppLocalizations.of(context)!.reportBugs,
AppLocalizations.of(context)!.review,
AppLocalizations.of(context)!.settings,
AppLocalizations.of(context)!.about,
AppLocalizations.of(context)!.signOut
}.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
),
],
),
body: Center(
child: Column(
children: [
const SizedBox(height: 10),
Text("Kredit: $kredit"),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
IconButton(
onPressed: () {
setState(() {
den = den.subtract(const Duration(days: 1));
nactiJidlo();
});
},
icon: const Icon(Icons.arrow_left)),
TextButton(
onPressed: () async {
var datePicked = await showDatePicker(
context: context,
initialDate: den,
currentDate: den,
firstDate: DateTime(2019, 1, 1),
lastDate: DateTime(den.year + 1, 12, 31),
locale: const Locale("cs"));
if (datePicked == null) return;
setState(() {
den = datePicked;
nactiJidlo();
});
},
child: Text(
"${den.day}. ${den.month}. ${den.year} - $denTydne")),
IconButton(
onPressed: () {
setState(() {
den = den.add(const Duration(days: 1));
nactiJidlo();
});
},
icon: const Icon(Icons.arrow_right)),
]),
SingleChildScrollView(
child: GestureDetector(
child: Column(children: obsah),
onHorizontalDragEnd: (details) {
if (details.primaryVelocity?.compareTo(0) == -1) {
setState(() {
den = den.subtract(const Duration(days: 1));
nactiJidlo();
});
} else {
setState(() {
den = den.add(const Duration(days: 1));
nactiJidlo();
});
}
},
),
)
],
body: RefreshIndicator(
onRefresh: loadMeals,
child: Center(
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: Column(
children: [
const SizedBox(height: 10),
Text("${AppLocalizations.of(context)!.balance}$balance"),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
onPressed: () {
setState(() {
day = day.subtract(const Duration(days: 1));
if (day.weekday == 7 && settings.skipWeekend) {
day = day.subtract(const Duration(days: 2));
}
loadMeals();
});
},
icon: const Icon(Icons.arrow_left)),
PlatformButton(
onPressed: () async {
var datePicked = await showDatePicker(
context: context,
initialDate: day,
currentDate: day,
firstDate: DateTime(2019, 1, 1),
lastDate: DateTime(day.year + 1, 12, 31),
locale: Localizations.localeOf(context));
if (datePicked == null) return;
setState(() {
day = datePicked;
loadMeals();
});
},
text: "${day.day}. ${day.month}. ${day.year} - $dayOWeek",
),
IconButton(
onPressed: () {
setState(() {
day = day.add(const Duration(days: 1));
if (day.weekday == 6 && settings.skipWeekend) {
day = day.add(const Duration(days: 2));
}
loadMeals();
});
},
icon: const Icon(Icons.arrow_right),
),
Tooltip(
message: AppLocalizations.of(context)!.todayTooltip,
child: IconButton(
onPressed: () => setState(
() {
day = DateTime.now();
loadMeals();
},
),
icon: const Icon(Icons.today),
),
)
],
),
SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: GestureDetector(
child: Container(
padding: const EdgeInsets.only(left: 20, right: 20),
color: Theme.of(context)
.colorScheme
.onPrimary
.withOpacity(0),
height: MediaQuery.of(context).size.height / 1.3,
child: Column(children: content),
),
onHorizontalDragEnd: (details) {
if (details.primaryVelocity?.compareTo(0) == -1) {
setState(() {
day = day.add(const Duration(days: 1));
if (day.weekday == 6 && settings.skipWeekend) {
day = day.add(const Duration(days: 2));
}
loadMeals();
});
} else {
setState(
() {
day = day.subtract(const Duration(days: 1));
if (day.weekday == 7 && settings.skipWeekend) {
day = day.subtract(const Duration(days: 2));
}
loadMeals();
},
);
}
},
),
)
],
),
),
),
),
);

247
lib/okna/login.dart Normal file
View file

@ -0,0 +1,247 @@
import 'package:canteenlib/canteenlib.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:opencanteen/okna/welcome.dart';
import 'package:opencanteen/pw/platformbutton.dart';
import 'package:opencanteen/pw/platformfield.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../../loginmanager.dart';
import '../../util.dart';
import '../pw/platformswitch.dart';
import 'jidelnicek.dart';
import 'offline_jidelnicek.dart';
class LoginPage extends StatefulWidget {
const LoginPage({super.key});
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
TextEditingController userControl = TextEditingController();
TextEditingController passControl = TextEditingController();
TextEditingController canteenControl = TextEditingController();
bool rememberMe = false;
bool _showUrl = false;
String dropdownUrl = instance.first["url"] ?? "";
@override
void initState() {
super.initState();
LoginManager.getDetails().then((r) async {
if (r != null) {
// Autologin
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => Dialog(
child: SizedBox(
height: 100,
child: Row(children: [
const Padding(
padding: EdgeInsets.all(10),
child: CircularProgressIndicator(),
),
Text(AppLocalizations.of(context)!.loggingIn)
]),
),
));
var canteen = Canteen(r["url"]!);
try {
var l = await canteen.login(r["user"]!, r["pass"]!);
if (!l) {
if (!mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalizations.of(context)!.loginFailed),
),
);
return;
}
const storage = FlutterSecureStorage();
var odsouhlasil = await storage.read(key: "oc_souhlas");
if (!mounted) return;
if (odsouhlasil == null || odsouhlasil != "ano") {
Navigator.pushAndRemoveUntil(
context,
platformRouter(
(c) => WelcomePage(canteen: canteen),
),
(route) => false);
} else {
Navigator.pushAndRemoveUntil(
context,
platformRouter(
(context) => MealView(canteen: canteen),
),
(route) => false);
}
} on PlatformException {
if (!mounted) return;
Navigator.of(context).pop();
showInfo(context, AppLocalizations.of(context)!.corrupted);
} catch (_) {
if (!mounted) return;
Navigator.of(context).pop();
showInfo(context, AppLocalizations.of(context)!.errorContacting);
goOffline();
}
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.logIn),
automaticallyImplyLeading: false,
),
body: Center(
child: SingleChildScrollView(
child: SizedBox(
width: MediaQuery.of(context).size.width - 50,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
AppLocalizations.of(context)!.appName,
textAlign: TextAlign.center,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 40),
),
Text(
AppLocalizations.of(context)!.logIn,
textAlign: TextAlign.center,
),
PlatformField(
controller: userControl,
autofillHints: const [AutofillHints.username],
labelText: AppLocalizations.of(context)!.username,
),
PlatformField(
autofillHints: const [AutofillHints.password],
labelText: AppLocalizations.of(context)!.password,
controller: passControl,
obscureText: true,
),
const SizedBox(
height: 10,
),
DropdownButton(
isExpanded: true,
value: dropdownUrl,
items: instance.map<DropdownMenuItem<String>>((e) {
return DropdownMenuItem<String>(
value: e["url"],
child: Text(e["name"]!),
);
}).toList(),
onChanged: (String? value) {
setState(() {
if (value == "") {
_showUrl = true;
} else {
_showUrl = false;
}
dropdownUrl = value!;
});
},
),
AnimatedOpacity(
opacity: _showUrl ? 1.0 : 0.0,
duration: const Duration(milliseconds: 300),
child: PlatformField(
autofillHints: const [AutofillHints.url],
labelText: AppLocalizations.of(context)!.iCanteenUrl,
keyboardType: TextInputType.url,
controller: canteenControl,
),
),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
PlatformSwitch(
value: rememberMe,
onChanged: (value) {
setState(() {
rememberMe = value;
});
},
),
Text(AppLocalizations.of(context)!.rememberMe)
]),
PlatformButton(
onPressed: () async {
var canteenUrl = (dropdownUrl == "")
? canteenControl.text
: dropdownUrl;
if (!canteenUrl.startsWith("https://") &&
!canteenUrl.startsWith("http://")) {
canteenUrl = "https://$canteenUrl";
}
var canteen = Canteen(canteenUrl);
try {
var l = await canteen.login(
userControl.text, passControl.text);
if (!l) {
if (!mounted) return;
showInfo(context,
AppLocalizations.of(context)!.loginFailed);
return;
}
if (rememberMe) {
LoginManager.setDetails(
userControl.text, passControl.text, canteenUrl);
}
// souhlas
const storage = FlutterSecureStorage();
var odsouhlasil = await storage.read(key: "oc_souhlas");
if (!mounted) return;
if (odsouhlasil == null || odsouhlasil != "ano") {
Navigator.pushAndRemoveUntil(
context,
platformRouter(
(context) => WelcomePage(
canteen: canteen,
),
),
(route) => false);
} else {
Navigator.pushAndRemoveUntil(
context,
platformRouter(
(context) => MealView(
canteen: canteen,
),
),
(route) => false);
}
} on PlatformException {
if (!mounted) return;
showInfo(
context, AppLocalizations.of(context)!.corrupted);
} on Exception catch (_) {
if (!mounted) return;
showInfo(context,
AppLocalizations.of(context)!.errorContacting);
//goOffline();
}
},
text: AppLocalizations.of(context)!.logIn),
],
),
),
),
),
);
}
/// Switch to offline view
void goOffline() async {
if (!mounted) return;
Navigator.pushAndRemoveUntil(context,
platformRouter((context) => const OfflineMealView()), (route) => false);
}
}

325
lib/okna/nastaveni.dart Normal file
View file

@ -0,0 +1,325 @@
import 'dart:io';
import 'package:canteenlib/canteenlib.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:opencanteen/pw/platformbutton.dart';
import 'package:opencanteen/pw/platformdialog.dart';
import 'package:opencanteen/pw/platformfield.dart';
import 'package:path_provider/path_provider.dart';
import 'package:settings_ui/settings_ui.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:timezone/timezone.dart' as tz;
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../../loginmanager.dart';
import '../../main.dart';
import '../../util.dart';
class AndroidNastaveni extends StatefulWidget {
const AndroidNastaveni({super.key});
@override
State<AndroidNastaveni> createState() => _AndroidNastaveniState();
}
class _AndroidNastaveniState extends State<AndroidNastaveni> {
bool _saveOffline = false;
bool _skipWeekend = false;
bool _checkWeek = false;
bool _notifyMeal = false;
bool _remember = false;
bool _allergens = false;
TimeOfDay _notifTime = TimeOfDay.now();
final TextEditingController _countController =
TextEditingController(text: "1");
SharedPreferences? preferences;
void loadSettings() async {
preferences = await SharedPreferences.getInstance();
_remember = await LoginManager.rememberme();
setState(
() {
_saveOffline = preferences!.getBool("offline") ?? false;
_skipWeekend = preferences!.getBool("skip") ?? false;
_checkWeek = preferences!.getBool("tyden") ?? false;
_notifyMeal = preferences!.getBool("oznamit") ?? false;
_countController.text =
(preferences!.getInt("offline_pocet") ?? 1).toString();
var casStr = preferences!.getString("oznameni_cas");
if (casStr == null) {
var now = DateTime.now();
_notifTime = TimeOfDay.fromDateTime(
DateTime.now().add(const Duration(hours: 1)));
preferences!.setString("oznameni_cas", now.toString());
} else {
_notifTime = TimeOfDay.fromDateTime(DateTime.parse(casStr));
}
},
);
}
void changeSetting(String key, bool value) async {
preferences!.setBool(key, value);
}
@override
void initState() {
super.initState();
loadSettings();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.settings),
),
body: SettingsList(
platform: DevicePlatform.device,
sections: [
SettingsSection(
tiles: [
SettingsTile.switchTile(
initialValue: _allergens,
onToggle: (value) {
_allergens = value;
settings.allergens = value;
changeSetting("allergens", _allergens);
setState(() {});
},
title: Text(AppLocalizations.of(context)!.showAllergens),
),
SettingsTile.switchTile(
initialValue: _saveOffline,
onToggle: (value) {
_saveOffline = value;
settings.saveOffline = value;
changeSetting("offline", value);
setState(() {});
},
title: Text(AppLocalizations.of(context)!.saveOffline),
),
CustomSettingsTile(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: MediaQuery.of(context).size.width * 0.76,
child: Text(
AppLocalizations.of(context)!.saveCount,
softWrap: true,
style: TextStyle(
fontSize: (Platform.isAndroid) ? 18 : 17,
fontWeight:
(Platform.isAndroid) ? FontWeight.w400 : null,
),
),
),
const SizedBox(
width: 10,
),
SizedBox(
width: 35,
child: PlatformField(
controller: _countController,
enabled: _saveOffline,
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly
],
onChanged: (c) {
var cislo = int.tryParse(c);
if (cislo != null) {
preferences!.setInt("offline_pocet", cislo);
}
},
),
)
],
),
),
SettingsTile.switchTile(
initialValue: _skipWeekend,
onToggle: (value) {
_skipWeekend = value;
settings.skipWeekend = value;
changeSetting("skip", value);
setState(() {});
},
title: Text(AppLocalizations.of(context)!.skipWeekend),
),
SettingsTile.switchTile(
initialValue: _checkWeek,
onToggle: (value) {
_checkWeek = value;
settings.checkOrdered = value;
changeSetting("tyden", value);
setState(() {});
},
title: Text(AppLocalizations.of(context)!.checkOrdered),
),
],
title: Text(AppLocalizations.of(context)!.settingsExperience),
),
SettingsSection(
tiles: [
SettingsTile.switchTile(
initialValue: _notifyMeal,
enabled: _remember,
onToggle: (value) {
if (!_remember) {
showDialog(
context: context,
builder: (bc) => PlatformDialog(
title: AppLocalizations.of(context)!.error,
content: AppLocalizations.of(context)!.needRemember,
actions: [
PlatformButton(
text: AppLocalizations.of(context)!.ok,
onPressed: () {
Navigator.of(bc).pop();
},
)
],
),
);
} else {
_notifyMeal = value;
if (_notifyMeal) {
showDialog(
context: context,
builder: (context) => PlatformDialog(
title: AppLocalizations.of(context)!.warning,
content: AppLocalizations.of(context)!.notifyWarning,
actions: [
PlatformButton(
text: AppLocalizations.of(context)!.ok,
onPressed: () {
Navigator.of(context).pop();
},
)
],
),
);
createNotif(timeToDate(_notifTime));
}
changeSetting("oznamit", value);
setState(() {});
}
},
title: Text(
AppLocalizations.of(context)!.notifyLunch,
),
),
CustomSettingsTile(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
AppLocalizations.of(context)!.notifyAt,
style: TextStyle(
fontSize: (Platform.isAndroid) ? 18 : 17,
fontWeight:
(Platform.isAndroid) ? FontWeight.w400 : null,
),
),
PlatformButton(
textStyle:
TextStyle(fontSize: (Platform.isAndroid ? 18 : 17)),
text: _notifTime.format(context),
onPressed: () async {
if (!_notifyMeal) return;
var cas = await showTimePicker(
context: context, initialTime: _notifTime);
if (cas == null) return;
var prefs = await SharedPreferences.getInstance();
prefs.setString(
"oznameni_cas",
timeToDate(cas)
.toString()); // aktualizovat vybraný čas
var den = timeToDate(cas);
debugPrint(den.isAfter(DateTime.now()).toString());
if (den.isAfter(DateTime.now())) {
// znovu vytvořit oznámení POUZE když je čas v budoucnosti
createNotif(den);
}
_notifTime = cas;
setState(() {});
},
)
],
),
)
],
title: Text(AppLocalizations.of(context)!.settingsFunctions),
)
],
),
);
}
void clear(bool value) async {
if (!value) {
Directory appDocDir = await getApplicationDocumentsDirectory();
for (var f in appDocDir.listSync()) {
// Vymažeme obsah
if (f.path.contains("jidelnicek")) {
f.deleteSync();
}
}
}
}
void createNotif(DateTime den) async {
await flutterLocalNotificationsPlugin.cancelAll();
var d = await LoginManager.getDetails(); // grab details
if (d != null) {
var c = Canteen(d["url"]!);
if (await c.login(d["user"]!, d["pass"]!)) {
var jidla = await c.jidelnicekDen();
try {
var jidlo = jidla.jidla.singleWhere((element) => element.objednano);
const AndroidNotificationDetails androidSpec =
AndroidNotificationDetails('opencanteen', 'predobjedem',
channelDescription: 'Oznámení o dnešním jídle',
importance: Importance.max,
priority: Priority.high,
ticker: 'today meal');
var l =
tz.getLocation(await FlutterNativeTimezone.getLocalTimezone());
var notifGranted = await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission() ??
true; // request android notification access
var granted = await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestExactAlarmsPermission() ??
true; // request android exact alarm permission
if (!granted || !notifGranted) return;
if (!mounted) return;
await flutterLocalNotificationsPlugin.zonedSchedule(
// schedules a notification
0,
AppLocalizations.of(context)!.lunchNotif,
"${jidlo.varianta} - ${jidlo.nazev}",
tz.TZDateTime.from(den, l),
const NotificationDetails(android: androidSpec),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime);
} on StateError catch (_) {
// no meal found
}
}
}
}
}

View file

@ -0,0 +1,270 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:opencanteen/okna/login.dart';
import 'package:opencanteen/pw/platformbutton.dart';
import 'package:opencanteen/util.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class OfflineMealView extends StatefulWidget {
const OfflineMealView({super.key});
@override
State<OfflineMealView> createState() => _OfflineMealViewState();
}
class _OfflineMealViewState extends State<OfflineMealView> {
List<Widget> content = [const CircularProgressIndicator()]; // view content
var _skipWeekend = false; // skip weekend setting
DateTime currentDay = DateTime.now(); // the day we are supposed to show
String dayOWeek = ""; // the name of the day (to show to user)
List<List<OfflineMeal>> data = []; // meal data
var mealIndex = 0; // index of the currently shown day
/// Loads the offline data from local storage
void loadFromFile() async {
Directory appDocDir = await getApplicationDocumentsDirectory();
for (var f in appDocDir.listSync()) {
if (f.path.contains("jidelnicek")) {
var soubor = File(f.path);
var input = await soubor.readAsString();
var r = jsonDecode(input);
List<OfflineMeal> jidla = [];
for (var j in r) {
jidla.add(OfflineMeal(
name: j["nazev"],
variant: j["varianta"],
ordered: j["objednano"],
price: j["cena"],
onExchange: j["naBurze"],
day: DateTime.parse(j["den"])));
}
data.add(jidla);
}
}
loadFood();
}
Future<void> loadFood() async {
var jidelnicek = data[mealIndex];
currentDay = jidelnicek[0].day;
switch (currentDay.weekday) {
case 2:
dayOWeek = AppLocalizations.of(context)!.tuesday;
break;
case 3:
dayOWeek = AppLocalizations.of(context)!.wednesday;
break;
case 4:
dayOWeek = AppLocalizations.of(context)!.thursday;
break;
case 5:
dayOWeek = AppLocalizations.of(context)!.friday;
break;
case 6:
dayOWeek = AppLocalizations.of(context)!.saturday;
break;
case 7:
dayOWeek = AppLocalizations.of(context)!.sunday;
break;
default:
dayOWeek = AppLocalizations.of(context)!.monday;
}
content = [];
for (OfflineMeal j in jidelnicek) {
content.add(
Padding(
padding: const EdgeInsets.only(top: 15),
child: InkWell(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(j.variant),
const SizedBox(width: 10),
Flexible(
child: Text(
j.name,
),
),
Text((j.onExchange)
? AppLocalizations.of(context)!.inExchange
: "${j.price}"),
Checkbox(
value: j.ordered,
fillColor: MaterialStateProperty.all(Colors.grey),
onChanged: (v) async {
return;
},
)
],
),
),
),
);
}
setState(() {});
}
void click(String value, BuildContext context) async {
if (value == AppLocalizations.of(context)!.signOut) {
const storage = FlutterSecureStorage();
storage.deleteAll();
Navigator.pushReplacement(
context, platformRouter((c) => const LoginPage()));
} else if (value == AppLocalizations.of(context)!.review) {
launchUrl(
Uri.parse((Platform.isAndroid)
? "market://details?id=cz.hernikplays.opencanteen"
: "https://apps.apple.com/cz/app/opencanteen/id1621124445"),
mode: LaunchMode.externalApplication);
} else if (value == AppLocalizations.of(context)!.reportBugs) {
launchUrl(Uri.parse("https://forms.gle/jKN7QeFJwpaApSbC8"),
mode: LaunchMode.externalApplication);
} else if (value == AppLocalizations.of(context)!.about) {
var packageInfo = await PackageInfo.fromPlatform();
if (!mounted) return;
showAboutDialog(
context: context,
applicationName: "OpenCanteen",
applicationLegalese:
"${AppLocalizations.of(context)!.copyright}\n${AppLocalizations.of(context)!.license}",
applicationVersion: packageInfo.version,
children: [
PlatformButton(
onPressed: (() => launchUrl(
Uri.parse("https://git.mnau.xyz/hernik/opencanteen"))),
text: AppLocalizations.of(context)!.source,
)
],
);
}
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
loadSettings();
}
void loadSettings() async {
var prefs = await SharedPreferences.getInstance();
_skipWeekend = prefs.getBool("skip") ?? false;
if (!mounted) return;
loadFromFile();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.menu),
automaticallyImplyLeading: false,
actions: [
PopupMenuButton(
onSelected: ((String value) => click(value, context)),
itemBuilder: (BuildContext context) {
return {
AppLocalizations.of(context)!.reportBugs,
AppLocalizations.of(context)!.review,
AppLocalizations.of(context)!.about,
AppLocalizations.of(context)!.signOut
}.map((String choice) {
return PopupMenuItem<String>(
value: choice,
child: Text(choice),
);
}).toList();
},
),
],
),
body: RefreshIndicator(
child: Center(
child: SizedBox(
width: MediaQuery.of(context).size.width - 50,
child: Column(
children: [
const SizedBox(height: 10),
Text(
AppLocalizations.of(context)!.offline,
style: const TextStyle(fontWeight: FontWeight.bold),
),
Text(AppLocalizations.of(context)!.mustLogout),
const SizedBox(height: 10),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
IconButton(
onPressed: () {
if (data.length <= 1) return;
content = [const CircularProgressIndicator()];
setState(() {
if (currentDay.weekday == 1 && _skipWeekend) {
// pokud je pondělí a chceme přeskočit víkend
if (mealIndex - 2 >= 0) {
mealIndex -= data.length - 3;
} else {
mealIndex = data.length - 1;
}
} else if (mealIndex == 0) {
mealIndex = data.length - 1;
} else {
mealIndex -= 1;
}
loadFood();
});
},
icon: const Icon(Icons.arrow_left)),
PlatformButton(
onPressed: () async {},
text:
"${currentDay.day}. ${currentDay.month}. ${currentDay.year} - $dayOWeek"),
IconButton(
onPressed: () {
if (data.length <= 1) return;
content = [const CircularProgressIndicator()];
setState(() {
if (currentDay.weekday == 5 && _skipWeekend) {
// pokud je pondělí a chceme přeskočit víkend
if (mealIndex + 2 <= data.length - 1) {
mealIndex += 2;
} else {
mealIndex = 0;
}
} else if (mealIndex == data.length) {
mealIndex = 0;
} else {
mealIndex += 1;
}
loadFood();
});
},
icon: const Icon(Icons.arrow_right),
),
IconButton(
onPressed: () {
mealIndex = 0;
},
icon: const Icon(Icons.today))
]),
SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
children: content,
),
),
],
),
),
),
onRefresh: () => Navigator.pushReplacement(
context, platformRouter((context) => const LoginPage())),
),
);
}
}

78
lib/okna/welcome.dart Normal file
View file

@ -0,0 +1,78 @@
import 'package:canteenlib/canteenlib.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:introduction_screen/introduction_screen.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:opencanteen/okna/jidelnicek.dart';
import 'package:opencanteen/util.dart';
class WelcomePage extends StatefulWidget {
const WelcomePage({super.key, required this.canteen});
final Canteen canteen;
@override
State<WelcomePage> createState() => _WelcomePageState();
}
class _WelcomePageState extends State<WelcomePage> {
@override
Widget build(BuildContext context) {
var listPagesViewModel = [
PageViewModel(
title: AppLocalizations.of(context)!.welcome,
body: AppLocalizations.of(context)!.appDesc,
image: const Center(
child: Icon(Icons.waving_hand_outlined, size: 175),
),
),
PageViewModel(
title: AppLocalizations.of(context)!.aboutOrder,
body: AppLocalizations.of(context)!.howOrder,
image: Center(
child: Image.asset('assets/objednavam.png',
width: MediaQuery.of(context).size.width * 0.85),
),
),
PageViewModel(
title: AppLocalizations.of(context)!.aboutToExch,
body: AppLocalizations.of(context)!.howToExch,
image: Center(
child: Image.asset('assets/doburzy.png',
width: MediaQuery.of(context).size.width * 0.85),
),
),
PageViewModel(
title: AppLocalizations.of(context)!.aboutFromExch,
body: AppLocalizations.of(context)!.howFromExch,
image: Center(
child: Image.asset('assets/burza.png',
width: MediaQuery.of(context).size.width * 0.85),
),
),
PageViewModel(
title: AppLocalizations.of(context)!.warning,
body: AppLocalizations.of(context)!.notOfficial,
image: const Center(
child: Icon(Icons.warning_amber_outlined, size: 175),
),
),
];
return Scaffold(
body: IntroductionScreen(
pages: listPagesViewModel,
next: Text(AppLocalizations.of(context)!.next),
done: Text(AppLocalizations.of(context)!.ok,
style: const TextStyle(fontWeight: FontWeight.w600)),
onDone: () async {
const storage = FlutterSecureStorage();
await storage.write(key: "oc_souhlas", value: "ano");
if (!mounted) return;
Navigator.of(context).pushAndRemoveUntil(
platformRouter((c) => MealView(canteen: widget.canteen)),
(route) => false);
},
),
);
}
}

View file

@ -0,0 +1,27 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:opencanteen/pw/platformwidget.dart';
class PlatformButton extends PlatformWidget<TextButton, CupertinoButton> {
final String text;
final void Function()? onPressed;
final TextStyle? textStyle;
const PlatformButton(
{super.key, required this.text, required this.onPressed, this.textStyle});
@override
TextButton createAndroidWidget(BuildContext context) => TextButton(
onPressed: onPressed,
child: Text(
text,
style: textStyle,
),
);
@override
CupertinoButton createIosWidget(BuildContext context) => CupertinoButton(
onPressed: onPressed,
child: Text(text, style: textStyle),
);
}

View file

@ -0,0 +1,30 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:opencanteen/pw/platformwidget.dart';
class PlatformDialog extends PlatformWidget<AlertDialog, CupertinoAlertDialog> {
final String title;
final String? content;
final List<Widget> actions;
const PlatformDialog(
{super.key, required this.title, this.content, this.actions = const []});
@override
AlertDialog createAndroidWidget(BuildContext context) => AlertDialog(
title: Text(title),
content: (content != null)
? SingleChildScrollView(child: Text(content!))
: null,
actions: actions,
);
@override
CupertinoAlertDialog createIosWidget(BuildContext context) =>
CupertinoAlertDialog(
title: Text(title),
content: (content != null)
? SingleChildScrollView(child: Text(content!))
: null,
actions: actions,
);
}

54
lib/pw/platformfield.dart Normal file
View file

@ -0,0 +1,54 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:opencanteen/pw/platformwidget.dart';
class PlatformField extends PlatformWidget<TextField, CupertinoTextField> {
final TextEditingController? controller;
final bool enabled;
final bool obscureText;
final String? labelText;
final bool autocorrect;
final TextInputType? keyboardType;
final List<TextInputFormatter> inputFormatters;
final void Function(String)? onChanged;
final List<String>? autofillHints;
const PlatformField({
super.key,
this.controller,
this.labelText,
this.obscureText = false,
this.autocorrect = false,
this.keyboardType,
this.inputFormatters = const [],
this.onChanged,
this.enabled = true,
this.autofillHints,
});
@override
TextField createAndroidWidget(BuildContext context) => TextField(
controller: controller,
enabled: enabled,
obscureText: obscureText,
decoration: InputDecoration(labelText: labelText),
autocorrect: autocorrect,
keyboardType: keyboardType,
inputFormatters: inputFormatters,
onChanged: onChanged,
autofillHints: autofillHints,
);
@override
CupertinoTextField createIosWidget(BuildContext context) =>
CupertinoTextField(
controller: controller,
enabled: enabled,
obscureText: obscureText,
prefix: (labelText == null) ? null : Text(labelText!),
autocorrect: autocorrect,
keyboardType: keyboardType,
inputFormatters: inputFormatters,
onChanged: onChanged,
);
}

View file

@ -0,0 +1,28 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:opencanteen/pw/platformwidget.dart';
class PlatformSwitch extends PlatformWidget<Switch, CupertinoSwitch> {
final bool value;
final void Function(bool)? onChanged;
final Color? thumbColor;
const PlatformSwitch(
{super.key,
required this.value,
required this.onChanged,
this.thumbColor});
@override
Switch createAndroidWidget(BuildContext context) => Switch(
value: value,
onChanged: onChanged,
thumbColor: MaterialStateProperty.all(thumbColor),
);
@override
CupertinoSwitch createIosWidget(BuildContext context) => CupertinoSwitch(
value: value,
onChanged: onChanged,
thumbColor: thumbColor,
);
}

View file

@ -0,0 +1,22 @@
import 'dart:io';
import 'package:flutter/material.dart';
/// Abstract class used to create widgets for the respective platform UI library
abstract class PlatformWidget<A extends Widget, I extends Widget>
extends StatelessWidget {
const PlatformWidget({super.key});
@override
Widget build(BuildContext context) {
if (Platform.isAndroid) {
return createAndroidWidget(context);
} else {
return createIosWidget(context);
}
}
A createAndroidWidget(BuildContext context);
I createIosWidget(BuildContext context);
}

View file

@ -1,12 +1,14 @@
import 'dart:io';
import 'package:canteenlib/canteenlib.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:opencanteen/okna/burza.dart';
import 'package:opencanteen/okna/jidelnicek.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'okna/home.dart';
import 'okna/jidelnicek.dart';
Drawer drawerGenerator(
BuildContext context, Canteen canteen, String user, int p) {
Drawer drawerGenerator(BuildContext context, Canteen canteen, int p) {
Drawer drawer = const Drawer();
switch (p) {
case 1:
@ -14,107 +16,47 @@ Drawer drawerGenerator(
drawer = Drawer(
child: ListView(
children: [
const DrawerHeader(
child: Text("OpenCanteen"),
DrawerHeader(
child: Text(AppLocalizations.of(context)!.appName),
),
ListTile(
selected: true,
title: const Text("Domů"),
title: Text(AppLocalizations.of(context)!.home),
leading: const Icon(Icons.home),
onTap: () => Navigator.pop(context),
),
ListTile(
leading: const Icon(Icons.restaurant),
title: const Text('Jídelníček'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
JidelnicekPage(canteen: canteen, user: user),
),
),
),
ListTile(
leading: const Icon(Icons.store),
title: const Text('Burza'),
title: Text(AppLocalizations.of(context)!.exchange),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BurzaPage(canteen: canteen, user: user),
),
platformRouter((context) => BurzaView(canteen: canteen)),
),
),
],
),
);
break;
case 2:
// Jidelnicek page
drawer = Drawer(
child: ListView(
children: [
const DrawerHeader(
child: Text("OpenCanteen"),
),
ListTile(
title: const Text("Domů"),
leading: const Icon(Icons.home),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (c) => HomePage(canteen: canteen, user: user))),
),
ListTile(
leading: const Icon(Icons.restaurant),
selected: true,
title: const Text('Jídelníček'),
onTap: () => Navigator.pop(context),
),
ListTile(
leading: const Icon(Icons.store),
title: const Text('Burza'),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BurzaPage(canteen: canteen, user: user),
),
),
),
],
),
);
break;
case 3:
drawer = Drawer(
child: ListView(
children: [
const DrawerHeader(
child: Text("OpenCanteen"),
DrawerHeader(
child: Text(AppLocalizations.of(context)!.appName),
),
ListTile(
leading: const Icon(Icons.home),
title: const Text("Domů"),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (c) => HomePage(canteen: canteen, user: user))),
),
ListTile(
leading: const Icon(Icons.restaurant),
title: const Text('Jídelníček'),
title: Text(AppLocalizations.of(context)!.home),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
JidelnicekPage(canteen: canteen, user: user),
),
platformRouter((c) => MealView(canteen: canteen)),
),
),
ListTile(
leading: const Icon(Icons.store),
selected: true,
title: const Text('Burza'),
title: Text(AppLocalizations.of(context)!.exchange),
onTap: () => Navigator.pop(context),
),
],
@ -123,3 +65,68 @@ Drawer drawerGenerator(
}
return drawer;
}
class OfflineMeal {
String name;
String variant;
bool ordered;
double price;
bool onExchange;
DateTime day;
OfflineMeal(
{required this.name,
required this.variant,
required this.ordered,
required this.price,
required this.onExchange,
required this.day});
}
/// Parses [DateTime] from [TimeOfDay]
DateTime timeToDate(TimeOfDay c) {
var now = DateTime.now();
return DateTime.parse(
"${now.year}-${(now.month < 10 ? "0" : "") + now.month.toString()}-${(now.day < 10 ? "0" : "") + now.day.toString()} ${(c.hour < 10 ? "0" : "") + c.hour.toString()}:${(c.minute < 10 ? "0" : "") + c.minute.toString()}:00");
}
/// List of instances to be used in the dropdown menu
List<Map<String, String>> instance = [
{"name": "SŠTE Brno, Olomoucká", "url": "https://stravovani.sstebrno.cz"},
{"name": "Jiné", "url": ""}
];
/// Used to display either a toas or a snackbar
void showInfo(BuildContext context, String message) {
if (Platform.isAndroid) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
duration: const Duration(seconds: 4),
),
);
} else {
Fluttertoast.showToast(
msg: message,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIosWeb: 3,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0,
);
}
}
Route platformRouter(Widget Function(BuildContext context) builder) =>
(Platform.isAndroid)
? MaterialPageRoute(builder: builder)
: CupertinoPageRoute(builder: builder);
class SettingsManager {
bool skipWeekend = false;
bool checkOrdered = false;
bool saveOffline = false;
bool allergens = false;
}

View file

@ -0,0 +1,2 @@
- lepší podpora pro Android 13
- změna na adaptivní ikony na Androidu

View file

@ -0,0 +1,3 @@
- Umožnit ukládat více dnů offline
- Pop-up "Přihlašování" nyní zmizí v případě neúspěšného přihlášení
- chyba při ukládání offline vás nyní již nevyhodí ale zobrazí pouze zprávu

View file

@ -0,0 +1,2 @@
- aktualizace knihovny canteenlib
- splitování APK

View file

@ -0,0 +1,2 @@
- Optimalizace ze strany kodu
- Úpravy vzhledu

View file

@ -0,0 +1 @@
- Opravit chybu s přidáváním jídla na burzu

View file

@ -0,0 +1,3 @@
- Aktualizovány knihovny
- Vylepšen kódový základ
- Přidána podpora Material 3

View file

@ -0,0 +1,9 @@
OpenCanteen je open-source alternativní klient pro obědový systém iCanteen
Aplikace nyní umožňuje:
- prohlížet jídelníček
- objednávat či rušit obědy
- přidávat do nebo objednávat z burzy
- zobrazit oznámení ve vybraný čas obsahující objednané jídlo v daný den
Aplikace nemusí na všech instancích fungovat, v případě problémů vytvořte issue v repu nebo zanechte zpětnou vazbu skrz tlačítko v aplikaci.

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

View file

@ -0,0 +1 @@
Neoficiální klient pro systém iCanteen

View file

@ -0,0 +1,2 @@
- better support for Android 13
- changed to adaptive + themed icons

View file

@ -0,0 +1,3 @@
- Support downloading multiple days of meal lists offline
- "Signing in" pop-up disappears when not signed in succesfully
- Error while saving menu offline no longer throws you to the log-in screen, but shows just an error message

View file

@ -0,0 +1,2 @@
- updated canteenlib library
- added support for APK splitting

View file

@ -0,0 +1,2 @@
- Code optimization
- Theme edits

View file

@ -0,0 +1 @@
- Fix issue with adding food to the exchange

View file

@ -0,0 +1,3 @@
- Updated libraries
- Polished codebase
- Added Material 3 support

View file

@ -0,0 +1,9 @@
OpenCanteen is an alternative free open-source client for the iCanteen food ordering system.
Using this app, you can:
- browse the menu of your iCanteen instance
- order or cancel meals
- place food into or the exchange
- have a notification displayed at a defined time with info about the ordered meal
The app may not work on every iCanteen instance, so in case of any bugs, make sure to open an issue in the repo.

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

View file

@ -0,0 +1 @@
An unofficial client for the iCanteen food system

1
metadata/en-US/title.txt Normal file
View file

@ -0,0 +1 @@
OpenCanteen

View file

@ -5,283 +5,553 @@ packages:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b"
url: "https://pub.dev"
source: hosted
version: "3.3.0"
version: "3.4.9"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.4.2"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.8.2"
version: "2.11.0"
canteenlib:
dependency: "direct main"
description:
name: canteenlib
url: "https://pub.dartlang.org"
sha256: "7051fd7ad1b2e4e5471b7f55dd092a6586972aad2c0c8f31edf7f0ee5a7e4ee9"
url: "https://pub.dev"
source: hosted
version: "0.1.0-alpha.13"
version: "3.0.6"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
charcode:
version: "1.3.0"
checked_yaml:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
name: checked_yaml
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://pub.dev"
source: hosted
version: "1.3.1"
version: "2.0.3"
cli_util:
dependency: transitive
description:
name: cli_util
sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7
url: "https://pub.dev"
source: hosted
version: "0.4.0"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.15.0"
connectivity_plus:
dependency: "direct main"
description:
name: connectivity_plus
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
connectivity_plus_linux:
version: "1.18.0"
convert:
dependency: transitive
description:
name: connectivity_plus_linux
url: "https://pub.dartlang.org"
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
connectivity_plus_macos:
dependency: transitive
description:
name: connectivity_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
connectivity_plus_platform_interface:
dependency: transitive
description:
name: connectivity_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
connectivity_plus_web:
dependency: transitive
description:
name: connectivity_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
connectivity_plus_windows:
dependency: transitive
description:
name: connectivity_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "3.1.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.1"
cupertino_icons:
dependency: "direct main"
version: "3.0.3"
csslib:
dependency: transitive
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
name: csslib
sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "1.0.0"
dbus:
dependency: transitive
description:
name: dbus
url: "https://pub.dartlang.org"
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.10"
dots_indicator:
dependency: transitive
description:
name: dots_indicator
sha256: f1599baa429936ba87f06ae5f2adc920a367b16d08f74db58c3d0f6e93bcdb5c
url: "https://pub.dev"
source: hosted
version: "2.1.2"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "2.1.0"
file:
dependency: transitive
description:
name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_keyboard_visibility:
dependency: transitive
description:
name: flutter_keyboard_visibility
sha256: "4983655c26ab5b959252ee204c2fffa4afeb4413cd030455194ec0caa3b8e7cb"
url: "https://pub.dev"
source: hosted
version: "5.4.1"
flutter_keyboard_visibility_linux:
dependency: transitive
description:
name: flutter_keyboard_visibility_linux
sha256: "6fba7cd9bb033b6ddd8c2beb4c99ad02d728f1e6e6d9b9446667398b2ac39f08"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_keyboard_visibility_macos:
dependency: transitive
description:
name: flutter_keyboard_visibility_macos
sha256: c5c49b16fff453dfdafdc16f26bdd8fb8d55812a1d50b0ce25fc8d9f2e53d086
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_keyboard_visibility_platform_interface:
dependency: transitive
description:
name: flutter_keyboard_visibility_platform_interface
sha256: e43a89845873f7be10cb3884345ceb9aebf00a659f479d1c8f4293fcb37022a4
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_keyboard_visibility_web:
dependency: transitive
description:
name: flutter_keyboard_visibility_web
sha256: d3771a2e752880c79203f8d80658401d0c998e4183edca05a149f5098ce6e3d1
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_keyboard_visibility_windows:
dependency: transitive
description:
name: flutter_keyboard_visibility_windows
sha256: fc4b0f0b6be9b93ae527f3d527fb56ee2d918cd88bbca438c478af7bcfd0ef73
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
url: "https://pub.dartlang.org"
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
url: "https://pub.dev"
source: hosted
version: "0.9.2"
version: "0.13.1"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
url: "https://pub.dartlang.org"
sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "3.0.1"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
sha256: bb5cd63ff7c91d6efe452e41d0d0ae6348925c82eafd10ce170ef585ea04776e
url: "https://pub.dev"
source: hosted
version: "16.2.0"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
sha256: "33f741ef47b5f63cc7f78fe75eeeac7e19f171ff3c3df054d84c1e38bedb6a03"
url: "https://pub.dev"
source: hosted
version: "4.0.0+1"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef"
url: "https://pub.dev"
source: hosted
version: "7.0.0+1"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_native_timezone:
dependency: "direct main"
description:
name: flutter_native_timezone
sha256: ed7bfb982f036243de1c068e269182a877100c994f05143c8b26a325e28c1b02
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_secure_storage:
dependency: "direct main"
description:
name: flutter_secure_storage
url: "https://pub.dartlang.org"
sha256: ffdbb60130e4665d2af814a0267c481bcf522c41ae2e43caf69fa0146876d685
url: "https://pub.dev"
source: hosted
version: "5.0.2"
version: "9.0.0"
flutter_secure_storage_linux:
dependency: transitive
description:
name: flutter_secure_storage_linux
url: "https://pub.dartlang.org"
sha256: "3d5032e314774ee0e1a7d0a9f5e2793486f0dff2dd9ef5a23f4e3fb2a0ae6a9e"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.2.0"
flutter_secure_storage_macos:
dependency: transitive
description:
name: flutter_secure_storage_macos
url: "https://pub.dartlang.org"
sha256: bd33935b4b628abd0b86c8ca20655c5b36275c3a3f5194769a7b3f37c905369c
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "3.0.1"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
name: flutter_secure_storage_platform_interface
url: "https://pub.dartlang.org"
sha256: "0d4d3a5dd4db28c96ae414d7ba3b8422fd735a8255642774803b2532c9a61d7e"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
version: "1.0.2"
flutter_secure_storage_web:
dependency: transitive
description:
name: flutter_secure_storage_web
url: "https://pub.dartlang.org"
sha256: "30f84f102df9dcdaa2241866a958c2ec976902ebdaa8883fbfe525f1f2f3cf20"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.1.2"
flutter_secure_storage_windows:
dependency: transitive
description:
name: flutter_secure_storage_windows
url: "https://pub.dartlang.org"
sha256: "5809c66f9dd3b4b93b0a6e2e8561539405322ee767ac2f64d084e2ab5429d108"
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "3.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
fluttertoast:
dependency: "direct main"
description:
name: fluttertoast
sha256: dfdde255317af381bfc1c486ed968d5a43a2ded9c931e87cbecd88767d6a71c1
url: "https://pub.dev"
source: hosted
version: "8.2.4"
html:
dependency: transitive
description:
name: html
sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
url: "https://pub.dev"
source: hosted
version: "0.15.4"
http:
dependency: transitive
description:
name: http
url: "https://pub.dartlang.org"
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
url: "https://pub.dev"
source: hosted
version: "0.13.4"
version: "1.1.2"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
version: "4.0.2"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
version: "4.1.3"
intl:
dependency: transitive
dependency: "direct main"
description:
name: intl
url: "https://pub.dartlang.org"
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev"
source: hosted
version: "0.17.0"
version: "0.18.1"
introduction_screen:
dependency: "direct main"
description:
name: introduction_screen
sha256: "72d25ceb71471773783f72783608e17585af93d4bc6474df577fcfe9e7842852"
url: "https://pub.dev"
source: hosted
version: "3.1.12"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
version: "0.6.3"
version: "0.6.7"
json_annotation:
dependency: transitive
description:
name: json_annotation
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
url: "https://pub.dev"
source: hosted
version: "4.8.1"
lints:
dependency: transitive
description:
name: lints
url: "https://pub.dartlang.org"
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "3.0.0"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev"
source: hosted
version: "0.1.3"
version: "0.5.0"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
url: "https://pub.dev"
source: hosted
version: "1.7.0"
nm:
version: "1.10.0"
package_info_plus:
dependency: "direct main"
description:
name: package_info_plus
sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79"
url: "https://pub.dev"
source: hosted
version: "5.0.1"
package_info_plus_platform_interface:
dependency: transitive
description:
name: nm
url: "https://pub.dartlang.org"
name: package_info_plus_platform_interface
sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
url: "https://pub.dev"
source: hosted
version: "0.5.0"
version: "2.0.1"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev"
source: hosted
version: "1.8.0"
version: "1.8.3"
path_provider:
dependency: "direct main"
description:
name: path_provider
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
url: "https://pub.dev"
source: hosted
version: "2.1.1"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
url: "https://pub.dev"
source: hosted
version: "2.3.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
sha256: eeb2d1428ee7f4170e2bd498827296a18d4e7fc462b71727d111c0ac7707cfa6
url: "https://pub.dev"
source: hosted
version: "4.4.0"
version: "6.0.1"
platform:
dependency: transitive
description:
name: platform
sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.7"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
url: "https://pub.dev"
source: hosted
version: "3.7.3"
settings_ui:
dependency: "direct main"
description:
name: settings_ui
sha256: d9838037cb554b24b4218b2d07666fbada3478882edefae375ee892b6c820ef3
url: "https://pub.dev"
source: hosted
version: "2.0.2"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7"
url: "https://pub.dev"
source: hosted
version: "2.3.4"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a
url: "https://pub.dev"
source: hosted
version: "2.3.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
sky_engine:
dependency: transitive
description: flutter
@ -291,51 +561,154 @@ packages:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.8.1"
version: "1.10.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.2.1"
timezone:
dependency: "direct main"
description:
name: timezone
sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0"
url: "https://pub.dev"
source: hosted
version: "0.9.2"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.3.2"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
sha256: b1c9e98774adf8820c96fbc7ae3601231d324a7d5ebd8babe27b6dfac91357ba
url: "https://pub.dev"
source: hosted
version: "6.2.1"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def"
url: "https://pub.dev"
source: hosted
version: "6.2.0"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3
url: "https://pub.dev"
source: hosted
version: "6.2.1"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
sha256: "9f2d390e096fdbe1e6e6256f97851e51afc2d9c423d3432f1d6a02a8a9a8b9fd"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234
url: "https://pub.dev"
source: hosted
version: "3.1.0"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
sha256: "138bd45b3a456dcfafc46d1a146787424f8d2edfbf2809c9324361e58f851cf7"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
sha256: "7754a1ad30ee896b265f8d14078b0513a4dba28d358eabb9d5f339886f4a1adc"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.4"
web:
dependency: transitive
description:
name: web
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
url: "https://pub.dev"
source: hosted
version: "0.3.0"
win32:
dependency: transitive
description:
name: win32
sha256: "7c99c0e1e2fa190b48d25c81ca5e42036d5cac81430ef249027d97b0935c553f"
url: "https://pub.dev"
source: hosted
version: "5.1.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2"
url: "https://pub.dev"
source: hosted
version: "1.0.3"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
sha256: af5e77e9b83f2f4adc5d3f0a4ece1c7f45a2467b695c2540381bac793e34e556
url: "https://pub.dev"
source: hosted
version: "5.3.1"
version: "6.4.2"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
version: "3.1.2"
sdks:
dart: ">=2.16.1 <3.0.0"
flutter: ">=2.0.0"
dart: ">=3.2.0 <4.0.0"
flutter: ">=3.16.0"

View file

@ -6,41 +6,50 @@ publish_to: 'none'
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
version: 0.1.0+1
version: 1.10.0+32
environment:
sdk: ">=2.16.1 <3.0.0"
sdk: ">=2.18.2 <3.0.0"
dependencies:
canteenlib: ^3.0.0
flutter:
sdk: flutter
flutter_localizations:
flutter_local_notifications: ^16.0.0
flutter_localizations:
sdk: flutter
canteenlib: ^0.1.0-alpha.13
cupertino_icons: ^1.0.2
connectivity_plus: ^2.2.1
flutter_secure_storage: ^5.0.2
flutter_native_timezone: ^2.0.0
flutter_secure_storage: ^9.0.0
fluttertoast: ^8.1.2
intl: ^0.18.0
introduction_screen: ^3.0.1
package_info_plus: ^5.0.0
path_provider: ^2.0.9
settings_ui: ^2.0.2
shared_preferences: ^2.0.13
timezone: ^0.9.0
url_launcher: ^6.0.20
dev_dependencies:
flutter_lints: ^1.0.0
flutter_launcher_icons: "^0.9.2"
flutter_launcher_icons: ^0.13.0
flutter_lints: ^3.0.0
flutter_icons:
android: "launcher_icon"
android: true
ios: true
image_path: "assets/icon.jpg"
adaptive_icon_background: "#4f4685"
adaptive_icon_foreground: "assets/fore.png"
flutter:
uses-material-design: true
generate: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- assets/
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a

8
renovate.json Normal file
View file

@ -0,0 +1,8 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended"
],
"baseBranches": ["dev"],
"enabledManagers":["pub"]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

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