Compare commits

..

180 Commits
5.0.0 ... 5.0.4

Author SHA1 Message Date
Márton Kiss
d642f19834 Merge pull request #130 from refilc/dev
dev to master
2024-08-22 22:08:37 +02:00
Kima
51b25395c1 version change 2024-08-22 22:08:11 +02:00
Kima
4474562538 login fix 2024-08-22 22:04:05 +02:00
zypherift
d93dce7857 maybe fix 2024-08-22 21:57:42 +02:00
zypherift
d6fe2812c7 fine tune anim speed 2024-08-22 21:27:22 +02:00
zypherift
ed0f69d155 add animation to fade in (pain) 2024-08-22 21:23:20 +02:00
zypherift
c4a17633f8 fix that, and add new progress indicator 2024-08-22 20:58:12 +02:00
zypherift
d426d4866a fix this 2024-08-22 20:57:56 +02:00
zypherift
89adf5a26f change trans from E-kreta to e-KRETA 2024-08-22 20:47:07 +02:00
zypherift
117ee63b18 Merge branch 'dev' of github.com:refilc/naplo into dev 2024-08-22 20:45:16 +02:00
zypherift
d27b5f8a51 re-revert new login 2024-08-22 20:45:14 +02:00
Kima
9671c250b9 Revert "change kretenlogin to widget"
This reverts commit 2d5c270641.
2024-08-21 23:33:15 +02:00
zypherift
2d5c270641 change kretenlogin to widget 2024-08-21 23:22:27 +02:00
zypherift
eda093a9b5 change trans 2024-08-21 21:54:49 +02:00
Kima
544e9c214a some modifications in login refresh 2024-08-18 13:27:52 +02:00
Kima
5c3dbcbd52 fixed privacy button and back button on new login screen 2024-08-18 13:00:40 +02:00
Kima
cd5f86db00 Merge branch 'dev' of github.com:refilc/naplo into dev 2024-08-17 23:34:43 +02:00
Kima
9adfe636d6 maybe finally fixed ios login problem (i hope so) 2024-08-17 23:34:39 +02:00
zypherift
210e8ce0d4 change gradient start 2024-08-16 18:14:14 +02:00
zypherift
b1a7deca4a change height again, and make text proportional 2024-08-16 17:49:44 +02:00
zypherift
fa96770c9c fix padding :3 2024-08-16 17:46:14 +02:00
zypherift
5be67693c2 recolor navbar, and change padding on login btn part 2024-08-16 17:38:26 +02:00
zypherift
9ee5e8a35e image again 2024-08-16 16:58:53 +02:00
zypherift
3372c1ffde Merge branch 'dev' of github.com:refilc/naplo into dev 2024-08-16 16:42:13 +02:00
zypherift
94989687fa add higher kualiti images 2024-08-16 16:40:03 +02:00
Kima
52b9b4f5db maybe fixed ios login 2024-08-16 14:40:48 +02:00
Kima
75a2fa3726 changed location of privacy button 2024-08-16 11:48:41 +02:00
Márton Kiss
2c1bde9398 Merge pull request #128 from refilc/dev
dev to master
2024-08-16 01:06:26 +02:00
Kima
fd9794f3bf changed build number 2024-08-16 00:49:00 +02:00
Kima
a673d3f1b3 finally the new login is completely working with refresh token as well 2024-08-16 00:25:46 +02:00
Kima
f2c8e869b5 moved news 2024-08-14 23:42:26 +02:00
Kima
b4f2d38e99 changed launch mode to in-app 2024-08-14 23:28:57 +02:00
Kima
d842b2d588 sticker map shit 2024-08-14 23:27:30 +02:00
zypherift
f4fd9a3c2f forgot this icon 2024-08-14 23:20:25 +02:00
zypherift
a215bd7313 create trans(lation), and finish url opening 2024-08-14 23:17:30 +02:00
zypherift
3211279a53 added trans, changed icon 2024-08-14 23:05:22 +02:00
zypherift
2d4e281682 rename classes, and create new file for other 2024-08-14 23:01:15 +02:00
zypherift
148f945f3b replace images with new ones 2024-08-14 21:11:12 +02:00
Kima
aaa783ac45 updated build number 2024-08-14 13:22:51 +02:00
Kima
d70f92d4e5 changed login button 2024-08-14 12:32:32 +02:00
Kima
0f08400d63 shit 2024-08-14 11:32:38 +02:00
Kima
140a8f8e78 revert shit in rfplus 2024-08-14 11:30:59 +02:00
zypherift
17c9d1c447 what 2024-08-14 02:54:03 +02:00
zypherift
d8e23d8fa9 asd 2024-08-14 02:44:29 +02:00
zypherift
c4491eb0c6 merged new login screen with web login 2024-08-14 02:44:05 +02:00
zypherift
4945468e02 yes 2024-08-14 02:09:14 +02:00
Kima
9845ae9539 changed version number 2024-08-14 00:55:24 +02:00
Kima
3a2fc67cb2 new login system complete, that's it for today :3 2024-08-14 00:53:12 +02:00
Kima
148a43663c made kreten web login work hah 2024-08-13 01:08:05 +02:00
Márton Kiss
4a45131359 Merge pull request #126 from refilc/dev
dev to master (v5.0.3)
2024-06-21 22:54:49 +02:00
Kima
4128018a59 blah blah blah 2024-06-21 22:39:53 +02:00
Kima
0d509c90b1 finished everything shake 2024-06-21 22:30:17 +02:00
Kima
3ef58974c9 added shake to current error report screen as well 2024-06-21 21:47:15 +02:00
Kima
df75fadfea added shake 2024-06-21 21:16:24 +02:00
Kima
4254a7998a build number change 2024-06-20 14:17:31 +02:00
Kima
17faa545e5 changed some repos to custom forks because android sucks 2024-06-20 14:09:26 +02:00
Kima
506fb82dd0 changed lots of thing bc pub upgrade 2024-06-20 13:53:10 +02:00
Kima
bc8eb1910e upgraded pub things 2024-06-20 12:06:50 +02:00
Kima
fd1b15df77 just don't touch fl_chart 2024-06-19 23:34:45 +02:00
Kima
dd86c7436a fix in package versioning 2024-06-19 23:24:37 +02:00
Kima
8860a0269c fixed warnings after update 2024-06-19 22:34:56 +02:00
Kima
ce02dda46c updated flutter and pub packages 2024-06-19 22:23:16 +02:00
Kima
f16a52d0fb changed required sdk version and app version 2024-06-19 22:17:12 +02:00
Kima
cc8ce40222 fixed warnings 2024-06-19 22:10:28 +02:00
Kima
b6a933fe85 removed total average calculatro from refilcplus and added grade export viewing 2024-06-19 22:09:00 +02:00
Kima
767eba3776 well idgaf anymore, it should be good like this (subject average thing) 2024-06-19 22:02:12 +02:00
Kima
320499a466 prevent double taps on new weird exam popup 2024-06-19 21:35:49 +02:00
Kima
52c2f3090d fixed grade provider translation issues 2024-06-19 21:28:04 +02:00
Kima
d4df0170a3 fixed final grades ugly ui 2024-06-19 21:23:19 +02:00
Kima
796b35e27c made lesson countdown rotatable 2024-06-19 21:15:47 +02:00
Kima
051cdc895e fixed issues 2024-06-19 20:28:47 +02:00
Kima
e23bdac995 fixed sort issue 2024-06-19 16:43:56 +02:00
Kima
de0e8e1317 fixed good student mode percentage bug 2024-06-18 21:26:43 +02:00
Kima
b5b0046ef5 things™️ 2024-06-18 14:44:53 +02:00
Kima
92f16e054d finished new badge thingie 2024-06-17 22:47:30 +02:00
Kima
9470c848bf added new feature badge and unseen new feature list to settings 2024-06-17 22:19:43 +02:00
Kima
c40026e594 removed no import warning from grade exporting 2024-06-17 17:58:18 +02:00
Márton Kiss
93eaa5a74b Merge pull request #125 from refilc/dev
dev to master (v5.0.2 final)
2024-06-16 22:02:12 +02:00
Kima
5503b41be3 fix 2024-06-16 21:54:59 +02:00
Kima
bd716e1717 fixed shit 2024-06-16 21:48:32 +02:00
Márton Kiss
7f8b716712 Merge pull request #124 from refilc/master
master back to dev
2024-06-16 21:43:53 +02:00
Márton Kiss
1a7b59f2fc Merge pull request #123 from refilc/dev
dev to master (v5.0.2)
2024-06-16 21:43:07 +02:00
Kima
9f62e44b52 Revert "add wearos button"
This reverts commit 9d863e1ec0.
2024-06-16 21:42:37 +02:00
Kima
7c34552aa5 Revert "what"
This reverts commit 9b947256c8.
2024-06-16 21:40:35 +02:00
Kima
57d784443a changed version number 2024-06-16 21:36:22 +02:00
Kima
e73ee5a1f2 translation for grade importing 2024-06-16 21:36:00 +02:00
Kima
4277f0662a added back premium check 2024-06-16 21:33:33 +02:00
Kima
604e9dcaad Merge branch 'dev' of github.com:refilc/naplo into dev 2024-06-16 21:32:33 +02:00
Kima
c0dd84c665 finished grade importing and exporting totally 2024-06-16 21:32:27 +02:00
zypherift
7dc33d3b87 Merge branch 'dev' of github.com:refilc/naplo into dev 2024-06-16 20:09:12 +02:00
zypherift
9bee0daeb5 kill me 2024-06-16 20:08:59 +02:00
Kima
dd8a4430a9 translation fixes 2024-06-16 20:01:22 +02:00
zypherift
47934620ea fix again 2024-06-14 15:16:03 +02:00
zypherift
9e815aff2f maybe fix token spam 2024-06-14 15:05:17 +02:00
zypherift
d8393b24e1 fix multiple schools appearing in personal details menu 2024-06-14 15:02:10 +02:00
zypherift
1abe990847 yes 2024-06-14 14:55:35 +02:00
zypherift
3a92716019 add ger/eng export translation 2024-06-14 14:54:34 +02:00
zypherift
9b947256c8 what 2024-06-14 14:09:34 +02:00
zypherift
0586da3742 Merge branch 'master' of github.com:refilc/naplo 2024-06-14 14:09:28 +02:00
zypherift
9d863e1ec0 add wearos button 2024-06-14 14:08:13 +02:00
zypherift
e080800aa8 Merge pull request #121 from balint1414/dev
Hiba ablak szövegének megváltoztatása.
2024-06-14 11:35:08 +02:00
balint1414
e6f7728e42 Hiba ablak szövegének megváltoztatása. (3) 2024-06-14 11:27:29 +02:00
balint1414
ac11da1744 Hiba ablak szövegének megváltoztatása. (2) 2024-06-14 10:58:26 +02:00
balint1414
cad7bd19dc Hiba ablak szövegének megváltoztatása. (2) 2024-06-14 10:56:15 +02:00
balint1414
e1870b08e5 Hiba ablak szövegének megváltoztatása. 2024-06-14 10:44:10 +02:00
Márton Kiss
7842aa447f Merge pull request #120 from refilc/dev
dev to master (beta v5.0.1)
2024-06-13 21:30:32 +02:00
Kima
a23b2d63e5 changed version number 2024-06-13 21:29:39 +02:00
Tihanyi Marcell
58faeb4fa2 Update Logo 2024-06-12 10:15:30 +02:00
Kima
48e64d7761 changed build number 2024-06-11 22:03:48 +02:00
Kima
aef8f78d16 fixed translations and added grade export to plus feature list 2024-06-11 22:02:12 +02:00
Kima
2b36528327 added grade exporting translation 2024-06-11 21:57:52 +02:00
Kima
918252ae4b finished grade exporting 2024-06-11 21:46:09 +02:00
Kima
63c650b68d fixed lesson number issue when it's null 2024-06-11 20:29:22 +02:00
Kima
090b0ccc85 fixed grades page translation 2024-06-11 20:22:53 +02:00
Kima
0768dc9404 fixed goal plan translation issues 2024-06-11 20:19:33 +02:00
Kima
d36351d76b updated version 2024-06-10 18:13:53 +02:00
Kima
45a8e0dd71 kinda finished new goal planner 2024-06-08 21:42:51 +02:00
Kima
94da2a9756 progress in new goal planner 2024-06-03 20:15:48 +02:00
Kima
37aa1858a8 added watch data to db 2024-06-03 17:06:11 +02:00
Kima
82f8a489dd updated version string 2024-06-02 12:23:33 +02:00
Kima
96b69b89ae started new login method in case kreten fucks up something 2024-05-29 19:58:43 +02:00
Kima
d9da7625ed added day to lesson tiles in subject page 2024-05-24 15:54:57 +02:00
Kima
c016258fb9 progress in new goal planner 2024-05-22 22:25:40 +02:00
Kima
855e48aea8 Merge branch 'dev' of github.com:refilc/naplo into dev 2024-05-22 18:09:46 +02:00
Kima
b7e83d10dc toggle to change new popups and fix in plus 2024-05-22 18:09:40 +02:00
Kima
45ffdff324 added option to use old popups and some fixes 2024-05-22 17:47:57 +02:00
Kima
cd0729fa5e bugfix on notes page 2024-05-22 17:22:02 +02:00
Kima
30cfdfe784 live activity color reset for non-subscribers 2024-05-22 17:21:52 +02:00
zypherift
16f2593d22 todo, and fix cd path 2024-05-21 23:24:45 +02:00
zypherift
14ab0c4ce3 remove duplicate path 2024-05-21 23:19:52 +02:00
zypherift
9eb1317143 fix typo 2024-05-21 23:17:37 +02:00
zypherift
910a38650d add env 2024-05-21 23:15:11 +02:00
zypherift
a1f166980d fix path again:) 2024-05-21 22:44:30 +02:00
zypherift
0598b94ab9 fix cp path 2024-05-21 22:42:00 +02:00
zypherift
1310ad4f2e jenkins test 2024-05-21 22:36:28 +02:00
Kima
4d32500d90 åh, versionsnumret 2024-05-21 20:35:30 +02:00
Kima
67558b76a3 fixed notification null check issues 2024-05-21 20:29:08 +02:00
Kima
7ab8914076 changed svg path 2024-05-21 20:25:12 +02:00
Kima
b0eb819afa added all new booklet backgrounds 2024-05-21 20:25:02 +02:00
Kima
416f42f42d fixed little issues with lesson popups 2024-05-21 19:46:47 +02:00
Kima
a319b26d82 theme sharing improvements 2024-05-15 21:32:20 +02:00
Kima
84537fdcef added handling for 404 grade colors 2024-05-15 20:42:00 +02:00
Kima
30f24d5d33 custom font improvements 2024-05-15 20:21:07 +02:00
Kima
8c118eedc1 finished 5s streak thing 2024-05-15 19:31:48 +02:00
Kima
4dbe3d07a3 all sliders visible where it's needed 2024-05-14 22:26:40 +02:00
Kima
f1b1b23234 version bump 2024-05-13 23:19:33 +02:00
Kima
540e4d2812 started grade streak 2024-05-13 22:35:20 +02:00
Kima
93dd275969 Merge branch 'dev' of github.com:refilc/naplo into dev 2024-05-13 20:06:32 +02:00
zypherift
c79c45705d Merge pull request #118 from geryyhu/dev
liveactivities bug fix
2024-05-13 19:52:37 +02:00
Kima
ce31182a5c crop fix 2024-05-13 19:50:53 +02:00
Kima
174046f954 Merge branch 'dev' of github.com:refilc/naplo into dev 2024-05-13 19:23:59 +02:00
Kima
3fc14ffbb8 added room to livecard break 2024-05-13 19:23:55 +02:00
Geryy
f579270886 liveactivities bug fix
- Forget to add LiveCardState check to the end, so to avoid create-end activity loop, I added currentstate check.
2024-05-13 19:06:25 +02:00
Márton Kiss
365bd7957e Merge pull request #117 from geryyhu/dev
fixed liveactivity issue
2024-05-13 06:09:45 +02:00
Geryy
d24c4ec187 fixed liveactivity issue
- Fixed a bug where if it's less than one hour before the first class, the LiveActivity is created, but if the user rolls back the time to more than one hour before the first class, the LiveActivity does not end."
2024-05-13 03:01:18 +02:00
Kima
75ba5405bb made full new grade color picker 2024-05-12 22:05:21 +02:00
Kima
e0bf8ac5e5 fixed exam related popup things 2024-05-12 19:23:45 +02:00
Kima
1a3d78a5bc absence page and graph fixes 2024-05-12 19:02:56 +02:00
Kima
c205bc592c idk 2024-05-12 12:10:34 +02:00
Kima
308c8f966f Merge branch 'dev' of github.com:refilc/naplo into dev 2024-05-09 22:09:32 +02:00
Márton Kiss
139ac28be6 Merge pull request #116 from geryyhu/dev
LiveActivities design fix
2024-05-09 17:15:14 +02:00
Geryy
bbe53b8c01 LiveActivities design fix
- Fixed issue where long subject names did not fit. 
- Formatting improvements on DynamicIsland and LockScreen notifications. 
- Smarter wrapping for long subjects.
- *I forgot to add a line break when there is a break, so I added it.*
2024-05-09 16:11:43 +02:00
Geryy
56a0c2c02e LiveActivities design fix
- Fixed issue where long subject names did not fit. 
- Formatting improvements on DynamicIsland and LockScreen notifications. 
- Smarter wrapping for long subjects.
2024-05-09 14:46:01 +02:00
Márton Kiss
122a5ea210 Merge pull request #114 from pml68/dev
Volt még fennmaradó hibás színkód a régi primary-ből
2024-05-08 19:15:45 +02:00
pml68
aaa3d79b30 fix: change only the widget's "filc" color to the new primary 2024-05-08 18:00:33 +02:00
pml68
cacf566794 Revert "fix: change all remaining #3D7BF4 color codes to #052460 (new primary)"
This reverts commit 9b29ede6eb.
2024-05-08 17:58:31 +02:00
pml68
9b29ede6eb fix: change all remaining #3D7BF4 color codes to #052460 (new primary) 2024-05-08 16:12:09 +02:00
Márton Kiss
9e9e46d0f8 Merge pull request #111 from geryyhu/dev
LiveActivities design fix
2024-05-06 21:29:42 +02:00
Geryy
9901251cfc LiveActivities design fix 2.0 2024-05-06 15:25:54 +02:00
Kima
e7ec93132d live card padding fix 2024-05-06 11:10:33 +02:00
Geryy
7cec2ff525 Merge branch 'refilc:dev' into dev 2024-05-06 06:03:34 +02:00
Horváth Gergely
2ca8f4b8fe LiveActivities design fix
- Fixed if the user opens the app 1 hour before their first class, the Room section is empty in LiveActivity lock screen
- DynamicIsland reworked and improved
- The room section moved to Flutter side
2024-05-06 06:03:06 +02:00
Horváth Gergely
ae66a462e7 LiveActivities design fix
- Fixed if the user opens the app 1 hour before their first class, the Room section is empty in LiveActivity lock screen
- DynamicIsland reworked and improved
- The room section moved to Flutter side
2024-05-06 06:01:15 +02:00
Kima
c85f15eb49 updated build number 2024-05-05 22:21:40 +02:00
Kima
e04cc5ea2b added analytics warning 2024-05-05 22:20:24 +02:00
Kima
3ed456c01f fixed subject page padding 2024-05-05 21:55:05 +02:00
Kima
f64b1360d9 images are now removable 2024-05-05 21:53:39 +02:00
Kima
c9db496e59 fixed text overflow and teacher custom name 2024-05-05 21:39:22 +02:00
Kima
d915200faa made task creation flow 2024-05-05 21:11:13 +02:00
Tihanyi Marcell
32abfe7037 New Icon + iOS version bump + chmod 2024-05-05 20:37:12 +02:00
147 changed files with 5231 additions and 1904 deletions

56
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,56 @@
pipeline {
agent any
environment {
ANDROID_SDK = '/home/jenkins/flutter_things/android-sdk'
ANDROID_PATH="$ANDROID_SDK/tools:$ANDROID_SDK/platform-tools"
FLUTTER = '/home/jenkins/flutter_things/flutter/bin'
PATH = "$PATH:$ANDROID_PATH:$FLUTTER"
//TODO: need to fix flutter
}
stages {
stage('Copy Key Properties') {
steps {
// Copy the key.properties file
sh 'cp /home/jenkins/key.properties refilc/android/key.properties'
}
}
stage('Flutter Doctor') {
steps {
// Ensure Flutter is set up correctly
sh 'flutter doctor'
}
}
stage('Dependencies') {
steps {
// Get Flutter dependencies
sh 'cd refilc && flutter pub get'
}
}
stage('Build') {
steps {
// Build the Flutter project
sh 'cd refilc && flutter build apk --release'
}
}
stage('Archive') {
steps {
// Archive the APK
archiveArtifacts artifacts: 'build/app/outputs/flutter-apk/app-release.apk', fingerprint: true
}
}
}
post {
always {
// Clean up workspace after build
cleanWs()
}
}
}

View File

@@ -58,7 +58,7 @@ android {
defaultConfig { defaultConfig {
applicationId "hu.refilc.naplo" applicationId "hu.refilc.naplo"
minSdkVersion 21 minSdkVersion 24
targetSdkVersion 34 targetSdkVersion 34
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName

View File

@@ -20,7 +20,7 @@
android:gravity="center" android:gravity="center"
android:text="1." android:text="1."
android:textColor="@color/filc" android:textColor="@color/filc"
android:textColorLink="#ff3D7BF4" android:textColorLink="#ff052460"
android:textSize="30sp" android:textSize="30sp"
android:textStyle="bold" android:textStyle="bold"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
@@ -110,4 +110,4 @@
android:textColor="@color/white" android:textColor="@color/white"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
</RelativeLayout> </RelativeLayout>

View File

@@ -27,7 +27,7 @@
<color name="yellow_light">#ffFFCC00</color> <color name="yellow_light">#ffFFCC00</color>
<color name="light_yellow_light">#40FFD60A</color> <color name="light_yellow_light">#40FFD60A</color>
<color name="green_light">#ff34C759</color> <color name="green_light">#ff34C759</color>
<color name="filc_light">#ff3D7BF4</color> <color name="filc_light">#ff052460</color>
<color name="teal_light">#ff5AC8FA</color> <color name="teal_light">#ff5AC8FA</color>
<color name="blue_light">#ff007AFF</color> <color name="blue_light">#ff007AFF</color>
<color name="indigo_light">#ff5856D6</color> <color name="indigo_light">#ff5856D6</color>
@@ -49,8 +49,8 @@
<color name="yellow">#ffFFD60A</color> <color name="yellow">#ffFFD60A</color>
<color name="light_yellow">#40FFD60A</color> <color name="light_yellow">#40FFD60A</color>
<color name="green">#ff32D74B</color> <color name="green">#ff32D74B</color>
<color name="filc">#ff3D7BF4</color> <color name="filc">#ff052460</color>
<color name="filc_gradient">#ff3D93F5</color> <color name="filc_gradient">#ff06348f</color>
<color name="teal">#ff64D2FF</color> <color name="teal">#ff64D2FF</color>
<color name="blue">#ff0A84FF</color> <color name="blue">#ff0A84FF</color>
<color name="indigo">#ff5E5CE6</color> <color name="indigo">#ff5E5CE6</color>
@@ -66,4 +66,4 @@
<color name="pink_shade300">#FFF06292</color> <color name="pink_shade300">#FFF06292</color>
<color name="purple_shade300">#FFBA68C8</color> <color name="purple_shade300">#FFBA68C8</color>
<color name="teal_shade300">#FF22AC9B</color> <color name="teal_shade300">#FF22AC9B</color>
</resources> </resources>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 364 KiB

After

Width:  |  Height:  |  Size: 696 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 581 KiB

After

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 KiB

After

Width:  |  Height:  |  Size: 1009 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 KiB

After

Width:  |  Height:  |  Size: 549 KiB

View File

@@ -0,0 +1,43 @@
<svg width="375" height="174" viewBox="0 0 375 174" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1575_5258)">
<g style="mix-blend-mode:color-burn">
<rect x="187.881" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="238.186" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="187.881" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="238.186" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="288.49" y="36.8047" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="337.652" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="288.49" y="-13.5" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="337.652" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="187.881" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="238.186" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="187.881" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
<rect x="238.186" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
<rect x="288.49" y="136.271" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="337.652" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="288.49" y="87.1099" width="49.3049" height="49.3049" stroke="#858585"/>
<rect x="337.652" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
<rect x="-12.1953" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="-12.1953" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="38.1094" y="36.8047" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="87.2705" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="38.1094" y="-13.5" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="87.2705" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="-12.1953" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="-12.1953" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
<rect x="38.1094" y="136.271" width="49.3049" height="50.4482" stroke="#858585"/>
<rect x="87.2705" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="38.1094" y="87.1099" width="49.3049" height="49.3049" stroke="#858585"/>
<rect x="87.2705" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
<rect x="137.576" y="36.8047" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="137.576" y="-13.5" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="137.576" y="136.271" width="50.4482" height="50.4482" stroke="#858585"/>
<rect x="137.576" y="87.1099" width="50.4482" height="49.3049" stroke="#858585"/>
</g>
</g>
<defs>
<clipPath id="clip0_1575_5258">
<rect width="375" height="173.78" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,27 @@
<svg width="375" height="175" viewBox="0 0 375 175" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1575_5259)">
<g style="mix-blend-mode:color-burn">
<mask id="path-1-inside-1_1575_5259" fill="white">
<path d="M0 37H375V89H0V37Z"/>
</mask>
<path d="M0 38H375V36H0V38Z" fill="#858585" mask="url(#path-1-inside-1_1575_5259)"/>
<mask id="path-3-inside-2_1575_5259" fill="white">
<path d="M0 -13H375V38H0V-13Z"/>
</mask>
<path d="M0 -12H375V-14H0V-12Z" fill="#858585" mask="url(#path-3-inside-2_1575_5259)"/>
<mask id="path-5-inside-3_1575_5259" fill="white">
<path d="M0 137H375V188H0V137Z"/>
</mask>
<path d="M0 138H375V136H0V138Z" fill="#858585" mask="url(#path-5-inside-3_1575_5259)"/>
<mask id="path-7-inside-4_1575_5259" fill="white">
<path d="M0 87H375V138H0V87Z"/>
</mask>
<path d="M0 88H375V86H0V88Z" fill="#858585" mask="url(#path-7-inside-4_1575_5259)"/>
</g>
</g>
<defs>
<clipPath id="clip0_1575_5259">
<rect width="375" height="173.78" fill="white" transform="translate(0 0.780518)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,47 @@
<svg width="375" height="175" viewBox="0 0 375 175" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1575_5260)">
<g style="mix-blend-mode:color-burn">
<circle cx="17" cy="19.561" r="1" fill="#858585"/>
<circle cx="59" cy="19.561" r="1" fill="#858585"/>
<circle cx="101" cy="19.561" r="1" fill="#858585"/>
<circle cx="143" cy="19.561" r="1" fill="#858585"/>
<circle cx="185" cy="19.561" r="1" fill="#858585"/>
<circle cx="227" cy="19.561" r="1" fill="#858585"/>
<circle cx="269" cy="19.561" r="1" fill="#858585"/>
<circle cx="311" cy="19.561" r="1" fill="#858585"/>
<circle cx="353" cy="19.561" r="1" fill="#858585"/>
<circle cx="17" cy="61.561" r="1" fill="#858585"/>
<circle cx="59" cy="61.561" r="1" fill="#858585"/>
<circle cx="101" cy="61.561" r="1" fill="#858585"/>
<circle cx="143" cy="61.561" r="1" fill="#858585"/>
<circle cx="185" cy="61.561" r="1" fill="#858585"/>
<circle cx="227" cy="61.561" r="1" fill="#858585"/>
<circle cx="269" cy="61.561" r="1" fill="#858585"/>
<circle cx="311" cy="61.561" r="1" fill="#858585"/>
<circle cx="353" cy="61.561" r="1" fill="#858585"/>
<circle cx="17" cy="103.561" r="1" fill="#858585"/>
<circle cx="59" cy="103.561" r="1" fill="#858585"/>
<circle cx="101" cy="103.561" r="1" fill="#858585"/>
<circle cx="143" cy="103.561" r="1" fill="#858585"/>
<circle cx="185" cy="103.561" r="1" fill="#858585"/>
<circle cx="227" cy="103.561" r="1" fill="#858585"/>
<circle cx="269" cy="103.561" r="1" fill="#858585"/>
<circle cx="311" cy="103.561" r="1" fill="#858585"/>
<circle cx="353" cy="103.561" r="1" fill="#858585"/>
<circle cx="17" cy="145.561" r="1" fill="#858585"/>
<circle cx="59" cy="145.561" r="1" fill="#858585"/>
<circle cx="101" cy="145.561" r="1" fill="#858585"/>
<circle cx="143" cy="145.561" r="1" fill="#858585"/>
<circle cx="185" cy="145.561" r="1" fill="#858585"/>
<circle cx="227" cy="145.561" r="1" fill="#858585"/>
<circle cx="269" cy="145.561" r="1" fill="#858585"/>
<circle cx="311" cy="145.561" r="1" fill="#858585"/>
<circle cx="353" cy="145.561" r="1" fill="#858585"/>
</g>
</g>
<defs>
<clipPath id="clip0_1575_5260">
<rect width="375" height="173.78" fill="white" transform="translate(0 0.561035)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,28 @@
<svg width="375" height="175" viewBox="0 0 375 175" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1575_5261)">
<g style="mix-blend-mode:color-burn">
<path d="M0 63.0001H375" stroke="#858585"/>
<path d="M0 75.0001H375" stroke="#858585"/>
<path d="M0 87.0001H375" stroke="#858585"/>
<path d="M0 99.0001H375" stroke="#858585"/>
<path d="M0 111H375" stroke="#858585"/>
</g>
<g style="mix-blend-mode:color-burn">
<path d="M0 135H375" stroke="#858585"/>
<path d="M0 147H375" stroke="#858585"/>
<path d="M0 159H375" stroke="#858585"/>
<path d="M0 171H375" stroke="#858585"/>
</g>
<g style="mix-blend-mode:color-burn">
<path d="M0 3.00012H375" stroke="#858585"/>
<path d="M0 15.0001H375" stroke="#858585"/>
<path d="M0 27.0001H375" stroke="#858585"/>
<path d="M0 39.0001H375" stroke="#858585"/>
</g>
</g>
<defs>
<clipPath id="clip0_1575_5261">
<rect width="375" height="173.78" fill="white" transform="translate(0 0.341431)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 973 B

View File

@@ -1,43 +0,0 @@
<svg width="375" height="174" viewBox="0 0 375 174" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_581_2504)">
<g style="mix-blend-mode:color-burn">
<rect x="138.881" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="189.186" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="138.881" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="189.186" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="239.49" y="36.8047" width="49.3049" height="50.4482" stroke="black"/>
<rect x="288.652" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="239.49" y="-13.5" width="49.3049" height="50.4482" stroke="black"/>
<rect x="288.652" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="138.881" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="189.186" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="138.881" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
<rect x="189.186" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
<rect x="239.49" y="136.271" width="49.3049" height="50.4482" stroke="black"/>
<rect x="288.652" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="239.49" y="87.1099" width="49.3049" height="49.3049" stroke="black"/>
<rect x="288.652" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
<rect x="338.957" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="338.957" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="338.957" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="338.957" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
<rect x="-10.8906" y="36.8047" width="49.3049" height="50.4482" stroke="black"/>
<rect x="38.2705" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="-10.8906" y="-13.5" width="49.3049" height="50.4482" stroke="black"/>
<rect x="38.2705" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="-10.8906" y="136.271" width="49.3049" height="50.4482" stroke="black"/>
<rect x="38.2705" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="-10.8906" y="87.1099" width="49.3049" height="49.3049" stroke="black"/>
<rect x="38.2705" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
<rect x="88.5762" y="36.8047" width="50.4482" height="50.4482" stroke="black"/>
<rect x="88.5762" y="-13.5" width="50.4482" height="50.4482" stroke="black"/>
<rect x="88.5762" y="136.271" width="50.4482" height="50.4482" stroke="black"/>
<rect x="88.5762" y="87.1099" width="50.4482" height="49.3049" stroke="black"/>
</g>
</g>
<defs>
<clipPath id="clip0_581_2504">
<rect width="375" height="173.78" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -517,7 +517,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 255; CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@@ -549,7 +549,7 @@
CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements; CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 255; CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -591,7 +591,7 @@
CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements; CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 255; CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -631,7 +631,7 @@
CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements; CODE_SIGN_ENTITLEMENTS = livecard/livecard.entitlements;
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 255; CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -775,7 +775,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 255; CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@@ -803,7 +803,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 255; CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 4DKAF249F3; DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;

View File

@@ -1,7 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "reFilc_Logo.png", "filename" : "rf_1024.png",
"idiom" : "universal", "idiom" : "universal",
"platform" : "ios", "platform" : "ios",
"size" : "1024x1024" "size" : "1024x1024"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 577 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

View File

@@ -52,14 +52,31 @@ struct LockScreenLiveActivityView: View {
VStack(alignment: .center) { VStack(alignment: .center) {
// Jelenlegi óra // Jelenlegi óra
VStack { VStack {
Text(context.state.index + " " + context.state.title) if(context.state.title.contains("Az első órádig")) {
.font(.body) Text(context.state.title)
.bold() .font(.system(size: 15))
.multilineTextAlignment(.center) .bold()
.multilineTextAlignment(.center)
} else if(context.state.title == "Szünet") {
Text(context.state.title)
.font(.body)
.bold()
.padding(.trailing, 90)
Text("Terem: \(context.state.subtitle)") } else {
.italic() MultilineTextView(text: "\(context.state.index) \(context.state.title)", limit: 25)
.font(.caption) .font(.body)
.bold()
.multilineTextAlignment(.center)
}
//Terem
if (!context.state.subtitle.isEmpty) {
Text(context.state.subtitle)
.italic()
.bold()
.font(.system(size: 13))
}
} }
// Leírás // Leírás
@@ -69,6 +86,7 @@ struct LockScreenLiveActivityView: View {
} }
// Következő óra // Következő óra
if(context.state.nextSubject != "" && context.state.nextRoom != "") {
HStack { HStack {
Image(systemName: "arrow.right") Image(systemName: "arrow.right")
.resizable() .resizable()
@@ -80,18 +98,24 @@ struct LockScreenLiveActivityView: View {
.font(.caption2) .font(.caption2)
} }
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
} else {
Spacer(minLength: 5)
Text("Ez az utolsó óra! Kitartást!")
.font(.system(size: 15))
}
} }
.padding(15) .padding(15)
Spacer() Spacer()
// Visszaszámláló // Visszaszámláló
Text(timerInterval: context.state.date, countsDown: true) Text(timerInterval: context.state.date, countsDown: true)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.frame(width: 85) .frame(width: 85)
.font(.title2) .font(.title2)
.monospacedDigit() .monospacedDigit()
.padding(.trailing, CGFloat(24)) .padding(.trailing)
} }
.activityBackgroundTint( .activityBackgroundTint(
context.state.color != "#676767" context.state.color != "#676767"
@@ -109,7 +133,7 @@ struct LiveCardWidget: Widget {
LockScreenLiveActivityView(context: context) LockScreenLiveActivityView(context: context)
/// Dynamic Island /// Dynamic Island
} dynamicIsland: { context in } dynamicIsland: { context in
/// Expanded /// Expanded
return DynamicIsland { return DynamicIsland {
DynamicIslandExpandedRegion(.leading) { DynamicIslandExpandedRegion(.leading) {
@@ -133,39 +157,95 @@ struct LiveCardWidget: Widget {
).progressViewStyle(.circular) ).progressViewStyle(.circular)
} }
} }
DynamicIslandExpandedRegion(.center) { DynamicIslandExpandedRegion(.center) {
VStack(alignment: .center) { VStack(alignment: .center) {
Text(context.state.index + context.state.title) // Első óra előtti expanded DynamicIsland
.lineLimit(1) if(context.state.title.contains("Az első órádig")) {
.font(.body) Text("Az első órád:")
.bold() .font(.body)
.bold()
Text(context.state.subtitle) .padding(.trailing, -15)
.lineLimit(1) MultilineTextView(text: "\(context.state.nextSubject)", limit: 25)
.font(.subheadline) .font(.body)
Spacer() .padding(.trailing, -25)
Text(context.state.description) Text("Ebben a teremben:")
.lineLimit(2) .font(.body)
.font(.caption) .bold()
}.padding(EdgeInsets(top: 0.0, leading: 5.0, bottom: 0.0, trailing: 0.0)) .padding(.leading, 15)
} Text(context.state.nextRoom)
.font(.body)
.padding(.leading, 15)
} else if(context.state.title == "Szünet") {
// Amikor szünet van, expanded DynamicIsland
Text(context.state.title)
.lineLimit(1)
.font(.body)
.bold()
.padding(.leading, 15)
Spacer(minLength: 5)
Text("Következő óra és terem:")
.font(.system(size: 13))
.padding(.leading, 25)
Text(context.state.nextSubject)
.font(.caption)
.padding(.leading, 15)
Text(context.state.nextRoom)
.font(.caption2)
.padding(.leading, 15)
} else {
// Amikor óra van, expanded DynamicIsland
MultilineTextView(text: "\(context.state.index) \(context.state.title)", limit: 25)
.lineLimit(1)
.font(.body)
.bold()
.padding(.trailing, -35)
Text(context.state.subtitle)
.lineLimit(1)
.italic()
.bold()
.font(.system(size: 13))
.padding(.trailing, -50)
Spacer(minLength: 5)
if(context.state.nextRoom != "" && context.state.nextSubject != "") {
Text("Következő óra és terem:")
.font(.system(size: 14))
.padding(.trailing, -35)
Spacer(minLength: 2)
Text(context.state.nextSubject)
.modifier(DynamicFontSizeModifier(text: context.state.nextSubject))
.padding(.trailing, -35)
Text(context.state.nextRoom)
// ignore: based on nextSubject characters, I check that the font size of the room is the same as the next subject.
.modifier(DynamicFontSizeModifier(text: context.state.nextSubject))
.padding(.trailing, -35)
} else {
Text("Ez az utolsó óra! Kitartást!")
.font(.system(size: 14))
.padding(.trailing, -30)
}
}
}.padding(EdgeInsets(top: 0.0, leading: 5.0, bottom: 0.0, trailing: 0.0))
}
/// Compact /// Compact
} compactLeading: { } compactLeading: {
Label { Image(systemName: context.state.icon)
Text(context.state.title)
} icon: {
Image(systemName: context.state.icon)
}
.font(.caption2)
} }
compactTrailing: { compactTrailing: {
Text(timerInterval: context.state.date, countsDown: true) Text(timerInterval: context.state.date, countsDown: true)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.frame(width: 40) .frame(width: 40)
.font(.caption2) .font(.caption2)
/// Collapsed /// Collapsed
} minimal: { } minimal: {
VStack(alignment: .center, content: { VStack(alignment: .center, content: {
@@ -191,7 +271,59 @@ struct LiveCardWidget: Widget {
context.state.color != "#676767" context.state.color != "#676767"
? Color(hex: context.state.color) ? Color(hex: context.state.color)
: Color.clear : Color.clear
) )
}
}
}
struct MultilineTextView: View {
var text: String
var limit: Int = 20 // default is 20 character
var body: some View {
let words = text.split(separator: " ")
var currentLine = ""
var lines: [String] = []
for word in words {
if (currentLine.count + word.count + 1) > limit {
lines.append(currentLine)
currentLine = ""
}
if !currentLine.isEmpty {
currentLine += " "
}
currentLine += word
}
if !currentLine.isEmpty {
lines.append(currentLine)
}
return VStack(alignment: .center) {
ForEach(lines, id: \.self) { line in
Text(line)
}
Spacer(minLength: 1)
}
}
}
struct DynamicFontSizeModifier: ViewModifier {
var text: String
func body(content: Content) -> some View {
content
.font(.system(size: fontSize(for: text)))
}
private func fontSize(for text: String) -> CGFloat {
let length = text.count
if length < 10 {
return 12
} else if length < 20 {
return 12
} else {
return 11
} }
} }
} }

View File

@@ -55,7 +55,7 @@ class FilcAPI {
static const stripeSheet = "$payment/stripe-sheet"; static const stripeSheet = "$payment/stripe-sheet";
static Future<bool> checkConnectivity() async => static Future<bool> checkConnectivity() async =>
(await Connectivity().checkConnectivity()) != ConnectivityResult.none; (await Connectivity().checkConnectivity())[0] != ConnectivityResult.none;
static Future<List<School>?> getSchools() async { static Future<List<School>?> getSchools() async {
try { try {
@@ -336,6 +336,8 @@ class FilcAPI {
if (res.statusCode == 200) { if (res.statusCode == 200) {
return (jsonDecode(res.body) as Map); return (jsonDecode(res.body) as Map);
} else if (res.statusCode == 404) {
return {"public_id": ""};
} else { } else {
throw "HTTP ${res.statusCode}: ${res.body}"; throw "HTTP ${res.statusCode}: ${res.body}";
} }

View File

@@ -1,5 +1,6 @@
// ignore_for_file: avoid_print, use_build_context_synchronously // ignore_for_file: avoid_print, use_build_context_synchronously
import 'package:flutter/foundation.dart';
import 'package:refilc/utils/jwt.dart'; import 'package:refilc/utils/jwt.dart';
import 'package:refilc_kreta_api/models/school.dart'; import 'package:refilc_kreta_api/models/school.dart';
import 'package:refilc_kreta_api/providers/absence_provider.dart'; import 'package:refilc_kreta_api/providers/absence_provider.dart';
@@ -66,6 +67,7 @@ Future loginAPI({
address: '1117 Budapest, Gábor Dénes utca 4.', address: '1117 Budapest, Gábor Dénes utca 4.',
), ),
role: Role.parent, role: Role.parent,
refreshToken: '',
); );
if (onLogin != null) onLogin(user); if (onLogin != null) onLogin(user);
@@ -107,7 +109,9 @@ Future loginAPI({
default: default:
// normal login from here // normal login from here
Provider.of<KretaClient>(context, listen: false).userAgent = Provider.of<KretaClient>(context, listen: false).userAgent =
Provider.of<SettingsProvider>(context, listen: false).config.userAgent; Provider.of<SettingsProvider>(context, listen: false)
.config
.userAgent;
Map<String, String> headers = { Map<String, String> headers = {
"content-type": "application/x-www-form-urlencoded", "content-type": "application/x-www-form-urlencoded",
@@ -127,6 +131,7 @@ Future loginAPI({
password: password, password: password,
instituteCode: instituteCode, instituteCode: instituteCode,
)); ));
if (res != null) { if (res != null) {
if (res.containsKey("error")) { if (res.containsKey("error")) {
if (res["error"] == "invalid_grant") { if (res["error"] == "invalid_grant") {
@@ -148,6 +153,7 @@ Future loginAPI({
name: student.name, name: student.name,
student: student, student: student,
role: JwtUtils.getRoleFromJWT(res["access_token"])!, role: JwtUtils.getRoleFromJWT(res["access_token"])!,
refreshToken: '',
); );
if (onLogin != null) onLogin(user); if (onLogin != null) onLogin(user);
@@ -157,7 +163,8 @@ Future loginAPI({
.store .store
.storeUser(user); .storeUser(user);
Provider.of<UserProvider>(context, listen: false).addUser(user); Provider.of<UserProvider>(context, listen: false).addUser(user);
Provider.of<UserProvider>(context, listen: false).setUser(user.id); Provider.of<UserProvider>(context, listen: false)
.setUser(user.id);
// Get user data // Get user data
try { try {
@@ -167,7 +174,8 @@ Future loginAPI({
.fetch(week: Week.current()), .fetch(week: Week.current()),
Provider.of<ExamProvider>(context, listen: false).fetch(), Provider.of<ExamProvider>(context, listen: false).fetch(),
Provider.of<HomeworkProvider>(context, listen: false).fetch(), Provider.of<HomeworkProvider>(context, listen: false).fetch(),
Provider.of<MessageProvider>(context, listen: false).fetchAll(), Provider.of<MessageProvider>(context, listen: false)
.fetchAll(),
Provider.of<MessageProvider>(context, listen: false) Provider.of<MessageProvider>(context, listen: false)
.fetchAllRecipients(), .fetchAllRecipients(),
Provider.of<NoteProvider>(context, listen: false).fetch(), Provider.of<NoteProvider>(context, listen: false).fetch(),
@@ -195,3 +203,112 @@ Future loginAPI({
return LoginState.failed; return LoginState.failed;
} }
// new login api
Future newLoginAPI({
required String code,
required BuildContext context,
void Function(User)? onLogin,
void Function()? onSuccess,
}) async {
// actual login (token grant) logic
Provider.of<KretaClient>(context, listen: false).userAgent =
Provider.of<SettingsProvider>(context, listen: false).config.userAgent;
Map<String, String> headers = {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"accept": "*/*",
"user-agent": "eKretaStudent/264745 CFNetwork/1494.0.7 Darwin/23.4.0",
};
Map? res = await Provider.of<KretaClient>(context, listen: false)
.postAPI(KretaAPI.login, headers: headers, body: {
"code": code,
"code_verifier": "DSpuqj_HhDX4wzQIbtn8lr8NLE5wEi1iVLMtMK0jY6c",
"redirect_uri":
"https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect",
"client_id": KretaAPI.clientId,
"grant_type": "authorization_code",
});
if (res != null) {
if (kDebugMode) {
print(res);
}
if (res.containsKey("error")) {
if (res["error"] == "invalid_grant") {
print("ERROR: invalid_grant");
return;
}
} else {
if (res.containsKey("access_token")) {
try {
Provider.of<KretaClient>(context, listen: false).accessToken =
res["access_token"];
Provider.of<KretaClient>(context, listen: false).refreshToken =
res["refresh_token"];
String instituteCode =
JwtUtils.getInstituteFromJWT(res["access_token"])!;
String username = JwtUtils.getUsernameFromJWT(res["access_token"])!;
Role role = JwtUtils.getRoleFromJWT(res["access_token"])!;
Map? studentJson =
await Provider.of<KretaClient>(context, listen: false)
.getAPI(KretaAPI.student(instituteCode));
Student student = Student.fromJson(studentJson!);
var user = User(
username: username,
password: '',
instituteCode: instituteCode,
name: student.name,
student: student,
role: role,
refreshToken: res["refresh_token"],
);
if (onLogin != null) onLogin(user);
// Store User in the database
await Provider.of<DatabaseProvider>(context, listen: false)
.store
.storeUser(user);
Provider.of<UserProvider>(context, listen: false).addUser(user);
Provider.of<UserProvider>(context, listen: false).setUser(user.id);
// Get user data
try {
await Future.wait([
Provider.of<GradeProvider>(context, listen: false).fetch(),
Provider.of<TimetableProvider>(context, listen: false)
.fetch(week: Week.current()),
Provider.of<ExamProvider>(context, listen: false).fetch(),
Provider.of<HomeworkProvider>(context, listen: false).fetch(),
Provider.of<MessageProvider>(context, listen: false).fetchAll(),
Provider.of<MessageProvider>(context, listen: false)
.fetchAllRecipients(),
Provider.of<NoteProvider>(context, listen: false).fetch(),
Provider.of<EventProvider>(context, listen: false).fetch(),
Provider.of<AbsenceProvider>(context, listen: false).fetch(),
]);
} catch (error) {
print("WARNING: failed to fetch user data: $error");
}
if (onSuccess != null) onSuccess();
return LoginState.success;
} catch (error) {
print("ERROR: loginAPI: $error");
// maybe check debug mode
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("ERROR: $error")));
return LoginState.failed;
}
}
}
}
return LoginState.failed;
}

View File

@@ -88,24 +88,24 @@ class LiveCardProvider extends ChangeNotifier {
case LiveCardState.morning: case LiveCardState.morning:
return { return {
"color": "color":
'#${_settings.liveActivityColor.toString().substring(10, 16)}', '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": nextLesson != null "icon": nextLesson != null
? SubjectIcon.resolveName(subject: nextLesson?.subject) ? SubjectIcon.resolveName(subject: nextLesson?.subject)
: "book", : "book",
"title": "Első órádig:", "title": "Jó reggelt! Az első órádig:",
"subtitle": "", "subtitle": "",
"description": "", "description": "",
"startDate": storeFirstRunDate != null "startDate": storeFirstRunDate != null
? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) -
(_delay.inMilliseconds)) (_delay.inMilliseconds))
.toString() .toString()
: "", : "",
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": nextLesson != null "nextSubject": nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: nextLesson?.subject).capital() ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "", : "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
@@ -113,24 +113,24 @@ class LiveCardProvider extends ChangeNotifier {
case LiveCardState.afternoon: case LiveCardState.afternoon:
return { return {
"color": "color":
'#${_settings.liveActivityColor.toString().substring(10, 16)}', '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": nextLesson != null "icon": nextLesson != null
? SubjectIcon.resolveName(subject: nextLesson?.subject) ? SubjectIcon.resolveName(subject: nextLesson?.subject)
: "book", : "book",
"title": "Első órádig:", "title": "Jó napot! Az első órádig:",
"subtitle": "", "subtitle": "",
"description": "", "description": "",
"startDate": storeFirstRunDate != null "startDate": storeFirstRunDate != null
? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) -
(_delay.inMilliseconds)) (_delay.inMilliseconds))
.toString() .toString()
: "", : "",
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": nextLesson != null "nextSubject": nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: nextLesson?.subject).capital() ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "", : "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
@@ -138,24 +138,24 @@ class LiveCardProvider extends ChangeNotifier {
case LiveCardState.night: case LiveCardState.night:
return { return {
"color": "color":
'#${_settings.liveActivityColor.toString().substring(10, 16)}', '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": nextLesson != null "icon": nextLesson != null
? SubjectIcon.resolveName(subject: nextLesson?.subject) ? SubjectIcon.resolveName(subject: nextLesson?.subject)
: "book", : "book",
"title": "Első órádig:", "title": "Jó estét! Az első órádig:",
"subtitle": "", "subtitle": "",
"description": "", "description": "",
"startDate": storeFirstRunDate != null "startDate": storeFirstRunDate != null
? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) - ? ((storeFirstRunDate?.millisecondsSinceEpoch ?? 0) -
(_delay.inMilliseconds)) (_delay.inMilliseconds))
.toString() .toString()
: "", : "",
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": nextLesson != null "nextSubject": nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: nextLesson?.subject).capital() ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "", : "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
@@ -163,28 +163,28 @@ class LiveCardProvider extends ChangeNotifier {
case LiveCardState.duringLesson: case LiveCardState.duringLesson:
return { return {
"color": "color":
'#${_settings.liveActivityColor.toString().substring(10, 16)}', '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": currentLesson != null "icon": currentLesson != null
? SubjectIcon.resolveName(subject: currentLesson?.subject) ? SubjectIcon.resolveName(subject: currentLesson?.subject)
: "book", : "book",
"index": "index":
currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "", currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
"title": currentLesson != null "title": currentLesson != null
? currentLesson?.subject.renamedTo ?? ? currentLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: currentLesson?.subject) ShortSubject.resolve(subject: currentLesson?.subject)
.capital() .capital()
: "", : "",
"subtitle": currentLesson?.room.replaceAll("_", " ") ?? "", "subtitle": "Terem: ${currentLesson?.room.replaceAll("_", " ") ?? ""}",
"description": currentLesson?.description ?? "", "description": currentLesson?.description ?? "",
"startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) - "startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) - "endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": nextLesson != null "nextSubject": nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: nextLesson?.subject).capital() ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "", : "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
@@ -200,23 +200,23 @@ class LiveCardProvider extends ChangeNotifier {
return { return {
"color": "color":
'#${_settings.liveActivityColor.toString().substring(10, 16)}', '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": iconFloorMap[diff] ?? "cup.and.saucer", "icon": iconFloorMap[diff] ?? "cup.and.saucer",
"title": "Szünet", "title": "Szünet",
"description": "go $diff".i18n.fill([ "description": "go $diff".i18n.fill([
diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room
]), ]),
"startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) - "startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - "endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": (nextLesson != null "nextSubject": (nextLesson != null
? nextLesson?.subject.renamedTo ?? ? nextLesson?.subject.renamedTo ??
ShortSubject.resolve(subject: nextLesson?.subject) ShortSubject.resolve(subject: nextLesson?.subject)
.capital() .capital()
: "") : "")
.capital(), .capital(),
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
"index": "", "index": "",
@@ -243,8 +243,8 @@ class LiveCardProvider extends ChangeNotifier {
DateTime now = _now().add(_delay); DateTime now = _now().add(_delay);
if ((currentState == LiveCardState.morning || if ((currentState == LiveCardState.morning ||
currentState == LiveCardState.afternoon || currentState == LiveCardState.afternoon ||
currentState == LiveCardState.night) && currentState == LiveCardState.night) &&
storeFirstRunDate == null) { storeFirstRunDate == null) {
storeFirstRunDate = now; storeFirstRunDate = now;
} }
@@ -253,9 +253,9 @@ class LiveCardProvider extends ChangeNotifier {
// Filter label lessons #128 // Filter label lessons #128
today = today today = today
.where((lesson) => .where((lesson) =>
lesson.status?.name != "Elmaradt" && lesson.status?.name != "Elmaradt" &&
lesson.subject.id != '' && lesson.subject.id != '' &&
!lesson.isEmpty) !lesson.isEmpty)
.toList(); .toList();
if (today.isNotEmpty) { if (today.isNotEmpty) {
@@ -263,7 +263,7 @@ class LiveCardProvider extends ChangeNotifier {
today.sort((a, b) => a.start.compareTo(b.start)); today.sort((a, b) => a.start.compareTo(b.start));
final _lesson = today.firstWhere( final _lesson = today.firstWhere(
(l) => l.start.isBefore(now) && l.end.isAfter(now), (l) => l.start.isBefore(now) && l.end.isAfter(now),
orElse: () => Lesson.fromJson({})); orElse: () => Lesson.fromJson({}));
if (_lesson.start.year != 0) { if (_lesson.start.year != 0) {
@@ -328,7 +328,7 @@ class LiveCardProvider extends ChangeNotifier {
hasActivityStarted = true; hasActivityStarted = true;
} else if (!hasActivityStarted && } else if (!hasActivityStarted &&
((currentState == LiveCardState.duringLesson && ((currentState == LiveCardState.duringLesson &&
currentLesson != null) || currentLesson != null) ||
currentState == LiveCardState.duringBreak)) { currentState == LiveCardState.duringBreak)) {
debugPrint("Óra van, vagy szünet, de nincs LiveActivity. létrehozás..."); debugPrint("Óra van, vagy szünet, de nincs LiveActivity. létrehozás...");
PlatformChannel.createLiveActivity(toMap()); PlatformChannel.createLiveActivity(toMap());
@@ -362,7 +362,12 @@ class LiveCardProvider extends ChangeNotifier {
} }
//END //END
if (hasActivityStarted && if ((currentState == LiveCardState.afternoon || currentState == LiveCardState.morning || currentState == LiveCardState.night) && hasActivityStarted && nextLesson != null &&
nextLesson!.start.difference(now).inMinutes > 60) {
debugPrint("Több, mint 1 óra van az első óráig. Befejezés...");
PlatformChannel.endLiveActivity();
hasActivityStarted = false;
} else if (hasActivityStarted &&
!hasDayEnd && !hasDayEnd &&
nextLesson == null && nextLesson == null &&
now.isAfter(prevLesson!.end)) { now.isAfter(prevLesson!.end)) {
@@ -384,4 +389,4 @@ class LiveCardProvider extends ChangeNotifier {
List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? []) List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? [])
.where((l) => _sameDate(l.date, _now())) .where((l) => _sameDate(l.date, _now()))
.toList(); .toList();
} }

View File

@@ -7,17 +7,23 @@ import 'package:provider/provider.dart';
class SelfNoteProvider with ChangeNotifier { class SelfNoteProvider with ChangeNotifier {
late List<SelfNote> _notes; late List<SelfNote> _notes;
late List<TodoItem> _todoItems;
late BuildContext _context; late BuildContext _context;
List<SelfNote> get notes => _notes; List<SelfNote> get notes => _notes;
List<TodoItem> get todos => _todoItems;
SelfNoteProvider({ SelfNoteProvider({
List<SelfNote> initialNotes = const [], List<SelfNote> initialNotes = const [],
List<TodoItem> initialTodoItems = const [],
required BuildContext context, required BuildContext context,
}) { }) {
_notes = List.castFrom(initialNotes); _notes = List.castFrom(initialNotes);
_todoItems = List.castFrom(initialTodoItems);
_context = context; _context = context;
if (_notes.isEmpty) restore(); if (_notes.isEmpty) restore();
if (_todoItems.isEmpty) restoreTodo();
} }
// restore self notes from db // restore self notes from db
@@ -38,6 +44,24 @@ class SelfNoteProvider with ChangeNotifier {
} }
} }
// restore todo items from db
Future<void> restoreTodo() async {
String? userId = Provider.of<UserProvider>(_context, listen: false).id;
// await Provider.of<DatabaseProvider>(_context, listen: false)
// .userStore
// .storeSelfNotes([], userId: userId!);
// load self notes from db
if (userId != null) {
var dbTodo = await Provider.of<DatabaseProvider>(_context, listen: false)
.userQuery
.getTodoItems(userId: userId);
_todoItems = dbTodo;
notifyListeners();
}
}
// fetches fresh data from api (not needed, cuz no api for that) // fetches fresh data from api (not needed, cuz no api for that)
// Future<void> fetch() async { // Future<void> fetch() async {
// } // }
@@ -54,4 +78,17 @@ class SelfNoteProvider with ChangeNotifier {
_notes = notes; _notes = notes;
notifyListeners(); notifyListeners();
} }
// store todo items in db
Future<void> storeTodo(List<TodoItem> todos) async {
User? user = Provider.of<UserProvider>(_context, listen: false).user;
if (user == null) throw "Cannot store Self Notes for User null";
String userId = user.id;
await Provider.of<DatabaseProvider>(_context, listen: false)
.userStore
.storeSelfTodoItems(todos, userId: userId);
_todoItems = todos;
notifyListeners();
}
} }

View File

@@ -15,7 +15,7 @@ class StatusProvider extends ChangeNotifier {
StatusProvider() { StatusProvider() {
_handleNetworkChanges(); _handleNetworkChanges();
_handleDNSFailure(); _handleDNSFailure();
Connectivity().checkConnectivity().then((value) => _networkType = value); Connectivity().checkConnectivity().then((value) => _networkType = value[0]);
} }
Status? getStatus() => _stack.isNotEmpty ? _stack[0] : null; Status? getStatus() => _stack.isNotEmpty ? _stack[0] : null;
@@ -24,8 +24,8 @@ class StatusProvider extends ChangeNotifier {
void _handleNetworkChanges() { void _handleNetworkChanges() {
Connectivity().onConnectivityChanged.listen((event) { Connectivity().onConnectivityChanged.listen((event) {
_networkType = event; _networkType = event[0];
if (event == ConnectivityResult.none) { if (event[0] == ConnectivityResult.none) {
if (!_stack.contains(Status.network)) { if (!_stack.contains(Status.network)) {
_stack.remove(Status.apiError); _stack.remove(Status.apiError);
_stack.insert(0, Status.network); _stack.insert(0, Status.network);

View File

@@ -23,6 +23,7 @@ class UserProvider with ChangeNotifier {
String? get nickname => user?.nickname; String? get nickname => user?.nickname;
String get picture => user?.picture ?? ""; String get picture => user?.picture ?? "";
String? get displayName => user?.displayName; String? get displayName => user?.displayName;
int? get gradeStreak => user?.gradeStreak;
final SettingsProvider _settings; final SettingsProvider _settings;

View File

@@ -31,6 +31,7 @@ import 'package:provider/provider.dart';
import 'package:refilc_mobile_ui/common/system_chrome.dart' as mobile; import 'package:refilc_mobile_ui/common/system_chrome.dart' as mobile;
import 'package:refilc_mobile_ui/screens/login/login_route.dart' as mobile; import 'package:refilc_mobile_ui/screens/login/login_route.dart' as mobile;
import 'package:refilc_mobile_ui/screens/login/login_screen.dart' as mobile; import 'package:refilc_mobile_ui/screens/login/login_screen.dart' as mobile;
// import 'package:refilc_mobile_ui/screens/login/kreten_login.dart' as mobileTest;
import 'package:refilc_mobile_ui/screens/navigation/navigation_screen.dart' import 'package:refilc_mobile_ui/screens/navigation/navigation_screen.dart'
as mobile; as mobile;
import 'package:refilc_mobile_ui/screens/settings/settings_route.dart' import 'package:refilc_mobile_ui/screens/settings/settings_route.dart'
@@ -80,7 +81,8 @@ class App extends StatelessWidget {
CorePalette? corePalette; CorePalette? corePalette;
final status = StatusProvider(); final status = StatusProvider();
final kreta = KretaClient(user: user, settings: settings, status: status); final kreta = KretaClient(
user: user, settings: settings, database: database, status: status);
final timetable = final timetable =
TimetableProvider(user: user, database: database, kreta: kreta); TimetableProvider(user: user, database: database, kreta: kreta);
final premium = PlusProvider(settings: settings); final premium = PlusProvider(settings: settings);

View File

@@ -45,6 +45,7 @@ const settingsDB = DatabaseStruct("settings", {
// more // more
"show_breaks": int, "show_breaks": int,
"font_family": String, "font_family": String,
"title_only_font": int,
"plus_session_id": String, "plus_session_id": String,
"cal_sync_room_location": String, "cal_sync_show_exams": int, "cal_sync_room_location": String, "cal_sync_show_exams": int,
"cal_sync_show_teacher": int, "cal_sync_renamed": int, "cal_sync_show_teacher": int, "cal_sync_renamed": int,
@@ -52,6 +53,8 @@ const settingsDB = DatabaseStruct("settings", {
"nav_shadow": int, "nav_shadow": int,
"new_colors": int, "new_colors": int,
"uwu_mode": int, "uwu_mode": int,
"new_popups": int,
"unseen_new_features": String,
// quick settings // quick settings
"q_timetable_lesson_num": int, "q_timetable_sub_tiles": int, "q_timetable_lesson_num": int, "q_timetable_sub_tiles": int,
"q_subjects_sub_tiles": int, "q_subjects_sub_tiles": int,
@@ -61,7 +64,9 @@ const settingsDB = DatabaseStruct("settings", {
const usersDB = DatabaseStruct("users", { const usersDB = DatabaseStruct("users", {
"id": String, "name": String, "username": String, "password": String, "id": String, "name": String, "username": String, "password": String,
"institute_code": String, "student": String, "role": int, "institute_code": String, "student": String, "role": int,
"nickname": String, "picture": String // premium only "nickname": String, "picture": String, // premium only (it's now plus btw)
"grade_streak": int,
"refresh_token": String,
}); });
const userDataDB = DatabaseStruct("user_data", { const userDataDB = DatabaseStruct("user_data", {
"id": String, "grades": String, "timetable": String, "exams": String, "id": String, "grades": String, "timetable": String, "exams": String,
@@ -84,12 +89,13 @@ const userDataDB = DatabaseStruct("user_data", {
"goal_befores": String, "goal_befores": String,
"goal_pin_dates": String, "goal_pin_dates": String,
// todo and notes // todo and notes
"todo_items": String, "self_notes": String, "todo_items": String, "self_notes": String, "self_todo": String,
// v5 shit // v5 shit
"roundings": String, "roundings": String,
"grade_rarities": String, "grade_rarities": String,
"linked_accounts": String, "linked_accounts": String,
"custom_lesson_desc": String, "custom_lesson_desc": String,
"watch_data": String,
}); });
Future<void> createTable(Database db, DatabaseStruct struct) => Future<void> createTable(Database db, DatabaseStruct struct) =>
@@ -129,7 +135,13 @@ Future<Database> initDB(DatabaseProvider database) async {
await migrateDB( await migrateDB(
db, db,
struct: usersDB, struct: usersDB,
defaultValues: {"role": 0, "nickname": "", "picture": ""}, defaultValues: {
"role": 0,
"nickname": "",
"picture": "",
"grade_streak": 0,
"refresh_token": "",
},
); );
await migrateDB(db, struct: userDataDB, defaultValues: { await migrateDB(db, struct: userDataDB, defaultValues: {
"grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]", "grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]",
@@ -152,12 +164,13 @@ Future<Database> initDB(DatabaseProvider database) async {
"goal_befores": "{}", "goal_befores": "{}",
"goal_pin_dates": "{}", "goal_pin_dates": "{}",
// todo and notes // todo and notes
"todo_items": "{}", "self_notes": "[]", "todo_items": "{}", "self_notes": "[]", "self_todo": "[]",
// v5 shit // v5 shit
"roundings": "{}", "roundings": "{}",
"grade_rarities": "{}", "grade_rarities": "{}",
"linked_accounts": "[]", "linked_accounts": "[]",
"custom_lesson_desc": "{}", "custom_lesson_desc": "{}",
"watch_data": "{}",
}); });
} catch (error) { } catch (error) {
print("ERROR: migrateDB: $error"); print("ERROR: migrateDB: $error");

View File

@@ -317,6 +317,18 @@ class UserDatabaseQuery {
return selfNotes; return selfNotes;
} }
Future<List<TodoItem>> getTodoItems({required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return [];
String? todoItemsJson = userData.elementAt(0)["self_todo"] as String?;
if (todoItemsJson == null) return [];
List<TodoItem> todoItems = (jsonDecode(todoItemsJson) as List)
.map((e) => TodoItem.fromJson(e))
.toList();
return todoItems;
}
// v5 // v5
Future<Map<String, String>> getRoundings({required String userId}) async { Future<Map<String, String>> getRoundings({required String userId}) async {
List<Map> userData = List<Map> userData =

View File

@@ -196,6 +196,13 @@ class UserDatabaseStore {
where: "id = ?", whereArgs: [userId]); where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeSelfTodoItems(List<TodoItem> todoItems,
{required String userId}) async {
String todoItemsJson = jsonEncode(todoItems.map((e) => e.json).toList());
await db.update("user_data", {"self_todo": todoItemsJson},
where: "id = ?", whereArgs: [userId]);
}
// v5 // v5
Future<void> storeRoundings(Map<String, String> roundings, Future<void> storeRoundings(Map<String, String> roundings,
{required String userId}) async { {required String userId}) async {

View File

@@ -8,10 +8,10 @@ class DatabaseStruct {
String typeName = ""; String typeName = "";
switch (type.runtimeType) { switch (type.runtimeType) {
case int: case const (int):
typeName = "integer"; typeName = "integer";
break; break;
case String: case const (String):
typeName = "text"; typeName = "text";
break; break;
} }

View File

@@ -71,9 +71,11 @@ class NotificationsHelper {
// Refresh kreta login for current user // Refresh kreta login for current user
final status = StatusProvider(); final status = StatusProvider();
KretaClient kretaClientForUser = KretaClient( KretaClient kretaClientForUser = KretaClient(
user: userProviderForUser, user: userProviderForUser,
settings: settingsProvider, settings: settingsProvider,
status: status); database: database,
status: status,
);
await kretaClientForUser.refreshLogin(); await kretaClientForUser.refreshLogin();
// Process notifications for current user // Process notifications for current user
@@ -95,7 +97,7 @@ class NotificationsHelper {
/* /*
ezt a kódot nagyon szépen megírta az AI, picit szerkesztgettem is rajta ezt a kódot nagyon szépen megírta az AI, picit szerkesztgettem is rajta //pearoo what did you do - zypherift
nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén kima bántani fog nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén kima bántani fog
Future<void> liveNotification(UserProvider currentuserProvider, KretaClient currentKretaClient) async { Future<void> liveNotification(UserProvider currentuserProvider, KretaClient currentKretaClient) async {
@@ -212,7 +214,7 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
), ),
notificationDetails, notificationDetails,
payload: "grades"); payload: "grades");
} else if (settingsProvider.gradeOpeningFun) { } else if (settingsProvider.gradeOpeningFun) {
// if surprise grades are enabled, show a notification without the grade // if surprise grades are enabled, show a notification without the grade
await flutterLocalNotificationsPlugin.show( await flutterLocalNotificationsPlugin.show(
grade.id.hashCode, grade.id.hashCode,
@@ -485,9 +487,10 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
lesson.lessonIndex, lesson.lessonIndex,
lesson.name, lesson.name,
dayTitle(lesson.date), dayTitle(lesson.date),
lesson.substituteTeacher!.isRenamed ((lesson.substituteTeacher?.isRenamed ?? false)
? lesson.substituteTeacher!.renamedTo! ? lesson.substituteTeacher?.renamedTo!
: lesson.substituteTeacher!.name : lesson.substituteTeacher?.name) ??
'',
], ],
), ),
notificationDetails, notificationDetails,
@@ -505,9 +508,10 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
dayTitle(lesson.date), dayTitle(lesson.date),
lesson.lessonIndex, lesson.lessonIndex,
lesson.name, lesson.name,
lesson.substituteTeacher!.isRenamed ((lesson.substituteTeacher?.isRenamed ?? false)
? lesson.substituteTeacher!.renamedTo! ? lesson.substituteTeacher?.renamedTo!
: lesson.substituteTeacher!.name : lesson.substituteTeacher?.name) ??
'',
], ],
), ),
notificationDetails, notificationDetails,
@@ -525,9 +529,10 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
lesson.lessonIndex, lesson.lessonIndex,
lesson.name, lesson.name,
dayTitle(lesson.date), dayTitle(lesson.date),
lesson.substituteTeacher!.isRenamed ((lesson.substituteTeacher?.isRenamed ?? false)
? lesson.substituteTeacher!.renamedTo! ? lesson.substituteTeacher?.renamedTo!
: lesson.substituteTeacher!.name : lesson.substituteTeacher?.name) ??
'',
], ],
), ),
notificationDetails, notificationDetails,
@@ -608,9 +613,10 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
lesson.lessonIndex, lesson.lessonIndex,
lesson.name, lesson.name,
dayTitle(lesson.date), dayTitle(lesson.date),
lesson.substituteTeacher!.isRenamed ((lesson.substituteTeacher?.isRenamed ?? false)
? lesson.substituteTeacher!.renamedTo! ? lesson.substituteTeacher?.renamedTo!
: lesson.substituteTeacher!.name : lesson.substituteTeacher?.name) ??
'',
], ],
), ),
notificationDetails, notificationDetails,
@@ -629,9 +635,10 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
dayTitle(lesson.date), dayTitle(lesson.date),
lesson.lessonIndex, lesson.lessonIndex,
lesson.name, lesson.name,
lesson.substituteTeacher!.isRenamed ((lesson.substituteTeacher?.isRenamed ?? false)
? lesson.substituteTeacher!.renamedTo! ? lesson.substituteTeacher?.renamedTo!
: lesson.substituteTeacher!.name : lesson.substituteTeacher?.name) ??
'',
], ],
), ),
notificationDetails, notificationDetails,
@@ -650,7 +657,7 @@ nem lesz tőle használhatatlan az app, de kikommenteltem, mert még a végén k
lesson.lessonIndex, lesson.lessonIndex,
lesson.name, lesson.name,
dayTitle(lesson.date), dayTitle(lesson.date),
lesson.substituteTeacher!.isRenamed (lesson.substituteTeacher?.isRenamed ?? false)
? lesson.substituteTeacher!.renamedTo! ? lesson.substituteTeacher!.renamedTo!
: lesson.substituteTeacher!.name : lesson.substituteTeacher!.name
], ],

View File

@@ -6,10 +6,9 @@ import 'package:share_plus/share_plus.dart';
class ShareHelper { class ShareHelper {
static Future<void> shareText(String text, {String? subject}) => static Future<void> shareText(String text, {String? subject}) =>
Share.share(text, subject: subject); Share.share(text, subject: subject);
// ignore: deprecated_member_use
static Future<void> shareFile(String path, {String? text, String? subject}) => static Future<void> shareFile(String path, {String? text, String? subject}) =>
// ignore: deprecated_member_use Share.shareXFiles([XFile(path)], text: text, subject: subject);
Share.shareFiles([path], text: text, subject: subject);
static Future<void> shareAttachment(Attachment attachment, static Future<void> shareAttachment(Attachment attachment,
{required BuildContext context}) async { {required BuildContext context}) async {

View File

@@ -292,3 +292,105 @@ class ShortSubject {
return subject?.name.capital() ?? subjectName?.capital() ?? "?"; return subject?.name.capital() ?? subjectName?.capital() ?? "?";
} }
} }
// new v5 thingie
class SubjectBooklet {
// static String resolveName({GradeSubject? subject, String? subjectName}) =>
// _resolve(subject: subject, subjectName: subjectName).name;
static String resolveVariant(
{GradeSubject? subject,
String? subjectName,
required BuildContext context}) =>
_resolve(subject: subject, subjectName: subjectName);
static String _resolve({GradeSubject? subject, String? subjectName}) {
assert(!(subject == null && subjectName == null));
String name = (subject?.name ?? subjectName ?? "")
.toLowerCase()
.specialChars()
.trim();
String category =
subject?.category.description.toLowerCase().specialChars() ?? "";
String basePath = "assets/svg/cover_arts";
// todo: check for categories
if (RegExp("mate(k|matika)").hasMatch(name) || category == "matematika") {
return "$basePath/grid.svg";
} else if (RegExp("magyar nyelv|nyelvtan").hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("irodalom").hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("tor(i|tenelem)").hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("foldrajz").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("rajz|muvtori|muveszet|vizualis").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("fizika").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("^enek|zene|szolfezs|zongora|korus").hasMatch(name)) {
return "$basePath/vocal.svg";
} else if (RegExp("^tes(i|tneveles)|sport|edzeselmelet").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("kemia").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("biologia").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp(
"kornyezet|termeszet ?(tudomany|ismeret)|hon( es nep)?ismeret")
.hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("(hit|erkolcs)tan|vallas|etika|bibliaismeret")
.hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("penzugy").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("informatika|szoftver|iroda|digitalis").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("prog").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("halozat").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("szinhaz").hasMatch(name)) {
return "$basePath/vocal.svg";
} else if (RegExp("film|media").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("elektro(tech)?nika").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("gepesz|mernok|ipar").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("technika").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("tanc").hasMatch(name)) {
return "$basePath/vocal.svg";
} else if (RegExp("filozofia").hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("osztaly(fonoki|kozosseg)|kozossegi|neveles")
.hasMatch(name) ||
name == "ofo") {
return "$basePath/plain.svg";
} else if (RegExp("gazdasag").hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("szorgalom").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("magatartas").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp(
"angol|nemet|francia|olasz|orosz|spanyol|latin|kinai|nyelv")
.hasMatch(name)) {
return "$basePath/line.svg";
} else if (RegExp("linux").hasMatch(name)) {
return "$basePath/plain.svg";
} else if (RegExp("adatbazis").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("asztali alkalmazasok").hasMatch(name)) {
return "$basePath/grid.svg";
} else if (RegExp("projekt").hasMatch(name)) {
return "$basePath/plain.svg";
}
return "$basePath/plain.svg";
}
}

View File

@@ -0,0 +1,130 @@
import 'dart:math';
class Uwuifier {
final Map<String, double> _spacesModifier;
final double _wordsModifier;
final List<String> faces = [
"OwO",
"UwU",
">w<",
"^w^",
"^-^",
":3",
];
final List<List<String>> uwuMap = [
['(?:r|l)', 'w'],
['(?:R|L)', 'W'],
['na', 'nya'],
['ne', 'nye'],
['NA', 'NYA'],
['NE', 'NYE'],
['Na', 'Nya'],
['Ne', 'Nye'],
['no', 'nyo'],
['NO', 'NYO'],
['No', 'Nyo'],
['nO', 'NYo'],
['ove', 'uv'],
['no', 'nwo'],
];
final Map<String, String> _uwuCache = {};
Uwuifier({
Map<String, double>? spaces,
double? words,
}) : _spacesModifier = spaces ?? {
'faces': 0.05,
'actions': 0.0,
'stutters': 0.1,
},
_wordsModifier = words ?? 1.0;
String uwuifyWords(String sentence) {
final words = sentence.split(' ');
final uwuifiedSentence = words.map((word) {
if (isAt(word) || isUri(word)) return word;
var seed = Random().nextDouble();
for (final uwuMapEntry in uwuMap) {
final oldWord = RegExp(uwuMapEntry[0], caseSensitive: false);
final newWord = uwuMapEntry[1];
if (seed > _wordsModifier) continue;
word = word.replaceAll(oldWord, newWord);
}
return word;
}).join(' ');
return uwuifiedSentence;
}
String uwuifySpaces(String sentence) {
final words = sentence.split(' ');
final faceThreshold = _spacesModifier['faces']!;
final actionThreshold = _spacesModifier['actions']! + faceThreshold;
final stutterThreshold = _spacesModifier['stutters']! + actionThreshold;
final uwuifiedSentence = words.map((word) {
final seed = Random().nextDouble();
final firstCharacter = word[0];
if (seed <= faceThreshold && faces.isNotEmpty) {
word += ' ${faces[Random().nextInt(faces.length)]}';
} else if (seed <= actionThreshold) {
// Skip actions
} else if (seed <= stutterThreshold && !isUri(word)) {
if (Random().nextInt(10) == 0) {
final stutter = Random().nextInt(3);
return '${firstCharacter * (stutter + 1)}-$word';
}
}
return word;
}).join(' ');
return uwuifiedSentence;
}
String uwuifySentence(String sentence) {
if (_uwuCache.containsKey(sentence)) {
return _uwuCache[sentence]!;
}
var uwuifiedSentence = uwuifyWords(sentence);
uwuifiedSentence = uwuifySpaces(uwuifiedSentence);
_uwuCache[sentence] = uwuifiedSentence;
return uwuifiedSentence;
}
bool isAt(String value) {
return value.startsWith('@');
}
bool isUri(String? value) {
if (value == null) return false;
final split = RegExp(
r'''(?:([^:/?#]+):)?(?:\/\/([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))?''')
.firstMatch(value);
if (split == null) return false;
final scheme = split.group(1);
final authority = split.group(2);
final path = split.group(3);
if (!(scheme?.isNotEmpty == true && path?.isNotEmpty == true)) return false;
if (authority != null && authority.isNotEmpty) {
if (!(path?.isEmpty == true || path!.startsWith('/'))) return false;
} else if (path?.startsWith('//') == true) {
return false;
}
if (!RegExp(r'''^[a-z][a-z0-9+\-\.]*$''', caseSensitive: false)
.hasMatch(scheme!.toLowerCase())) {
return false;
}
return true;
}
}

View File

@@ -15,6 +15,8 @@ import 'package:refilc/utils/service_locator.dart';
import 'package:refilc_mobile_ui/screens/error_screen.dart'; import 'package:refilc_mobile_ui/screens/error_screen.dart';
import 'package:refilc_mobile_ui/screens/error_report_screen.dart'; import 'package:refilc_mobile_ui/screens/error_report_screen.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:shake_flutter/models/shake_report_configuration.dart';
import 'package:shake_flutter/shake_flutter.dart';
import 'helpers/live_activity_helper.dart'; import 'helpers/live_activity_helper.dart';
@@ -38,6 +40,28 @@ void main() async {
BackgroundFetch.registerHeadlessTask(backgroundHeadlessTask); BackgroundFetch.registerHeadlessTask(backgroundHeadlessTask);
// setting up things for shakebugs
// List<ShakePickerItem> pickerItems = [
// ShakePickerItem('Bug', 'Hiba', tag: 'bug'),
// ShakePickerItem('Suggestion', 'Fejlesztési javaslat', tag: 'suggestion'),
// ShakePickerItem('Question', 'Kérdés', tag: 'question')
// ];
// ShakePicker picker =
// ShakePicker('Feedback type', 'Visszajelzés típusa', pickerItems);
// ShakeTitle title = ShakeTitle('Title', 'Leírás', required: true);
// ShakeInspectButton inspect = ShakeInspectButton();
// ShakeAttachments attachments = ShakeAttachments();
// List<ShakeFormComponent> components = [picker, title, inspect, attachments];
// ShakeForm form = ShakeForm(components);
// Shake.setShakeForm(form);
// shakebugs initialization
// Shake.setInvokeShakeOnScreenshot(true);
Shake.start('Y44AwzfY6091xO2Nr0w59RHSpNxJhhiSFGs4enmoJwelN82ZRzTLE5X');
// pre-cache required icons // pre-cache required icons
const todaySvg = SvgAssetLoader('assets/svg/menu_icons/today_selected.svg'); const todaySvg = SvgAssetLoader('assets/svg/menu_icons/today_selected.svg');
const gradesSvg = SvgAssetLoader('assets/svg/menu_icons/grades_selected.svg'); const gradesSvg = SvgAssetLoader('assets/svg/menu_icons/grades_selected.svg');
@@ -170,6 +194,18 @@ Widget errorBuilder(FlutterErrorDetails details) {
Navigator.of(context, rootNavigator: true) Navigator.of(context, rootNavigator: true)
.push(MaterialPageRoute(builder: (context) { .push(MaterialPageRoute(builder: (context) {
if (kReleaseMode) { if (kReleaseMode) {
// silent report to shakebugs
ShakeReportConfiguration configuration = ShakeReportConfiguration();
configuration.blackBoxData = true;
configuration.activityHistoryData = true;
configuration.screenshot = true;
configuration.video = false;
Shake.silentReport(
configuration: configuration,
description:
'Silent Report #${DateTime.now().year}${DateTime.now().month}${DateTime.now().day}',
);
// show error report screen
return ErrorReportScreen(details); return ErrorReportScreen(details);
} else { } else {
return ErrorScreen(details); return ErrorScreen(details);
@@ -244,7 +280,8 @@ void backgroundHeadlessTask(HeadlessTask task) {
LiveActivityHelper().backgroundJob(); LiveActivityHelper().backgroundJob();
} else { } else {
NotificationsHelper().backgroundJob(); NotificationsHelper().backgroundJob();
} BackgroundFetch.finish(task.taskId); }
BackgroundFetch.finish(task.taskId);
} }
Future<void> initAdditionalBackgroundFetch() async { Future<void> initAdditionalBackgroundFetch() async {

View File

@@ -33,3 +33,37 @@ class SelfNote {
'note_type': noteType == NoteType.image ? 'image' : 'text', 'note_type': noteType == NoteType.image ? 'image' : 'text',
}; };
} }
class TodoItem {
String id;
String title;
String content;
bool done;
Map? json;
TodoItem({
required this.id,
required this.title,
required this.content,
required this.done,
this.json,
});
factory TodoItem.fromJson(Map json) {
return TodoItem(
id: json['id'],
title: json['title'],
content: json['content'],
done: json['done'],
json: json,
);
}
Map<String, dynamic> get toJson => {
'id': id,
'title': title,
'content': content,
'done': done,
};
}

View File

@@ -96,6 +96,7 @@ class SettingsProvider extends ChangeNotifier {
// more // more
bool _showBreaks; bool _showBreaks;
String _fontFamily; String _fontFamily;
bool _titleOnlyFont;
String _plusSessionId; String _plusSessionId;
String _calSyncRoomLocation; String _calSyncRoomLocation;
bool _calSyncShowExams; bool _calSyncShowExams;
@@ -105,6 +106,8 @@ class SettingsProvider extends ChangeNotifier {
bool _navShadow; bool _navShadow;
bool _newColors; bool _newColors;
bool _uwuMode; bool _uwuMode;
bool _newPopups;
List<String> _unseenNewFeatures;
// quick settings // quick settings
bool _qTimetableLessonNum; bool _qTimetableLessonNum;
bool _qTimetableSubTiles; bool _qTimetableSubTiles;
@@ -167,6 +170,7 @@ class SettingsProvider extends ChangeNotifier {
required String pinSetNotify, required String pinSetNotify,
required String pinSetExtras, required String pinSetExtras,
required String fontFamily, required String fontFamily,
required bool titleOnlyFont,
required String plusSessionId, required String plusSessionId,
required String calSyncRoomLocation, required String calSyncRoomLocation,
required bool calSyncShowExams, required bool calSyncShowExams,
@@ -176,6 +180,8 @@ class SettingsProvider extends ChangeNotifier {
required bool navShadow, required bool navShadow,
required bool newColors, required bool newColors,
required bool uwuMode, required bool uwuMode,
required bool newPopups,
required List<String> unseenNewFeatures,
required bool qTimetableLessonNum, required bool qTimetableLessonNum,
required bool qTimetableSubTiles, required bool qTimetableSubTiles,
required bool qSubjectsSubTiles, required bool qSubjectsSubTiles,
@@ -235,6 +241,7 @@ class SettingsProvider extends ChangeNotifier {
_pinSetNotify = pinSetNotify, _pinSetNotify = pinSetNotify,
_pinSetExtras = pinSetExtras, _pinSetExtras = pinSetExtras,
_fontFamily = fontFamily, _fontFamily = fontFamily,
_titleOnlyFont = titleOnlyFont,
_plusSessionId = plusSessionId, _plusSessionId = plusSessionId,
_calSyncRoomLocation = calSyncRoomLocation, _calSyncRoomLocation = calSyncRoomLocation,
_calSyncShowExams = calSyncShowExams, _calSyncShowExams = calSyncShowExams,
@@ -244,6 +251,8 @@ class SettingsProvider extends ChangeNotifier {
_navShadow = navShadow, _navShadow = navShadow,
_newColors = newColors, _newColors = newColors,
_uwuMode = uwuMode, _uwuMode = uwuMode,
_newPopups = newPopups,
_unseenNewFeatures = unseenNewFeatures,
_qTimetableLessonNum = qTimetableLessonNum, _qTimetableLessonNum = qTimetableLessonNum,
_qTimetableSubTiles = qTimetableSubTiles, _qTimetableSubTiles = qTimetableSubTiles,
_qSubjectsSubTiles = qSubjectsSubTiles; _qSubjectsSubTiles = qSubjectsSubTiles;
@@ -322,6 +331,7 @@ class SettingsProvider extends ChangeNotifier {
pinSetNotify: map['notify_s_pin'], pinSetNotify: map['notify_s_pin'],
pinSetExtras: map['extras_s_pin'], pinSetExtras: map['extras_s_pin'],
fontFamily: map['font_family'], fontFamily: map['font_family'],
titleOnlyFont: map['title_only_font'] == 1,
plusSessionId: map['plus_session_id'], plusSessionId: map['plus_session_id'],
calSyncRoomLocation: map['cal_sync_room_location'], calSyncRoomLocation: map['cal_sync_room_location'],
calSyncShowExams: map['cal_sync_show_exams'] == 1, calSyncShowExams: map['cal_sync_show_exams'] == 1,
@@ -331,6 +341,8 @@ class SettingsProvider extends ChangeNotifier {
navShadow: map['nav_shadow'] == 1, navShadow: map['nav_shadow'] == 1,
newColors: map['new_colors'] == 1, newColors: map['new_colors'] == 1,
uwuMode: map['uwu_mode'] == 1, uwuMode: map['uwu_mode'] == 1,
newPopups: map['new_popups'] == 1,
unseenNewFeatures: jsonDecode(map["unseen_new_features"]).cast<String>(),
qTimetableLessonNum: map['q_timetable_lesson_num'] == 1, qTimetableLessonNum: map['q_timetable_lesson_num'] == 1,
qTimetableSubTiles: map['q_timetable_sub_tiles'] == 1, qTimetableSubTiles: map['q_timetable_sub_tiles'] == 1,
qSubjectsSubTiles: map['q_subjects_sub_tiles'] == 1, qSubjectsSubTiles: map['q_subjects_sub_tiles'] == 1,
@@ -397,6 +409,7 @@ class SettingsProvider extends ChangeNotifier {
"notify_s_pin": _pinSetNotify, "notify_s_pin": _pinSetNotify,
"extras_s_pin": _pinSetExtras, "extras_s_pin": _pinSetExtras,
"font_family": _fontFamily, "font_family": _fontFamily,
"title_only_font": _titleOnlyFont ? 1 : 0,
"plus_session_id": _plusSessionId, "plus_session_id": _plusSessionId,
"cal_sync_room_location": _calSyncRoomLocation, "cal_sync_room_location": _calSyncRoomLocation,
"cal_sync_show_exams": _calSyncShowExams ? 1 : 0, "cal_sync_show_exams": _calSyncShowExams ? 1 : 0,
@@ -406,6 +419,8 @@ class SettingsProvider extends ChangeNotifier {
"nav_shadow": _navShadow ? 1 : 0, "nav_shadow": _navShadow ? 1 : 0,
"new_colors": _newColors ? 1 : 0, "new_colors": _newColors ? 1 : 0,
"uwu_mode": _uwuMode ? 1 : 0, "uwu_mode": _uwuMode ? 1 : 0,
"new_popups": _newPopups ? 1 : 0,
"unseen_new_features": jsonEncode(_unseenNewFeatures),
"q_timetable_lesson_num": _qTimetableLessonNum ? 1 : 0, "q_timetable_lesson_num": _qTimetableLessonNum ? 1 : 0,
"q_timetable_sub_tiles": _qTimetableSubTiles ? 1 : 0, "q_timetable_sub_tiles": _qTimetableSubTiles ? 1 : 0,
"q_subjects_sub_tiles": _qSubjectsSubTiles ? 1 : 0, "q_subjects_sub_tiles": _qSubjectsSubTiles ? 1 : 0,
@@ -476,6 +491,7 @@ class SettingsProvider extends ChangeNotifier {
pinSetNotify: '', pinSetNotify: '',
pinSetExtras: '', pinSetExtras: '',
fontFamily: '', fontFamily: '',
titleOnlyFont: false,
plusSessionId: '', plusSessionId: '',
calSyncRoomLocation: 'location', calSyncRoomLocation: 'location',
calSyncShowExams: true, calSyncShowExams: true,
@@ -485,6 +501,8 @@ class SettingsProvider extends ChangeNotifier {
navShadow: true, navShadow: true,
newColors: true, newColors: true,
uwuMode: false, uwuMode: false,
newPopups: true,
unseenNewFeatures: ['grade_exporting'],
qTimetableLessonNum: true, qTimetableLessonNum: true,
qTimetableSubTiles: true, qTimetableSubTiles: true,
qSubjectsSubTiles: true, qSubjectsSubTiles: true,
@@ -546,6 +564,7 @@ class SettingsProvider extends ChangeNotifier {
String get currentThemeCreator => _currentThemeCreator; String get currentThemeCreator => _currentThemeCreator;
bool get showBreaks => _showBreaks; bool get showBreaks => _showBreaks;
String get fontFamily => _fontFamily; String get fontFamily => _fontFamily;
bool get titleOnlyFont => _titleOnlyFont;
String get plusSessionId => _plusSessionId; String get plusSessionId => _plusSessionId;
String get calSyncRoomLocation => _calSyncRoomLocation; String get calSyncRoomLocation => _calSyncRoomLocation;
bool get calSyncShowExams => _calSyncShowExams; bool get calSyncShowExams => _calSyncShowExams;
@@ -555,6 +574,8 @@ class SettingsProvider extends ChangeNotifier {
bool get navShadow => _navShadow; bool get navShadow => _navShadow;
bool get newColors => _newColors; bool get newColors => _newColors;
bool get uwuMode => _uwuMode; bool get uwuMode => _uwuMode;
bool get newPopups => _newPopups;
List<String> get unseenNewFeatures => _unseenNewFeatures;
bool get qTimetableLessonNum => _qTimetableLessonNum; bool get qTimetableLessonNum => _qTimetableLessonNum;
bool get qTimetableSubTiles => _qTimetableSubTiles; bool get qTimetableSubTiles => _qTimetableSubTiles;
bool get qSubjectsSubTiles => _qSubjectsSubTiles; bool get qSubjectsSubTiles => _qSubjectsSubTiles;
@@ -612,6 +633,7 @@ class SettingsProvider extends ChangeNotifier {
String? currentThemeCreator, String? currentThemeCreator,
bool? showBreaks, bool? showBreaks,
String? fontFamily, String? fontFamily,
bool? titleOnlyFont,
String? plusSessionId, String? plusSessionId,
String? calSyncRoomLocation, String? calSyncRoomLocation,
bool? calSyncShowExams, bool? calSyncShowExams,
@@ -621,6 +643,8 @@ class SettingsProvider extends ChangeNotifier {
bool? navShadow, bool? navShadow,
bool? newColors, bool? newColors,
bool? uwuMode, bool? uwuMode,
bool? newPopups,
List<String>? unseenNewFeatures,
bool? qTimetableLessonNum, bool? qTimetableLessonNum,
bool? qTimetableSubTiles, bool? qTimetableSubTiles,
bool? qSubjectsSubTiles, bool? qSubjectsSubTiles,
@@ -777,6 +801,9 @@ class SettingsProvider extends ChangeNotifier {
if (fontFamily != null && fontFamily != _fontFamily) { if (fontFamily != null && fontFamily != _fontFamily) {
_fontFamily = fontFamily; _fontFamily = fontFamily;
} }
if (titleOnlyFont != null && titleOnlyFont != _titleOnlyFont) {
_titleOnlyFont = titleOnlyFont;
}
if (plusSessionId != null && plusSessionId != _plusSessionId) { if (plusSessionId != null && plusSessionId != _plusSessionId) {
_plusSessionId = plusSessionId; _plusSessionId = plusSessionId;
} }
@@ -806,6 +833,12 @@ class SettingsProvider extends ChangeNotifier {
if (uwuMode != null && uwuMode != _uwuMode) { if (uwuMode != null && uwuMode != _uwuMode) {
_uwuMode = uwuMode; _uwuMode = uwuMode;
} }
if (newPopups != null && newPopups != _newPopups) {
_newPopups = newPopups;
}
if (unseenNewFeatures != null && unseenNewFeatures != _unseenNewFeatures) {
_unseenNewFeatures = unseenNewFeatures;
}
if (qTimetableLessonNum != null && if (qTimetableLessonNum != null &&
qTimetableLessonNum != _qTimetableLessonNum) { qTimetableLessonNum != _qTimetableLessonNum) {
_qTimetableLessonNum = qTimetableLessonNum; _qTimetableLessonNum = qTimetableLessonNum;

View File

@@ -16,8 +16,12 @@ class User {
Role role; Role role;
String nickname; String nickname;
String picture; String picture;
int gradeStreak;
// new login method
String refreshToken;
String get displayName => nickname != '' ? nickname : name; String get displayName => nickname != '' ? nickname : name;
bool get hasStreak => gradeStreak > 0;
User({ User({
String? id, String? id,
@@ -29,6 +33,8 @@ class User {
required this.role, required this.role,
this.nickname = "", this.nickname = "",
this.picture = "", this.picture = "",
this.gradeStreak = 0,
required this.refreshToken,
}) { }) {
if (id != null) { if (id != null) {
this.id = id; this.id = id;
@@ -57,6 +63,8 @@ class User {
role: Role.values[map["role"] ?? 0], role: Role.values[map["role"] ?? 0],
nickname: map["nickname"] ?? "", nickname: map["nickname"] ?? "",
picture: map["picture"] ?? "", picture: map["picture"] ?? "",
gradeStreak: map["grade_streak"] ?? 0,
refreshToken: map["refresh_token"] ?? "",
); );
} }
@@ -71,6 +79,8 @@ class User {
"role": role.index, "role": role.index,
"nickname": nickname, "nickname": nickname,
"picture": picture, "picture": picture,
"grade_streak": gradeStreak,
"refresh_token": refreshToken,
}; };
} }

View File

@@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
import 'package:home_widget/home_widget.dart'; import 'package:home_widget/home_widget.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:shake_flutter/models/shake_theme.dart';
import 'package:shake_flutter/shake_flutter.dart';
Future<bool?> updateWidget() async { Future<bool?> updateWidget() async {
try { try {
@@ -22,7 +24,9 @@ class ThemeModeObserver extends ChangeNotifier {
ThemeMode get themeMode => _themeMode; ThemeMode get themeMode => _themeMode;
bool get updateNavbarColor => _updateNavbarColor; bool get updateNavbarColor => _updateNavbarColor;
ThemeModeObserver({ThemeMode initialTheme = ThemeMode.system, bool updateNavbarColor = true}) ThemeModeObserver(
{ThemeMode initialTheme = ThemeMode.system,
bool updateNavbarColor = true})
: _themeMode = initialTheme, : _themeMode = initialTheme,
_updateNavbarColor = updateNavbarColor; _updateNavbarColor = updateNavbarColor;
@@ -31,5 +35,12 @@ class ThemeModeObserver extends ChangeNotifier {
_updateNavbarColor = updateNavbarColor; _updateNavbarColor = updateNavbarColor;
if (Platform.isAndroid) updateWidget(); if (Platform.isAndroid) updateWidget();
notifyListeners(); notifyListeners();
// change shake theme as well
ShakeTheme darkTheme = ShakeTheme();
darkTheme.accentColor = "#FFFFFF";
ShakeTheme lightTheme = ShakeTheme();
lightTheme.accentColor = "#000000";
Shake.setShakeTheme(mode == ThemeMode.dark ? darkTheme : lightTheme);
} }
} }

View File

@@ -104,9 +104,10 @@ class AppTheme {
brightness: Brightness.light, brightness: Brightness.light,
useMaterial3: true, useMaterial3: true,
fontFamily: _defaultFontFamily, fontFamily: _defaultFontFamily,
textTheme: textTheme: !settings.titleOnlyFont
googleFontsMap[settings.fontFamily]?.apply(bodyColor: textColor) ?? ? (googleFontsMap[settings.fontFamily]?.apply(bodyColor: textColor) ??
const TextTheme().apply(bodyColor: textColor), const TextTheme().apply(bodyColor: textColor))
: null,
scaffoldBackgroundColor: backgroundColor, scaffoldBackgroundColor: backgroundColor,
primaryColor: lightColors.filc, primaryColor: lightColors.filc,
dividerColor: const Color(0x00000000), dividerColor: const Color(0x00000000),
@@ -124,8 +125,6 @@ class AppTheme {
onTertiary: onTertiary:
(newTertiary.computeLuminance() > 0.5 ? Colors.black : Colors.white) (newTertiary.computeLuminance() > 0.5 ? Colors.black : Colors.white)
.withOpacity(.9), .withOpacity(.9),
background: highlightColor,
onBackground: Colors.black.withOpacity(.9),
brightness: Brightness.light, brightness: Brightness.light,
error: lightColors.red, error: lightColors.red,
onError: Colors.white.withOpacity(.9), onError: Colors.white.withOpacity(.9),
@@ -140,9 +139,9 @@ class AppTheme {
indicatorColor: indicatorColor:
accent.withOpacity(accentColor == AccentColor.adaptive ? 0.4 : 0.8), accent.withOpacity(accentColor == AccentColor.adaptive ? 0.4 : 0.8),
iconTheme: iconTheme:
MaterialStateProperty.all(IconThemeData(color: lightColors.text)), WidgetStateProperty.all(IconThemeData(color: lightColors.text)),
backgroundColor: highlightColor, backgroundColor: highlightColor,
labelTextStyle: MaterialStateProperty.all(TextStyle( labelTextStyle: WidgetStateProperty.all(TextStyle(
fontSize: 13.0, fontSize: 13.0,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: lightColors.text.withOpacity(0.8), color: lightColors.text.withOpacity(0.8),
@@ -229,8 +228,9 @@ class AppTheme {
brightness: Brightness.dark, brightness: Brightness.dark,
useMaterial3: true, useMaterial3: true,
fontFamily: _defaultFontFamily, fontFamily: _defaultFontFamily,
textTheme: textTheme: !settings.titleOnlyFont
googleFontsMap[settings.fontFamily]?.apply(bodyColor: textColor), ? (googleFontsMap[settings.fontFamily]?.apply(bodyColor: textColor))
: null,
scaffoldBackgroundColor: backgroundColor, scaffoldBackgroundColor: backgroundColor,
primaryColor: darkColors.filc, primaryColor: darkColors.filc,
dividerColor: const Color(0x00000000), dividerColor: const Color(0x00000000),
@@ -248,8 +248,6 @@ class AppTheme {
onTertiary: onTertiary:
(newTertiary.computeLuminance() > 0.5 ? Colors.black : Colors.white) (newTertiary.computeLuminance() > 0.5 ? Colors.black : Colors.white)
.withOpacity(.9), .withOpacity(.9),
background: highlightColor,
onBackground: Colors.white.withOpacity(.9),
brightness: Brightness.dark, brightness: Brightness.dark,
error: darkColors.red, error: darkColors.red,
onError: Colors.black.withOpacity(.9), onError: Colors.black.withOpacity(.9),
@@ -264,9 +262,9 @@ class AppTheme {
indicatorColor: indicatorColor:
accent.withOpacity(accentColor == AccentColor.adaptive ? 0.4 : 0.8), accent.withOpacity(accentColor == AccentColor.adaptive ? 0.4 : 0.8),
iconTheme: iconTheme:
MaterialStateProperty.all(IconThemeData(color: darkColors.text)), WidgetStateProperty.all(IconThemeData(color: darkColors.text)),
backgroundColor: highlightColor, backgroundColor: highlightColor,
labelTextStyle: MaterialStateProperty.all(TextStyle( labelTextStyle: WidgetStateProperty.all(TextStyle(
fontSize: 13.0, fontSize: 13.0,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: darkColors.text.withOpacity(0.8), color: darkColors.text.withOpacity(0.8),

View File

@@ -259,7 +259,7 @@ Widget filterItemBuilder(
? const EdgeInsets.symmetric(vertical: 8.0) ? const EdgeInsets.symmetric(vertical: 8.0)
: const EdgeInsets.symmetric(vertical: 4.0), : const EdgeInsets.symmetric(vertical: 4.0),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.vertical( borderRadius: BorderRadius.vertical(
top: separated || isAfterSeparated top: separated || isAfterSeparated
? const Radius.circular(16.0) ? const Radius.circular(16.0)

View File

@@ -192,6 +192,8 @@ class FilcColorPickerState extends State<FilcColorPicker> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
bool advOverride = widget.colorMode == CustomColorMode.grade ? true : false;
if (MediaQuery.of(context).orientation == Orientation.portrait || if (MediaQuery.of(context).orientation == Orientation.portrait ||
widget.portraitOnly) { widget.portraitOnly) {
return Column( return Column(
@@ -218,7 +220,7 @@ class FilcColorPickerState extends State<FilcColorPicker> {
child: colorPickerSlider(TrackType.saturation), child: colorPickerSlider(TrackType.saturation),
), ),
), ),
if (isAdvancedView) if (isAdvancedView || advOverride)
Padding( Padding(
padding: const EdgeInsets.only(left: 12.0, right: 12.0), padding: const EdgeInsets.only(left: 12.0, right: 12.0),
child: SizedBox( child: SizedBox(
@@ -230,7 +232,7 @@ class FilcColorPickerState extends State<FilcColorPicker> {
], ],
), ),
), ),
if (isAdvancedView && if ((isAdvancedView || advOverride) &&
widget.colorMode != CustomColorMode.theme && widget.colorMode != CustomColorMode.theme &&
widget.colorMode != CustomColorMode.enterId) widget.colorMode != CustomColorMode.enterId)
Padding( Padding(
@@ -295,7 +297,8 @@ class FilcColorPickerState extends State<FilcColorPicker> {
], ],
), ),
), ),
if (widget.colorMode != CustomColorMode.enterId) if (widget.colorMode != CustomColorMode.enterId &&
widget.colorMode != CustomColorMode.grade)
SizedBox( SizedBox(
height: 70 * (widget.colorMode == CustomColorMode.theme ? 2 : 1), height: 70 * (widget.colorMode == CustomColorMode.theme ? 2 : 1),
child: BlockPicker( child: BlockPicker(
@@ -347,7 +350,8 @@ class FilcColorPickerState extends State<FilcColorPicker> {
), ),
), ),
if (widget.colorMode != CustomColorMode.theme && if (widget.colorMode != CustomColorMode.theme &&
widget.colorMode != CustomColorMode.enterId) widget.colorMode != CustomColorMode.enterId &&
!advOverride)
Material( Material(
color: Colors.transparent, color: Colors.transparent,
child: InkWell( child: InkWell(

View File

@@ -364,7 +364,7 @@ class ColorPickerInputState extends State<ColorPickerInput> {
controller: textEditingController, controller: textEditingController,
style: TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,
color: Theme.of(context).colorScheme.onBackground, color: Theme.of(context).colorScheme.onSurface,
), ),
inputFormatters: [ inputFormatters: [
UpperCaseTextFormatter(), UpperCaseTextFormatter(),

View File

@@ -1,3 +1,4 @@
import 'package:i18n_extension/i18n_extension.dart';
import 'package:refilc/models/settings.dart'; import 'package:refilc/models/settings.dart';
import 'package:refilc_kreta_api/providers/exam_provider.dart'; import 'package:refilc_kreta_api/providers/exam_provider.dart';
import 'package:refilc_kreta_api/providers/homework_provider.dart'; import 'package:refilc_kreta_api/providers/homework_provider.dart';
@@ -8,7 +9,8 @@ import 'package:refilc_kreta_api/models/lesson.dart';
import 'package:refilc/utils/format.dart'; import 'package:refilc/utils/format.dart';
import 'package:refilc_mobile_ui/common/panel/panel.dart'; import 'package:refilc_mobile_ui/common/panel/panel.dart';
import 'package:refilc_mobile_ui/common/round_border_icon.dart'; import 'package:refilc_mobile_ui/common/round_border_icon.dart';
import 'package:refilc_mobile_ui/common/widgets/exam/exam_view.dart'; // import 'package:refilc_mobile_ui/common/widgets/exam/exam_view.dart';
import 'package:refilc_mobile_ui/common/widgets/exam/exam_viewable.dart';
import 'package:refilc_mobile_ui/common/widgets/homework/homework_view.dart'; import 'package:refilc_mobile_ui/common/widgets/homework/homework_view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
@@ -109,7 +111,8 @@ class LessonTile extends StatelessWidget {
title: exam.description != "" title: exam.description != ""
? exam.description ? exam.description
: exam.mode?.description ?? "exam".i18n, : exam.mode?.description ?? "exam".i18n,
onPressed: () => ExamView.show(exam, context: context), // onPressed: () => ExamView.show(exam, context: context),
onPressed: () => ExamPopup.show(context: context, exam: exam),
)); ));
} }
} }
@@ -190,7 +193,7 @@ class LessonTile extends StatelessWidget {
: Transform.translate( : Transform.translate(
offset: const Offset(0, -2.0), offset: const Offset(0, -2.0),
child: Text( child: Text(
"${DateFormat("H:mm").format(lesson.start)}-${DateFormat("H:mm").format(lesson.end)}", "${DateFormat("E, H:mm", I18n.of(context).locale.toString()).format(lesson.start)}-${DateFormat("H:mm").format(lesson.end)}",
textAlign: TextAlign.start, textAlign: TextAlign.start,
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,

View File

@@ -39,4 +39,16 @@ class JwtUtils {
} }
return null; return null;
} }
static String? getInstituteFromJWT(String jwt) {
var jwtData = decodeJwt(jwt);
return jwtData?["kreta:institute_code"];
}
static String? getUsernameFromJWT(String jwt) {
var jwtData = decodeJwt(jwt);
return jwtData?["kreta:user_name"];
}
} }

View File

@@ -3,10 +3,10 @@ description: "Egy nem hivatalos e-KRÉTA kliens, diákoktól diákoknak."
homepage: https://refilc.hu homepage: https://refilc.hu
publish_to: "none" publish_to: "none"
version: 5.0.0+257 version: 5.0.4+274
environment: environment:
sdk: ">=2.17.0 <=3.3.2" sdk: ">=3.3.2 <=3.4.3"
dependencies: dependencies:
flutter: flutter:
@@ -25,9 +25,9 @@ dependencies:
flutter_localizations: flutter_localizations:
sdk: flutter sdk: flutter
i18n_extension: ^11.0.11 i18n_extension: ^12.0.1
sqflite: ^2.2.0+2 sqflite: ^2.2.0+2
intl: ^0.18.1 intl: ^0.19.0
provider: ^6.1.1 provider: ^6.1.1
http: ^1.1.2 http: ^1.1.2
uuid: ^4.2.1 uuid: ^4.2.1
@@ -39,40 +39,46 @@ dependencies:
# ref: master # ref: master
path_provider: ^2.0.2 path_provider: ^2.0.2
permission_handler: ^11.0.1 permission_handler: ^11.0.1
share_plus: ^7.0.2 share_plus: ^9.0.0
connectivity_plus: ^5.0.2 connectivity_plus: ^6.0.3
flutter_displaymode: ^0.6.0 flutter_displaymode: ^0.6.0
quick_actions: ^1.0.1 quick_actions: ^1.0.1
animated_list_plus: ^0.5.0 animated_list_plus: ^0.5.0
dynamic_color: ^1.2.2 dynamic_color: ^1.2.2
material_color_utilities: ^0.8.0 material_color_utilities: ^0.8.0
crypto: ^3.0.2 crypto: ^3.0.2
elegant_notification: ^1.6.1 elegant_notification: ^2.2.0
flutter_feather_icons: ^2.0.0+1 flutter_feather_icons: ^2.0.0+1
live_activities: ^1.7.4 live_activities: ^1.7.4
animated_flip_counter: ^0.2.5 animated_flip_counter: ^0.3.4
lottie: ^3.1.0 lottie: ^3.1.0
rive: ^0.12.4 rive: ^0.12.4
animated_background: ^2.0.0 animated_background: ^2.0.0
dropdown_button2: ^2.3.9 dropdown_button2: ^2.3.9
home_widget: ^0.4.1 home_widget:
git:
url: https://github.com/refilc/home_widget.git
ref: flutter-beta
flutter_expandable_fab: ^2.0.0 flutter_expandable_fab: ^2.0.0
uni_links: ^0.5.1 uni_links: ^0.5.1
url_launcher: ^6.1.6 url_launcher: ^6.1.6
workmanager: ^0.5.1 workmanager:
git:
url: https://github.com/refilc/flutter_workmanager.git
ref: v0.5.1
flutter_svg: ^2.0.10+1 flutter_svg: ^2.0.10+1
image_picker: ^1.0.7 image_picker: ^1.0.7
animations: ^2.0.1 animations: ^2.0.1
background_fetch: ^1.1.5 background_fetch: ^1.1.5
flutter_local_notifications: ^16.2.0 flutter_local_notifications: ^17.1.2
package_info_plus: ^5.0.1 package_info_plus: ^8.0.0
screenshot: ^2.1.0 screenshot: ^3.0.0
flutter_staggered_grid_view: ^0.7.0 flutter_staggered_grid_view: ^0.7.0
sqflite_common_ffi_web: ^0.4.0 sqflite_common_ffi_web: ^0.4.0
image_crop: image_crop:
git: git:
url: https://github.com/kimaah/image_crop.git url: https://github.com/kimaah/image_crop.git
googleapis: ^12.0.0 googleapis: ^13.2.0
google_sign_in: ^6.2.1 google_sign_in: ^6.2.1
extension_google_sign_in_as_googleapis_auth: ^2.0.12 extension_google_sign_in_as_googleapis_auth: ^2.0.12
maps_launcher: ^2.2.0 maps_launcher: ^2.2.0
@@ -82,9 +88,10 @@ dependencies:
xml: ^6.5.0 xml: ^6.5.0
carousel_slider: ^4.2.1 carousel_slider: ^4.2.1
flutter_portal: ^1.1.4 flutter_portal: ^1.1.4
shake_flutter: ^17.0.0
dev_dependencies: dev_dependencies:
flutter_lints: ^3.0.1 flutter_lints: ^4.0.0
flutter_launcher_icons: "^0.13.1" flutter_launcher_icons: "^0.13.1"
flutter_native_splash: "^2.3.10" flutter_native_splash: "^2.3.10"
sqflite_common_ffi: ^2.0.0+3 sqflite_common_ffi: ^2.0.0+3
@@ -104,6 +111,7 @@ flutter:
- assets/svg/menu_icons/ - assets/svg/menu_icons/
- assets/other/dirtywords.xml - assets/other/dirtywords.xml
- assets/svg/ - assets/svg/
- assets/svg/cover_arts/
fonts: fonts:
- family: FilcIcons - family: FilcIcons

View File

@@ -41,7 +41,7 @@ class FilterBar extends StatelessWidget implements PreferredSizeWidget {
color: Theme.of(context).colorScheme.secondary.withOpacity(0.25), color: Theme.of(context).colorScheme.secondary.withOpacity(0.25),
borderRadius: BorderRadius.circular(45.0), borderRadius: BorderRadius.circular(45.0),
), ),
overlayColor: MaterialStateProperty.all(const Color(0x00000000)), overlayColor: WidgetStateProperty.all(const Color(0x00000000)),
// Tabs // Tabs
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
tabs: items, tabs: items,

View File

@@ -287,7 +287,7 @@ class AbsencesPageState extends State<AbsencesPage>
return FadeThroughTransition( return FadeThroughTransition(
animation: primaryAnimation, animation: primaryAnimation,
secondaryAnimation: secondaryAnimation, secondaryAnimation: secondaryAnimation,
fillColor: Theme.of(context).colorScheme.background, fillColor: Theme.of(context).colorScheme.surface,
child: child, child: child,
); );
}, },

View File

@@ -268,7 +268,7 @@ class GradesPageState extends State<GradesPage> {
title: Padding( title: Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Text( child: Text(
"Grades".i18n, "page_title_grades".i18n,
style: TextStyle( style: TextStyle(
color: AppColors.of(context).text, color: AppColors.of(context).text,
fontSize: 32.0, fontSize: 32.0,

View File

@@ -68,7 +68,7 @@ class LoginScreenState extends State<LoginScreen> {
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.red), style: const TextStyle(color: Colors.red),
), ),
onActionPressed: () {}, // onActionPressed: () {},
onCloseButtonPressed: () {}, onCloseButtonPressed: () {},
onDismiss: () {}, onDismiss: () {},
onProgressFinished: () {}, onProgressFinished: () {},
@@ -340,7 +340,7 @@ class LoginScreenState extends State<LoginScreen> {
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
), ),
onActionPressed: () {}, // onActionPressed: () {},
onCloseButtonPressed: () {}, onCloseButtonPressed: () {},
onDismiss: () {}, onDismiss: () {},
onProgressFinished: () {}, onProgressFinished: () {},

View File

@@ -776,7 +776,7 @@ class SettingsScreenState extends State<SettingsScreen>
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context) color: Theme.of(context)
.colorScheme .colorScheme
.background), .surface),
child: Material( child: Material(
type: MaterialType.transparency, type: MaterialType.transparency,
child: SwitchListTile( child: SwitchListTile(

View File

@@ -2,7 +2,7 @@ name: refilc_desktop_ui
publish_to: "none" publish_to: "none"
environment: environment:
sdk: ">=2.17.0 <=3.3.2" sdk: ">=3.3.2 <=3.4.3"
dependencies: dependencies:
flutter: flutter:
@@ -26,22 +26,22 @@ dependencies:
provider: ^6.1.1 provider: ^6.1.1
url_launcher: ^6.2.5 url_launcher: ^6.2.5
flutter_linkify: ^6.0.0 flutter_linkify: ^6.0.0
flutter_markdown: ^0.6.20+1 flutter_markdown: ^0.7.2+1
animations: ^2.0.11 animations: ^2.0.11
confetti: ^0.7.0 confetti: ^0.7.0
auto_size_text: ^3.0.0 auto_size_text: ^3.0.0
flutter_acrylic: ^1.1.3 flutter_acrylic: ^1.1.3
elegant_notification: ^1.13.0 elegant_notification: ^2.2.0
flutter_staggered_grid_view: ^0.7.0 flutter_staggered_grid_view: ^0.7.0
i18n_extension: ^11.0.12 i18n_extension: ^12.0.1
flutter_expandable_fab: ^2.0.0 flutter_expandable_fab: ^2.0.0
collection: ^1.18.0 collection: ^1.18.0
animated_list_plus: ^0.5.2 animated_list_plus: ^0.5.2
intl: ^0.18.1 intl: ^0.19.0
flutter_custom_tabs: ^2.0.0+1 flutter_custom_tabs: ^2.0.0+1
dev_dependencies: dev_dependencies:
flutter_lints: ^3.0.1 flutter_lints: ^4.0.0
flutter: flutter:
uses-material-design: true uses-material-design: true

View File

@@ -5,7 +5,7 @@ class KretaAPI {
static const login = BaseKreta.kretaIdp + KretaApiEndpoints.token; static const login = BaseKreta.kretaIdp + KretaApiEndpoints.token;
static const logout = BaseKreta.kretaIdp + KretaApiEndpoints.revoke; static const logout = BaseKreta.kretaIdp + KretaApiEndpoints.revoke;
static const nonce = BaseKreta.kretaIdp + KretaApiEndpoints.nonce; static const nonce = BaseKreta.kretaIdp + KretaApiEndpoints.nonce;
static const clientId = "kreta-ellenorzo-mobile-android"; static const clientId = "kreta-ellenorzo-student-mobile-ios";
// ELLENORZO API // ELLENORZO API
static String notes(String iss) => static String notes(String iss) =>

View File

@@ -1,15 +1,16 @@
// ignore_for_file: avoid_print // ignore_for_file: avoid_print, use_build_context_synchronously
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:refilc/api/login.dart'; // import 'package:refilc/api/login.dart';
import 'package:refilc/api/nonce.dart'; // import 'package:refilc/api/nonce.dart';
import 'package:refilc/api/providers/database_provider.dart';
import 'package:refilc/api/providers/user_provider.dart'; import 'package:refilc/api/providers/user_provider.dart';
import 'package:refilc/api/providers/status_provider.dart'; import 'package:refilc/api/providers/status_provider.dart';
import 'package:refilc/models/settings.dart'; import 'package:refilc/models/settings.dart';
import 'package:refilc/models/user.dart'; import 'package:refilc/models/user.dart';
import 'package:refilc/utils/jwt.dart'; // import 'package:refilc/utils/jwt.dart';
import 'package:refilc_kreta_api/client/api.dart'; import 'package:refilc_kreta_api/client/api.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:http/io_client.dart' as http; import 'package:http/io_client.dart' as http;
@@ -24,6 +25,7 @@ class KretaClient {
late final SettingsProvider _settings; late final SettingsProvider _settings;
late final UserProvider _user; late final UserProvider _user;
late final DatabaseProvider _database;
late final StatusProvider _status; late final StatusProvider _status;
bool _loginRefreshing = false; bool _loginRefreshing = false;
@@ -32,9 +34,11 @@ class KretaClient {
this.accessToken, this.accessToken,
required SettingsProvider settings, required SettingsProvider settings,
required UserProvider user, required UserProvider user,
required DatabaseProvider database,
required StatusProvider status, required StatusProvider status,
}) : _settings = settings, }) : _settings = settings,
_user = user, _user = user,
_database = database,
_status = status, _status = status,
userAgent = settings.config.userAgent { userAgent = settings.config.userAgent {
var ioclient = HttpClient(); var ioclient = HttpClient();
@@ -80,8 +84,8 @@ class KretaClient {
_status.triggerRequest(res); _status.triggerRequest(res);
if (res.statusCode == 401) { if (res.statusCode == 401) {
await refreshLogin();
headerMap.remove("authorization"); headerMap.remove("authorization");
await refreshLogin();
} else { } else {
break; break;
} }
@@ -212,8 +216,8 @@ class KretaClient {
res = await request.send(); res = await request.send();
if (res.statusCode == 401) { if (res.statusCode == 401) {
await refreshLogin();
headerMap.remove("authorization"); headerMap.remove("authorization");
await refreshLogin();
} else { } else {
break; break;
} }
@@ -232,65 +236,76 @@ class KretaClient {
} }
} }
Future<void> refreshLogin() async { Future<String?> refreshLogin() async {
if (_loginRefreshing) return; if (_loginRefreshing) return null;
_loginRefreshing = true; _loginRefreshing = true;
User? loginUser = _user.user; User? loginUser = _user.user;
if (loginUser == null) return; if (loginUser == null) return null;
Map<String, String> headers = { Map<String, String> headers = {
"content-type": "application/x-www-form-urlencoded", "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"accept": "*/*",
"user-agent": "eKretaStudent/264745 CFNetwork/1494.0.7 Darwin/23.4.0",
}; };
String nonceStr = await getAPI(KretaAPI.nonce, json: false);
Nonce nonce =
getNonce(nonceStr, loginUser.username, loginUser.instituteCode);
headers.addAll(nonce.header());
if (_settings.presentationMode) { if (_settings.presentationMode) {
print("DEBUG: refreshLogin: ${loginUser.id}"); print("DEBUG: refreshLogin: ${loginUser.id}");
} else { } else {
print("DEBUG: refreshLogin: ${loginUser.id} ${loginUser.name}"); print("DEBUG: refreshLogin: ${loginUser.id} ${loginUser.name}");
} }
Map? loginRes = await postAPI( refreshToken ??= loginUser.refreshToken;
KretaAPI.login,
headers: headers,
body: User.loginBody(
username: loginUser.username,
password: loginUser.password,
instituteCode: loginUser.instituteCode,
),
);
if (loginRes != null) { // print("REFRESH TOKEN BELOW");
if (loginRes.containsKey("access_token")) { // print(refreshToken);
accessToken = loginRes["access_token"];
}
if (loginRes.containsKey("refresh_token")) {
refreshToken = loginRes["refresh_token"];
}
// Update role
loginUser.role =
JwtUtils.getRoleFromJWT(accessToken ?? "") ?? Role.student;
}
if (refreshToken != null) { if (refreshToken != null) {
Map? refreshRes = await postAPI(KretaAPI.login, // print("REFRESHING LOGIN");
Map? res = await postAPI(KretaAPI.login,
headers: headers, headers: headers,
body: User.refreshBody( body: User.refreshBody(
refreshToken: refreshToken!, refreshToken: loginUser.refreshToken,
instituteCode: loginUser.instituteCode)); instituteCode: loginUser.instituteCode,
if (refreshRes != null) { ));
if (refreshRes.containsKey("id_token")) { // print("REFRESH RESPONSE BELOW");
idToken = refreshRes["id_token"]; // print(res);
if (res != null) {
if (res.containsKey("error")) {
// remove user if refresh token expired
if (res["error"] == "invalid_grant") {
// remove user from app
// _user.removeUser(loginUser.id);
// await _database.store.removeUser(loginUser.id);
print("invalid refresh token (invalid_grant)");
// return error
return "refresh_token_expired";
}
} }
if (res.containsKey("access_token")) {
accessToken = res["access_token"];
}
if (res.containsKey("refresh_token")) {
refreshToken = res["refresh_token"];
loginUser.refreshToken = res["refresh_token"];
_database.store.storeUser(loginUser);
_user.refresh();
}
if (res.containsKey("id_token")) {
idToken = res["id_token"];
}
_loginRefreshing = false;
} else {
_loginRefreshing = false;
} }
} else {
_loginRefreshing = false;
} }
_loginRefreshing = false; return null;
} }
Future<void> logout() async { Future<void> logout() async {

View File

@@ -1,6 +1,7 @@
// ignore_for_file: no_leading_underscores_for_local_identifiers // ignore_for_file: no_leading_underscores_for_local_identifiers
import 'package:refilc/utils/format.dart'; import 'package:refilc/utils/format.dart';
import 'package:uuid/uuid.dart';
import 'category.dart'; import 'category.dart';
import 'subject.dart'; import 'subject.dart';
import 'teacher.dart'; import 'teacher.dart';
@@ -75,6 +76,40 @@ class Grade {
); );
} }
factory Grade.fromExportJson(Map json) {
return Grade(
id: const Uuid().v4(),
date: json["date"] != null ? DateTime.parse(json["date"]) : DateTime(0),
value: GradeValue(
json["value"] ?? 0,
json["value_name"] ?? "",
json["value_name"] ?? "",
json["weight"] ?? 0,
percentage: false,
),
teacher: Teacher.fromString((json["teacher"] ?? "").trim()),
description: json["description"] ?? "",
type: json["type"] != null
? Category.getGradeType(json["type"]
.replaceAll("midYear", "evkozi_jegy_ertekeles")
.replaceAll("halfYear", "felevi_jegy_ertekeles")
.replaceAll("endYear", "evvegi_jegy_ertekeles"))
: GradeType.unknown,
groupId: const Uuid().v4(),
subject: GradeSubject(
id: const Uuid().v4(),
category: Category.fromJson({}),
name: json["subject"] ?? ""),
mode: Category.fromJson({}),
writeDate:
json["date"] != null ? DateTime.parse(json["date"]) : DateTime(0),
seenDate:
json["date"] != null ? DateTime.parse(json["date"]) : DateTime(0),
form: "",
json: json,
);
}
bool compareTo(dynamic other) { bool compareTo(dynamic other) {
if (runtimeType != other.runtimeType) return false; if (runtimeType != other.runtimeType) return false;

View File

@@ -11,6 +11,7 @@ class Student {
String? address; String? address;
String? groupId; String? groupId;
List<String> parents; List<String> parents;
// List<String> parentsPhone;
String? className; String? className;
Student({ Student({
@@ -21,6 +22,7 @@ class Student {
required this.yearId, required this.yearId,
this.address, this.address,
required this.parents, required this.parents,
// required this.parentsPhone,
this.json, this.json,
}); });

View File

@@ -50,7 +50,8 @@ class GradeProvider with ChangeNotifier {
String? userId = _user.id; String? userId = _user.id;
if (userId != null) { if (userId != null) {
final userStore = _database.userStore; final userStore = _database.userStore;
userStore.storeLastSeen(DateTime.now(), userId: userId, category: LastSeenCategory.surprisegrade); userStore.storeLastSeen(DateTime.now(),
userId: userId, category: LastSeenCategory.surprisegrade);
_lastSeen = DateTime.now(); _lastSeen = DateTime.now();
} }
} }
@@ -59,7 +60,8 @@ class GradeProvider with ChangeNotifier {
String? userId = _user.id; String? userId = _user.id;
if (userId != null) { if (userId != null) {
final userStore = _database.userStore; final userStore = _database.userStore;
userStore.storeLastSeen(DateTime(1969), userId: userId, category: LastSeenCategory.surprisegrade); userStore.storeLastSeen(DateTime(1969),
userId: userId, category: LastSeenCategory.surprisegrade);
_lastSeen = DateTime(1969); _lastSeen = DateTime(1969);
} }
} }
@@ -73,9 +75,11 @@ class GradeProvider with ChangeNotifier {
_grades = await userQuery.getGrades(userId: userId); _grades = await userQuery.getGrades(userId: userId);
await convertBySettings(); await convertBySettings();
await getGradeStreak();
_groupAvg = await userQuery.getGroupAverages(userId: userId); _groupAvg = await userQuery.getGroupAverages(userId: userId);
notifyListeners(); notifyListeners();
DateTime lastSeenDB = await userQuery.lastSeen(userId: userId, category: LastSeenCategory.surprisegrade); DateTime lastSeenDB = await userQuery.lastSeen(
userId: userId, category: LastSeenCategory.surprisegrade);
if (lastSeenDB.millisecondsSinceEpoch == 0 || if (lastSeenDB.millisecondsSinceEpoch == 0 ||
lastSeenDB.year == 0 || lastSeenDB.year == 0 ||
!_settings.gradeOpeningFun) { !_settings.gradeOpeningFun) {
@@ -107,13 +111,16 @@ class GradeProvider with ChangeNotifier {
grade.teacher.renamedTo = grade.teacher.renamedTo =
renamedTeachers.isNotEmpty ? renamedTeachers[grade.teacher.id] : null; renamedTeachers.isNotEmpty ? renamedTeachers[grade.teacher.id] : null;
grade.value.value = grade.value.value = _settings.goodStudent
_settings.goodStudent ? 5 : grade.json!["SzamErtek"] ?? 0; ? (grade.value.percentage ? 100 : 5)
: grade.json!["SzamErtek"] ?? 0;
grade.value.valueName = _settings.goodStudent grade.value.valueName = _settings.goodStudent
? "Jeles".i18n ? "Jeles".i18n
: '${grade.json!["SzovegesErtek"]}' : (grade.value.percentage
.replaceAll(RegExp(r'[(]+[12345]?[)]'), '') ? '${grade.json!["SzovegesErtek"]}'
.i18n; : '${grade.json!["SzovegesErtek"]}'
.replaceAll(RegExp(r'[(]+[12345]?[)]'), '')
.i18n);
grade.value.shortName = _settings.goodStudent grade.value.shortName = _settings.goodStudent
? "Jeles".i18n ? "Jeles".i18n
: '${grade.json!["SzovegesErtekelesRovidNev"]}' != "null" && : '${grade.json!["SzovegesErtekelesRovidNev"]}' != "null" &&
@@ -133,6 +140,28 @@ class GradeProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
// get current grade streak and set it to the user
Future<void> getGradeStreak() async {
User? user = _user.user;
if (user == null) throw "Cannot get Grade Streak for User null";
// streak magic
int gradeStreak = 0;
List<Grade> grs = _grades;
grs.sort((a, b) => -a.date.compareTo(b.date));
for (Grade grade in grs) {
if (grade.value.value == 5) {
gradeStreak++;
} else {
break;
}
}
user.gradeStreak = gradeStreak;
notifyListeners();
}
// Fetches Grades from the Kreta API then stores them in the database // Fetches Grades from the Kreta API then stores them in the database
Future<void> fetch() async { Future<void> fetch() async {
// test cucc // test cucc
@@ -173,6 +202,7 @@ class GradeProvider with ChangeNotifier {
await _database.userStore.storeGrades(grades, userId: userId); await _database.userStore.storeGrades(grades, userId: userId);
_grades = grades; _grades = grades;
await convertBySettings(); await convertBySettings();
await getGradeStreak();
} }
Future<void> storeGroupAvg(List<GroupAverage> groupAvgs) async { Future<void> storeGroupAvg(List<GroupAverage> groupAvgs) async {

View File

@@ -8,21 +8,27 @@ extension Localization on String {
"Elégséges": "Warning but passing", "Elégséges": "Warning but passing",
"Közepes": "Passed", "Közepes": "Passed",
"": "Good", "": "Good",
"Jeles": "Excellent" "Jeles": "Excellent",
"Példás": "Excellent",
"Nem írt": "Did not write",
}, },
"hu_hu": { "hu_hu": {
"Elégtelen": "Elégtelen", "Elégtelen": "Elégtelen",
"Elégséges": "Elégséges", "Elégséges": "Elégséges",
"Közepes": "Közepes", "Közepes": "Közepes",
"": "", "": "",
"Jeles": "Jeles" "Jeles": "Jeles",
"Példás": "Példás",
"Nem írt": "Nem írt",
}, },
"de_de": { "de_de": {
"Elégtelen": "Ungenügend", "Elégtelen": "Ungenügend",
"Elégséges": "Mangelhaft", "Elégséges": "Mangelhaft",
"Közepes": "Ausreichend", "Közepes": "Ausreichend",
"": "Befriedigend", "": "Befriedigend",
"Jeles": "Gut" "Jeles": "Gut",
"Példás": "Gut",
"Nem írt": "Nicht geschrieben",
}, },
}; };

View File

@@ -19,11 +19,13 @@ class ShareProvider extends ChangeNotifier {
// } // }
// themes // themes
Future<SharedTheme> shareCurrentTheme(BuildContext context, Future<SharedTheme> shareCurrentTheme(
{bool isPublic = false, BuildContext context, {
bool shareNick = true, bool isPublic = false,
required SharedGradeColors gradeColors, bool shareNick = true,
String displayName = ''}) async { required SharedGradeColors gradeColors,
String displayName = '',
}) async {
final SettingsProvider settings = final SettingsProvider settings =
Provider.of<SettingsProvider>(context, listen: false); Provider.of<SettingsProvider>(context, listen: false);
@@ -69,7 +71,25 @@ class ShareProvider extends ChangeNotifier {
if (gradeColorsJson != null) { if (gradeColorsJson != null) {
SharedTheme theme = SharedTheme.fromJson( SharedTheme theme = SharedTheme.fromJson(
themeJson, SharedGradeColors.fromJson(gradeColorsJson)); themeJson,
SharedGradeColors.fromJson(gradeColorsJson["public_id"] != ''
? gradeColorsJson
: {
"public_id": "0",
"is_public": false,
"nickname": "Anonymous",
"five_color":
SettingsProvider.defaultSettings().gradeColors[4].value,
"four_color":
SettingsProvider.defaultSettings().gradeColors[3].value,
"three_color":
SettingsProvider.defaultSettings().gradeColors[2].value,
"two_color":
SettingsProvider.defaultSettings().gradeColors[1].value,
"one_color":
SettingsProvider.defaultSettings().gradeColors[0].value,
}),
);
return theme; return theme;
} }
} }
@@ -93,7 +113,25 @@ class ShareProvider extends ChangeNotifier {
if (gradeColorsJson != null) { if (gradeColorsJson != null) {
SharedTheme theme = SharedTheme.fromJson( SharedTheme theme = SharedTheme.fromJson(
t, SharedGradeColors.fromJson(gradeColorsJson)); t,
SharedGradeColors.fromJson(gradeColorsJson["public_id"] != ''
? gradeColorsJson
: {
"public_id": "0",
"is_public": false,
"nickname": "Anonymous",
"five_color":
SettingsProvider.defaultSettings().gradeColors[4].value,
"four_color":
SettingsProvider.defaultSettings().gradeColors[3].value,
"three_color":
SettingsProvider.defaultSettings().gradeColors[2].value,
"two_color":
SettingsProvider.defaultSettings().gradeColors[1].value,
"one_color":
SettingsProvider.defaultSettings().gradeColors[0].value,
}),
);
themes.add(theme); themes.add(theme);
} }
@@ -134,8 +172,25 @@ class ShareProvider extends ChangeNotifier {
Map? gradeColorsJson = await FilcAPI.getSharedGradeColors(id); Map? gradeColorsJson = await FilcAPI.getSharedGradeColors(id);
if (gradeColorsJson != null) { if (gradeColorsJson != null) {
SharedGradeColors gradeColors = SharedGradeColors gradeColors = SharedGradeColors.fromJson(
SharedGradeColors.fromJson(gradeColorsJson); gradeColorsJson["public_id"] != ''
? gradeColorsJson
: {
"public_id": "0",
"is_public": false,
"nickname": "Anonymous",
"five_color":
SettingsProvider.defaultSettings().gradeColors[4].value,
"four_color":
SettingsProvider.defaultSettings().gradeColors[3].value,
"three_color":
SettingsProvider.defaultSettings().gradeColors[2].value,
"two_color":
SettingsProvider.defaultSettings().gradeColors[1].value,
"one_color":
SettingsProvider.defaultSettings().gradeColors[0].value,
},
);
return gradeColors; return gradeColors;
} }

View File

@@ -2,7 +2,7 @@ name: refilc_kreta_api
publish_to: "none" publish_to: "none"
environment: environment:
sdk: ">=2.17.0 <=3.3.2" sdk: ">=3.3.2 <=3.4.3"
dependencies: dependencies:
flutter: flutter:
@@ -11,10 +11,10 @@ dependencies:
path: ../refilc/ path: ../refilc/
http: ^1.1.2 http: ^1.1.2
provider: ^6.1.1 provider: ^6.1.1
file_picker: ^6.1.1 file_picker: ^8.0.5
intl: ^0.18.1 intl: ^0.19.0
i18n_extension: ^11.0.11 i18n_extension: ^12.0.1
uuid: ^4.3.3 uuid: ^4.3.3
dev_dependencies: dev_dependencies:
flutter_lints: ^3.0.1 flutter_lints: ^4.0.0

View File

@@ -1,13 +1,22 @@
import 'package:dotted_border/dotted_border.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/ui/widgets/grade/grade_tile.dart'; import 'package:refilc/ui/widgets/grade/grade_tile.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:i18n_extension/i18n_extension.dart'; import 'package:i18n_extension/i18n_extension.dart';
class AverageDisplay extends StatelessWidget { class AverageDisplay extends StatelessWidget {
const AverageDisplay({super.key, this.average = 0.0, this.border = false}); const AverageDisplay({
super.key,
this.average = 0.0,
this.border = false,
this.dashed = false,
this.scale = 1.0,
});
final double average; final double average;
final bool border; final bool border;
final bool dashed;
final double scale;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -20,25 +29,44 @@ class AverageDisplay extends StatelessWidget {
averageText = averageText.replaceAll(".", ","); averageText = averageText.replaceAll(".", ",");
} }
Widget txtWidget = Text(
average == 0.0 ? "-" : averageText,
textAlign: TextAlign.center,
style: TextStyle(
color: color, fontWeight: FontWeight.w600, fontSize: scale * 15.0),
maxLines: 1,
);
return Container( return Container(
width: border ? 57.0 : 54.0, width: (border ? 57.0 : 54.0) * scale,
padding: EdgeInsets.symmetric( padding: (border && dashed)
horizontal: 6.0 - (border ? 2 : 0), vertical: 5.0 - (border ? 2 : 0)), ? null
: EdgeInsets.symmetric(
horizontal: (6.0 - (border ? 2 : 0)) * scale,
vertical: (5.0 - (border ? 2 : 0))) *
scale,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(45.0), borderRadius:
border: border (border && dashed) ? null : BorderRadius.circular(45.0 * scale),
border: border && !dashed
? Border.fromBorderSide( ? Border.fromBorderSide(
BorderSide(color: color.withOpacity(.5), width: 1.0)) BorderSide(color: color.withOpacity(.5), width: 1.0 * scale))
: null, : null,
color: !border ? color.withOpacity(average == 0.0 ? .15 : .25) : null, color: !border ? color.withOpacity(average == 0.0 ? .15 : .25) : null,
), ),
child: Text( child: (border && dashed)
average == 0.0 ? "-" : averageText, ? DottedBorder(
textAlign: TextAlign.center, strokeWidth: 1.0 * scale,
style: TextStyle( padding: EdgeInsets.all(4.0 * scale),
color: color, fontWeight: FontWeight.w600, fontSize: 15.0), color: color.withOpacity(.5),
maxLines: 1, dashPattern: const [6, 6],
), radius: Radius.circular(45.0 * scale),
borderType: BorderType.RRect,
child: Center(
child: txtWidget,
),
)
: txtWidget,
); );
} }
} }

View File

@@ -14,7 +14,7 @@ class BottomCard extends StatelessWidget {
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(14.0), borderRadius: BorderRadius.circular(14.0),
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
), ),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

View File

@@ -22,7 +22,7 @@ class RoundedBottomSheet extends StatelessWidget {
return AnimatedContainer( return AnimatedContainer(
duration: const Duration(milliseconds: 500), duration: const Duration(milliseconds: 500),
decoration: BoxDecoration( decoration: BoxDecoration(
color: backgroundColor ?? Theme.of(context).colorScheme.background, color: backgroundColor ?? Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
topLeft: Radius.circular(borderRadius), topLeft: Radius.circular(borderRadius),
topRight: Radius.circular(borderRadius), topRight: Radius.circular(borderRadius),

View File

@@ -1,5 +1,6 @@
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'chips.i18n.dart';
class BetaChip extends StatelessWidget { class BetaChip extends StatelessWidget {
const BetaChip({super.key, this.disabled = false}); const BetaChip({super.key, this.disabled = false});
@@ -22,7 +23,7 @@ class BetaChip extends StatelessWidget {
padding: const EdgeInsets.only(left: 8, right: 8), padding: const EdgeInsets.only(left: 8, right: 8),
child: Center( child: Center(
child: Text( child: Text(
"BETA", "beta".i18n,
softWrap: true, softWrap: true,
style: TextStyle( style: TextStyle(
fontSize: 10, fontSize: 10,

View File

@@ -0,0 +1,24 @@
import 'package:i18n_extension/i18n_extension.dart';
extension ScreensLocalization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"new": "NEW",
"beta": "BETA",
},
"hu_hu": {
"new": "ÚJ",
"beta": "BÉTA",
},
"de_de": {
"new": "NEU",
"beta": "BETA",
},
};
String get i18n => localize(this, _t);
String fill(List<Object> params) => localizeFill(this, params);
String plural(int value) => localizePlural(value, this, _t);
String version(Object modifier) => localizeVersion(modifier, this, _t);
}

View File

@@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:refilc/theme/colors/colors.dart';
import 'chips.i18n.dart';
class NewChip extends StatelessWidget {
const NewChip({super.key, this.disabled = false});
final bool disabled;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color:
disabled ? AppColors.of(context).text.withOpacity(.25) : Colors.red,
borderRadius: BorderRadius.circular(12.0),
),
padding:
const EdgeInsets.only(left: 6.0, right: 8.0, top: 4.0, bottom: 4.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.hotel_class_rounded,
color: disabled
? AppColors.of(context).text.withOpacity(.5)
: Colors.white,
size: 14.0,
),
const SizedBox(width: 2.0),
Text(
'new'.i18n,
style: TextStyle(
color: disabled
? AppColors.of(context).text.withOpacity(.5)
: Colors.white,
fontSize: 12.0,
fontWeight: FontWeight.bold,
),
),
],
),
);
}
}

View File

@@ -49,7 +49,7 @@ class _FilterBarState extends State<FilterBar> {
controller: widget.controller, controller: widget.controller,
isScrollable: widget.scrollable, isScrollable: widget.scrollable,
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
// Label // label
labelStyle: Theme.of(context).textTheme.titleMedium!.copyWith( labelStyle: Theme.of(context).textTheme.titleMedium!.copyWith(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
fontSize: 15.0, fontSize: 15.0,
@@ -57,15 +57,17 @@ class _FilterBarState extends State<FilterBar> {
labelPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3), labelPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3),
labelColor: Theme.of(context).colorScheme.secondary, labelColor: Theme.of(context).colorScheme.secondary,
unselectedLabelColor: AppColors.of(context).text.withOpacity(0.65), unselectedLabelColor: AppColors.of(context).text.withOpacity(0.65),
// Indicator // indicator
indicatorSize: TabBarIndicatorSize.tab, indicatorSize: TabBarIndicatorSize.tab,
indicatorPadding: const EdgeInsets.symmetric(vertical: 8.0), indicatorPadding: const EdgeInsets.symmetric(vertical: 8.0),
indicator: BoxDecoration( indicator: BoxDecoration(
color: Theme.of(context).colorScheme.tertiary.withOpacity(.2), color: Theme.of(context).colorScheme.tertiary.withOpacity(.2),
borderRadius: BorderRadius.circular(45.0), borderRadius: BorderRadius.circular(45.0),
), ),
overlayColor: MaterialStateProperty.all(const Color(0x00000000)), overlayColor: WidgetStateProperty.all(const Color(0x00000000)),
// Tabs // underline (bottom border)
dividerColor: Colors.transparent,
// tabs
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
tabs: widget.censored tabs: widget.censored
? censoredItemsWidth ? censoredItemsWidth

View File

@@ -1,4 +1,5 @@
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:refilc/helpers/subject.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:refilc/theme/colors/utils.dart'; import 'package:refilc/theme/colors/utils.dart';
@@ -113,7 +114,9 @@ class HeroScrollViewState extends State<HeroScrollView> {
Padding( Padding(
padding: const EdgeInsets.only(top: 26.0), padding: const EdgeInsets.only(top: 26.0),
child: SvgPicture.asset( child: SvgPicture.asset(
"assets/svg/mesh_bg.svg", // "assets/svg/mesh_bg.svg",
SubjectBooklet.resolveVariant(
context: context, subjectName: widget.title),
// ignore: deprecated_member_use // ignore: deprecated_member_use
color: ColorsUtils() color: ColorsUtils()
.darken( .darken(

View File

@@ -22,7 +22,7 @@ class OutlinedRoundButton extends StatelessWidget {
width: size, width: size,
height: size, height: size,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
border: Border.all( border: Border.all(
color: Theme.of(context).colorScheme.secondary.withOpacity(0.1), color: Theme.of(context).colorScheme.secondary.withOpacity(0.1),
width: 1.1, width: 1.1,

View File

@@ -35,7 +35,7 @@ class Panel extends StatelessWidget {
borderRadius: BorderRadius.circular(16.0), borderRadius: BorderRadius.circular(16.0),
color: isTransparent color: isTransparent
? Colors.transparent ? Colors.transparent
: Theme.of(context).colorScheme.background, : Theme.of(context).colorScheme.surface,
boxShadow: [ boxShadow: [
if ((hasShadow && !isTransparent) && if ((hasShadow && !isTransparent) &&
Provider.of<SettingsProvider>(context, listen: false) Provider.of<SettingsProvider>(context, listen: false)
@@ -87,7 +87,7 @@ class PanelHeader extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0)), topLeft: Radius.circular(16.0), topRight: Radius.circular(16.0)),
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
boxShadow: [ boxShadow: [
if (Provider.of<SettingsProvider>(context, listen: false) if (Provider.of<SettingsProvider>(context, listen: false)
.shadowEffect) .shadowEffect)
@@ -113,7 +113,7 @@ class PanelBody extends StatelessWidget {
return Container( return Container(
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
boxShadow: [ boxShadow: [
if (Provider.of<SettingsProvider>(context, listen: false) if (Provider.of<SettingsProvider>(context, listen: false)
.shadowEffect) .shadowEffect)
@@ -144,7 +144,7 @@ class PanelFooter extends StatelessWidget {
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(16.0), bottomLeft: Radius.circular(16.0),
bottomRight: Radius.circular(16.0)), bottomRight: Radius.circular(16.0)),
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
boxShadow: [ boxShadow: [
if (Provider.of<SettingsProvider>(context, listen: false) if (Provider.of<SettingsProvider>(context, listen: false)
.shadowEffect) .shadowEffect)

View File

@@ -49,6 +49,8 @@ extension Localization on String {
"d_npc": "d_npc":
"You're such a non-player character, we couldn't give you a personality.", "You're such a non-player character, we couldn't give you a personality.",
"s_npc": "In-game playtime (hours)", "s_npc": "In-game playtime (hours)",
// other
"year_index": "Lesson Number",
}, },
"hu_hu": { "hu_hu": {
// main // main
@@ -96,6 +98,8 @@ extension Localization on String {
"d_npc": "d_npc":
"Egy akkora nagy non-player character vagy, hogy neked semmilyen személyiség nem jutott ezen kívül.", "Egy akkora nagy non-player character vagy, hogy neked semmilyen személyiség nem jutott ezen kívül.",
"s_npc": "In-game playtime (óra)", "s_npc": "In-game playtime (óra)",
// other
"year_index": "Éves óraszám",
}, },
"de_de": { "de_de": {
// main // main
@@ -144,6 +148,8 @@ extension Localization on String {
"d_npc": "d_npc":
"Du bist einfach so sehr wie ein Computer, dass wir dir nicht einmal eine Persönlichkeit geben konnten.", "Du bist einfach so sehr wie ein Computer, dass wir dir nicht einmal eine Persönlichkeit geben konnten.",
"s_npc": "Spielzeit (Stunden)", "s_npc": "Spielzeit (Stunden)",
// other
"year_index": "Ordinalzahl",
} }
}; };

View File

@@ -65,6 +65,7 @@ class ProfileButton extends StatelessWidget {
radius: child.radius, radius: child.radius,
badge: child.badge, badge: child.badge,
role: child.role, role: child.role,
gradeStreak: child.gradeStreak,
profilePictureString: child.profilePictureString, profilePictureString: child.profilePictureString,
onTap: () { onTap: () {
showSlidingBottomSheet( showSlidingBottomSheet(

View File

@@ -21,6 +21,7 @@ class ProfileImage extends StatefulWidget {
this.censored = false, this.censored = false,
this.profilePictureString = "", this.profilePictureString = "",
this.isNotePfp = false, this.isNotePfp = false,
this.gradeStreak = false,
}); });
final void Function()? onTap; final void Function()? onTap;
@@ -35,6 +36,7 @@ class ProfileImage extends StatefulWidget {
final bool censored; final bool censored;
final String profilePictureString; final String profilePictureString;
final bool isNotePfp; final bool isNotePfp;
final bool gradeStreak;
@override @override
State<ProfileImage> createState() => _ProfileImageState(); State<ProfileImage> createState() => _ProfileImageState();
@@ -145,6 +147,20 @@ class _ProfileImageState extends State<ProfileImage> {
color: roleColor, size: widget.radius / 1.3), color: roleColor, size: widget.radius / 1.3),
), ),
), ),
// streak indicator
// if (widget.gradeStreak)
// SizedBox(
// height: widget.radius * 2,
// width: widget.radius * 2,
// child: Container(
// alignment: Alignment.topLeft,
// child: Text(
// '🔥',
// style: TextStyle(fontSize: widget.radius * 0.9),
// ),
// ),
// ),
], ],
); );
} }
@@ -238,6 +254,29 @@ class _ProfileImageState extends State<ProfileImage> {
), ),
), ),
// streak indicator
if (widget.gradeStreak)
Hero(
tag: "${widget.heroTag!}streak_indicator",
child: FittedBox(
fit: BoxFit.fitHeight,
child: SizedBox(
height: widget.radius * 2,
width: widget.radius * 2,
child: Transform.translate(
offset: Offset(-widget.radius / 4, -widget.radius / 4),
child: Container(
alignment: Alignment.topLeft,
child: Text(
'🔥',
style: TextStyle(fontSize: widget.radius * 0.8),
),
),
),
),
),
),
Material( Material(
color: Colors.transparent, color: Colors.transparent,
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,

View File

@@ -9,7 +9,7 @@ void showSlidingBottomSheet(
cornerRadius: 16, cornerRadius: 16,
cornerRadiusOnFullscreen: 0, cornerRadiusOnFullscreen: 0,
avoidStatusBar: true, avoidStatusBar: true,
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
duration: const Duration(milliseconds: 400), duration: const Duration(milliseconds: 400),
snapSpec: const ss.SnapSpec( snapSpec: const ss.SnapSpec(
snap: true, snap: true,
@@ -18,7 +18,7 @@ void showSlidingBottomSheet(
), ),
headerBuilder: (context, state) { headerBuilder: (context, state) {
return Material( return Material(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -37,7 +37,7 @@ void showSlidingBottomSheet(
}, },
builder: (context, state) { builder: (context, state) {
return Material( return Material(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
child: Padding( child: Padding(
padding: const EdgeInsets.fromLTRB(12.0, 0, 12.0, 8.0), padding: const EdgeInsets.fromLTRB(12.0, 0, 12.0, 8.0),
child: child), child: child),

View File

@@ -46,7 +46,7 @@ class SplittedPanel extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: isTransparent color: isTransparent
? Colors.transparent ? Colors.transparent
: Theme.of(context).colorScheme.background, : Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.vertical( borderRadius: BorderRadius.vertical(
top: Radius.circular(i == 0 ? 16.0 : 8.0), top: Radius.circular(i == 0 ? 16.0 : 8.0),
bottom: Radius.circular(children!.length == i + 1 ? 16.0 : 8.0), bottom: Radius.circular(children!.length == i + 1 ? 16.0 : 8.0),

View File

@@ -10,7 +10,8 @@ import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
double valueFromPercentageInRange({required final double min, max, percentage}) { double valueFromPercentageInRange(
{required final double min, max, percentage}) {
return percentage * (max - min) + min; return percentage * (max - min) + min;
} }
@@ -44,7 +45,8 @@ typedef _ViewablePreviewBuilderChildless = Widget Function(
Rect _getRect(GlobalKey globalKey) { Rect _getRect(GlobalKey globalKey) {
assert(globalKey.currentContext != null); assert(globalKey.currentContext != null);
final RenderBox renderBoxContainer = globalKey.currentContext!.findRenderObject()! as RenderBox; final RenderBox renderBoxContainer =
globalKey.currentContext!.findRenderObject()! as RenderBox;
final Offset containerOffset = renderBoxContainer.localToGlobal( final Offset containerOffset = renderBoxContainer.localToGlobal(
renderBoxContainer.paintBounds.topLeft, renderBoxContainer.paintBounds.topLeft,
); );
@@ -101,7 +103,8 @@ class _ViewableState extends State<Viewable> with TickerProviderStateMixin {
final double screenWidth = MediaQuery.of(context).size.width; final double screenWidth = MediaQuery.of(context).size.width;
final double center = screenWidth / 2; final double center = screenWidth / 2;
final bool centerDividesChild = childRect.left < center && childRect.right > center; final bool centerDividesChild =
childRect.left < center && childRect.right > center;
final double distanceFromCenter = (center - childRect.center.dx).abs(); final double distanceFromCenter = (center - childRect.center.dx).abs();
if (centerDividesChild && distanceFromCenter <= childRect.width / 4) { if (centerDividesChild && distanceFromCenter <= childRect.width / 4) {
return _ViewableLocation.center; return _ViewableLocation.center;
@@ -132,7 +135,7 @@ class _ViewableState extends State<Viewable> with TickerProviderStateMixin {
return ClipRRect( return ClipRRect(
borderRadius: BorderRadius.circular(16.0), borderRadius: BorderRadius.circular(16.0),
child: Material( child: Material(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(16.0), borderRadius: BorderRadius.circular(16.0),
child: Stack( child: Stack(
children: [ children: [
@@ -270,7 +273,8 @@ class _DecoyChild extends StatefulWidget {
_DecoyChildState createState() => _DecoyChildState(); _DecoyChildState createState() => _DecoyChildState();
} }
class _DecoyChildState extends State<_DecoyChild> with TickerProviderStateMixin { class _DecoyChildState extends State<_DecoyChild>
with TickerProviderStateMixin {
static const Color _lightModeMaskColor = Color(0xFF888888); static const Color _lightModeMaskColor = Color(0xFF888888);
static const Color _masklessColor = Color(0xFFFFFFFF); static const Color _masklessColor = Color(0xFFFFFFFF);
@@ -327,7 +331,9 @@ class _DecoyChildState extends State<_DecoyChild> with TickerProviderStateMixin
} }
Widget _buildAnimation(BuildContext context, Widget? child) { Widget _buildAnimation(BuildContext context, Widget? child) {
final Color color = widget.controller.status == AnimationStatus.reverse ? _masklessColor : _mask.value; final Color color = widget.controller.status == AnimationStatus.reverse
? _masklessColor
: _mask.value;
return Positioned.fromRect( return Positioned.fromRect(
rect: _rect.value!, rect: _rect.value!,
child: ShaderMask( child: ShaderMask(
@@ -373,7 +379,8 @@ class _ViewableRoute<T> extends PopupRoute<T> {
static const Color _kModalBarrierColor = Color(0x6604040F); static const Color _kModalBarrierColor = Color(0x6604040F);
static const Duration _kModalPopupTransitionDuration = Duration(milliseconds: 335); static const Duration _kModalPopupTransitionDuration =
Duration(milliseconds: 335);
final List<Widget> _actions; final List<Widget> _actions;
final _ViewablePreviewBuilderChildless? _builder; final _ViewablePreviewBuilderChildless? _builder;
@@ -396,7 +403,8 @@ class _ViewableRoute<T> extends PopupRoute<T> {
static final RectTween _rectTween = RectTween(); static final RectTween _rectTween = RectTween();
static final Animatable<Rect?> _rectAnimatable = _rectTween.chain(_curve); static final Animatable<Rect?> _rectAnimatable = _rectTween.chain(_curve);
static final RectTween _rectTweenReverse = RectTween(); static final RectTween _rectTweenReverse = RectTween();
static final Animatable<Rect?> _rectAnimatableReverse = _rectTweenReverse.chain( static final Animatable<Rect?> _rectAnimatableReverse =
_rectTweenReverse.chain(
_curveReverse, _curveReverse,
); );
static final RectTween _sheetRectTween = RectTween(); static final RectTween _sheetRectTween = RectTween();
@@ -407,10 +415,12 @@ class _ViewableRoute<T> extends PopupRoute<T> {
_curveReverse, _curveReverse,
); );
static final Tween<double> _sheetScaleTween = Tween<double>(); static final Tween<double> _sheetScaleTween = Tween<double>();
static final Animatable<double> _sheetScaleAnimatable = _sheetScaleTween.chain( static final Animatable<double> _sheetScaleAnimatable =
_sheetScaleTween.chain(
_curve, _curve,
); );
static final Animatable<double> _sheetScaleAnimatableReverse = _sheetScaleTween.chain( static final Animatable<double> _sheetScaleAnimatableReverse =
_sheetScaleTween.chain(
_curveReverse, _curveReverse,
); );
final Tween<double> _opacityTween = Tween<double>(begin: 0.0, end: 1.0); final Tween<double> _opacityTween = Tween<double>(begin: 0.0, end: 1.0);
@@ -441,7 +451,8 @@ class _ViewableRoute<T> extends PopupRoute<T> {
return offsetScaled & sizeScaled; return offsetScaled & sizeScaled;
} }
static AlignmentDirectional getSheetAlignment(_ViewableLocation contextMenuLocation) { static AlignmentDirectional getSheetAlignment(
_ViewableLocation contextMenuLocation) {
switch (contextMenuLocation) { switch (contextMenuLocation) {
case _ViewableLocation.center: case _ViewableLocation.center:
return AlignmentDirectional.topCenter; return AlignmentDirectional.topCenter;
@@ -452,17 +463,24 @@ class _ViewableRoute<T> extends PopupRoute<T> {
} }
} }
static Rect _getSheetRectBegin(Orientation? orientation, _ViewableLocation contextMenuLocation, Rect childRect, Rect sheetRect) { static Rect _getSheetRectBegin(Orientation? orientation,
_ViewableLocation contextMenuLocation, Rect childRect, Rect sheetRect) {
switch (contextMenuLocation) { switch (contextMenuLocation) {
case _ViewableLocation.center: case _ViewableLocation.center:
final Offset target = orientation == Orientation.portrait ? childRect.bottomCenter : childRect.topCenter; final Offset target = orientation == Orientation.portrait
? childRect.bottomCenter
: childRect.topCenter;
final Offset centered = target - Offset(sheetRect.width / 2, 0.0); final Offset centered = target - Offset(sheetRect.width / 2, 0.0);
return centered & sheetRect.size; return centered & sheetRect.size;
case _ViewableLocation.right: case _ViewableLocation.right:
final Offset target = orientation == Orientation.portrait ? childRect.bottomRight : childRect.topRight; final Offset target = orientation == Orientation.portrait
? childRect.bottomRight
: childRect.topRight;
return (target - Offset(sheetRect.width, 0.0)) & sheetRect.size; return (target - Offset(sheetRect.width, 0.0)) & sheetRect.size;
case _ViewableLocation.left: case _ViewableLocation.left:
final Offset target = orientation == Orientation.portrait ? childRect.bottomLeft : childRect.topLeft; final Offset target = orientation == Orientation.portrait
? childRect.bottomLeft
: childRect.topLeft;
return target & sheetRect.size; return target & sheetRect.size;
} }
} }
@@ -478,7 +496,9 @@ class _ViewableRoute<T> extends PopupRoute<T> {
} }
void _updateTweenRects() { void _updateTweenRects() {
final Rect childRect = _scale == null ? _getRect(_childGlobalKey) : _getScaledRect(_childGlobalKey, _scale!); final Rect childRect = _scale == null
? _getRect(_childGlobalKey)
: _getScaledRect(_childGlobalKey, _scale!);
_rectTween.begin = _previousChildRect; _rectTween.begin = _previousChildRect;
_rectTween.end = childRect; _rectTween.end = childRect;
@@ -546,21 +566,29 @@ class _ViewableRoute<T> extends PopupRoute<T> {
} }
@override @override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) { Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return Container(); return Container();
} }
@override @override
Widget buildTransitions(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) { Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
return OrientationBuilder( return OrientationBuilder(
builder: (BuildContext context, Orientation orientation) { builder: (BuildContext context, Orientation orientation) {
_lastOrientation = orientation; _lastOrientation = orientation;
if (!animation.isCompleted) { if (!animation.isCompleted) {
final bool reverse = animation.status == AnimationStatus.reverse; final bool reverse = animation.status == AnimationStatus.reverse;
final Rect rect = reverse ? _rectAnimatableReverse.evaluate(animation)! : _rectAnimatable.evaluate(animation)!; final Rect rect = reverse
final Rect sheetRect = reverse ? _sheetRectAnimatableReverse.evaluate(animation)! : _sheetRectAnimatable.evaluate(animation)!; ? _rectAnimatableReverse.evaluate(animation)!
final double sheetScale = reverse ? _sheetScaleAnimatableReverse.evaluate(animation) : _sheetScaleAnimatable.evaluate(animation); : _rectAnimatable.evaluate(animation)!;
final Rect sheetRect = reverse
? _sheetRectAnimatableReverse.evaluate(animation)!
: _sheetRectAnimatable.evaluate(animation)!;
final double sheetScale = reverse
? _sheetScaleAnimatableReverse.evaluate(animation)
: _sheetScaleAnimatable.evaluate(animation);
return Stack( return Stack(
children: <Widget>[ children: <Widget>[
Positioned.fromRect( Positioned.fromRect(
@@ -623,7 +651,8 @@ class _ContextMenuRouteStatic extends StatefulWidget {
_ContextMenuRouteStaticState createState() => _ContextMenuRouteStaticState(); _ContextMenuRouteStaticState createState() => _ContextMenuRouteStaticState();
} }
class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with TickerProviderStateMixin { class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic>
with TickerProviderStateMixin {
static const double _kMinScale = 0.8; static const double _kMinScale = 0.8;
static const double _kSheetScaleThreshold = 0.9; static const double _kSheetScaleThreshold = 0.9;
@@ -639,7 +668,8 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T
late Animation<double> _sheetScaleAnimation; late Animation<double> _sheetScaleAnimation;
late Animation<double> _sheetOpacityAnimation; late Animation<double> _sheetOpacityAnimation;
static double _getScale(Orientation orientation, double maxDragDistance, double dy) { static double _getScale(
Orientation orientation, double maxDragDistance, double dy) {
final double dyDirectional = dy <= 0.0 ? dy : -dy; final double dyDirectional = dy <= 0.0 ? dy : -dy;
return math.max( return math.max(
_kMinScale, _kMinScale,
@@ -659,11 +689,13 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T
void _onPanEnd(DragEndDetails details) { void _onPanEnd(DragEndDetails details) {
if (details.velocity.pixelsPerSecond.dy.abs() >= kMinFlingVelocity) { if (details.velocity.pixelsPerSecond.dy.abs() >= kMinFlingVelocity) {
final bool flingIsAway = details.velocity.pixelsPerSecond.dy > 0; final bool flingIsAway = details.velocity.pixelsPerSecond.dy > 0;
final double finalPosition = flingIsAway ? _moveAnimation.value.dy + 100.0 : 0.0; final double finalPosition =
flingIsAway ? _moveAnimation.value.dy + 100.0 : 0.0;
if (flingIsAway && _sheetController.status != AnimationStatus.forward) { if (flingIsAway && _sheetController.status != AnimationStatus.forward) {
_sheetController.forward(); _sheetController.forward();
} else if (!flingIsAway && _sheetController.status != AnimationStatus.reverse) { } else if (!flingIsAway &&
_sheetController.status != AnimationStatus.reverse) {
_sheetController.reverse(); _sheetController.reverse();
} }
@@ -713,20 +745,29 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T
widget.onDismiss!(context, _lastScale, _sheetOpacityAnimation.value); widget.onDismiss!(context, _lastScale, _sheetOpacityAnimation.value);
} }
Alignment _getChildAlignment(Orientation orientation, _ViewableLocation contextMenuLocation) { Alignment _getChildAlignment(
Orientation orientation, _ViewableLocation contextMenuLocation) {
switch (contextMenuLocation) { switch (contextMenuLocation) {
case _ViewableLocation.center: case _ViewableLocation.center:
return orientation == Orientation.portrait ? Alignment.bottomCenter : Alignment.topRight; return orientation == Orientation.portrait
? Alignment.bottomCenter
: Alignment.topRight;
case _ViewableLocation.right: case _ViewableLocation.right:
return orientation == Orientation.portrait ? Alignment.bottomCenter : Alignment.topLeft; return orientation == Orientation.portrait
? Alignment.bottomCenter
: Alignment.topLeft;
case _ViewableLocation.left: case _ViewableLocation.left:
return orientation == Orientation.portrait ? Alignment.bottomCenter : Alignment.topRight; return orientation == Orientation.portrait
? Alignment.bottomCenter
: Alignment.topRight;
} }
} }
void _setDragOffset(Offset dragOffset) { void _setDragOffset(Offset dragOffset) {
final double endX = _kPadding * dragOffset.dx / _kDamping; final double endX = _kPadding * dragOffset.dx / _kDamping;
final double endY = dragOffset.dy >= 0.0 ? dragOffset.dy : _kPadding * dragOffset.dy / _kDamping; final double endY = dragOffset.dy >= 0.0
? dragOffset.dy
: _kPadding * dragOffset.dy / _kDamping;
setState(() { setState(() {
_dragOffset = dragOffset; _dragOffset = dragOffset;
_moveAnimation = Tween<Offset>( _moveAnimation = Tween<Offset>(
@@ -742,15 +783,20 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T
), ),
); );
if (_lastScale <= _kSheetScaleThreshold && _sheetController.status != AnimationStatus.forward && _sheetScaleAnimation.value != 0.0) { if (_lastScale <= _kSheetScaleThreshold &&
_sheetController.status != AnimationStatus.forward &&
_sheetScaleAnimation.value != 0.0) {
_sheetController.forward(); _sheetController.forward();
} else if (_lastScale > _kSheetScaleThreshold && _sheetController.status != AnimationStatus.reverse && _sheetScaleAnimation.value != 1.0) { } else if (_lastScale > _kSheetScaleThreshold &&
_sheetController.status != AnimationStatus.reverse &&
_sheetScaleAnimation.value != 1.0) {
_sheetController.reverse(); _sheetController.reverse();
} }
}); });
} }
List<Widget> _getChildren(Orientation orientation, _ViewableLocation contextMenuLocation) { List<Widget> _getChildren(
Orientation orientation, _ViewableLocation contextMenuLocation) {
final Expanded child = Expanded( final Expanded child = Expanded(
child: Align( child: Align(
alignment: _getChildAlignment( alignment: _getChildAlignment(
@@ -781,7 +827,9 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T
case _ViewableLocation.center: case _ViewableLocation.center:
return <Widget>[child, spacer, sheet]; return <Widget>[child, spacer, sheet];
case _ViewableLocation.right: case _ViewableLocation.right:
return orientation == Orientation.portrait ? <Widget>[child, spacer, sheet] : <Widget>[sheet, spacer, child]; return orientation == Orientation.portrait
? <Widget>[child, spacer, sheet]
: <Widget>[sheet, spacer, child];
case _ViewableLocation.left: case _ViewableLocation.left:
return <Widget>[child, spacer, sheet]; return <Widget>[child, spacer, sheet];
} }
@@ -915,7 +963,8 @@ class _ViewableSheet extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(
top: BorderSide( top: BorderSide(
color: CupertinoDynamicColor.resolve(_borderColor, context), color:
CupertinoDynamicColor.resolve(_borderColor, context),
width: 0.5, width: 0.5,
)), )),
), ),

View File

@@ -9,7 +9,7 @@ extension Localization on String {
"unexcused": "unexcused %s", "unexcused": "unexcused %s",
"absence": "absence", "absence": "absence",
"delay": "delay", "delay": "delay",
"minute": " minutes of ".one(" minute of "), "minute": " minute(s) of ",
}, },
"hu_hu": { "hu_hu": {
"excused": "igazolt %s", "excused": "igazolt %s",
@@ -25,7 +25,7 @@ extension Localization on String {
"unexcused": "unanerkannt %s", "unexcused": "unanerkannt %s",
"absence": "Abwesenheit", "absence": "Abwesenheit",
"delay": "Verspätung", "delay": "Verspätung",
"minute": " Minuten ".one(" Minute "), "minute": " Minute(n) ",
} }
}; };

View File

@@ -9,7 +9,7 @@ extension Localization on String {
"Mode": "Mode", "Mode": "Mode",
"Submit date": "Submit Date", "Submit date": "Submit Date",
"show in timetable": "Show in timetable", "show in timetable": "Show in timetable",
"minutes": "minutes".one("minute"), "minutes": "minute(s)",
"delay": "Delay", "delay": "Delay",
}, },
"hu_hu": { "hu_hu": {
@@ -27,7 +27,7 @@ extension Localization on String {
"Mode": "Typ", "Mode": "Typ",
"Submit date": "Datum einreichen", "Submit date": "Datum einreichen",
"show in timetable": "im Stundenplan anzeigen", "show in timetable": "im Stundenplan anzeigen",
"minutes": "Minuten".one("Minute"), "minutes": "Minute(n)",
"delay": "Verspätung", "delay": "Verspätung",
} }
}; };

View File

@@ -59,7 +59,7 @@ class CertificationTile extends StatelessWidget {
} }
return Material( return Material(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
child: Padding( child: Padding(
padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0), padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0),

View File

@@ -13,31 +13,43 @@ class CertificationView extends StatelessWidget {
final List<Grade> grades; final List<Grade> grades;
final GradeType gradeType; final GradeType gradeType;
static show(List<Grade> grades, {required BuildContext context, required GradeType gradeType}) => static show(List<Grade> grades,
Navigator.of(context, rootNavigator: true).push(CupertinoPageRoute(builder: (context) => CertificationView(grades, gradeType: gradeType))); {required BuildContext context, required GradeType gradeType}) =>
Navigator.of(context, rootNavigator: true).push(CupertinoPageRoute(
builder: (context) =>
CertificationView(grades, gradeType: gradeType)));
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
grades.sort((a, b) => a.subject.name.compareTo(b.subject.name)); grades.sort((a, b) => a.subject.name.compareTo(b.subject.name));
List<Widget> tiles = grades.map((e) => CertificationTile(e)).toList(); List<Widget> tiles = grades
.map((e) => CertificationTile(
e,
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 5.0),
))
.toList();
return Scaffold( return Scaffold(
body: HeroScrollView( body: HeroScrollView(
title: getGradeTypeTitle(gradeType), title: getGradeTypeTitle(gradeType),
icon: FeatherIcons.award, icon: FeatherIcons.award,
iconSize: 50, iconSize: 50,
child: ListView( child: ListView(
shrinkWrap: true, shrinkWrap: true,
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
children: [ children: [
SafeArea( SafeArea(
child: Panel( child: Panel(
padding:
const EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0),
child: Column( child: Column(
children: tiles, children: tiles,
), ),
), ),
) )
], ],
))); ),
),
);
} }
} }

View File

@@ -38,7 +38,7 @@ class CustomSegmentedControl extends StatelessWidget {
borderRadius: BorderRadius.circular(12.0), borderRadius: BorderRadius.circular(12.0),
), ),
thumbDecoration: BoxDecoration( thumbDecoration: BoxDecoration(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(10.0), borderRadius: BorderRadius.circular(10.0),
// boxShadow: [ // boxShadow: [
// BoxShadow( // BoxShadow(

View File

@@ -13,7 +13,7 @@ class EventTile extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Material( return Material(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(14.0), borderRadius: BorderRadius.circular(14.0),
child: Padding( child: Padding(
padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0), padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0),

View File

@@ -1,6 +1,7 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:i18n_extension/i18n_extension.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:refilc/helpers/subject.dart'; import 'package:refilc/helpers/subject.dart';
@@ -13,8 +14,11 @@ import 'package:refilc_kreta_api/models/exam.dart';
import 'package:refilc_kreta_api/models/lesson.dart'; import 'package:refilc_kreta_api/models/lesson.dart';
import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart'; import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart';
import 'package:refilc_mobile_ui/common/round_border_icon.dart'; import 'package:refilc_mobile_ui/common/round_border_icon.dart';
import 'package:refilc_mobile_ui/common/viewable.dart';
import 'package:refilc_mobile_ui/common/widgets/card_handle.dart';
import 'package:refilc_mobile_ui/common/widgets/exam/exam_tile.dart'; import 'package:refilc_mobile_ui/common/widgets/exam/exam_tile.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:refilc_mobile_ui/common/widgets/exam/exam_view.dart';
class ExamViewable extends StatelessWidget { class ExamViewable extends StatelessWidget {
const ExamViewable(this.exam, const ExamViewable(this.exam,
@@ -26,22 +30,35 @@ class ExamViewable extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( if (Provider.of<SettingsProvider>(context).newPopups) {
onTap: () => ExamPopup.show(context: context, exam: exam), bool pressed = false;
child: ExamTile(
return GestureDetector(
onTap: () {
// prevent double tap things
if (pressed) return;
pressed = true;
ExamPopup.show(context: context, exam: exam);
Future.delayed(const Duration(seconds: 2), () {
pressed = false;
});
},
child: ExamTile(
exam,
showSubject: showSubject,
padding: tilePadding,
),
);
}
return Viewable(
tile: ExamTile(
exam, exam,
showSubject: showSubject, showSubject: showSubject,
padding: tilePadding, padding: tilePadding,
), ),
view: CardHandle(child: ExamView(exam)),
); );
// return Viewable(
// tile: ExamTile(
// exam,
// showSubject: showSubject,
// padding: tilePadding,
// ),
// view: CardHandle(child: ExamView(exam)),
// );
} }
} }
@@ -98,7 +115,9 @@ class ExamPopup extends StatelessWidget {
Stack( Stack(
children: [ children: [
SvgPicture.asset( SvgPicture.asset(
"assets/svg/mesh_bg.svg", // "assets/svg/mesh_bg.svg",
SubjectBooklet.resolveVariant(
context: context, subject: exam.subject),
// ignore: deprecated_member_use // ignore: deprecated_member_use
color: ColorsUtils() color: ColorsUtils()
.fade(context, Theme.of(context).colorScheme.secondary, .fade(context, Theme.of(context).colorScheme.secondary,
@@ -189,7 +208,7 @@ class ExamPopup extends StatelessWidget {
Container( Container(
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.vertical( borderRadius: const BorderRadius.vertical(
top: Radius.circular(12.0), top: Radius.circular(12.0),
bottom: Radius.circular(6.0)), bottom: Radius.circular(6.0)),
@@ -210,13 +229,19 @@ class ExamPopup extends StatelessWidget {
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( SizedBox(
exam.description.capital(), width: MediaQuery.of(context).size.width * 0.7,
style: TextStyle( child: Text(
color: exam.description.capital(),
AppColors.of(context).text.withOpacity(0.9), style: TextStyle(
fontSize: 16.0, color: AppColors.of(context)
fontWeight: FontWeight.w600, .text
.withOpacity(0.9),
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
maxLines: 3,
overflow: TextOverflow.ellipsis,
), ),
), ),
Text( Text(
@@ -241,7 +266,7 @@ class ExamPopup extends StatelessWidget {
Container( Container(
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.vertical( borderRadius: const BorderRadius.vertical(
top: Radius.circular(6.0), top: Radius.circular(6.0),
bottom: Radius.circular(12.0)), bottom: Radius.circular(12.0)),
@@ -288,7 +313,7 @@ class ExamPopup extends StatelessWidget {
], ],
), ),
Text( Text(
'${DateFormat('H:mm').format(lesson!.start)} - ${DateFormat('H:mm').format(lesson!.end)}', '${DateFormat('MMM d, H:mm', I18n.locale.countryCode).format(lesson!.start).capital()} - ${DateFormat('H:mm').format(lesson!.end)}',
style: TextStyle( style: TextStyle(
color: color:
AppColors.of(context).text.withOpacity(0.85), AppColors.of(context).text.withOpacity(0.85),
@@ -323,7 +348,7 @@ class ExamPopup extends StatelessWidget {
// child: Container( // child: Container(
// width: double.infinity, // width: double.infinity,
// decoration: BoxDecoration( // decoration: BoxDecoration(
// color: Theme.of(context).colorScheme.background, // color: Theme.of(context).colorScheme.surface,
// borderRadius: BorderRadius.circular(12.0), // borderRadius: BorderRadius.circular(12.0),
// ), // ),
// padding: const EdgeInsets.all(16.0), // padding: const EdgeInsets.all(16.0),

View File

@@ -34,7 +34,7 @@ class ChangedLessonTile extends StatelessWidget {
} }
return Material( return Material(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(14.0), borderRadius: BorderRadius.circular(14.0),
child: Padding( child: Padding(
padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0), padding: padding ?? const EdgeInsets.symmetric(horizontal: 8.0),

View File

@@ -12,6 +12,7 @@ extension Localization on String {
"l_desc": "Description...", "l_desc": "Description...",
"done": "Done", "done": "Done",
"cancel": "Cancel", "cancel": "Cancel",
"year_index": "Lesson Number",
}, },
"hu_hu": { "hu_hu": {
"Room": "Terem", "Room": "Terem",
@@ -22,6 +23,7 @@ extension Localization on String {
"l_desc": "Leírás...", "l_desc": "Leírás...",
"done": "Kész", "done": "Kész",
"cancel": "Mégse", "cancel": "Mégse",
"year_index": "Éves óraszám",
}, },
"de_de": { "de_de": {
"Room": "Raum", "Room": "Raum",
@@ -32,6 +34,7 @@ extension Localization on String {
"l_desc": "Beschreibung...", "l_desc": "Beschreibung...",
"done": "Erledigt", "done": "Erledigt",
"cancel": "Abbrechen", "cancel": "Abbrechen",
"year_index": "Ordinalzahl",
} }
}; };

View File

@@ -1,3 +1,4 @@
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -8,11 +9,21 @@ import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/theme/colors/utils.dart'; import 'package:refilc/theme/colors/utils.dart';
import 'package:refilc/utils/format.dart'; import 'package:refilc/utils/format.dart';
import 'package:refilc_kreta_api/models/exam.dart';
import 'package:refilc_kreta_api/models/lesson.dart'; import 'package:refilc_kreta_api/models/lesson.dart';
import 'package:refilc_kreta_api/providers/exam_provider.dart';
import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart'; import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart';
import 'package:refilc_mobile_ui/common/panel/panel_button.dart';
import 'package:refilc_mobile_ui/common/round_border_icon.dart'; import 'package:refilc_mobile_ui/common/round_border_icon.dart';
import 'package:refilc/ui/widgets/lesson/lesson_tile.dart'; import 'package:refilc/ui/widgets/lesson/lesson_tile.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:refilc_mobile_ui/common/viewable.dart';
import 'package:refilc_mobile_ui/common/widgets/card_handle.dart';
import 'package:refilc_mobile_ui/common/widgets/lesson/lesson_view.dart';
import 'package:refilc_plus/models/premium_scopes.dart';
import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
import 'lesson_view.i18n.dart';
class LessonViewable extends StatefulWidget { class LessonViewable extends StatefulWidget {
const LessonViewable( const LessonViewable(
@@ -59,174 +70,169 @@ class LessonViewableState extends State<LessonViewable> {
if (lsn.subject.id == '' || tile.lesson.isEmpty) return tile; if (lsn.subject.id == '' || tile.lesson.isEmpty) return tile;
return GestureDetector( // check if new popup needed
onTap: () => TimetableLessonPopup.show( if (Provider.of<SettingsProvider>(context).newPopups) {
context: context, return GestureDetector(
lesson: lsn, onTap: () => TimetableLessonPopup.show(
), context: context,
child: LessonTile( lesson: lsn,
lsn, ),
swapDesc: widget.swapDesc, child: tile,
showSubTiles: widget.showSubTiles, );
// onTap: () => TimetableLessonPopup.show( }
// context: context,
// lesson: lsn, return Viewable(
// ), tile: tile,
), view: CardHandle(child: LessonView(lsn)),
actions: [
PanelButton(
background: true,
title: Text(
"edit_lesson".i18n,
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop();
if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.timetableNotes)) {
PlusLockedFeaturePopup.show(
context: context, feature: PremiumFeature.timetableNotes);
return;
}
showDialog(
context: context,
builder: (context) => StatefulBuilder(builder: (context, setS) {
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(14.0))),
title: Text("edit_lesson".i18n),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
// description
TextField(
controller: _descTxt,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: const BorderSide(
color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(
color: Colors.grey, width: 1.5),
borderRadius: BorderRadius.circular(12.0),
),
contentPadding:
const EdgeInsets.symmetric(horizontal: 12.0),
hintText: 'l_desc'.i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
size: 18.0,
),
onPressed: () {
setState(() {
_descTxt.text = '';
});
},
),
),
),
// const SizedBox(
// height: 14.0,
// ),
// // class
// TextField(
// controller: _descTxt,
// onEditingComplete: () async {
// // SharedTheme? theme = await shareProvider.getThemeById(
// // context,
// // id: _paintId.text.replaceAll(' ', ''),
// // );
// // if (theme != null) {
// // // set theme variable
// // newThemeByID = theme;
// // _paintId.clear();
// // } else {
// // ScaffoldMessenger.of(context).showSnackBar(
// // CustomSnackBar(
// // content: Text("theme_not_found".i18n,
// // style: const TextStyle(color: Colors.white)),
// // backgroundColor: AppColors.of(context).red,
// // context: context,
// // ),
// // );
// // }
// },
// decoration: InputDecoration(
// border: OutlineInputBorder(
// borderSide: const BorderSide(
// color: Colors.grey, width: 1.5),
// borderRadius: BorderRadius.circular(12.0),
// ),
// focusedBorder: OutlineInputBorder(
// borderSide: const BorderSide(
// color: Colors.grey, width: 1.5),
// borderRadius: BorderRadius.circular(12.0),
// ),
// contentPadding:
// const EdgeInsets.symmetric(horizontal: 12.0),
// hintText: 'l_desc'.i18n,
// suffixIcon: IconButton(
// icon: const Icon(
// FeatherIcons.x,
// color: Colors.grey,
// size: 18.0,
// ),
// onPressed: () {
// setState(() {
// _descTxt.text = '';
// });
// },
// ),
// ),
// ),
],
),
actions: [
TextButton(
child: Text(
"cancel".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () {
Navigator.of(context).maybePop();
},
),
TextButton(
child: Text(
"done".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () async {
saveLesson();
Navigator.of(context).pop();
setState(() {});
},
),
],
);
}),
);
},
),
],
); );
// return Viewable(
// tile: tile,
// view: CardHandle(child: LessonView(lsn)),
// actions: [
// PanelButton(
// background: true,
// title: Text(
// "edit_lesson".i18n,
// textAlign: TextAlign.center,
// maxLines: 2,
// overflow: TextOverflow.ellipsis,
// ),
// onPressed: () {
// Navigator.of(context, rootNavigator: true).pop();
// if (!Provider.of<PlusProvider>(context, listen: false)
// .hasScope(PremiumScopes.timetableNotes)) {
// PlusLockedFeaturePopup.show(
// context: context, feature: PremiumFeature.timetableNotes);
// return;
// }
// showDialog(
// context: context,
// builder: (context) => StatefulBuilder(builder: (context, setS) {
// return AlertDialog(
// shape: const RoundedRectangleBorder(
// borderRadius: BorderRadius.all(Radius.circular(14.0))),
// title: Text("edit_lesson".i18n),
// content: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// // description
// TextField(
// controller: _descTxt,
// decoration: InputDecoration(
// border: OutlineInputBorder(
// borderSide: const BorderSide(
// color: Colors.grey, width: 1.5),
// borderRadius: BorderRadius.circular(12.0),
// ),
// focusedBorder: OutlineInputBorder(
// borderSide: const BorderSide(
// color: Colors.grey, width: 1.5),
// borderRadius: BorderRadius.circular(12.0),
// ),
// contentPadding:
// const EdgeInsets.symmetric(horizontal: 12.0),
// hintText: 'l_desc'.i18n,
// suffixIcon: IconButton(
// icon: const Icon(
// FeatherIcons.x,
// color: Colors.grey,
// size: 18.0,
// ),
// onPressed: () {
// setState(() {
// _descTxt.text = '';
// });
// },
// ),
// ),
// ),
// // const SizedBox(
// // height: 14.0,
// // ),
// // // class
// // TextField(
// // controller: _descTxt,
// // onEditingComplete: () async {
// // // SharedTheme? theme = await shareProvider.getThemeById(
// // // context,
// // // id: _paintId.text.replaceAll(' ', ''),
// // // );
// // // if (theme != null) {
// // // // set theme variable
// // // newThemeByID = theme;
// // // _paintId.clear();
// // // } else {
// // // ScaffoldMessenger.of(context).showSnackBar(
// // // CustomSnackBar(
// // // content: Text("theme_not_found".i18n,
// // // style: const TextStyle(color: Colors.white)),
// // // backgroundColor: AppColors.of(context).red,
// // // context: context,
// // // ),
// // // );
// // // }
// // },
// // decoration: InputDecoration(
// // border: OutlineInputBorder(
// // borderSide: const BorderSide(
// // color: Colors.grey, width: 1.5),
// // borderRadius: BorderRadius.circular(12.0),
// // ),
// // focusedBorder: OutlineInputBorder(
// // borderSide: const BorderSide(
// // color: Colors.grey, width: 1.5),
// // borderRadius: BorderRadius.circular(12.0),
// // ),
// // contentPadding:
// // const EdgeInsets.symmetric(horizontal: 12.0),
// // hintText: 'l_desc'.i18n,
// // suffixIcon: IconButton(
// // icon: const Icon(
// // FeatherIcons.x,
// // color: Colors.grey,
// // size: 18.0,
// // ),
// // onPressed: () {
// // setState(() {
// // _descTxt.text = '';
// // });
// // },
// // ),
// // ),
// // ),
// ],
// ),
// actions: [
// TextButton(
// child: Text(
// "cancel".i18n,
// style: const TextStyle(fontWeight: FontWeight.w500),
// ),
// onPressed: () {
// Navigator.of(context).maybePop();
// },
// ),
// TextButton(
// child: Text(
// "done".i18n,
// style: const TextStyle(fontWeight: FontWeight.w500),
// ),
// onPressed: () async {
// saveLesson();
// Navigator.of(context).pop();
// setState(() {});
// },
// ),
// ],
// );
// }),
// );
// },
// ),
// ],
// );
} }
void saveLesson() async { void saveLesson() async {
@@ -283,6 +289,18 @@ class TimetableLessonPopup extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Exam? lessonExam;
if (lesson.exam != "") {
Exam exam = Provider.of<ExamProvider>(context, listen: false)
.exams
.firstWhere((t) => t.id == lesson.exam,
orElse: () => Exam.fromJson({}));
if (exam.id != "") {
lessonExam = exam;
}
}
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
@@ -295,7 +313,9 @@ class TimetableLessonPopup extends StatelessWidget {
Stack( Stack(
children: [ children: [
SvgPicture.asset( SvgPicture.asset(
"assets/svg/mesh_bg.svg", // "assets/svg/mesh_bg.svg",
SubjectBooklet.resolveVariant(
context: context, subject: lesson.subject),
// ignore: deprecated_member_use // ignore: deprecated_member_use
color: ColorsUtils() color: ColorsUtils()
.fade(context, Theme.of(context).colorScheme.secondary, .fade(context, Theme.of(context).colorScheme.secondary,
@@ -319,13 +339,13 @@ class TimetableLessonPopup extends StatelessWidget {
.withOpacity(0.1), .withOpacity(0.1),
Theme.of(context).scaffoldBackgroundColor, Theme.of(context).scaffoldBackgroundColor,
], ],
stops: const [0.1, 0.5, 0.7, 1.0], stops: const [0.0, 0.3, 0.6, 0.95],
begin: Alignment.topCenter, begin: Alignment.topCenter,
end: Alignment.bottomCenter, end: Alignment.bottomCenter,
), ),
), ),
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
height: 175.0, height: 200.0,
), ),
], ],
), ),
@@ -340,16 +360,27 @@ class TimetableLessonPopup extends StatelessWidget {
width: 40, width: 40,
height: 4, height: 4,
decoration: BoxDecoration( decoration: BoxDecoration(
color: ColorsUtils() color: Theme.of(context).scaffoldBackgroundColor,
.fade(
context, Theme.of(context).colorScheme.secondary,
darkenAmount: 0.1, lightenAmount: 0.1)
.withOpacity(0.33),
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
2.0, 2.0,
), ),
), ),
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: ColorsUtils()
.fade(context,
Theme.of(context).colorScheme.secondary,
darkenAmount: 0.1, lightenAmount: 0.1)
.withOpacity(0.33),
borderRadius: BorderRadius.circular(
2.0,
),
),
),
), ),
const SizedBox( const SizedBox(
height: 38.0, height: 38.0,
), ),
@@ -386,12 +417,10 @@ class TimetableLessonPopup extends StatelessWidget {
Container( Container(
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.vertical( borderRadius: const BorderRadius.vertical(
top: const Radius.circular(12.0), top: Radius.circular(12.0),
bottom: (lesson.description.replaceAll(' ', '') != '') bottom: Radius.circular(6.0),
? const Radius.circular(6.0)
: const Radius.circular(12.0),
), ),
), ),
padding: const EdgeInsets.all(14.0), padding: const EdgeInsets.all(14.0),
@@ -466,7 +495,15 @@ class TimetableLessonPopup extends StatelessWidget {
height: 8.0, height: 8.0,
), ),
Text( Text(
lesson.teacher.name, ((lesson.substituteTeacher == null ||
lesson.substituteTeacher!.name == "")
? (lesson.teacher.isRenamed
? lesson.teacher.renamedTo
: lesson.teacher.name)
: (lesson.substituteTeacher!.isRenamed
? lesson.substituteTeacher!.renamedTo
: lesson.substituteTeacher!.name)) ??
'',
style: TextStyle( style: TextStyle(
color: AppColors.of(context).text.withOpacity(0.9), color: AppColors.of(context).text.withOpacity(0.9),
fontSize: 14.0, fontSize: 14.0,
@@ -484,10 +521,10 @@ class TimetableLessonPopup extends StatelessWidget {
Container( Container(
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.vertical( borderRadius: const BorderRadius.vertical(
top: Radius.circular(6.0), top: Radius.circular(6.0),
bottom: Radius.circular(12.0), bottom: Radius.circular(6.0),
), ),
), ),
padding: const EdgeInsets.all(14.0), padding: const EdgeInsets.all(14.0),
@@ -506,6 +543,94 @@ class TimetableLessonPopup extends StatelessWidget {
], ],
), ),
), ),
const SizedBox(
height: 6.0,
),
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.vertical(
top: const Radius.circular(6.0),
bottom: lesson.exam != ''
? const Radius.circular(6.0)
: const Radius.circular(12.0),
),
),
padding: const EdgeInsets.all(14.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${'year_index'.i18n}: ${lesson.lessonYearIndex ?? '?'}',
style: TextStyle(
color: AppColors.of(context).text.withOpacity(0.9),
fontSize: 14.0,
fontWeight: FontWeight.w600,
),
),
],
),
),
if (lesson.exam != '')
const SizedBox(
height: 6.0,
),
if (lesson.exam != '' && lessonExam != null)
Container(
width: double.infinity,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(6.0),
bottom: Radius.circular(12.0)),
),
padding: const EdgeInsets.all(14.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
const Icon(
FeatherIcons.file,
size: 20.0,
),
const SizedBox(
width: 10.0,
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
child: Text(
lessonExam.description.capital(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: AppColors.of(context)
.text
.withOpacity(0.9),
fontSize: 16.0,
fontWeight: FontWeight.w600,
),
),
),
],
),
Flexible(
child: Text(
lessonExam.mode?.description ?? 'Dolgozat',
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: AppColors.of(context)
.text
.withOpacity(0.85),
fontSize: 14.0,
fontWeight: FontWeight.w500,
),
),
),
],
),
),
// const SizedBox( // const SizedBox(
// height: 24.0, // height: 24.0,
// ), // ),
@@ -529,7 +654,7 @@ class TimetableLessonPopup extends StatelessWidget {
// child: Container( // child: Container(
// width: double.infinity, // width: double.infinity,
// decoration: BoxDecoration( // decoration: BoxDecoration(
// color: Theme.of(context).colorScheme.background, // color: Theme.of(context).colorScheme.surface,
// borderRadius: BorderRadius.circular(12.0), // borderRadius: BorderRadius.circular(12.0),
// ), // ),
// padding: const EdgeInsets.all(16.0), // padding: const EdgeInsets.all(16.0),

View File

@@ -23,9 +23,9 @@ class MessageViewable extends StatelessWidget {
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
closedShape: closedShape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)), RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
middleColor: Theme.of(context).colorScheme.background, middleColor: Theme.of(context).colorScheme.surface,
openColor: Theme.of(context).scaffoldBackgroundColor, openColor: Theme.of(context).scaffoldBackgroundColor,
closedColor: Theme.of(context).colorScheme.background, closedColor: Theme.of(context).colorScheme.surface,
transitionType: ContainerTransitionType.fadeThrough, transitionType: ContainerTransitionType.fadeThrough,
transitionDuration: const Duration(milliseconds: 400), transitionDuration: const Duration(milliseconds: 400),
useRootNavigator: true, useRootNavigator: true,

View File

@@ -17,7 +17,7 @@ extension Localization on String {
"Messages": "Messages", "Messages": "Messages",
"Absences": "Absences", "Absences": "Absences",
"update_available": "Update Available", "update_available": "Update Available",
"missed_exams": "You missed %s exams this week.".one("You missed an exam this week."), "missed_exams": "You missed %s exam(s) this week.",
"missed_exam_contact": "Contact %s, to resolve it!", "missed_exam_contact": "Contact %s, to resolve it!",
}, },
"hu_hu": { "hu_hu": {
@@ -34,7 +34,7 @@ extension Localization on String {
"Messages": "Üzenetek", "Messages": "Üzenetek",
"Absences": "Hiányok", "Absences": "Hiányok",
"update_available": "Frissítés elérhető", "update_available": "Frissítés elérhető",
"missed_exams": "Ezen a héten hiányoztál %s dolgozatról.".one("Ezen a héten hiányoztál egy dolgozatról."), "missed_exams": "Ezen a héten hiányoztál %s dolgozatról.",
"missed_exam_contact": "Keresd %s-t, ha pótolni szeretnéd!", "missed_exam_contact": "Keresd %s-t, ha pótolni szeretnéd!",
}, },
"de_de": { "de_de": {
@@ -51,7 +51,7 @@ extension Localization on String {
"Messages": "Nachrichten", "Messages": "Nachrichten",
"Absences": "Fehlen", "Absences": "Fehlen",
"update_available": "Update verfügbar", "update_available": "Update verfügbar",
"missed_exams": "Diese Woche haben Sie %s Prüfungen verpasst.".one("Diese Woche haben Sie eine Prüfung verpasst."), "missed_exams": "Diese Woche haben Sie %s Prüfungen verpasst.",
"missed_exam_contact": "Wenden Sie sich an %s, um sie zu erneuern!", "missed_exam_contact": "Wenden Sie sich an %s, um sie zu erneuern!",
}, },
}; };

View File

@@ -48,7 +48,7 @@ class StatisticsTile extends StatelessWidget {
padding: const EdgeInsets.all(18.0), padding: const EdgeInsets.all(18.0),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0), borderRadius: BorderRadius.circular(12.0),
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
boxShadow: [ boxShadow: [
if (Provider.of<SettingsProvider>(context, listen: false) if (Provider.of<SettingsProvider>(context, listen: false)
.shadowEffect) .shadowEffect)

View File

@@ -4,7 +4,9 @@ import 'dart:math';
import 'package:animations/animations.dart'; import 'package:animations/animations.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:refilc/api/providers/update_provider.dart'; import 'package:refilc/api/providers/update_provider.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/utils.dart'; import 'package:refilc/theme/colors/utils.dart';
import 'package:refilc/ui/date_widget.dart'; import 'package:refilc/ui/date_widget.dart';
import 'package:refilc_kreta_api/models/absence.dart'; import 'package:refilc_kreta_api/models/absence.dart';
@@ -169,6 +171,7 @@ class AbsencesPageState extends State<AbsencesPage>
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
), ),
), ),
), ),
@@ -179,10 +182,22 @@ class AbsencesPageState extends State<AbsencesPage>
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Text( child: Text(
"Absences".i18n, "Absences".i18n,
style: TextStyle( style: Provider.of<SettingsProvider>(context).fontFamily !=
color: AppColors.of(context).text, '' &&
fontSize: 32.0, Provider.of<SettingsProvider>(context).titleOnlyFont
fontWeight: FontWeight.bold), ? GoogleFonts.getFont(
Provider.of<SettingsProvider>(context).fontFamily,
textStyle: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold,
),
)
: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold,
),
), ),
), ),
bottom: FilterBar( bottom: FilterBar(
@@ -504,7 +519,9 @@ class AbsencesPageState extends State<AbsencesPage>
style: TextStyle( style: TextStyle(
fontSize: 18.0, fontSize: 18.0,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
color: AppColors.of(context).green, color: value1 > 0
? AppColors.of(context).green
: AppColors.of(context).text,
), ),
), ),
Text( Text(
@@ -513,12 +530,14 @@ class AbsencesPageState extends State<AbsencesPage>
fontSize: 16.0, fontSize: 16.0,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
height: 1.1, height: 1.1,
color: ColorsUtils().fade( color: value1 > 0
context, ? ColorsUtils().fade(
AppColors.of(context).green, context,
darkenAmount: 0.5, AppColors.of(context).green,
lightenAmount: 0.4, darkenAmount: 0.5,
), lightenAmount: 0.4,
)
: AppColors.of(context).text,
), ),
), ),
], ],
@@ -535,7 +554,9 @@ class AbsencesPageState extends State<AbsencesPage>
style: TextStyle( style: TextStyle(
fontSize: 18.0, fontSize: 18.0,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
color: AppColors.of(context).red, color: value2 > 0
? AppColors.of(context).red
: AppColors.of(context).text,
), ),
), ),
Text( Text(
@@ -544,12 +565,14 @@ class AbsencesPageState extends State<AbsencesPage>
fontSize: 16.0, fontSize: 16.0,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
height: 1.1, height: 1.1,
color: ColorsUtils().fade( color: value2 > 0
context, ? ColorsUtils().fade(
AppColors.of(context).red, context,
darkenAmount: 0.4, AppColors.of(context).red,
lightenAmount: 0.2, darkenAmount: 0.4,
), lightenAmount: 0.2,
)
: AppColors.of(context).text,
), ),
), ),
], ],
@@ -597,8 +620,9 @@ class AbsencesPageState extends State<AbsencesPage>
children: [ children: [
Row( Row(
children: [ children: [
const Icon( Icon(
Icons.av_timer_rounded, Icons.av_timer_rounded,
color: value3 > 0 ? Colors.orange : null,
), ),
const SizedBox( const SizedBox(
width: 10.0, width: 10.0,

View File

@@ -84,9 +84,9 @@ class AverageSelectorState extends State<AverageSelector> {
elevation: 8, elevation: 8,
scrollbarTheme: ScrollbarThemeData( scrollbarTheme: ScrollbarThemeData(
radius: const Radius.circular(40), radius: const Radius.circular(40),
thickness: MaterialStateProperty.all<double>(6.0), thickness: WidgetStateProperty.all<double>(6.0),
trackVisibility: MaterialStateProperty.all<bool>(true), trackVisibility: WidgetStateProperty.all<bool>(true),
thumbVisibility: MaterialStateProperty.all<bool>(true), thumbVisibility: WidgetStateProperty.all<bool>(true),
), ),
offset: const Offset(-10, -10), offset: const Offset(-10, -10),
), ),

View File

@@ -34,7 +34,6 @@ import 'package:refilc_mobile_ui/pages/grades/calculator/grade_calculator_provid
import 'package:refilc_mobile_ui/pages/grades/grades_count.dart'; import 'package:refilc_mobile_ui/pages/grades/grades_count.dart';
import 'package:refilc_mobile_ui/pages/grades/graph.dart'; import 'package:refilc_mobile_ui/pages/grades/graph.dart';
import 'package:refilc_mobile_ui/pages/grades/subject_grades_container.dart'; import 'package:refilc_mobile_ui/pages/grades/subject_grades_container.dart';
import 'package:refilc_plus/ui/mobile/goal_planner/goal_planner_screen.dart';
// import 'package:refilc_plus/models/premium_scopes.dart'; // import 'package:refilc_plus/models/premium_scopes.dart';
// import 'package:refilc_plus/providers/plus_provider.dart'; // import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/goal_planner/goal_state_screen.dart'; import 'package:refilc_plus/ui/mobile/goal_planner/goal_state_screen.dart';
@@ -44,6 +43,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:refilc_plus/ui/mobile/goal_planner/goal_track_popup.dart';
import 'grades_page.i18n.dart'; import 'grades_page.i18n.dart';
// import 'package:refilc_plus/ui/mobile/goal_planner/new_goal.dart'; // import 'package:refilc_plus/ui/mobile/goal_planner/new_goal.dart';
@@ -425,9 +425,10 @@ class _GradeSubjectViewState extends State<GradeSubjectView>
// ScaffoldMessenger.of(context).showSnackBar( // ScaffoldMessenger.of(context).showSnackBar(
// const SnackBar(content: Text("Hamarosan..."))); // const SnackBar(content: Text("Hamarosan...")));
Navigator.of(context).push(CupertinoPageRoute( // Navigator.of(context).push(CupertinoPageRoute(
builder: (context) => // builder: (context) =>
GoalPlannerScreen(subject: widget.subject))); // GoalPlannerScreen(subject: widget.subject)));
GoalTrackPopup.show(context, subject: widget.subject);
}, },
child: const Icon(FeatherIcons.flag, size: 20.0), child: const Icon(FeatherIcons.flag, size: 20.0),
), ),

View File

@@ -1,9 +1,14 @@
// ignore_for_file: no_leading_underscores_for_local_identifiers // ignore_for_file: no_leading_underscores_for_local_identifiers
import 'dart:convert';
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:auto_size_text/auto_size_text.dart'; import 'package:auto_size_text/auto_size_text.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:refilc/api/providers/update_provider.dart'; import 'package:refilc/api/providers/update_provider.dart';
import 'package:refilc/models/settings.dart'; import 'package:refilc/models/settings.dart';
import 'package:refilc/ui/widgets/grade/grade_tile.dart'; import 'package:refilc/ui/widgets/grade/grade_tile.dart';
@@ -79,6 +84,7 @@ class GradesPageState extends State<GradesPage> {
late GradeCalculatorProvider calculatorProvider; late GradeCalculatorProvider calculatorProvider;
late HomeworkProvider homeworkProvider; late HomeworkProvider homeworkProvider;
late ExamProvider examProvider; late ExamProvider examProvider;
late SettingsProvider settingsProvider;
late String firstName; late String firstName;
late Widget yearlyGraph; late Widget yearlyGraph;
@@ -88,19 +94,18 @@ class GradesPageState extends State<GradesPage> {
int avgDropValue = 0; int avgDropValue = 0;
bool gradeCalcMode = false; bool gradeCalcMode = false;
bool importedViewMode = false;
List<Grade> jsonGrades = [];
List<Grade> getSubjectGrades(GradeSubject subject, List<Grade> getSubjectGrades(GradeSubject subject,
{int days = 0}) => {int days = 0}) =>
!gradeCalcMode !gradeCalcMode
? gradeProvider ? (importedViewMode ? jsonGrades : gradeProvider.grades)
.grades
.where((e) => .where((e) =>
e e.subject == subject &&
.subject ==
subject &&
e.type == GradeType.midYear && e.type == GradeType.midYear &&
(days == (days == 0 ||
0 ||
e.date.isBefore( e.date.isBefore(
DateTime.now().subtract(Duration(days: days))))) DateTime.now().subtract(Duration(days: days)))))
.toList() .toList()
@@ -109,18 +114,19 @@ class GradesPageState extends State<GradesPage> {
.toList(); .toList();
void generateTiles() { void generateTiles() {
List<GradeSubject> subjects = gradeProvider.grades List<GradeSubject> subjects =
.map((e) => GradeSubject( (importedViewMode ? jsonGrades : gradeProvider.grades)
category: e.subject.category, .map((e) => GradeSubject(
id: e.subject.id, category: e.subject.category,
name: e.subject.name, id: e.subject.id,
renamedTo: e.subject.renamedTo, name: e.subject.name,
customRounding: e.subject.customRounding, renamedTo: e.subject.renamedTo,
teacher: e.teacher, customRounding: e.subject.customRounding,
)) teacher: e.teacher,
.toSet() ))
.toList() .toSet()
..sort((a, b) => a.name.compareTo(b.name)); .toList()
..sort((a, b) => a.name.compareTo(b.name));
List<Widget> tiles = []; List<Widget> tiles = [];
Map<GradeSubject, double> subjectAvgs = {}; Map<GradeSubject, double> subjectAvgs = {};
@@ -158,13 +164,21 @@ class GradesPageState extends State<GradesPage> {
bool hasHomework = homeworkCount > 0; bool hasHomework = homeworkCount > 0;
List<Exam> allExams = examProvider.exams; List<Exam> allExams = examProvider.exams;
allExams.sort((a, b) => a.date.compareTo(b.date)); try {
allExams.sort((a, b) => a.date.compareTo(b.date));
} catch (e) {
if (kDebugMode) {
print('failed to sort exams, reason: flutter');
}
allExams = [];
}
Exam? nearestExam = allExams.firstWhereOrNull((e) => Exam? nearestExam = allExams.firstWhereOrNull((e) =>
e.subject.id == subject.id && e.writeDate.isAfter(DateTime.now())); e.subject.id == subject.id && e.writeDate.isAfter(DateTime.now()));
bool hasUnder = (hasHomework || nearestExam != null) && bool hasUnder = (hasHomework || nearestExam != null) &&
Provider.of<SettingsProvider>(context).qSubjectsSubTiles; Provider.of<SettingsProvider>(context, listen: false)
.qSubjectsSubTiles;
return Padding( return Padding(
padding: i > 1 ? const EdgeInsets.only(top: 9.0) : EdgeInsets.zero, padding: i > 1 ? const EdgeInsets.only(top: 9.0) : EdgeInsets.zero,
@@ -191,7 +205,7 @@ class GradesPageState extends State<GradesPage> {
? const Radius.circular(8.0) ? const Radius.circular(8.0)
: const Radius.circular(16.0), : const Radius.circular(16.0),
), ),
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@@ -219,7 +233,8 @@ class GradesPageState extends State<GradesPage> {
height: 6.0, height: 6.0,
), ),
if (hasHomework && if (hasHomework &&
Provider.of<SettingsProvider>(context).qSubjectsSubTiles) Provider.of<SettingsProvider>(context, listen: false)
.qSubjectsSubTiles)
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
boxShadow: [ boxShadow: [
@@ -241,7 +256,7 @@ class GradesPageState extends State<GradesPage> {
? const Radius.circular(8.0) ? const Radius.circular(8.0)
: const Radius.circular(16.0), : const Radius.circular(16.0),
), ),
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
@@ -267,6 +282,12 @@ class GradesPageState extends State<GradesPage> {
), ),
), ),
), ),
if (hasHomework &&
nearestExam != null &&
Provider.of<SettingsProvider>(context).qSubjectsSubTiles)
const SizedBox(
height: 6.0,
),
if (nearestExam != null && if (nearestExam != null &&
Provider.of<SettingsProvider>(context).qSubjectsSubTiles) Provider.of<SettingsProvider>(context).qSubjectsSubTiles)
Container( Container(
@@ -286,7 +307,7 @@ class GradesPageState extends State<GradesPage> {
bottomLeft: Radius.circular(16.0), bottomLeft: Radius.circular(16.0),
bottomRight: Radius.circular(16.0), bottomRight: Radius.circular(16.0),
), ),
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
), ),
child: ExamViewable( child: ExamViewable(
nearestExam, nearestExam,
@@ -356,8 +377,14 @@ class GradesPageState extends State<GradesPage> {
); );
} }
// print('rounding:');
// print(settingsProvider.rounding);
double subjectAvg = subjectAvgs.isNotEmpty double subjectAvg = subjectAvgs.isNotEmpty
? subjectAvgs.values.fold(0.0, (double a, double b) => a + b) / ? subjectAvgs.values.fold(
0.0,
(double a, double b) =>
a.round().toDouble() + b.round().toDouble()) /
subjectAvgs.length subjectAvgs.length
: 0.0; : 0.0;
final double classAvg = gradeProvider.groupAverages.isNotEmpty final double classAvg = gradeProvider.groupAverages.isNotEmpty
@@ -428,6 +455,7 @@ class GradesPageState extends State<GradesPage> {
calculatorProvider = Provider.of<GradeCalculatorProvider>(context); calculatorProvider = Provider.of<GradeCalculatorProvider>(context);
homeworkProvider = Provider.of<HomeworkProvider>(context); homeworkProvider = Provider.of<HomeworkProvider>(context);
examProvider = Provider.of<ExamProvider>(context); examProvider = Provider.of<ExamProvider>(context);
settingsProvider = Provider.of<SettingsProvider>(context);
context.watch<PlusProvider>(); context.watch<PlusProvider>();
@@ -441,25 +469,28 @@ class GradesPageState extends State<GradesPage> {
.fold(0.0, (double a, double b) => a + b) / .fold(0.0, (double a, double b) => a + b) /
gradeProvider.groupAverages.length; gradeProvider.groupAverages.length;
final now = gradeProvider.grades.isNotEmpty final now =
? gradeProvider.grades (importedViewMode ? jsonGrades : gradeProvider.grades).isNotEmpty
.reduce((v, e) => e.date.isAfter(v.date) ? e : v) ? (importedViewMode ? jsonGrades : gradeProvider.grades)
.date .reduce((v, e) => e.date.isAfter(v.date) ? e : v)
: DateTime.now(); .date
: DateTime.now();
final currentStudentAvg = AverageHelper.averageEvals(!gradeCalcMode final currentStudentAvg = AverageHelper.averageEvals(!gradeCalcMode
? gradeProvider.grades ? (importedViewMode ? jsonGrades : gradeProvider.grades)
.where((e) => e.type == GradeType.midYear) .where((e) => e.type == GradeType.midYear)
.toList() .toList()
: calculatorProvider.grades); : calculatorProvider.grades);
final prevStudentAvg = AverageHelper.averageEvals(gradeProvider.grades final prevStudentAvg = AverageHelper.averageEvals((importedViewMode
? jsonGrades
: gradeProvider.grades)
.where((e) => e.type == GradeType.midYear) .where((e) => e.type == GradeType.midYear)
.where((e) => e.date.isBefore(now.subtract(const Duration(days: 30)))) .where((e) => e.date.isBefore(now.subtract(const Duration(days: 30))))
.toList()); .toList());
List<Grade> graphGrades = !gradeCalcMode List<Grade> graphGrades = !gradeCalcMode
? gradeProvider.grades ? (importedViewMode ? jsonGrades : gradeProvider.grades)
.where((e) => .where((e) =>
e.type == GradeType.midYear && e.type == GradeType.midYear &&
(avgDropValue == 0 || (avgDropValue == 0 ||
@@ -493,7 +524,7 @@ class GradesPageState extends State<GradesPage> {
// const SizedBox(width: 4.0), // const SizedBox(width: 4.0),
TrendDisplay( TrendDisplay(
previous: prevStudentAvg, current: currentStudentAvg), previous: prevStudentAvg, current: currentStudentAvg),
if (gradeProvider.grades if ((importedViewMode ? jsonGrades : gradeProvider.grades)
.where((e) => e.type == GradeType.midYear) .where((e) => e.type == GradeType.midYear)
.isNotEmpty) .isNotEmpty)
AverageDisplay(average: currentStudentAvg), AverageDisplay(average: currentStudentAvg),
@@ -560,6 +591,7 @@ class GradesPageState extends State<GradesPage> {
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
), ),
), ),
), ),
@@ -568,11 +600,21 @@ class GradesPageState extends State<GradesPage> {
title: Padding( title: Padding(
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Text( child: Text(
"Grades".i18n, "page_title_grades".i18n,
style: TextStyle( style: Provider.of<SettingsProvider>(context).fontFamily !=
color: AppColors.of(context).text, '' &&
fontSize: 32.0, Provider.of<SettingsProvider>(context).titleOnlyFont
fontWeight: FontWeight.bold), ? GoogleFonts.getFont(
Provider.of<SettingsProvider>(context).fontFamily,
textStyle: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold),
)
: TextStyle(
color: AppColors.of(context).text,
fontSize: 32.0,
fontWeight: FontWeight.bold),
), ),
), ),
shadowColor: Theme.of(context).shadowColor, shadowColor: Theme.of(context).shadowColor,
@@ -614,7 +656,8 @@ class GradesPageState extends State<GradesPage> {
void gradeCalcTotal(BuildContext context) { void gradeCalcTotal(BuildContext context) {
calculatorProvider.clear(); calculatorProvider.clear();
calculatorProvider.addAllGrades(gradeProvider.grades); calculatorProvider
.addAllGrades((importedViewMode ? jsonGrades : gradeProvider.grades));
_sheetController = _scaffoldKey.currentState?.showBottomSheet( _sheetController = _scaffoldKey.currentState?.showBottomSheet(
(context) => const RoundedBottomSheet( (context) => const RoundedBottomSheet(
@@ -646,7 +689,7 @@ class GradesPageState extends State<GradesPage> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0), borderRadius: BorderRadius.circular(12.0),
color: Theme.of(context).colorScheme.background), color: Theme.of(context).colorScheme.surface),
child: ListTile( child: ListTile(
title: Row( title: Row(
children: [ children: [
@@ -658,15 +701,17 @@ class GradesPageState extends State<GradesPage> {
], ],
), ),
onTap: () { onTap: () {
if (!Provider.of<PlusProvider>(context, listen: false) // if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.totalGradeCalculator)) { // .hasScope(PremiumScopes.totalGradeCalculator)) {
PlusLockedFeaturePopup.show( // PlusLockedFeaturePopup.show(
context: context, feature: PremiumFeature.gradeCalculation); // context: context, feature: PremiumFeature.gradeCalculation);
return; // return;
} // }
// SoonAlert.show(context: context); // SoonAlert.show(context: context);
gradeCalcTotal(context); gradeCalcTotal(context);
Navigator.of(context, rootNavigator: true).pop();
}, },
), ),
), ),
@@ -676,7 +721,65 @@ class GradesPageState extends State<GradesPage> {
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0), borderRadius: BorderRadius.circular(12.0),
color: Theme.of(context).colorScheme.background), color: Theme.of(context).colorScheme.surface),
child: ListTile(
title: Row(
children: [
const Icon(Icons.toll_rounded),
const SizedBox(
width: 10.0,
),
Text('import_grades'.i18n),
],
),
trailing: importedViewMode ? const Icon(FeatherIcons.x) : null,
onTap: () {
if (importedViewMode) {
importedViewMode = false;
generateTiles();
setState(() {});
Navigator.of(context, rootNavigator: true).pop();
return;
}
if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.gradeExporting)) {
PlusLockedFeaturePopup.show(
context: context, feature: PremiumFeature.gradeExporting);
return;
}
// show file picker
FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['json'],
).then((value) {
if (value != null) {
final File file = File(value.files.single.path!);
final String content = file.readAsStringSync();
final List<dynamic> json = jsonDecode(content);
jsonGrades = json.map((e) => Grade.fromJson(e)).toList();
importedViewMode = true;
generateTiles();
setState(() {});
}
});
Navigator.of(context, rootNavigator: true).pop();
},
),
),
const SizedBox(
height: 10.0,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Theme.of(context).colorScheme.surface),
child: SwitchListTile( child: SwitchListTile(
title: Row( title: Row(
children: [ children: [

View File

@@ -4,8 +4,9 @@ extension Localization on String {
static final _t = Translations.byLocale("hu_hu") + static final _t = Translations.byLocale("hu_hu") +
{ {
"en_en": { "en_en": {
"Grades": "Subjects", "Grades": "Grades",
"Ghost Grades": "Grades", "page_title_grades": "Subjects",
"Ghost Grades": "Ghost Grades",
"Subjects": "Your Subjects", "Subjects": "Your Subjects",
"Subjects_changes": "Subject Differences", "Subjects_changes": "Subject Differences",
"empty": "You don't have any subjects.", "empty": "You don't have any subjects.",
@@ -17,8 +18,7 @@ extension Localization on String {
"subjectavg": "Subject Average", "subjectavg": "Subject Average",
"classavg": "Class Average", "classavg": "Class Average",
"fail_warning": "Failure warning", "fail_warning": "Failure warning",
"fail_warning_description": "fail_warning_description": "You are failing %d subject(s)!",
"You are failing %d subjects!".one("You are failing a subject!"),
"data": "Data", "data": "Data",
"you_have_hw": "You have %s homework(s) to do", "you_have_hw": "You have %s homework(s) to do",
"grades_cnt": "Grade count: %s", "grades_cnt": "Grade count: %s",
@@ -29,9 +29,11 @@ extension Localization on String {
"grades": "Grades", "grades": "Grades",
"show_exams_homework": "Exams and Homework", "show_exams_homework": "Exams and Homework",
"grade_calc": "Grade Calculator", "grade_calc": "Grade Calculator",
"import_grades": "Import Grades (JSON)",
}, },
"hu_hu": { "hu_hu": {
"Grades": "Tantárgyak", "Grades": "Jegyek",
"page_title_grades": "Tantárgyak",
"Ghost Grades": "Szellem jegyek", "Ghost Grades": "Szellem jegyek",
"Subjects": "Tantárgyaid", "Subjects": "Tantárgyaid",
"Subjects_changes": "Tantárgyi változások", "Subjects_changes": "Tantárgyi változások",
@@ -55,9 +57,11 @@ extension Localization on String {
"grades": "Jegyek", "grades": "Jegyek",
"show_exams_homework": "Dolgozatok és házik", "show_exams_homework": "Dolgozatok és házik",
"grade_calc": "Jegy kalkulátor", "grade_calc": "Jegy kalkulátor",
"import_grades": "Jegyek importálása (JSON)",
}, },
"de_de": { "de_de": {
"Grades": "Fächer", "Grades": "Klassen",
"page_title_grades": "Themen",
"Ghost Grades": "Geist Noten", "Ghost Grades": "Geist Noten",
"Subjects": "Ihre Themen", "Subjects": "Ihre Themen",
"Subjects_changes": "Betreff Änderungen", "Subjects_changes": "Betreff Änderungen",
@@ -81,6 +85,7 @@ extension Localization on String {
"grades": "Noten", "grades": "Noten",
"show_exams_homework": "Referate und Hausaufgaben", "show_exams_homework": "Referate und Hausaufgaben",
"grade_calc": "Noten-Rechner", "grade_calc": "Noten-Rechner",
"import_grades": "Noten importieren (JSON)",
}, },
}; };

View File

@@ -179,7 +179,7 @@ class GradeGraphState extends State<GradeGraph> {
? Alignment.topRight ? Alignment.topRight
: Alignment.topLeft, : Alignment.topLeft,
style: TextStyle( style: TextStyle(
backgroundColor: Theme.of(context).colorScheme.background, backgroundColor: Theme.of(context).colorScheme.surface,
color: AppColors.of(context).text, color: AppColors.of(context).text,
fontSize: 16.0, fontSize: 16.0,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@@ -217,7 +217,7 @@ class GradeGraphState extends State<GradeGraph> {
height: 158, height: 158,
child: subjectSpots.length > 1 child: subjectSpots.length > 1
? Padding( ? Padding(
padding: const EdgeInsets.only(top: 8.0, right: 8.0), padding: const EdgeInsets.only(top: 6.0, right: 0.0),
child: LineChart( child: LineChart(
LineChartData( LineChartData(
extraLinesData: ExtraLinesData( extraLinesData: ExtraLinesData(
@@ -228,50 +228,74 @@ class GradeGraphState extends State<GradeGraph> {
preventCurveOverShooting: false, preventCurveOverShooting: false,
spots: subjectSpots, spots: subjectSpots,
isCurved: true, isCurved: true,
colors: averageColors.reversed.toList(), // colors: averageColors.reversed.toList(),
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: averageColors.reversed.toList(),
),
barWidth: 6, barWidth: 6,
curveSmoothness: 0.2, curveSmoothness: 0.2,
isStrokeCapRound: true, isStrokeCapRound: true,
dotData: FlDotData(show: false), dotData: const FlDotData(show: false),
belowBarData: BarAreaData( belowBarData: BarAreaData(
show: true, show: true,
colors: [ gradient: LinearGradient(
averageColor.withOpacity(0.7), begin: Alignment.topCenter,
averageColor.withOpacity(0.3), end: Alignment.bottomCenter,
averageColor.withOpacity(0.2), colors: [
averageColor.withOpacity(0.1), averageColor.withOpacity(0.7),
], averageColor.withOpacity(0.3),
gradientColorStops: [0.1, 0.6, 0.8, 1], averageColor.withOpacity(0.2),
gradientFrom: const Offset(0, 0), averageColor.withOpacity(0.1),
gradientTo: const Offset(0, 1), ],
stops: const [0.1, 0.6, 0.8, 1],
),
// gradientColorStops: [0.1, 0.6, 0.8, 1],
// gradientFrom: const Offset(0, 0),
// gradientTo: const Offset(0, 1),
), ),
), ),
if (ghostData.isNotEmpty && ghostSpots.isNotEmpty) if (ghostData.isNotEmpty && ghostSpots.isNotEmpty)
LineChartBarData( LineChartBarData(
preventCurveOverShooting: true, preventCurveOverShooting: false,
spots: ghostSpots, spots: ghostSpots,
isCurved: true, isCurved: true,
colors: [AppColors.of(context).text], color: AppColors.of(context).text,
barWidth: 8, barWidth: 6,
curveSmoothness: 0.2,
isStrokeCapRound: true, isStrokeCapRound: true,
dotData: FlDotData(show: false), dotData: const FlDotData(show: false),
belowBarData: BarAreaData( belowBarData: BarAreaData(
show: true, show: true,
colors: [ gradient: LinearGradient(
AppColors.of(context).text.withOpacity(0.7), begin: Alignment.topCenter,
AppColors.of(context).text.withOpacity(0.3), end: Alignment.bottomCenter,
AppColors.of(context).text.withOpacity(0.2), colors: [
AppColors.of(context).text.withOpacity(0.1), AppColors.of(context)
], .text
gradientColorStops: [0.1, 0.6, 0.8, 1], .withOpacity(0.7),
gradientFrom: const Offset(0, 0), AppColors.of(context)
gradientTo: const Offset(0, 1), .text
.withOpacity(0.3),
AppColors.of(context)
.text
.withOpacity(0.2),
AppColors.of(context)
.text
.withOpacity(0.1),
],
stops: const [0.1, 0.6, 0.8, 1],
),
// gradientColorStops: [0.1, 0.6, 0.8, 1],
// gradientFrom: const Offset(0, 0),
// gradientTo: const Offset(0, 1),
), ),
), ),
], ],
minY: 1, minY: 1,
maxY: 5, maxY: 5,
gridData: FlGridData( gridData: const FlGridData(
show: true, show: true,
horizontalInterval: 1, horizontalInterval: 1,
// checkToShowVerticalLine: (_) => false, // checkToShowVerticalLine: (_) => false,
@@ -285,8 +309,8 @@ class GradeGraphState extends State<GradeGraph> {
// ), // ),
), ),
lineTouchData: LineTouchData( lineTouchData: LineTouchData(
touchTooltipData: LineTouchTooltipData( touchTooltipData: const LineTouchTooltipData(
tooltipBgColor: Colors.grey.shade800, // tooltipBgColor: Colors.grey.shade800,
fitInsideVertically: true, fitInsideVertically: true,
fitInsideHorizontally: true, fitInsideHorizontally: true,
), ),
@@ -320,64 +344,111 @@ class GradeGraphState extends State<GradeGraph> {
), ),
), ),
titlesData: FlTitlesData( titlesData: FlTitlesData(
bottomTitles: SideTitles( bottomTitles: AxisTitles(
showTitles: true, sideTitles: SideTitles(
reservedSize: 24, showTitles: true,
getTextStyles: (context, value) => TextStyle( reservedSize: 25,
color: getTitlesWidget: (value, meta) {
AppColors.of(context).text.withOpacity(.75), if (value == meta.max || value == meta.min) {
fontWeight: FontWeight.bold, return Container();
fontSize: 14.0, }
),
margin: 12.0,
getTitles: (value) {
var format = DateFormat(
"MMM", I18n.of(context).locale.toString());
String title = format var format = DateFormat("MMM",
.format(DateTime(0, value.floor() % 12)) I18n.of(context).locale.toString());
.replaceAll(".", "");
title =
title.substring(0, min(title.length, 4));
return title.toUpperCase(); String title = format
}, .format(DateTime(0, value.floor() % 12))
interval: () { .replaceAll(".", "");
List<Grade> tData = title =
ghostData.isNotEmpty ? ghostData : data; title.substring(0, min(title.length, 4));
tData.sort((a, b) =>
a.writeDate.compareTo(b.writeDate)); return Text(
return ghostData.isNotEmpty title.toUpperCase(),
? 3.0 style: TextStyle(
: tData.first.writeDate color: AppColors.of(context)
.add(const Duration(days: 120)) .text
.isBefore(tData.last.writeDate) .withOpacity(.75),
? 2.0 fontWeight: FontWeight.bold,
: 2.5; fontSize: 14.0,
}(), ),
checkToShowTitle: (double minValue, );
double maxValue, },
SideTitles sideTitles, // getTextStyles: (context, value) => TextStyle(
double appliedInterval, // color: AppColors.of(context)
double value) { // .text
if (value == maxValue || value == minValue) { // .withOpacity(.75),
return false; // fontWeight: FontWeight.bold,
} // fontSize: 14.0,
return true; // ),
}, // margin: 12.0,
), // getTitles: (value) {
leftTitles: SideTitles( // var format = DateFormat("MMM",
showTitles: true, // I18n.of(context).locale.toString());
interval: 1.0,
getTextStyles: (context, value) => TextStyle( // String title = format
color: AppColors.of(context).text, // .format(DateTime(0, value.floor() % 12))
fontWeight: FontWeight.bold, // .replaceAll(".", "");
fontSize: 18.0, // title =
// title.substring(0, min(title.length, 4));
// return title.toUpperCase();
// },
interval: () {
List<Grade> tData =
ghostData.isNotEmpty ? ghostData : data;
tData.sort((a, b) =>
a.writeDate.compareTo(b.writeDate));
return ghostData.isNotEmpty
? 3.0
: tData.first.writeDate
.add(const Duration(days: 120))
.isBefore(tData.last.writeDate)
? 2.0
: 2.5;
}(),
// checkToShowTitle: (double minValue,
// double maxValue,
// SideTitles sideTitles,
// double appliedInterval,
// double value) {
// if (value == maxValue || value == minValue) {
// return false;
// }
// return true;
// },
), ),
margin: 16,
), ),
rightTitles: SideTitles(showTitles: false), leftTitles: AxisTitles(
topTitles: SideTitles(showTitles: false), sideTitles: SideTitles(
showTitles: true,
interval: 1.0,
reservedSize: 26.0,
getTitlesWidget: (value, meta) => Padding(
padding: const EdgeInsets.only(
left: 6.0, right: 10.0),
child: Text(
value.toInt().toString(),
style: TextStyle(
color: AppColors.of(context).text,
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
),
// getTextStyles: (context, value) => TextStyle(
// color: AppColors.of(context).text,
// fontWeight: FontWeight.bold,
// fontSize: 18.0,
// ),
// margin: 16,
),
),
rightTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: const AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
), ),
), ),
), ),

View File

@@ -3,6 +3,7 @@ import 'dart:math';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:refilc/api/providers/live_card_provider.dart'; import 'package:refilc/api/providers/live_card_provider.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/ui/date_widget.dart'; import 'package:refilc/ui/date_widget.dart';
@@ -244,14 +245,34 @@ class HomePageState extends State<HomePage> with TickerProviderStateMixin {
greeting, greeting,
overflow: TextOverflow.fade, overflow: TextOverflow.fade,
textAlign: TextAlign.start, textAlign: TextAlign.start,
style: TextStyle( style:
fontWeight: FontWeight.bold, Provider.of<SettingsProvider>(context)
fontSize: 18.0, .fontFamily !=
color: Theme.of(context) '' &&
.textTheme Provider.of<SettingsProvider>(
.bodyMedium context)
?.color, .titleOnlyFont
), ? GoogleFonts.getFont(
Provider.of<SettingsProvider>(
context)
.fontFamily,
textStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Theme.of(context)
.textTheme
.bodyMedium
?.color,
),
)
: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Theme.of(context)
.textTheme
.bodyMedium
?.color,
),
), ),
Text( Text(
DateFormat('EEEE, MMM d', DateFormat('EEEE, MMM d',
@@ -317,6 +338,7 @@ class HomePageState extends State<HomePage> with TickerProviderStateMixin {
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
), ),
), ),
), ),
@@ -355,7 +377,7 @@ class HomePageState extends State<HomePage> with TickerProviderStateMixin {
LiveCardState.duringLesson || LiveCardState.duringLesson ||
_liveCard.currentState == _liveCard.currentState ==
LiveCardState.duringBreak) LiveCardState.duringBreak)
? 55.0 ? 62.0
: 52.0), : 52.0),
), ),
child: Transform.scale( child: Transform.scale(

View File

@@ -19,8 +19,7 @@ extension Localization on String {
"Messages": "Messages", "Messages": "Messages",
"Absences": "Absences", "Absences": "Absences",
"update_available": "Update Available", "update_available": "Update Available",
"missed_exams": "You missed %s exams this week." "missed_exams": "You missed %s exam(s) this week.",
.one("You missed an exam this week."),
"missed_exam_contact": "Contact %s to resolve it!", "missed_exam_contact": "Contact %s to resolve it!",
}, },
"hu_hu": { "hu_hu": {
@@ -39,8 +38,7 @@ extension Localization on String {
"Messages": "Üzenetek", "Messages": "Üzenetek",
"Absences": "Hiányzások", "Absences": "Hiányzások",
"update_available": "Frissítés elérhető", "update_available": "Frissítés elérhető",
"missed_exams": "Ezen a héten hiányoztál %s dolgozatról." "missed_exams": "Ezen a héten hiányoztál %s dolgozatról.",
.one("Ezen a héten hiányoztál egy dolgozatról."),
"missed_exam_contact": "Keresd %s tanár urat/hölgyet, hogy pótold!", "missed_exam_contact": "Keresd %s tanár urat/hölgyet, hogy pótold!",
}, },
"de_de": { "de_de": {
@@ -59,8 +57,7 @@ extension Localization on String {
"Messages": "Nachrichten", "Messages": "Nachrichten",
"Absences": "Fehlen", "Absences": "Fehlen",
"update_available": "Update verfügbar", "update_available": "Update verfügbar",
"missed_exams": "Diese Woche haben Sie %s Prüfungen verpasst." "missed_exams": "Diese Woche haben Sie %s Prüfungen verpasst.",
.one("Diese Woche haben Sie eine Prüfung verpasst."),
"missed_exam_contact": "Wenden Sie sich an %s, um sie zu erneuern!", "missed_exam_contact": "Wenden Sie sich an %s, um sie zu erneuern!",
}, },
}; };

View File

@@ -1,6 +1,7 @@
// ignore_for_file: unnecessary_null_comparison // ignore_for_file: unnecessary_null_comparison
import 'package:animations/animations.dart'; import 'package:animations/animations.dart';
import 'package:flutter/services.dart';
import 'package:refilc/api/providers/user_provider.dart'; import 'package:refilc/api/providers/user_provider.dart';
import 'package:refilc/helpers/subject.dart'; import 'package:refilc/helpers/subject.dart';
import 'package:refilc/models/settings.dart'; import 'package:refilc/models/settings.dart';
@@ -43,6 +44,10 @@ class LiveCardStateA extends State<LiveCard> {
_userProvider = Provider.of<UserProvider>(context, listen: false); _userProvider = Provider.of<UserProvider>(context, listen: false);
liveCard = Provider.of<LiveCardProvider>(context, listen: false); liveCard = Provider.of<LiveCardProvider>(context, listen: false);
_userProvider.addListener(liveCard.update); _userProvider.addListener(liveCard.update);
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
} }
@override @override
@@ -404,7 +409,7 @@ class LiveCardStateA extends State<LiveCard> {
swapRoom: true, swapRoom: true,
currentLessonIndicator: false, currentLessonIndicator: false,
padding: padding:
const EdgeInsets.only(top: 6.0, bottom: 4.0), const EdgeInsets.only(top: 2.0, bottom: 4.0),
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
showSubTiles: false, showSubTiles: false,
), ),
@@ -419,14 +424,38 @@ class LiveCardStateA extends State<LiveCard> {
if (progressCurrent != null && if (progressCurrent != null &&
progressMax != null) progressMax != null)
GestureDetector( GestureDetector(
onTap: () { onTap: () async {
showDialog( SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness:
Brightness.dark,
systemNavigationBarColor:
Colors.transparent,
systemNavigationBarIconBrightness:
Brightness.dark,
));
var result = await showDialog(
barrierColor: Colors.black, barrierColor: Colors.black,
context: context, context: context,
builder: (context) => HeadsUpCountdown( builder: (context) => HeadsUpCountdown(
maxTime: maxTime, maxTime: maxTime,
elapsedTime: elapsedTime), elapsedTime: elapsedTime),
); );
if (result != null) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
}
}, },
child: Container( child: Container(
color: Colors.transparent, color: Colors.transparent,
@@ -825,14 +854,38 @@ class LiveCardStateA extends State<LiveCard> {
if (progressCurrent != null && if (progressCurrent != null &&
progressMax != null) progressMax != null)
GestureDetector( GestureDetector(
onTap: () { onTap: () async {
showDialog( SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
DeviceOrientation.landscapeRight,
DeviceOrientation.landscapeLeft,
]);
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness:
Brightness.dark,
systemNavigationBarColor:
Colors.transparent,
systemNavigationBarIconBrightness:
Brightness.dark,
));
var result = await showDialog(
barrierColor: Colors.black, barrierColor: Colors.black,
context: context, context: context,
builder: (context) => HeadsUpCountdown( builder: (context) => HeadsUpCountdown(
maxTime: maxTime, maxTime: maxTime,
elapsedTime: elapsedTime), elapsedTime: elapsedTime),
); );
if (result != null) {
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
}
}, },
child: Container( child: Container(
color: Colors.transparent, color: Colors.transparent,
@@ -911,6 +964,37 @@ class LiveCardStateA extends State<LiveCard> {
Row( Row(
children: liveCard.nextLesson != null children: liveCard.nextLesson != null
? [ ? [
Container(
width: (liveCard.nextLesson?.room
.length ??
0) >
20
? 111
: null,
padding: const EdgeInsets.symmetric(
horizontal: 5.5, vertical: 3.0),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.tertiary
.withOpacity(.15),
borderRadius:
BorderRadius.circular(10.0),
),
child: Text(
liveCard.nextLesson!.room,
overflow: TextOverflow.ellipsis,
style: TextStyle(
height: 1.1,
fontSize: 12.0,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.9),
),
),
),
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),

View File

@@ -5,8 +5,8 @@ extension Localization on String {
{ {
"en_en": { "en_en": {
"next": "Next", "next": "Next",
"remaining min": "%d mins".one("%d min"), "remaining min": "%d min(s)",
"remaining sec": "%d secs".one("%d sec"), "remaining sec": "%d sec(s)",
"break": "Break", "break": "Break",
"go to room": "Go to room %s.", "go to room": "Go to room %s.",
"go ground floor": "Go to the ground floor.", "go ground floor": "Go to the ground floor.",
@@ -27,8 +27,8 @@ extension Localization on String {
}, },
"hu_hu": { "hu_hu": {
"next": "Következő", "next": "Következő",
"remaining min": "%d perc".one("%d perc"), "remaining min": "%d perc",
"remaining sec": "%d másodperc".one("%d másodperc"), "remaining sec": "%d másodperc",
"break": "Szünet", "break": "Szünet",
"go to room": "Menj a(z) %s terembe.", "go to room": "Menj a(z) %s terembe.",
"go ground floor": "Menj a földszintre.", "go ground floor": "Menj a földszintre.",
@@ -49,8 +49,8 @@ extension Localization on String {
}, },
"de_de": { "de_de": {
"next": "Nächste", "next": "Nächste",
"remaining min": "%d Minuten".one("%d Minute"), "remaining min": "%d Minute(n)",
"remaining sec": "%d Sekunden".one("%d Sekunden"), "remaining sec": "%d Sekunde(n)",
"break": "Pause", "break": "Pause",
"go to room": "Geh in den Raum %s.", "go to room": "Geh in den Raum %s.",
"go ground floor": "Geh dir Treppe hinunter.", "go ground floor": "Geh dir Treppe hinunter.",

View File

@@ -72,10 +72,10 @@ class _LiveCardWidgetState extends State<LiveCardWidget> {
? const EdgeInsets.all(12.0) ? const EdgeInsets.all(12.0)
: EdgeInsets.zero, : EdgeInsets.zero,
decoration: BoxDecoration( decoration: BoxDecoration(
// color: Theme.of(context).colorScheme.background, // color: Theme.of(context).colorScheme.surface,
color: widget.children != null color: widget.children != null
? Colors.transparent ? Colors.transparent
: Theme.of(context).colorScheme.background, : Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(16.0), borderRadius: BorderRadius.circular(16.0),
boxShadow: [ boxShadow: [
if (Provider.of<SettingsProvider>(context, listen: false) if (Provider.of<SettingsProvider>(context, listen: false)

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