Compare commits

..

2 commits

Author SHA1 Message Date
Matyáš Caras 68ee7d16c4 feat(autoburza): vytvořit základ pro autoburzu 2022-10-20 17:44:04 +02:00
Matyáš Caras 656c5739a8 chore(npm): odstranit husky skript 2022-10-20 17:26:55 +02:00
99 changed files with 4027 additions and 2489 deletions

View file

@ -0,0 +1,5 @@
{
"name": "Flutter",
"image": "matspfeiffer/flutter:beta",
"extensions": ["dart-code.dart-code", "dart-code.flutter"]
}

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

13
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1,13 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: hernikplays
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View file

@ -0,0 +1,28 @@
---
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 systému zařízení: [např. Android 12, iOS 9]
- Verze aplikace [např. 0.1.0]
**Ostatní**
Sem vepište doplňující informace

View file

@ -0,0 +1,11 @@
---
name: Nápad na vylepšení
about: Navrhněte co změnit nebo přidat do aplikace
title: ''
labels: vylepšení
assignees: hernikplays
---
**Souvisí váš navrh s nějakým problémem?**
Popište váš problém a co čekáte za řešení.

8
.github/labeler.yml vendored Normal file
View file

@ -0,0 +1,8 @@
'pr: pubspec':
- pubspec.yaml
'pr: funkce':
- lib/*
'pr: okno':
- lib/okna/*

14
.github/pull_request_template.md vendored Normal file
View file

@ -0,0 +1,14 @@
Opravuje/implementuje # .
Změny:
- 1
- 2
```
Text výše slouží jen jako předloha, není nutné se ho držet, ale šetříte ostatním čas
```
- [ ] Otestoval jsem funkčnost celé aplikace po přidání svého kódu
- [ ] Přidaný kód nebo knihovny neobsahují žádný kód pod nekompatibilní licencí
Doplňující/ostatní informace:

30
.github/workflows/main.yml vendored Normal file
View file

@ -0,0 +1,30 @@
# This is a basic workflow to help you get started with Actions
name: Analyze
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main ]
pull_request:
branches: [ main ]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
fossa-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: fossas/fossa-action@main
with:
api-key: ${{secrets.fossaApiKey}}
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
- run: flutter pub get
- run: flutter analyze

33
.github/workflows/pr.yml vendored Normal file
View file

@ -0,0 +1,33 @@
name: "Lint PR"
on:
pull_request_target:
types:
- opened
- edited
- synchronize
jobs:
main:
name: Validate PR
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: amannn/action-semantic-pull-request@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: wagoid/commitlint-github-action@v4
- uses: actions/labeler@v4
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
branch:
name: Uzavřít PRy mimo dev větev
needs: main
if: github.base_ref == 'main' && github.actor != 'hernikplays'
runs-on: ubuntu-latest
steps:
- uses: superbrothers/close-pull-request@v3
with:
comment: "Všechny pull requesty by měly směřovat na jinou větev, než `main`. Pokud je tohle chyba, napište správci repozitáře."

4
.gitmodules vendored
View file

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

View file

@ -1,45 +1,10 @@
# This file tracks properties of this Flutter project. # This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc. # Used by Flutter tool to assess capabilities and perform upgrades etc.
# #
# This file should be version controlled. # This file should be version controlled and should not be manually edited.
version: version:
revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 revision: 097d3313d8e2c7f901932d63e537c1acefb87800
channel: stable channel: stable
project_type: app 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'

View file

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

View file

@ -1,42 +1,3 @@
# 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 # 1.4.1
- aktualizovat knihovnu canteenlib - aktualizovat knihovnu canteenlib
- změnit odkaz na odeslání zpětné vazby - změnit odkaz na odeslání zpětné vazby
@ -88,4 +49,4 @@
- Dialogové okno k burze se nezobrazí u jídel, která nelze přidat do burzy - 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) - Přidán načítací dialog při objednání (#6)
# 0.1.0 # 0.1.0
- První verze - První verze

View file

@ -2,16 +2,6 @@
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). 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 ## 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 ### 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). 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).

View file

@ -2,9 +2,7 @@
Open-Source **neoficiální** aplikace pro přístup do iCanteen 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) [![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/) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fhernikplays%2Fopencanteen.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fhernikplays%2Fopencanteen?ref=badge_shield) [![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í ## Co umí
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. 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.
@ -27,23 +25,9 @@ Jednoduchý návod k použití naleznete [zde](https://github.com/hernikplays/op
<img src="https://repobeats.axiom.co/api/embed/ce91f6018ce5523dc8d655df771f4f504c2c6664.svg" alt="repobeats stats"> <img src="https://repobeats.axiom.co/api/embed/ce91f6018ce5523dc8d655df771f4f504c2c6664.svg" alt="repobeats stats">
</div> </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 ## Licence
[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B12838%2Fgithub.com%2Fhernikplays%2Fopencanteen.svg?type=large)](https://app.fossa.com/projects/custom%2B12838%2Fgithub.com%2Fhernikplays%2Fopencanteen?ref=badge_large)
**Copyright (c) 2022 Matyáš Caras a přispěvatelé** **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) 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,12 +31,9 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
} }
android { android {
compileSdkVersion 33 compileSdkVersion flutter.compileSdkVersion
compileOptions { compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 8
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
@ -51,8 +48,8 @@ android {
defaultConfig { defaultConfig {
applicationId "cz.hernikplays.opencanteen" applicationId "cz.hernikplays.opencanteen"
minSdkVersion 21 minSdkVersion 18
targetSdkVersion 33 targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
multiDexEnabled true multiDexEnabled true
@ -81,16 +78,4 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:multidex:1.0.3' implementation 'com.android.support:multidex:1.0.3'
implementation 'androidx.appcompat:appcompat:1.3.1' 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,11 +1,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cz.hernikplays.opencanteen"> package="cz.hernikplays.opencanteen">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<application <application
android:label="OpenCanteen" android:label="OpenCanteen"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/launcher_icon"
android:allowBackup="false" android:allowBackup="false"
android:fullBackupContent="false"> android:fullBackupContent="false">
<activity <activity

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1,6 +0,0 @@
<?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: 2 KiB

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

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

View file

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

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

1
commitlint.config.js Normal file
View file

@ -0,0 +1 @@
module.exports = {extends: ['@commitlint/config-conventional']}

113
flutterw
View file

@ -1,113 +0,0 @@
#!/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> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>11.0</string> <string>9.0</string>
</dict> </dict>
</plist> </plist>

View file

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
# platform :ios, '11.0' platform :ios, '10.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'

View file

@ -1,79 +1,53 @@
PODS: PODS:
- connectivity_plus (0.0.1):
- Flutter
- ReachabilitySwift
- Flutter (1.0.0) - Flutter (1.0.0)
- flutter_keyboard_visibility (0.0.1): - flutter_secure_storage (3.3.1):
- Flutter - Flutter
- flutter_local_notifications (0.0.1): - path_provider_ios (0.0.1):
- Flutter - Flutter
- flutter_native_timezone (0.0.1): - ReachabilitySwift (5.0.0)
- shared_preferences_ios (0.0.1):
- Flutter - 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): - url_launcher_ios (0.0.1):
- Flutter - Flutter
DEPENDENCIES: DEPENDENCIES:
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- Flutter (from `Flutter`) - 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`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/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`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- Toast - ReachabilitySwift
EXTERNAL SOURCES: EXTERNAL SOURCES:
connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/ios"
Flutter: Flutter:
:path: 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: flutter_secure_storage:
:path: ".symlinks/plugins/flutter_secure_storage/ios" :path: ".symlinks/plugins/flutter_secure_storage/ios"
fluttertoast: path_provider_ios:
:path: ".symlinks/plugins/fluttertoast/ios" :path: ".symlinks/plugins/path_provider_ios/ios"
package_info_plus: shared_preferences_ios:
:path: ".symlinks/plugins/package_info_plus/ios" :path: ".symlinks/plugins/shared_preferences_ios/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
url_launcher_ios: url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios" :path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS: SPEC CHECKSUMS:
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
flutter_native_timezone: 5f05b2de06c9776b4cc70e1839f03de178394d22 path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7 url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3 PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
COCOAPODS: 1.12.1 COCOAPODS: 1.11.3

View file

@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 54; objectVersion = 50;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
@ -156,7 +156,7 @@
97C146E61CF9000F007C117D /* Project object */ = { 97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1430; LastUpgradeCheck = 1300;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {
@ -222,12 +222,10 @@
}; };
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
); );
name = "Thin Binary"; name = "Thin Binary";
outputPaths = ( outputPaths = (
@ -238,7 +236,6 @@
}; };
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
@ -343,7 +340,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@ -420,7 +417,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -469,7 +466,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@ -550,3 +547,9 @@
}; };
rootObject = 97C146E61CF9000F007C117D /* Project object */; rootObject = 97C146E61CF9000F007C117D /* Project object */;
} }
SystemCapabilities = {
com.apple.BackgroundModes = {
enabled = 1;
};
};

View file

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

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

View file

@ -4,7 +4,7 @@
<dict> <dict>
<key>CFBundleLocalizations</key> <key>CFBundleLocalizations</key>
<array> <array>
<string>cs</string> <string>Czech</string>
<string>en</string> <string>en</string>
</array> </array>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
@ -50,7 +50,13 @@
<false/> <false/>
<key>CADisableMinimumFrameDurationOnPhone</key> <key>CADisableMinimumFrameDurationOnPhone</key>
<true/> <true/>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIBackgroundModes</key>
<true/> <array>
<string>processing</string>
</array>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>oc_bg</string>
</array>
</dict> </dict>
</plist> </plist>

View file

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

View file

@ -1,69 +0,0 @@
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),
);

View file

@ -1,83 +0,0 @@
{
"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é"
}

View file

@ -1,83 +0,0 @@
{
"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"
}

173
lib/lang/lang.dart Normal file
View file

@ -0,0 +1,173 @@
import 'package:flutter/material.dart';
abstract class Languages {
static Languages? of(BuildContext context) {
return Localizations.of<Languages>(context, Languages);
}
String get appName;
String get home;
// Login
String get errorContacting;
String get loggingIn;
String get logIn;
String get username;
String get password;
String get iCanteenUrl;
String get rememberMe;
String get httpLogin;
String get yes;
String get noChange;
String get notOfficial;
String get agree;
String get disagree;
String get loginFailed;
String get warning;
String get corrupted;
// Jídelníček
String get loading;
String get monday;
String get tuesday;
String get wednesday;
String get thursday;
String get friday;
String get saturday;
String get sunday;
String get noFood;
String get inExchange;
String get ordering;
String get errorOrdering;
String get close;
String get verifyExchange;
String get no;
String get exchangeError;
String get signOut;
String get reportBugs;
String get review;
String get about;
String get menu;
String get balance;
String get noOrder;
String get signOutWarn;
String get jump;
// Uvítací obrazovka
String get welcome;
String get appDesc;
String get aboutOrder;
String get howOrder;
String get aboutToExch;
String get howToExch;
String get aboutFromExch;
String get howFromExch;
String get next;
// Burza
String get exchange;
String get noExchange;
String get pullToReload;
String get ordered;
String get orderSuccess;
String get ok;
String get cannotOrder;
String get order;
// About
String get license;
String get copyright;
String get source;
// Nastavení
String get settings;
String get saveOffline;
String get skipWeekend;
String get checkOrdered;
String get notifyLunch;
String get notifyAt;
String get notifyWarning;
String get autoburzaSetting;
// Offline
String get offline;
String get mustLogout;
// Oznámit před obědem
String get lunchNotif;
String get error;
String get needRemember;
}

244
lib/lang/lang_cz.dart Normal file
View file

@ -0,0 +1,244 @@
import 'package:opencanteen/lang/lang.dart';
class LanguageCz extends Languages {
@override
String get about => "O Aplikaci";
@override
String get agree => "Souhlasím";
@override
String get appName => "OpenCanteen";
@override
String get balance => "Kredit: ";
@override
String get cannotOrder => "Toto jídlo není možné objednat.";
@override
String get close => "Zavřít";
@override
String get copyright => "© 2022 Matyáš Caras a přispěvatelé";
@override
String get disagree => "Nesouhlasím";
@override
String get errorContacting =>
"Nastala chyba při kontaktování serveru, zkontrolujte připojení";
@override
String get errorOrdering => "Jídlo se nepodařilo objednat";
@override
String get exchange => "Burza";
@override
String get exchangeError => "Nepodařilo se vložit jídlo na burzu";
@override
String get friday => "Pátek";
@override
String get home => "Domů";
@override
String get httpLogin =>
"Snažíte se přihlásit přes nešifrované spojení HTTP, jste si jisti, že tak chcete učinit?";
@override
String get iCanteenUrl => "iCanteen URL";
@override
String get inExchange => "V BURZE";
@override
String get license => "Vydáno pod licencí GNU GPLv3";
@override
String get loading => "Načítání...";
@override
String get logIn => "Přihlášení";
@override
String get loggingIn => "Přihlašuji vás...";
@override
String get loginFailed => "Přihlášení se nezdařilo";
@override
String get menu => "Jídelníček";
@override
String get monday => "Pondělí";
@override
String get mustLogout => "Online přejdete přetažením dolů.";
@override
String get no => "Ne";
@override
String get noChange => "Ne, změnit";
@override
String get noExchange => "Žádné jídlo v burze";
@override
String get noFood => "Žádné jídlo pro tento den";
@override
String get 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.";
@override
String get offline => "JSTE OFFLINE";
@override
String get ok => "OK";
@override
String get order => "Objednat";
@override
String get orderSuccess => "Jídlo bylo úspěšně objednáno";
@override
String get ordered => "Objednáno";
@override
String get ordering => "Objednávám...";
@override
String get password => "Heslo";
@override
String get pullToReload => "Potáhněte zvrchu pro načtení";
@override
String get rememberMe => "Zapamatovat si mě";
@override
String get reportBugs => "Zpětná vazba";
@override
String get saturday => "Sobota";
@override
String get saveOffline => "Ukládat jídelníček na dnešní den offline";
@override
String get settings => "Nastavení";
@override
String get signOut => "Odhlásit se";
@override
String get skipWeekend => "Při procházení menu přeskočit víkend";
@override
String get sunday => "Neděle";
@override
String get thursday => "Čtvrtek";
@override
String get tuesday => "Úterý";
@override
String get username => "Uživatelské jméno";
@override
String get verifyExchange => "Opravdu chcete vložit jídlo na burzu?";
@override
String get warning => "Pozor!";
@override
String get wednesday => "Středa";
@override
String get yes => "Ano";
@override
String get aboutFromExch => "Žádné jídlo? Žádný problém!";
@override
String get aboutOrder => "Klepnutím objednáte";
@override
String get aboutToExch => "Nemáte chuť?";
@override
String get appDesc =>
"OpenCanteen je neoficiální aplikace pro přístup do obědového systému iCanteen";
@override
String get howFromExch =>
"Z vysunovacího menu přejděte do burzy a objednejte si z dostupných jídel";
@override
String get howOrder =>
"Jednoduše klepněte na jídlo s modrým políčkem a máte objednáno";
@override
String get howToExch =>
"Stačí dlouze podržet jméno objednaného jídla a můžete ho přesunout na nebo z burzy";
@override
String get welcome => "Vítejte v OpenCanteen";
@override
String get next => "Další";
@override
String get checkOrdered =>
"Kontrolovat, jestli mám objednáno na příští týden";
@override
String get noOrder => "Na přístí týden nemáte objednané žádné jídlo!";
@override
String get corrupted =>
"Nastal problém s dešifrováním uložených údajů, prosím zkuste vyčistit veškerá data této aplikace.";
@override
String get notifyAt => "Odeslat v";
@override
String get notifyLunch =>
"V určený čas odeslat notifikaci s informacemi o obědě";
@override
String get lunchNotif => "Dnes máte objednáno";
@override
String get error => "Chyba";
@override
String get needRemember =>
"Musíte své přihlašovací údaje uložit na přihlašovací obrazovce";
@override
String get 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í.";
@override
String get signOutWarn => "Opravdu se chcete odhlásit?";
@override
String get jump => "Přeskočit";
@override
String get source => "Zdrojový kód";
@override
String get review => "Ohodnotit aplikaci";
@override
String get autoburzaSetting =>
"Automaticky objednat jídlo z burzy když bude dostupné";
}

242
lib/lang/lang_en.dart Normal file
View file

@ -0,0 +1,242 @@
import 'package:opencanteen/lang/lang.dart';
class LanguageEn extends Languages {
@override
String get about => "About";
@override
String get agree => "I agree";
@override
String get appName => "OpenCanteen";
@override
String get balance => "Balance: ";
@override
String get cannotOrder => "This food cannot be ordered.";
@override
String get close => "Close";
@override
String get copyright => "© 2022 Matyáš Caras and contributors";
@override
String get disagree => "I disagree";
@override
String get errorContacting =>
"Failed to contact the server, check your connection.";
@override
String get errorOrdering => "Could not order food.";
@override
String get exchange => "Exchange";
@override
String get exchangeError => "Could not put food on exchange.";
@override
String get friday => "Friday";
@override
String get home => "Home";
@override
String get httpLogin =>
"You are trying to sign in using an insecure HTTP connection, are you sure you want to continue?";
@override
String get iCanteenUrl => "iCanteen URL";
@override
String get inExchange => "ON EXCHANGE";
@override
String get license => "Released under the GNU GPLv3";
@override
String get loading => "Loading...";
@override
String get logIn => "Sign in";
@override
String get loggingIn => "Signing you in...";
@override
String get loginFailed => "Sign in failed";
@override
String get menu => "Food Menu";
@override
String get monday => "Monday";
@override
String get mustLogout => "To go online, pull down.";
@override
String get no => "No";
@override
String get noChange => "No, change";
@override
String get noExchange => "No meal in exchange";
@override
String get noFood => "No meal for this day";
@override
String get 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.";
@override
String get offline => "YOU ARE OFFLINE";
@override
String get ok => "OK";
@override
String get order => "Order";
@override
String get orderSuccess => "Meal ordered succesfully";
@override
String get ordered => "Ordered";
@override
String get ordering => "Ordering...";
@override
String get password => "Password";
@override
String get pullToReload => "Pull to reload";
@override
String get rememberMe => "Remember me";
@override
String get reportBugs => "Feedback";
@override
String get saturday => "Saturday";
@override
String get saveOffline => "Save today's menu offline";
@override
String get settings => "Settings";
@override
String get signOut => "Sign out";
@override
String get skipWeekend => "Skip weekends when browsing menu";
@override
String get sunday => "Sunday";
@override
String get thursday => "Thursday";
@override
String get tuesday => "Tuesday";
@override
String get username => "Username";
@override
String get verifyExchange =>
"Are you sure you want to put this meal on exchange?";
@override
String get warning => "Warning!";
@override
String get wednesday => "Wednesday";
@override
String get yes => "Yes";
@override
String get appDesc => "OpenCanteen is a mobile app for accessing iCanteen.";
@override
String get welcome => "Welcome to OpenCanteen";
@override
String get aboutOrder => "Order with a tap";
@override
String get howOrder =>
"Simply tap on a meal with a blue checkbox next to it and it's done!";
@override
String get aboutToExch => "Don't want your food?";
@override
String get howToExch =>
"If you cannot cancel your order, simply long-tap on the ordered food and put it into the exchange.";
@override
String get aboutFromExch => "No food? No problem!";
@override
String get howFromExch =>
"Simply check the exchange from the sidebar and order when a meal is available.";
@override
String get next => "Next";
@override
String get checkOrdered => "Check if I have ordered food for the next week";
@override
String get noOrder => "You did not order any food for the next week!";
@override
String get corrupted =>
"The saved credentials seem to be corrupted, please try clearing the application's data.";
@override
String get notifyAt => "Send notification at";
@override
String get notifyLunch => "Send a notification with meal info";
@override
String get lunchNotif => "Today's ordered meal";
@override
String get error => "Error";
@override
String get needRemember =>
"You need to save your login details on the login screen first";
@override
String get 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.";
@override
String get signOutWarn => "Do you really want to sign out?";
@override
String get jump => "Jump";
@override
String get source => "Source code";
@override
String get review => "Review the app";
@override
String get autoburzaSetting =>
"Automatically order food from exchange when available";
}

View file

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

View file

@ -1,21 +1,28 @@
import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.dart'; import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:opencanteen/lang/lang_cz.dart';
import 'package:opencanteen/loginmanager.dart';
import 'package:canteenlib/canteenlib.dart'; import 'package:canteenlib/canteenlib.dart';
import 'package:opencanteen/okna/login.dart'; import 'package:opencanteen/okna/offline_jidelnicek.dart';
import 'package:opencanteen/okna/welcome.dart';
import 'package:opencanteen/util.dart'; import 'package:opencanteen/util.dart';
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:timezone/data/latest_all.dart' as tz; import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/timezone.dart' as tz; import 'package:timezone/timezone.dart' as tz;
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'lang/lang.dart';
import 'color_schemes.g.dart'; import 'lang/lang_en.dart';
import 'loginmanager.dart'; import 'okna/jidelnicek.dart';
/* /*
Copyright (C) 2022 Matyáš Caras a přispěvatelé Copyright (C) 2022 Matyáš Caras a přispěvatelé
@ -35,60 +42,59 @@ Copyright (C) 2022 Matyáš Caras a přispěvatelé
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin(); FlutterLocalNotificationsPlugin();
final settings = SettingsManager();
/// Used to setup notifications about ordered food void oznamitPredem(SharedPreferences prefs, tz.Location l) async {
void setupNotification(SharedPreferences prefs, tz.Location l) async {
String title; String title;
String locale = Intl.getCurrentLocale(); String locale = Intl.getCurrentLocale();
switch (locale) { switch (locale) {
case "cs_CZ": case "cs_CZ":
title = "Dnes máte objednáno"; title = LanguageCz().lunchNotif;
break; break;
default: default:
title = "Today's ordered meal"; title = LanguageEn().lunchNotif;
} }
/*if (prefs.getBool("offline") ?? false) { /*if (prefs.getBool("offline") ?? false) {
// TODO grab data from offline storage // TODO možnost brát z offline dat
} else {*/ } else {*/
// data from the web // bere online
var d = await LoginManager.getDetails(); // grab login var d = await LoginManager.getDetails(); // získat údaje
if (d != null) { if (d != null) {
var c = Canteen(d["url"]!); var c = Canteen(d["url"]!);
if (await c.login(d["user"]!, d["pass"]!)) { if (await c.login(d["user"]!, d["pass"]!)) {
var jidla = await c.jidelnicekDen(); var jidla = await c.jidelnicekDen();
try { try {
var jidlo = jidla.jidla var jidlo = jidla.jidla.singleWhere(
.singleWhere((element) => element.objednano); // grab ordered meal (element) => element.objednano); // získá objednané jídlo
var kdy = DateTime.parse(prefs.getString( var kdy = DateTime.parse(prefs.getString(
"oznameni_cas")!); // save the time the notif should be sent "oznameni_cas")!); // uložíme čas, kdy se odeslat oznámení
var cas = timeToDate( var cas = casNaDate(
TimeOfDay(hour: kdy.hour, minute: kdy.minute), TimeOfDay(hour: kdy.hour, minute: kdy.minute),
); );
if (cas.isBefore(DateTime.now())) return; if (cas.isBefore(DateTime.now())) return;
// notif data // data o oznámení
const AndroidNotificationDetails androidSpec = const AndroidNotificationDetails androidSpec =
AndroidNotificationDetails('predobedem', 'Oznámení před obědem', AndroidNotificationDetails('predobedem', 'Oznámení před obědem',
channelDescription: 'Oznámení o dnešním jídle', channelDescription: 'Oznámení o dnešním jídle',
importance: Importance.max, importance: Importance.max,
priority: Priority.high, priority: Priority.high,
styleInformation: BigTextStyleInformation(''),
ticker: 'today meal'); ticker: 'today meal');
const IOSNotificationDetails iOSpec =
IOSNotificationDetails(presentAlert: true, presentBadge: true);
// plan through lib // naplánovat
await flutterLocalNotificationsPlugin.zonedSchedule( await flutterLocalNotificationsPlugin.zonedSchedule(
0, 0,
title, title,
"${jidlo.varianta} - ${jidlo.nazev}", "${jidlo.varianta} - ${jidlo.nazev}",
tz.TZDateTime.from(cas, l), tz.TZDateTime.from(cas, l),
const NotificationDetails(android: androidSpec), const NotificationDetails(android: androidSpec, iOS: iOSpec),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, androidAllowWhileIdle: true,
uiLocalNotificationDateInterpretation: uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime); UILocalNotificationDateInterpretation.absoluteTime);
} on StateError catch (_) { } on StateError catch (_) {
// no ordered meal found // nenalezeno
} }
} }
// } // }
@ -96,75 +102,380 @@ void setupNotification(SharedPreferences prefs, tz.Location l) async {
} }
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized();
tz.initializeTimeZones(); tz.initializeTimeZones();
var l = tz.getLocation(await FlutterNativeTimezone.getLocalTimezone()); var l = tz.getLocation(await FlutterNativeTimezone.getLocalTimezone());
tz.setLocalLocation(l); tz.setLocalLocation(l);
var prefs = await SharedPreferences.getInstance(); var prefs = await SharedPreferences.getInstance();
if (prefs.getBool("oznamit") ?? false) { if (prefs.getBool("oznamit") ?? false) {
setupNotification(prefs, l); oznamitPredem(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 // nastavit oznámení
const AndroidInitializationSettings initializationSettingsAndroid = const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('notif_icon'); AndroidInitializationSettings('notif_icon');
const ios = DarwinInitializationSettings(); final IOSInitializationSettings initializationSettingsIOS =
IOSInitializationSettings(onDidReceiveLocalNotification: (
int id,
String? title,
String? body,
String? payload,
) async {
debugPrint(body);
});
const InitializationSettings initializationSettings = final InitializationSettings initializationSettings = InitializationSettings(
InitializationSettings(android: initializationSettingsAndroid, iOS: ios); android: initializationSettingsAndroid,
await flutterLocalNotificationsPlugin.initialize(initializationSettings); iOS: initializationSettingsIOS,
);
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: (String? payload) async {
if (payload != null) {
debugPrint('notification payload: $payload');
}
});
WidgetsFlutterBinding.ensureInitialized();
// spustit aplikaci
runApp(const MyApp()); runApp(const MyApp());
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
const MyApp({super.key}); const MyApp({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return (Platform return MaterialApp(
.isAndroid) // run app based on current platform to make use of the platform's respective UI lib debugShowCheckedModeBanner: false,
? MaterialApp( localizationsDelegates: const [
debugShowCheckedModeBanner: false, AppLocalizationsDelegate(),
localizationsDelegates: const [ ...GlobalMaterialLocalizations.delegates
AppLocalizations.delegate, ],
...GlobalMaterialLocalizations.delegates supportedLocales: const [Locale("cs", ""), Locale("en", "")],
], title: "OpenCanteen",
supportedLocales: AppLocalizations.supportedLocales, theme: ThemeData(
title: "OpenCanteen", primarySwatch: Colors.purple,
theme: ThemeData(useMaterial3: true, colorScheme: lightColorScheme), ),
darkTheme: ThemeData( darkTheme: ThemeData(
brightness: Brightness.dark, brightness: Brightness.dark,
useMaterial3: true, primarySwatch: Colors.purple,
colorScheme: darkColorScheme), ),
home: const LoginPage(), 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(),
),
);
} }
} }
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;
bool _showUrl = false;
String dropdownUrl = instance.first["url"] ?? "";
@override
void initState() {
super.initState();
LoginManager.getDetails().then((r) async {
if (Platform.isIOS) {
// žádat o oprávnění na iOS
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: true,
badge: true,
sound: true,
);
}
if (r != null) {
// Automaticky přihlásit
showDialog(
context: context,
barrierDismissible: false,
builder: (_) => Dialog(
child: SizedBox(
height: 100,
child: Row(children: [
const Padding(
padding: EdgeInsets.all(10),
child: CircularProgressIndicator(),
),
Text(Languages.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(Languages.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,
MaterialPageRoute(
builder: (c) => WelcomeScreen(
canteen: canteen, n: flutterLocalNotificationsPlugin),
),
(route) => false);
} else {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => JidelnicekPage(
canteen: canteen, n: flutterLocalNotificationsPlugin),
),
(route) => false);
}
} on PlatformException {
if (!mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(Languages.of(context)!.corrupted),
),
);
} catch (_) {
if (!mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(Languages.of(context)!.errorContacting),
),
);
goOffline();
}
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(Languages.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(
Languages.of(context)!.appName,
textAlign: TextAlign.center,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 40),
),
Text(
Languages.of(context)!.logIn,
textAlign: TextAlign.center,
),
TextField(
controller: userControl,
autofillHints: const [AutofillHints.username],
decoration: InputDecoration(
labelText: Languages.of(context)!.username),
),
TextField(
autofillHints: const [AutofillHints.password],
decoration: InputDecoration(
labelText: Languages.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: TextField(
autofillHints: const [AutofillHints.url],
decoration: InputDecoration(
labelText: Languages.of(context)!.iCanteenUrl),
keyboardType: TextInputType.url,
controller: canteenControl,
),
),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Switch(
value: rememberMe,
onChanged: (value) {
setState(() {
rememberMe = value;
});
}),
Text(Languages.of(context)!.rememberMe)
]),
TextButton(
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;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text(Languages.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,
MaterialPageRoute(
builder: (c) => WelcomeScreen(
canteen: canteen,
n: flutterLocalNotificationsPlugin)),
(route) => false);
} else {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) => JidelnicekPage(
canteen: canteen,
n: flutterLocalNotificationsPlugin)),
(route) => false);
}
} on PlatformException {
if (!mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(Languages.of(context)!.corrupted),
),
);
} on Exception catch (_) {
if (!mounted) return;
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content:
Text(Languages.of(context)!.errorContacting),
),
);
goOffline();
}
},
child: Text(Languages.of(context)!.logIn)),
],
),
),
),
));
}
/// Získá offline soubor a zobrazí údaje
void goOffline() async {
Directory appDocDir = await getApplicationDocumentsDirectory();
var den = DateTime.now();
var soubor = File(
"${appDocDir.path}/jidelnicek_${den.year}-${den.month}-${den.day}.json");
if (soubor.existsSync()) {
// načteme offline jídelníček
var input = await soubor.readAsString();
var r = jsonDecode(input);
List<OfflineJidlo> jidla = [];
for (var j in r) {
jidla.add(OfflineJidlo(
nazev: j["nazev"],
varianta: j["varianta"],
objednano: j["objednano"],
cena: j["cena"],
naBurze: j["naBurze"],
den: DateTime.parse(j["den"])));
}
if (!mounted) return;
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: ((context) => OfflineJidelnicek(jidla: jidla))),
(route) => false);
}
}
}
class AppLocalizationsDelegate extends LocalizationsDelegate<Languages> {
const AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) => ['cs', 'en'].contains(locale.languageCode);
@override
Future<Languages> load(Locale locale) => _load(locale);
static Future<Languages> _load(Locale locale) async {
switch (locale.languageCode) {
case 'cs':
return LanguageCz();
default:
return LanguageEn();
}
}
@override
bool shouldReload(LocalizationsDelegate<Languages> old) => false;
}

View file

@ -1,126 +1,123 @@
import 'package:canteenlib/canteenlib.dart'; import 'package:canteenlib/canteenlib.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:opencanteen/okna/login.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:opencanteen/pw/platformbutton.dart';
import 'package:opencanteen/pw/platformdialog.dart';
import 'package:opencanteen/util.dart'; import 'package:opencanteen/util.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../lang/lang.dart';
import '../main.dart';
class BurzaView extends StatefulWidget { class BurzaPage extends StatefulWidget {
const BurzaView({super.key, required this.canteen}); const BurzaPage({Key? key, required this.canteen, required this.n})
: super(key: key);
final Canteen canteen; final Canteen canteen;
final FlutterLocalNotificationsPlugin n;
@override @override
State<BurzaView> createState() => _BurzaViewState(); State<BurzaPage> createState() => _BurzaPageState();
} }
class _BurzaViewState extends State<BurzaView> { class _BurzaPageState extends State<BurzaPage> {
List<Widget> content = []; List<Widget> obsah = [];
double balance = 0.0; double kredit = 0.0;
Future<void> nactiBurzu(BuildContext context) async {
Future<void> loadExchange(BuildContext context) async { obsah = [const CircularProgressIndicator()];
content = [const CircularProgressIndicator()]; widget.canteen.ziskejUzivatele().then((kr) {
var uzivatel = await widget.canteen.ziskejUzivatele().catchError((o) { kredit = kr.kredit;
widget.canteen.ziskatBurzu().then((burza) {
setState(() {
obsah = [];
if (burza.isEmpty) {
obsah = [
Text(
Languages.of(context)!.noExchange,
style: const TextStyle(fontSize: 20),
),
Text(Languages.of(context)!.pullToReload)
];
} 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((a) {
if (a) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(Languages.of(context)!.ordered),
content: Text(
Languages.of(context)!.orderSuccess),
actions: [
TextButton(
child: Text(Languages.of(context)!.ok),
onPressed: () =>
Navigator.of(context).pop(),
)
],
),
);
} else {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(
Languages.of(context)!.cannotOrder),
content: Text(
Languages.of(context)!.errorOrdering),
actions: [
TextButton(
child: Text(Languages.of(context)!.ok),
onPressed: () =>
Navigator.of(context).pop(),
)
],
),
);
}
nactiBurzu(context);
});
},
child: Text(Languages.of(context)!.order)),
],
),
),
);
}
}
});
});
}).catchError((o) {
if (!widget.canteen.prihlasen) { if (!widget.canteen.prihlasen) {
Navigator.pushReplacement( Navigator.pushReplacement(
context, platformRouter((c) => const LoginPage())); context, MaterialPageRoute(builder: (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 @override
void initState() { void initState() {
super.initState(); super.initState();
loadExchange(context); nactiBurzu(context);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
drawer: drawerGenerator(context, widget.canteen, 3), drawer: drawerGenerator(context, widget.canteen, 3, widget.n),
appBar: AppBar( appBar: AppBar(
title: Text(AppLocalizations.of(context)!.exchange), title: Text(Languages.of(context)!.exchange),
), ),
body: RefreshIndicator( body: RefreshIndicator(
child: Center( child: Center(
@ -129,20 +126,20 @@ class _BurzaViewState extends State<BurzaView> {
child: Column( child: Column(
children: [ children: [
const SizedBox(height: 10), const SizedBox(height: 10),
Text("${AppLocalizations.of(context)!.balance}$balance"), Text("${Languages.of(context)!.balance}$kredit"),
const SizedBox(height: 10), const SizedBox(height: 10),
SingleChildScrollView( SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
child: SizedBox( child: SizedBox(
height: MediaQuery.of(context).size.height / 1.3, height: MediaQuery.of(context).size.height / 1.3,
child: Column(children: content), child: Column(children: obsah),
), ),
) )
], ],
), ),
), ),
), ),
onRefresh: () => loadExchange(context)), onRefresh: () => nactiBurzu(context)),
); );
} }
} }

View file

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

View file

@ -1,247 +0,0 @@
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);
}
}

View file

@ -2,267 +2,224 @@ import 'dart:io';
import 'package:canteenlib/canteenlib.dart'; import 'package:canteenlib/canteenlib.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_native_timezone/flutter_native_timezone.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:path_provider/path_provider.dart';
import 'package:settings_ui/settings_ui.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:timezone/timezone.dart' as tz; import 'package:timezone/timezone.dart' as tz;
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../lang/lang.dart';
import '../../loginmanager.dart'; import '../loginmanager.dart';
import '../../main.dart'; import '../util.dart';
import '../../util.dart';
class AndroidNastaveni extends StatefulWidget { class Nastaveni extends StatefulWidget {
const AndroidNastaveni({super.key}); const Nastaveni({Key? key, required this.n}) : super(key: key);
final FlutterLocalNotificationsPlugin n;
@override @override
State<AndroidNastaveni> createState() => _AndroidNastaveniState(); State<Nastaveni> createState() => _NastaveniState();
} }
class _AndroidNastaveniState extends State<AndroidNastaveni> { class _NastaveniState extends State<Nastaveni> {
bool _saveOffline = false; bool _ukladatOffline = false;
bool _skipWeekend = false; bool _preskakovatVikend = false;
bool _checkWeek = false; bool _kontrolovatTyden = false;
bool _notifyMeal = false; bool _oznameniObed = false;
bool _remember = false; bool _zapamatovany = false;
bool _allergens = false; bool _autoburza = false;
TimeOfDay _notifTime = TimeOfDay.now(); TimeOfDay _oznameniCas = TimeOfDay.now();
final TextEditingController _countController =
TextEditingController(text: "1");
SharedPreferences? preferences;
void loadSettings() async { void najitNastaveni() async {
preferences = await SharedPreferences.getInstance(); var preferences = await SharedPreferences.getInstance();
_remember = await LoginManager.rememberme(); _zapamatovany = await LoginManager.zapamatovat();
setState( setState(() {
() { _ukladatOffline = preferences.getBool("offline") ?? false;
_saveOffline = preferences!.getBool("offline") ?? false; _preskakovatVikend = preferences.getBool("skip") ?? false;
_skipWeekend = preferences!.getBool("skip") ?? false; _kontrolovatTyden = preferences.getBool("tyden") ?? false;
_checkWeek = preferences!.getBool("tyden") ?? false; _oznameniObed = preferences.getBool("oznamit") ?? false;
_notifyMeal = preferences!.getBool("oznamit") ?? false; _autoburza = preferences.getBool("autoburza") ?? false;
_countController.text = var casStr = preferences.getString("oznameni_cas");
(preferences!.getInt("offline_pocet") ?? 1).toString(); if (casStr == null) {
var casStr = preferences!.getString("oznameni_cas"); var now = DateTime.now();
if (casStr == null) { _oznameniCas = TimeOfDay.fromDateTime(
var now = DateTime.now(); DateTime.now().add(const Duration(hours: 1)));
_notifTime = TimeOfDay.fromDateTime( preferences.setString("oznameni_cas", now.toString());
DateTime.now().add(const Duration(hours: 1))); } else {
preferences!.setString("oznameni_cas", now.toString()); _oznameniCas = TimeOfDay.fromDateTime(DateTime.parse(casStr));
} else { }
_notifTime = TimeOfDay.fromDateTime(DateTime.parse(casStr)); });
}
},
);
} }
void changeSetting(String key, bool value) async { void zmenitNastaveni(String key, bool value) async {
preferences!.setBool(key, value); var preferences = await SharedPreferences.getInstance();
preferences.setBool(key, value);
} }
@override @override
void initState() { void initState() {
super.initState(); super.initState();
loadSettings(); najitNastaveni();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(AppLocalizations.of(context)!.settings), title: Text(Languages.of(context)!.settings),
), ),
body: SettingsList( body: Center(
platform: DevicePlatform.device, child: SizedBox(
sections: [ width: MediaQuery.of(context).size.width / 1.1,
SettingsSection( child: Column(
tiles: [ children: [
SettingsTile.switchTile( Row(
initialValue: _allergens, mainAxisAlignment: MainAxisAlignment.spaceBetween,
onToggle: (value) { children: [
_allergens = value; Text(Languages.of(context)!.saveOffline),
settings.allergens = value; Switch(
changeSetting("allergens", _allergens); value: _ukladatOffline,
setState(() {}); onChanged: (value) {
}, setState(() {
title: Text(AppLocalizations.of(context)!.showAllergens), _ukladatOffline = value;
), cistit(value);
SettingsTile.switchTile( zmenitNastaveni("offline", value);
initialValue: _saveOffline, });
onToggle: (value) { })
_saveOffline = value; ],
settings.saveOffline = value; ),
changeSetting("offline", value); Row(
setState(() {}); mainAxisAlignment: MainAxisAlignment.spaceBetween,
}, children: [
title: Text(AppLocalizations.of(context)!.saveOffline), Text(Languages.of(context)!.skipWeekend),
), Switch(
CustomSettingsTile( value: _preskakovatVikend,
child: Row( onChanged: (value) {
mainAxisAlignment: MainAxisAlignment.center, setState(() {
children: [ _preskakovatVikend = value;
SizedBox( zmenitNastaveni("skip", value);
width: MediaQuery.of(context).size.width * 0.76, });
child: Text( })
AppLocalizations.of(context)!.saveCount, ],
softWrap: true, ),
style: TextStyle( Row(
fontSize: (Platform.isAndroid) ? 18 : 17, mainAxisAlignment: MainAxisAlignment.spaceBetween,
fontWeight: children: [
(Platform.isAndroid) ? FontWeight.w400 : null, Flexible(child: Text(Languages.of(context)!.checkOrdered)),
), Switch(
), value: _kontrolovatTyden,
), onChanged: (value) {
const SizedBox( setState(() {
width: 10, _kontrolovatTyden = value;
), zmenitNastaveni("tyden", value);
SizedBox( });
width: 35, })
child: PlatformField( ],
controller: _countController, ),
enabled: _saveOffline, Row(
keyboardType: TextInputType.number, mainAxisAlignment: MainAxisAlignment.spaceBetween,
inputFormatters: [ children: [
FilteringTextInputFormatter.digitsOnly Flexible(child: Text(Languages.of(context)!.autoburzaSetting)),
], Switch(
onChanged: (c) { value: _autoburza,
var cislo = int.tryParse(c); onChanged: (value) {
if (cislo != null) { setState(() {
preferences!.setInt("offline_pocet", cislo); _kontrolovatTyden = value;
zmenitNastaveni("autoburza", value);
});
})
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(child: Text(Languages.of(context)!.notifyLunch)),
Switch(
value: _oznameniObed,
thumbColor: (!_zapamatovany
? MaterialStateProperty.all(Colors.grey)
: null),
onChanged: (value) {
if (!_zapamatovany) {
showDialog(
context: context,
builder: (bc) => AlertDialog(
title: Text(Languages.of(context)!.error),
content:
Text(Languages.of(context)!.needRemember),
actions: [
TextButton(
child: Text(Languages.of(context)!.ok),
onPressed: () {
Navigator.of(context).pop();
},
)
],
));
} else {
setState(() {
_oznameniObed = value;
if (_oznameniObed) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title:
Text(Languages.of(context)!.warning),
content: Text(
Languages.of(context)!.notifyWarning),
actions: [
TextButton(
child:
Text(Languages.of(context)!.ok),
onPressed: () {
Navigator.of(context).pop();
},
)
],
));
vytvoritOznameni(casNaDate(_oznameniCas));
} }
}, zmenitNastaveni("oznamit", value);
), });
) }
], })
), ],
), ),
SettingsTile.switchTile( Text(Languages.of(context)!.notifyAt),
initialValue: _skipWeekend, TextButton(
onToggle: (value) { onPressed: () async {
_skipWeekend = value; if (_oznameniObed) {
settings.skipWeekend = value; var cas = await showTimePicker(
changeSetting("skip", value); context: context, initialTime: _oznameniCas);
setState(() {}); if (cas != null) {
}, var prefs = await SharedPreferences.getInstance();
title: Text(AppLocalizations.of(context)!.skipWeekend), prefs.setString("oznameni_cas",
), casNaDate(cas).toString()); // aktualizovat vybraný čas
SettingsTile.switchTile( var den = casNaDate(cas);
initialValue: _checkWeek, debugPrint(den.isAfter(DateTime.now()).toString());
onToggle: (value) { if (den.isAfter(DateTime.now())) {
_checkWeek = value; // znovu vytvořit oznámení POUZE když je čas v budoucnosti
settings.checkOrdered = value; vytvoritOznameni(den);
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(() {});
} }
}, setState(() {
title: Text( _oznameniCas = cas ?? _oznameniCas;
AppLocalizations.of(context)!.notifyLunch, });
), }
},
child: Text(
"${(_oznameniCas.hour < 10 ? "0" : "") + _oznameniCas.hour.toString()}:${(_oznameniCas.minute < 10 ? "0" : "") + _oznameniCas.minute.toString()}",
style: TextStyle(
color: (!_oznameniObed) ? Colors.grey : Colors.purple),
), ),
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 { void cistit(bool value) async {
if (!value) { if (!value) {
Directory appDocDir = await getApplicationDocumentsDirectory(); Directory appDocDir = await getApplicationDocumentsDirectory();
for (var f in appDocDir.listSync()) { for (var f in appDocDir.listSync()) {
@ -274,10 +231,11 @@ class _AndroidNastaveniState extends State<AndroidNastaveni> {
} }
} }
void createNotif(DateTime den) async { void vytvoritOznameni(DateTime den) async {
await flutterLocalNotificationsPlugin.cancelAll(); await widget.n.cancelAll();
var d = await LoginManager.getDetails(); // grab details var d = await LoginManager.getDetails(); // získat údaje
if (d != null) { if (d != null) {
// Nové oznámení
var c = Canteen(d["url"]!); var c = Canteen(d["url"]!);
if (await c.login(d["user"]!, d["pass"]!)) { if (await c.login(d["user"]!, d["pass"]!)) {
var jidla = await c.jidelnicekDen(); var jidla = await c.jidelnicekDen();
@ -290,34 +248,23 @@ class _AndroidNastaveniState extends State<AndroidNastaveni> {
importance: Importance.max, importance: Importance.max,
priority: Priority.high, priority: Priority.high,
ticker: 'today meal'); ticker: 'today meal');
const IOSNotificationDetails iOSpec =
IOSNotificationDetails(presentAlert: true, presentBadge: true);
var l = var l =
tz.getLocation(await FlutterNativeTimezone.getLocalTimezone()); 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; if (!mounted) return;
await flutterLocalNotificationsPlugin.zonedSchedule( await widget.n.zonedSchedule(
// schedules a notification // Vytvoří nové oznámení pro daný čas a datum
0, 0,
AppLocalizations.of(context)!.lunchNotif, Languages.of(context)!.lunchNotif,
"${jidlo.varianta} - ${jidlo.nazev}", "${jidlo.varianta} - ${jidlo.nazev}",
tz.TZDateTime.from(den, l), tz.TZDateTime.from(den, l),
const NotificationDetails(android: androidSpec), const NotificationDetails(android: androidSpec, iOS: iOSpec),
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, androidAllowWhileIdle: true,
uiLocalNotificationDateInterpretation: uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime); UILocalNotificationDateInterpretation.absoluteTime);
} on StateError catch (_) { } on StateError catch (_) {
// no meal found // nenalezeno
} }
} }
} }

View file

@ -1,179 +1,139 @@
import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.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:opencanteen/util.dart';
import 'package:package_info_plus/package_info_plus.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:url_launcher/url_launcher.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import '../lang/lang.dart';
import '../main.dart';
class OfflineMealView extends StatefulWidget { class OfflineJidelnicek extends StatefulWidget {
const OfflineMealView({super.key}); const OfflineJidelnicek({Key? key, required this.jidla}) : super(key: key);
final List<OfflineJidlo> jidla;
@override @override
State<OfflineMealView> createState() => _OfflineMealViewState(); State<OfflineJidelnicek> createState() => _OfflineJidelnicekState();
} }
class _OfflineMealViewState extends State<OfflineMealView> { class _OfflineJidelnicekState extends State<OfflineJidelnicek> {
List<Widget> content = [const CircularProgressIndicator()]; // view content List<Widget> obsah = [const CircularProgressIndicator()];
var _skipWeekend = false; // skip weekend setting DateTime den = DateTime.now();
DateTime currentDay = DateTime.now(); // the day we are supposed to show String denTydne = "";
String dayOWeek = ""; // the name of the day (to show to user) Future<void> nactiJidlo() async {
List<List<OfflineMeal>> data = []; // meal data den = widget.jidla[0].den;
var mealIndex = 0; // index of the currently shown day switch (den.weekday) {
/// 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: case 2:
dayOWeek = AppLocalizations.of(context)!.tuesday; denTydne = Languages.of(context)!.tuesday;
break; break;
case 3: case 3:
dayOWeek = AppLocalizations.of(context)!.wednesday; denTydne = Languages.of(context)!.wednesday;
break; break;
case 4: case 4:
dayOWeek = AppLocalizations.of(context)!.thursday; denTydne = Languages.of(context)!.thursday;
break; break;
case 5: case 5:
dayOWeek = AppLocalizations.of(context)!.friday; denTydne = Languages.of(context)!.friday;
break; break;
case 6: case 6:
dayOWeek = AppLocalizations.of(context)!.saturday; denTydne = Languages.of(context)!.saturday;
break; break;
case 7: case 7:
dayOWeek = AppLocalizations.of(context)!.sunday; denTydne = Languages.of(context)!.sunday;
break; break;
default: default:
dayOWeek = AppLocalizations.of(context)!.monday; denTydne = Languages.of(context)!.monday;
} }
content = []; obsah = [];
for (OfflineMeal j in jidelnicek) { for (OfflineJidlo j in widget.jidla) {
content.add( obsah.add(
Padding( Padding(
padding: const EdgeInsets.only(top: 15), padding: const EdgeInsets.only(top: 15),
child: InkWell( child: InkWell(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text(j.variant), Text(j.varianta),
const SizedBox(width: 10), const SizedBox(width: 10),
Flexible( Flexible(
child: Text( child: Text(
j.name, j.nazev,
),
), ),
Text((j.onExchange) ),
? AppLocalizations.of(context)!.inExchange Text((j.naBurze)
: "${j.price}"), ? Languages.of(context)!.inExchange
Checkbox( : "${j.cena}"),
value: j.ordered, Checkbox(
value: j.objednano,
fillColor: MaterialStateProperty.all(Colors.grey), fillColor: MaterialStateProperty.all(Colors.grey),
onChanged: (v) async { onChanged: (v) async {
return; return;
}, })
) ],
], )),
),
),
), ),
); );
} }
setState(() {}); setState(() {});
} }
void click(String value, BuildContext context) async { void kliknuti(String value, BuildContext context) async {
if (value == AppLocalizations.of(context)!.signOut) { if (value == Languages.of(context)!.signOut) {
const storage = FlutterSecureStorage(); const storage = FlutterSecureStorage();
storage.deleteAll(); storage.deleteAll();
Navigator.pushReplacement( Navigator.pushReplacement(
context, platformRouter((c) => const LoginPage())); context, MaterialPageRoute(builder: (c) => const LoginPage()));
} else if (value == AppLocalizations.of(context)!.review) { } else if (value == Languages.of(context)!.review) {
launchUrl( (Platform.isAndroid)
Uri.parse((Platform.isAndroid) ? launchUrl(
? "market://details?id=cz.hernikplays.opencanteen" Uri.parse("market://details?id=cz.hernikplays.opencanteen"),
: "https://apps.apple.com/cz/app/opencanteen/id1621124445"), mode: LaunchMode.externalApplication)
mode: LaunchMode.externalApplication); : launchUrl(
} else if (value == AppLocalizations.of(context)!.reportBugs) { Uri.parse(
"https://apps.apple.com/cz/app/opencanteen/id1621124445"),
mode: LaunchMode.externalApplication);
} else if (value == Languages.of(context)!.reportBugs) {
launchUrl(Uri.parse("https://forms.gle/jKN7QeFJwpaApSbC8"), launchUrl(Uri.parse("https://forms.gle/jKN7QeFJwpaApSbC8"),
mode: LaunchMode.externalApplication); mode: LaunchMode.externalApplication);
} else if (value == AppLocalizations.of(context)!.about) { } else if (value == Languages.of(context)!.about) {
var packageInfo = await PackageInfo.fromPlatform(); var packageInfo = await PackageInfo.fromPlatform();
if (!mounted) return; if (!mounted) return;
showAboutDialog( showAboutDialog(
context: context, context: context,
applicationName: "OpenCanteen", applicationName: "OpenCanteen",
applicationLegalese: applicationLegalese:
"${AppLocalizations.of(context)!.copyright}\n${AppLocalizations.of(context)!.license}", "${Languages.of(context)!.copyright}\n${Languages.of(context)!.license}",
applicationVersion: packageInfo.version, applicationVersion: packageInfo.version,
children: [ children: [
PlatformButton( TextButton(
onPressed: (() => launchUrl( onPressed: (() => launchUrl(
Uri.parse("https://git.mnau.xyz/hernik/opencanteen"))), Uri.parse("https://github.com/hernikplays/opencanteen"))),
text: AppLocalizations.of(context)!.source, child: Text(Languages.of(context)!.source))
) ]);
],
);
} }
} }
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
loadSettings(); nactiJidlo();
}
void loadSettings() async {
var prefs = await SharedPreferences.getInstance();
_skipWeekend = prefs.getBool("skip") ?? false;
if (!mounted) return;
loadFromFile();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(AppLocalizations.of(context)!.menu), title: Text(Languages.of(context)!.menu),
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
actions: [ actions: [
PopupMenuButton( PopupMenuButton(
onSelected: ((String value) => click(value, context)), onSelected: ((String value) => kliknuti(value, context)),
itemBuilder: (BuildContext context) { itemBuilder: (BuildContext context) {
return { return {
AppLocalizations.of(context)!.reportBugs, Languages.of(context)!.reportBugs,
AppLocalizations.of(context)!.review, Languages.of(context)!.review,
AppLocalizations.of(context)!.about, Languages.of(context)!.about,
AppLocalizations.of(context)!.signOut Languages.of(context)!.signOut
}.map((String choice) { }.map((String choice) {
return PopupMenuItem<String>( return PopupMenuItem<String>(
value: choice, value: choice,
@ -192,78 +152,28 @@ class _OfflineMealViewState extends State<OfflineMealView> {
children: [ children: [
const SizedBox(height: 10), const SizedBox(height: 10),
Text( Text(
AppLocalizations.of(context)!.offline, Languages.of(context)!.offline,
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
), ),
Text(AppLocalizations.of(context)!.mustLogout), Text(Languages.of(context)!.mustLogout),
const SizedBox(height: 10), const SizedBox(height: 10),
Row(mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton(
IconButton( child:
onPressed: () { Text("${den.day}. ${den.month}. ${den.year} - $denTydne"),
if (data.length <= 1) return; onPressed: () => {},
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( SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
child: Column( child: Column(
children: content, children: obsah,
), ),
), ),
], ],
), ),
), ),
), ),
onRefresh: () => Navigator.pushReplacement( onRefresh: () => Navigator.pushReplacement(context,
context, platformRouter((context) => const LoginPage())), MaterialPageRoute(builder: ((context) => const LoginPage()))),
), ),
); );
} }

View file

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

View file

@ -1,27 +0,0 @@
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

@ -1,30 +0,0 @@
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,
);
}

View file

@ -1,54 +0,0 @@
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

@ -1,28 +0,0 @@
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

@ -1,22 +0,0 @@
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,14 +1,13 @@
import 'dart:io';
import 'package:canteenlib/canteenlib.dart'; import 'package:canteenlib/canteenlib.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:opencanteen/okna/burza.dart'; import 'package:opencanteen/okna/burza.dart';
import 'package:opencanteen/okna/jidelnicek.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
Drawer drawerGenerator(BuildContext context, Canteen canteen, int p) { import 'lang/lang.dart';
import 'okna/jidelnicek.dart';
Drawer drawerGenerator(BuildContext context, Canteen canteen, int p,
FlutterLocalNotificationsPlugin n) {
Drawer drawer = const Drawer(); Drawer drawer = const Drawer();
switch (p) { switch (p) {
case 1: case 1:
@ -17,20 +16,22 @@ Drawer drawerGenerator(BuildContext context, Canteen canteen, int p) {
child: ListView( child: ListView(
children: [ children: [
DrawerHeader( DrawerHeader(
child: Text(AppLocalizations.of(context)!.appName), child: Text(Languages.of(context)!.appName),
), ),
ListTile( ListTile(
selected: true, selected: true,
title: Text(AppLocalizations.of(context)!.home), title: Text(Languages.of(context)!.home),
leading: const Icon(Icons.home), leading: const Icon(Icons.home),
onTap: () => Navigator.pop(context), onTap: () => Navigator.pop(context),
), ),
ListTile( ListTile(
leading: const Icon(Icons.store), leading: const Icon(Icons.store),
title: Text(AppLocalizations.of(context)!.exchange), title: Text(Languages.of(context)!.exchange),
onTap: () => Navigator.push( onTap: () => Navigator.push(
context, context,
platformRouter((context) => BurzaView(canteen: canteen)), MaterialPageRoute(
builder: (context) => BurzaPage(canteen: canteen, n: n),
),
), ),
), ),
], ],
@ -43,20 +44,20 @@ Drawer drawerGenerator(BuildContext context, Canteen canteen, int p) {
child: ListView( child: ListView(
children: [ children: [
DrawerHeader( DrawerHeader(
child: Text(AppLocalizations.of(context)!.appName), child: Text(Languages.of(context)!.appName),
), ),
ListTile( ListTile(
leading: const Icon(Icons.home), leading: const Icon(Icons.home),
title: Text(AppLocalizations.of(context)!.home), title: Text(Languages.of(context)!.home),
onTap: () => Navigator.push( onTap: () => Navigator.push(
context, context,
platformRouter((c) => MealView(canteen: canteen)), MaterialPageRoute(
), builder: (c) => JidelnicekPage(canteen: canteen, n: n))),
), ),
ListTile( ListTile(
leading: const Icon(Icons.store), leading: const Icon(Icons.store),
selected: true, selected: true,
title: Text(AppLocalizations.of(context)!.exchange), title: Text(Languages.of(context)!.exchange),
onTap: () => Navigator.pop(context), onTap: () => Navigator.pop(context),
), ),
], ],
@ -66,67 +67,31 @@ Drawer drawerGenerator(BuildContext context, Canteen canteen, int p) {
return drawer; return drawer;
} }
class OfflineMeal { class OfflineJidlo {
String name; String nazev;
String variant; String varianta;
bool ordered; bool objednano;
double price; double cena;
bool onExchange; bool naBurze;
DateTime day; DateTime den;
OfflineMeal( OfflineJidlo(
{required this.name, {required this.nazev,
required this.variant, required this.varianta,
required this.ordered, required this.objednano,
required this.price, required this.cena,
required this.onExchange, required this.naBurze,
required this.day}); required this.den});
} }
/// Parses [DateTime] from [TimeOfDay] /// Vytvoří [DateTime] z [TimeOfDay]
DateTime timeToDate(TimeOfDay c) { DateTime casNaDate(TimeOfDay c) {
var now = DateTime.now(); var now = DateTime.now();
return DateTime.parse( 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"); "${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 = [ List<Map<String, String>> instance = [
{"name": "SŠTE Brno, Olomoucká", "url": "https://stravovani.sstebrno.cz"}, {"name": "SŠTE Brno, Olomoucká", "url": "https://stravovani.sstebrno.cz"},
{"name": "Jiné", "url": ""} {"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

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

View file

@ -1,3 +0,0 @@
- 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

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

View file

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

View file

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

View file

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

View file

@ -1,9 +0,0 @@
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.

Before

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

View file

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

View file

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

View file

@ -1,3 +0,0 @@
- 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

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

View file

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

View file

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

View file

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

View file

@ -1,9 +0,0 @@
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.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

View file

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

View file

@ -1 +0,0 @@
OpenCanteen

12
package.json Normal file
View file

@ -0,0 +1,12 @@
{
"devDependencies": {
"@commitlint/cli": "^17.0.0",
"@commitlint/config-conventional": "^17.0.0",
"cz-conventional-changelog": "^3.3.0"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}
}

1744
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load diff

View file

@ -5,223 +5,126 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: archive name: archive
sha256: "7b875fd4a20b165a3084bd2d210439b22ebc653f21cea4842729c0c30c82596b" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.9" version: "3.3.1"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.2" version: "2.3.1"
async: async:
dependency: transitive dependency: transitive
description: description:
name: async name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.11.0" version: "2.9.0"
canteenlib: canteenlib:
dependency: "direct main" dependency: "direct main"
description: description:
name: canteenlib name: canteenlib
sha256: "7051fd7ad1b2e4e5471b7f55dd092a6586972aad2c0c8f31edf7f0ee5a7e4ee9" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.6" version: "1.0.1"
characters: characters:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.2.1"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://pub.dev"
source: hosted
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: clock:
dependency: transitive dependency: transitive
description: description:
name: clock name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.1.1"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.18.0" version: "1.16.0"
convert:
dependency: transitive
description:
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.3" version: "3.0.2"
csslib:
dependency: transitive
description:
name: csslib
sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
dbus: dbus:
dependency: transitive dependency: transitive
description: description:
name: dbus name: dbus
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.10" version: "0.7.8"
dots_indicator: dots_indicator:
dependency: transitive dependency: transitive
description: description:
name: dots_indicator name: dots_indicator
sha256: f1599baa429936ba87f06ae5f2adc920a367b16d08f74db58c3d0f6e93bcdb5c url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.0"
ffi: ffi:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.0.1"
file: file:
dependency: transitive dependency: transitive
description: description:
name: file name: file
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "6.1.4"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" 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: flutter_launcher_icons:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_launcher_icons name: flutter_launcher_icons
sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.1" version: "0.9.3"
flutter_lints: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_lints name: flutter_lints
sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.1" version: "2.0.1"
flutter_local_notifications: flutter_local_notifications:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_local_notifications name: flutter_local_notifications
sha256: bb5cd63ff7c91d6efe452e41d0d0ae6348925c82eafd10ce170ef585ea04776e url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "16.2.0" version: "9.5.3+1"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
name: flutter_local_notifications_linux name: flutter_local_notifications_linux
sha256: "33f741ef47b5f63cc7f78fe75eeeac7e19f171ff3c3df054d84c1e38bedb6a03" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0+1" version: "0.4.2"
flutter_local_notifications_platform_interface: flutter_local_notifications_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: flutter_local_notifications_platform_interface name: flutter_local_notifications_platform_interface
sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0+1" version: "5.0.0"
flutter_localizations: flutter_localizations:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -231,327 +134,301 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_native_timezone name: flutter_native_timezone
sha256: ed7bfb982f036243de1c068e269182a877100c994f05143c8b26a325e28c1b02 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
flutter_secure_storage: flutter_secure_storage:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_secure_storage name: flutter_secure_storage
sha256: ffdbb60130e4665d2af814a0267c481bcf522c41ae2e43caf69fa0146876d685 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "9.0.0" version: "5.0.2"
flutter_secure_storage_linux: flutter_secure_storage_linux:
dependency: transitive dependency: transitive
description: description:
name: flutter_secure_storage_linux name: flutter_secure_storage_linux
sha256: "3d5032e314774ee0e1a7d0a9f5e2793486f0dff2dd9ef5a23f4e3fb2a0ae6a9e" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.1.1"
flutter_secure_storage_macos: flutter_secure_storage_macos:
dependency: transitive dependency: transitive
description: description:
name: flutter_secure_storage_macos name: flutter_secure_storage_macos
sha256: bd33935b4b628abd0b86c8ca20655c5b36275c3a3f5194769a7b3f37c905369c url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.1" version: "1.1.1"
flutter_secure_storage_platform_interface: flutter_secure_storage_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: flutter_secure_storage_platform_interface name: flutter_secure_storage_platform_interface
sha256: "0d4d3a5dd4db28c96ae414d7ba3b8422fd735a8255642774803b2532c9a61d7e" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.0"
flutter_secure_storage_web: flutter_secure_storage_web:
dependency: transitive dependency: transitive
description: description:
name: flutter_secure_storage_web name: flutter_secure_storage_web
sha256: "30f84f102df9dcdaa2241866a958c2ec976902ebdaa8883fbfe525f1f2f3cf20" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.2" version: "1.0.2"
flutter_secure_storage_windows: flutter_secure_storage_windows:
dependency: transitive dependency: transitive
description: description:
name: flutter_secure_storage_windows name: flutter_secure_storage_windows
sha256: "5809c66f9dd3b4b93b0a6e2e8561539405322ee767ac2f64d084e2ab5429d108" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "1.1.2"
flutter_web_plugins: flutter_web_plugins:
dependency: transitive dependency: transitive
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" 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: http:
dependency: transitive dependency: transitive
description: description:
name: http name: http
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.2" version: "0.13.5"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
name: http_parser name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.2" version: "4.0.1"
image: image:
dependency: transitive dependency: transitive
description: description:
name: image name: image
sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "4.1.3" version: "3.2.0"
intl: intl:
dependency: "direct main" dependency: "direct main"
description: description:
name: intl name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.1" version: "0.17.0"
introduction_screen: introduction_screen:
dependency: "direct main" dependency: "direct main"
description: description:
name: introduction_screen name: introduction_screen
sha256: "72d25ceb71471773783f72783608e17585af93d4bc6474df577fcfe9e7842852" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.12" version: "3.0.2"
js: js:
dependency: transitive dependency: transitive
description: description:
name: js name: js
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.6.7" version: "0.6.4"
json_annotation:
dependency: transitive
description:
name: json_annotation
sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
url: "https://pub.dev"
source: hosted
version: "4.8.1"
lints: lints:
dependency: transitive dependency: transitive
description: description:
name: lints name: lints
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "2.0.0"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.0" version: "0.1.5"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.8.0"
package_info_plus: package_info_plus:
dependency: "direct main" dependency: "direct main"
description: description:
name: package_info_plus name: package_info_plus
sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.1" version: "1.4.3+1"
package_info_plus_linux:
dependency: transitive
description:
name: package_info_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
package_info_plus_macos:
dependency: transitive
description:
name: package_info_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
package_info_plus_platform_interface: package_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: package_info_plus_platform_interface name: package_info_plus_platform_interface
sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "1.0.2"
package_info_plus_web:
dependency: transitive
description:
name: package_info_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.5"
package_info_plus_windows:
dependency: transitive
description:
name: package_info_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
path: path:
dependency: transitive dependency: transitive
description: description:
name: path name: path
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.3" version: "1.8.2"
path_provider: path_provider:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider name: path_provider
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.0.11"
path_provider_android: path_provider_android:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.0.20"
path_provider_foundation: path_provider_ios:
dependency: transitive dependency: transitive
description: description:
name: path_provider_foundation name: path_provider_ios
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.0.11"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
name: path_provider_linux name: path_provider_linux
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.1.7"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.6"
path_provider_platform_interface: path_provider_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: path_provider_platform_interface name: path_provider_platform_interface
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.0.4"
path_provider_windows: path_provider_windows:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.1.3"
petitparser: petitparser:
dependency: transitive dependency: transitive
description: description:
name: petitparser name: petitparser
sha256: eeb2d1428ee7f4170e2bd498827296a18d4e7fc462b71727d111c0ac7707cfa6 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.1" version: "5.0.0"
platform: platform:
dependency: transitive dependency: transitive
description: description:
name: platform name: platform
sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.3" version: "3.1.0"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: plugin_platform_interface name: plugin_platform_interface
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.7" version: "2.1.2"
pointycastle: process:
dependency: transitive dependency: transitive
description: description:
name: pointycastle name: process
sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.7.3" version: "4.2.4"
settings_ui:
dependency: "direct main"
description:
name: settings_ui
sha256: d9838037cb554b24b4218b2d07666fbada3478882edefae375ee892b6c820ef3
url: "https://pub.dev"
source: hosted
version: "2.0.2"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
name: shared_preferences name: shared_preferences
sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.0.15"
shared_preferences_android: shared_preferences_android:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.0.12"
shared_preferences_foundation: shared_preferences_ios:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_foundation name: shared_preferences_ios
sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.4" version: "2.1.1"
shared_preferences_linux: shared_preferences_linux:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_linux name: shared_preferences_linux
sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.1.1"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
shared_preferences_platform_interface: shared_preferences_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_platform_interface name: shared_preferences_platform_interface
sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.1" version: "2.1.0"
shared_preferences_web: shared_preferences_web:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_web name: shared_preferences_web
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.0.4"
shared_preferences_windows: shared_preferences_windows:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_windows name: shared_preferences_windows
sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.1.1"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -561,154 +438,135 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.9.1"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.1.1"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.1" version: "1.2.1"
timezone: timezone:
dependency: "direct main" dependency: "direct main"
description: description:
name: timezone name: timezone
sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.2" version: "0.8.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.2" version: "1.3.1"
url_launcher: url_launcher:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: b1c9e98774adf8820c96fbc7ae3601231d324a7d5ebd8babe27b6dfac91357ba url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.1" version: "6.1.5"
url_launcher_android: url_launcher_android:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_android name: url_launcher_android
sha256: "31222ffb0063171b526d3e569079cf1f8b294075ba323443fdc690842bfd4def" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.0" version: "6.0.17"
url_launcher_ios: url_launcher_ios:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_ios name: url_launcher_ios
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "6.2.1" version: "6.0.17"
url_launcher_linux: url_launcher_linux:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_linux name: url_launcher_linux
sha256: "9f2d390e096fdbe1e6e6256f97851e51afc2d9c423d3432f1d6a02a8a9a8b9fd" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.0" version: "3.0.1"
url_launcher_macos: url_launcher_macos:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_macos name: url_launcher_macos
sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.0" version: "3.0.1"
url_launcher_platform_interface: url_launcher_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_platform_interface name: url_launcher_platform_interface
sha256: "980e8d9af422f477be6948bdfb68df8433be71f5743a188968b0c1b887807e50" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.1.0"
url_launcher_web: url_launcher_web:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "138bd45b3a456dcfafc46d1a146787424f8d2edfbf2809c9324361e58f851cf7" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.1" version: "2.0.13"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_windows name: url_launcher_windows
sha256: "7754a1ad30ee896b265f8d14078b0513a4dba28d358eabb9d5f339886f4a1adc" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.0" version: "3.0.1"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.2"
web:
dependency: transitive
description:
name: web
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
url: "https://pub.dev"
source: hosted
version: "0.3.0"
win32: win32:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: "7c99c0e1e2fa190b48d25c81ca5e42036d5cac81430ef249027d97b0935c553f" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.0" version: "3.0.0"
workmanager:
dependency: "direct main"
description:
name: workmanager
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.1"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
name: xdg_directories name: xdg_directories
sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.3" version: "0.2.0+2"
xml: xml:
dependency: transitive dependency: transitive
description: description:
name: xml name: xml
sha256: af5e77e9b83f2f4adc5d3f0a4ece1c7f45a2467b695c2540381bac793e34e556 url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "6.4.2" version: "6.1.0"
yaml: yaml:
dependency: transitive dependency: transitive
description: description:
name: yaml name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" url: "https://pub.dartlang.org"
url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.2" version: "3.1.1"
sdks: sdks:
dart: ">=3.2.0 <4.0.0" dart: ">=2.18.0 <3.0.0"
flutter: ">=3.16.0" flutter: ">=3.0.0"

View file

@ -6,50 +6,48 @@ publish_to: 'none'
# The following defines the version and build number for your application. # The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43 # A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +. # followed by an optional build number separated by a +.
version: 1.10.0+32 version: 1.5.0+21
environment: environment:
sdk: ">=2.18.2 <3.0.0" sdk: ">=2.16.1 <3.0.0"
dependencies: dependencies:
canteenlib: ^3.0.0
flutter: flutter:
sdk: flutter sdk: flutter
flutter_local_notifications: ^16.0.0 flutter_localizations:
flutter_localizations:
sdk: flutter sdk: flutter
flutter_native_timezone: ^2.0.0 canteenlib: ^1.0.1
flutter_secure_storage: ^9.0.0 flutter_secure_storage: 5.0.2
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 url_launcher: ^6.0.20
path_provider: ^2.0.9
shared_preferences: ^2.0.13
introduction_screen: ^3.0.1
flutter_local_notifications: 9.5.3+1
timezone: ^0.8.0
flutter_native_timezone: ^2.0.0
intl: ^0.17.0
package_info_plus: ^1.4.3+1
workmanager: ^0.5.1
dev_dependencies: dev_dependencies:
flutter_launcher_icons: ^0.13.0 flutter_lints: ^2.0.1
flutter_lints: ^3.0.0 flutter_launcher_icons: "^0.9.2"
flutter_icons: flutter_icons:
android: true android: "launcher_icon"
ios: true ios: true
image_path: "assets/icon.jpg" image_path: "assets/icon.jpg"
adaptive_icon_background: "#4f4685"
adaptive_icon_foreground: "assets/fore.png"
flutter: flutter:
uses-material-design: true uses-material-design: true
generate: true
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
assets: assets:
- assets/ - assets/
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware. # https://flutter.dev/assets-and-images/#resolution-aware.
# To add custom fonts to your application, add a fonts section here, # To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a # 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 # "family" key with the font family name, and a "fonts" key with a

View file

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