Compare commits

...

103 Commits
5.0.0 ... 5.0.2

Author SHA1 Message Date
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
88 changed files with 3176 additions and 702 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

@@ -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>

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

@@ -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

@@ -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

@@ -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

@@ -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,7 @@ 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,
// 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 +63,8 @@ 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,
}); });
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 +87,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 +133,12 @@ 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
},
); );
await migrateDB(db, struct: userDataDB, defaultValues: { await migrateDB(db, struct: userDataDB, defaultValues: {
"grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]", "grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]",
@@ -152,12 +161,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

@@ -22,7 +22,7 @@ import 'package:intl/intl.dart';
import 'package:refilc_kreta_api/models/message.dart'; import 'package:refilc_kreta_api/models/message.dart';
// if you want to add a new category, also add it to the DB or else the app will probably crash // if you want to add a new category, also add it to the DB or else the app will probably crash
enum LastSeenCategory { enum LastSeenCategory {
grade, grade,
surprisegrade, surprisegrade,
absence, absence,
@@ -212,7 +212,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 +485,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 +506,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 +527,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 +611,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 +633,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,

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

@@ -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,
);
}
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,7 @@ class SettingsProvider extends ChangeNotifier {
bool _navShadow; bool _navShadow;
bool _newColors; bool _newColors;
bool _uwuMode; bool _uwuMode;
bool _newPopups;
// quick settings // quick settings
bool _qTimetableLessonNum; bool _qTimetableLessonNum;
bool _qTimetableSubTiles; bool _qTimetableSubTiles;
@@ -167,6 +169,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 +179,7 @@ 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 bool qTimetableLessonNum, required bool qTimetableLessonNum,
required bool qTimetableSubTiles, required bool qTimetableSubTiles,
required bool qSubjectsSubTiles, required bool qSubjectsSubTiles,
@@ -235,6 +239,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 +249,7 @@ class SettingsProvider extends ChangeNotifier {
_navShadow = navShadow, _navShadow = navShadow,
_newColors = newColors, _newColors = newColors,
_uwuMode = uwuMode, _uwuMode = uwuMode,
_newPopups = newPopups,
_qTimetableLessonNum = qTimetableLessonNum, _qTimetableLessonNum = qTimetableLessonNum,
_qTimetableSubTiles = qTimetableSubTiles, _qTimetableSubTiles = qTimetableSubTiles,
_qSubjectsSubTiles = qSubjectsSubTiles; _qSubjectsSubTiles = qSubjectsSubTiles;
@@ -322,6 +328,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 +338,7 @@ 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,
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 +405,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 +415,7 @@ 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,
"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 +486,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 +496,7 @@ class SettingsProvider extends ChangeNotifier {
navShadow: true, navShadow: true,
newColors: true, newColors: true,
uwuMode: false, uwuMode: false,
newPopups: true,
qTimetableLessonNum: true, qTimetableLessonNum: true,
qTimetableSubTiles: true, qTimetableSubTiles: true,
qSubjectsSubTiles: true, qSubjectsSubTiles: true,
@@ -546,6 +558,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 +568,7 @@ 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;
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 +626,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 +636,7 @@ class SettingsProvider extends ChangeNotifier {
bool? navShadow, bool? navShadow,
bool? newColors, bool? newColors,
bool? uwuMode, bool? uwuMode,
bool? newPopups,
bool? qTimetableLessonNum, bool? qTimetableLessonNum,
bool? qTimetableSubTiles, bool? qTimetableSubTiles,
bool? qSubjectsSubTiles, bool? qSubjectsSubTiles,
@@ -777,6 +793,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 +825,9 @@ 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 (qTimetableLessonNum != null && if (qTimetableLessonNum != null &&
qTimetableLessonNum != _qTimetableLessonNum) { qTimetableLessonNum != _qTimetableLessonNum) {
_qTimetableLessonNum = qTimetableLessonNum; _qTimetableLessonNum = qTimetableLessonNum;

View File

@@ -16,8 +16,10 @@ class User {
Role role; Role role;
String nickname; String nickname;
String picture; String picture;
int gradeStreak;
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 +31,7 @@ class User {
required this.role, required this.role,
this.nickname = "", this.nickname = "",
this.picture = "", this.picture = "",
this.gradeStreak = 0,
}) { }) {
if (id != null) { if (id != null) {
this.id = id; this.id = id;
@@ -57,6 +60,7 @@ 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,
); );
} }

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),
@@ -229,8 +230,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),

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

@@ -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

@@ -3,7 +3,7 @@ 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.2+266
environment: environment:
sdk: ">=2.17.0 <=3.3.2" sdk: ">=2.17.0 <=3.3.2"
@@ -104,6 +104,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

@@ -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

@@ -80,8 +80,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 +212,8 @@ class KretaClient {
res = await request.send(); res = await request.send();
if (res.statusCode == 401) { if (res.statusCode == 401) {
headerMap.remove("authorization");
await refreshLogin(); await refreshLogin();
headerMap.remove("authorization");
} else { } else {
break; break;
} }

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) {
@@ -133,6 +137,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 +199,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

@@ -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

@@ -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

@@ -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

@@ -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 @@ 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

@@ -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,25 @@ 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), return GestureDetector(
child: ExamTile( onTap: () => ExamPopup.show(context: context, exam: exam),
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 +105,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,
@@ -210,13 +219,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(
@@ -288,7 +303,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),

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,
), ),
@@ -387,11 +418,9 @@ class TimetableLessonPopup extends StatelessWidget {
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.background,
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,
@@ -487,7 +524,7 @@ class TimetableLessonPopup extends StatelessWidget {
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.background,
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.background,
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.background,
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,
// ), // ),

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

@@ -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

@@ -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,13 @@
// 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: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';
@@ -88,19 +92,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 +112,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 = {};
@@ -164,7 +168,8 @@ class GradesPageState extends State<GradesPage> {
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,
@@ -219,7 +224,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: [
@@ -267,6 +273,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(
@@ -441,25 +453,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 +508,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 +575,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 +584,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 +640,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(
@@ -667,6 +694,66 @@ class GradesPageState extends State<GradesPage> {
// SoonAlert.show(context: context); // SoonAlert.show(context: context);
gradeCalcTotal(context); gradeCalcTotal(context);
Navigator.of(context, rootNavigator: true).pop();
},
),
),
const SizedBox(
height: 10.0,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Theme.of(context).colorScheme.background),
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();
}, },
), ),
), ),

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

@@ -248,11 +248,12 @@ class GradeGraphState extends State<GradeGraph> {
), ),
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], colors: [AppColors.of(context).text],
barWidth: 8, barWidth: 6,
curveSmoothness: 0.2,
isStrokeCapRound: true, isStrokeCapRound: true,
dotData: FlDotData(show: false), dotData: FlDotData(show: false),
belowBarData: BarAreaData( belowBarData: BarAreaData(

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

@@ -404,7 +404,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,
), ),
@@ -911,6 +911,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

@@ -1,6 +1,8 @@
import 'dart:math'; import 'dart:math';
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/ui/date_widget.dart'; import 'package:refilc/ui/date_widget.dart';
import 'package:refilc_kreta_api/providers/message_provider.dart'; import 'package:refilc_kreta_api/providers/message_provider.dart';
import 'package:refilc/api/providers/user_provider.dart'; import 'package:refilc/api/providers/user_provider.dart';
@@ -109,6 +111,7 @@ class MessagesPageState extends State<MessagesPage>
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
), ),
), ),
), ),
@@ -128,10 +131,22 @@ class MessagesPageState extends State<MessagesPage>
), ),
Text( Text(
"Messages".i18n, "Messages".i18n,
style: TextStyle( style: Provider.of<SettingsProvider>(context)
color: AppColors.of(context).text, .fontFamily !=
fontSize: 32.0, '' &&
fontWeight: FontWeight.bold), Provider.of<SettingsProvider>(context)
.titleOnlyFont
? 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),
), ),
], ],
), ),

View File

@@ -5,6 +5,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/database_provider.dart'; import 'package:refilc/api/providers/database_provider.dart';
import 'package:refilc/api/providers/self_note_provider.dart'; import 'package:refilc/api/providers/self_note_provider.dart';
import 'package:refilc/api/providers/update_provider.dart'; import 'package:refilc/api/providers/update_provider.dart';
@@ -35,6 +36,7 @@ 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/plus/premium_inline.dart'; import 'package:refilc_plus/ui/mobile/plus/premium_inline.dart';
import 'package:refilc_plus/ui/mobile/plus/upsell.dart'; import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
import 'package:uuid/uuid.dart';
import 'notes_page.i18n.dart'; import 'notes_page.i18n.dart';
enum AbsenceFilter { absences, delays, misses } enum AbsenceFilter { absences, delays, misses }
@@ -65,9 +67,14 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
Map<String, bool> doneItems = {}; Map<String, bool> doneItems = {};
List<Widget> noteTiles = []; List<Widget> noteTiles = [];
List<TodoItem> todoItems = [];
final TextEditingController _taskName = TextEditingController();
final TextEditingController _taskContent = TextEditingController();
void generateTiles() async { void generateTiles() async {
doneItems = await databaseProvider.userQuery.toDoItems(userId: user.id!); doneItems = await databaseProvider.userQuery.toDoItems(userId: user.id!);
todoItems = await databaseProvider.userQuery.getTodoItems(userId: user.id!);
List<Widget> tiles = []; List<Widget> tiles = [];
@@ -82,7 +89,7 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
List<Widget> toDoTiles = []; List<Widget> toDoTiles = [];
if (hw.isNotEmpty && if (hw.isNotEmpty &&
!Provider.of<PlusProvider>(context, listen: false) Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.unlimitedSelfNotes)) { .hasScope(PremiumScopes.unlimitedSelfNotes)) {
toDoTiles.addAll(hw.map((e) => TickTile( toDoTiles.addAll(hw.map((e) => TickTile(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
@@ -102,6 +109,21 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
))); )));
} }
if (selfNoteProvider.todos.isNotEmpty) {
toDoTiles.addAll(selfNoteProvider.todos.map((e) => TickTile(
padding: EdgeInsets.zero,
title: e.title,
description: e.content,
isTicked: e.done,
onTap: (p0) async {
todoItems.firstWhere((element) => element.id == e.id).done = p0;
await databaseProvider.userStore
.storeSelfTodoItems(todoItems, userId: user.id!);
},
)));
}
if (toDoTiles.isNotEmpty) { if (toDoTiles.isNotEmpty) {
tiles.add(const SizedBox( tiles.add(const SizedBox(
height: 10.0, height: 10.0,
@@ -128,26 +150,31 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
CupertinoPageRoute( CupertinoPageRoute(
builder: (context) => NoteViewScreen(note: e))), builder: (context) => NoteViewScreen(note: e))),
) )
: Container( : GestureDetector(
height: MediaQuery.of(context).size.width / 2.42, onTap: () => Navigator.of(context, rootNavigator: true).push(
width: MediaQuery.of(context).size.width / 2.42, CupertinoPageRoute(
decoration: BoxDecoration( builder: (context) => NoteViewScreen(note: e))),
boxShadow: [ child: Container(
if (Provider.of<SettingsProvider>(context, listen: false) height: MediaQuery.of(context).size.width / 2.42,
.shadowEffect) width: MediaQuery.of(context).size.width / 2.42,
BoxShadow( decoration: BoxDecoration(
offset: const Offset(0, 21), boxShadow: [
blurRadius: 23.0, if (Provider.of<SettingsProvider>(context, listen: false)
color: Theme.of(context).shadowColor, .shadowEffect)
), BoxShadow(
], offset: const Offset(0, 21),
), blurRadius: 23.0,
child: ClipRRect( color: Theme.of(context).shadowColor,
borderRadius: BorderRadius.circular(16.0), ),
child: Image.memory( ],
const Base64Decoder().convert(e.content), ),
fit: BoxFit.cover, child: ClipRRect(
gaplessPlayback: true, borderRadius: BorderRadius.circular(16.0),
child: Image.memory(
const Base64Decoder().convert(e.content),
fit: BoxFit.cover,
gaplessPlayback: true,
),
), ),
), ),
), ),
@@ -289,6 +316,7 @@ class NotesPageState extends State<NotesPage> 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,
), ),
), ),
), ),
@@ -299,10 +327,20 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
padding: const EdgeInsets.only(left: 8.0), padding: const EdgeInsets.only(left: 8.0),
child: Text( child: Text(
"notes".i18n, "notes".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),
), ),
), ),
), ),
@@ -313,6 +351,8 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
.fetch( .fetch(
from: DateTime.now().subtract(const Duration(days: 30))); from: DateTime.now().subtract(const Duration(days: 30)));
Provider.of<SelfNoteProvider>(context, listen: false).restore(); Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false)
.restoreTodo();
generateTiles(); generateTiles();
@@ -410,7 +450,159 @@ class NotesPageState extends State<NotesPage> with TickerProviderStateMixin {
}, },
), ),
), ),
const SizedBox(
height: 10.0,
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: Theme.of(context).colorScheme.background),
child: ListTile(
title: Row(
children: [
const Icon(Icons.task_outlined),
const SizedBox(
width: 10.0,
),
Text('new_task'.i18n),
],
),
onTap: () {
if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.unlimitedSelfNotes)) {
PlusLockedFeaturePopup.show(
context: context, feature: PremiumFeature.selfNotes);
return;
}
showTaskCreation(context);
},
),
),
]), ]),
); );
} }
void showTaskCreation(context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(14.0))),
contentPadding: const EdgeInsets.only(top: 10.0),
title: Text("new_task".i18n),
content: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 10.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: _taskName,
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: "task_name".i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
),
onPressed: () {
setState(() {
_taskName.text = "";
});
},
),
),
),
const SizedBox(
height: 10.0,
),
TextField(
controller: _taskContent,
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: "task_content".i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
),
onPressed: () {
setState(() {
_taskContent.text = "";
});
},
),
),
),
],
),
),
actions: [
TextButton(
child: Text(
"cancel".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () {
Navigator.of(context).maybePop();
},
),
TextButton(
child: Text(
"next".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () async {
todoItems.add(TodoItem.fromJson({
'id': const Uuid().v4(),
'title': _taskName.text.replaceAll(' ', '') != ""
? _taskName.text
: 'no_title'.i18n,
'content': _taskContent.text,
'done': false,
}));
await databaseProvider.userStore
.storeSelfTodoItems(todoItems, userId: user.id!);
setState(() {
_taskName.text = "";
_taskContent.text = "";
});
Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false)
.restoreTodo();
generateTiles();
Navigator.of(context).pop(true);
},
),
],
),
);
}
} }

View File

@@ -14,6 +14,10 @@ extension ScreensLocalization on String {
"hint_t": "Note title...", "hint_t": "Note title...",
"your_notes": "Your Notes", "your_notes": "Your Notes",
"new_image": "New Image", "new_image": "New Image",
"no_title": "No title",
"task_content": "Task content...",
"task_name": "Task title...",
"new_task": "New Task",
}, },
"hu_hu": { "hu_hu": {
"notes": "Füzet", "notes": "Füzet",
@@ -26,6 +30,10 @@ extension ScreensLocalization on String {
"hint_t": "Jegyzet címe...", "hint_t": "Jegyzet címe...",
"your_notes": "Jegyzeteid", "your_notes": "Jegyzeteid",
"new_image": "Új kép", "new_image": "Új kép",
"no_title": "Nincs cím",
"task_content": "Feladat tartalma...",
"task_name": "Feladat címe...",
"new_task": "Új feladat",
}, },
"de_de": { "de_de": {
"notes": "Broschüre", "notes": "Broschüre",
@@ -38,6 +46,10 @@ extension ScreensLocalization on String {
"hint_t": "Titel notieren...", "hint_t": "Titel notieren...",
"your_notes": "Deine Noten", "your_notes": "Deine Noten",
"new_image": "Neues Bild", "new_image": "Neues Bild",
"no_title": "Kein Titel",
"task_content": "Aufgabeninhalt...",
"task_name": "Aufgabentitel...",
"new_task": "Neue Aufgabe",
}, },
}; };

View File

@@ -257,6 +257,8 @@ class AddNoteScreenState extends State<AddNoteScreen> {
style: const TextStyle(fontSize: 16.0), style: const TextStyle(fontSize: 16.0),
), ),
), ),
if (MediaQuery.of(context).viewInsets.bottom != 0)
const SizedBox(height: 60),
], ],
), ),
), ),

View File

@@ -6,6 +6,7 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:image_crop/image_crop.dart'; import 'package:image_crop/image_crop.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -27,6 +28,8 @@ class ImageNoteEditor extends StatefulWidget {
} }
class _ImageNoteEditorState extends State<ImageNoteEditor> { class _ImageNoteEditorState extends State<ImageNoteEditor> {
final _title = TextEditingController();
final cropKey = GlobalKey<CropState>(); final cropKey = GlobalKey<CropState>();
File? _file; File? _file;
File? _sample; File? _sample;
@@ -62,7 +65,7 @@ class _ImageNoteEditorState extends State<ImageNoteEditor> {
child: Crop.file( child: Crop.file(
_sample!, _sample!,
key: cropKey, key: cropKey,
aspectRatio: 1.0, // aspectRatio: 1.0,
), ),
); );
} }
@@ -135,7 +138,8 @@ class _ImageNoteEditorState extends State<ImageNoteEditor> {
selfNotes.add(SelfNote.fromJson({ selfNotes.add(SelfNote.fromJson({
'id': const Uuid().v4(), 'id': const Uuid().v4(),
'content': base64Image, 'content': base64Image,
'note_type': 'image' 'note_type': 'image',
'title': _title.text,
})); }));
await Provider.of<DatabaseProvider>(context, listen: false) await Provider.of<DatabaseProvider>(context, listen: false)
@@ -143,6 +147,7 @@ class _ImageNoteEditorState extends State<ImageNoteEditor> {
.storeSelfNotes(selfNotes, userId: widget.u.id); .storeSelfNotes(selfNotes, userId: widget.u.id);
Provider.of<SelfNoteProvider>(context, listen: false).restore(); Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false).restoreTodo();
debugPrint('$file'); debugPrint('$file');
} }
@@ -170,6 +175,37 @@ class _ImageNoteEditorState extends State<ImageNoteEditor> {
const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
child: _sample == null ? openImageWidget() : cropImageWidget(), child: _sample == null ? openImageWidget() : cropImageWidget(),
), ),
Padding(
padding:
const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
child: TextField(
controller: _title,
onEditingComplete: () async {},
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: 'title'.i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
),
onPressed: () {
setState(() {
_title.text = '';
});
},
),
),
),
),
// if (widget.u.picture != "") // if (widget.u.picture != "")
// TextButton( // TextButton(
// child: Text( // child: Text(

View File

@@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:refilc/api/providers/self_note_provider.dart'; import 'package:refilc/api/providers/self_note_provider.dart';
import 'package:refilc/models/self_note.dart'; import 'package:refilc/models/self_note.dart';
@@ -8,6 +10,7 @@ import 'package:flutter/material.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:markdown/markdown.dart' as md; import 'package:markdown/markdown.dart' as md;
import 'notes_screen.i18n.dart';
class NoteViewScreen extends StatefulWidget { class NoteViewScreen extends StatefulWidget {
const NoteViewScreen({super.key, required this.note}); const NoteViewScreen({super.key, required this.note});
@@ -30,7 +33,9 @@ class NoteViewScreenState extends State<NoteViewScreen> {
surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, surfaceTintColor: Theme.of(context).scaffoldBackgroundColor,
leading: BackButton(color: AppColors.of(context).text), leading: BackButton(color: AppColors.of(context).text),
title: Text( title: Text(
widget.note.title ?? '${widget.note.content.split(' ')[0]}...', widget.note.noteType == NoteType.text
? (widget.note.title ?? '${widget.note.content.split(' ')[0]}...')
: 'image_note'.i18n,
style: TextStyle( style: TextStyle(
color: AppColors.of(context).text, color: AppColors.of(context).text,
fontSize: 26.0, fontSize: 26.0,
@@ -38,52 +43,55 @@ class NoteViewScreenState extends State<NoteViewScreen> {
), ),
), ),
actions: [ actions: [
ClipRRect( if (widget.note.noteType == NoteType.text)
borderRadius: BorderRadius.circular(10.1), ClipRRect(
child: GestureDetector( borderRadius: BorderRadius.circular(10.1),
onTap: () { child: GestureDetector(
// handle tap onTap: () {
Navigator.of(context, rootNavigator: true).push( // handle tap
CupertinoPageRoute( Navigator.of(context, rootNavigator: true).push(
builder: (context) => CupertinoPageRoute(
AddNoteScreen(initialNote: widget.note))); builder: (context) =>
}, AddNoteScreen(initialNote: widget.note)));
child: Container( },
color: Theme.of(context).colorScheme.secondary.withOpacity(0.2), child: Container(
child: Padding( color:
padding: const EdgeInsets.all(8.0), Theme.of(context).colorScheme.secondary.withOpacity(0.2),
child: Stack( child: Padding(
children: [ padding: const EdgeInsets.all(8.0),
IconTheme( child: Stack(
data: IconThemeData( children: [
color: Theme.of(context).colorScheme.secondary, IconTheme(
data: IconThemeData(
color: Theme.of(context).colorScheme.secondary,
),
child: const Icon(
FeatherIcons.edit,
size: 20.0,
),
), ),
child: const Icon( IconTheme(
FeatherIcons.edit, data: IconThemeData(
size: 20.0, color:
Theme.of(context).brightness == Brightness.light
? Colors.black.withOpacity(.5)
: Colors.white.withOpacity(.3),
),
child: const Icon(
FeatherIcons.edit,
size: 20.0,
),
), ),
), ],
IconTheme( ),
data: IconThemeData(
color:
Theme.of(context).brightness == Brightness.light
? Colors.black.withOpacity(.5)
: Colors.white.withOpacity(.3),
),
child: const Icon(
FeatherIcons.edit,
size: 20.0,
),
),
],
), ),
), ),
), ),
), ),
), if (widget.note.noteType == NoteType.text)
const SizedBox( const SizedBox(
width: 10, width: 10,
), ),
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular(10.1), borderRadius: BorderRadius.circular(10.1),
child: GestureDetector( child: GestureDetector(
@@ -140,21 +148,30 @@ class NoteViewScreenState extends State<NoteViewScreen> {
child: Column( child: Column(
children: [ children: [
Expanded( Expanded(
child: MarkdownBody( child: widget.note.noteType == NoteType.text
data: widget.note.content, ? MarkdownBody(
extensionSet: md.ExtensionSet( data: widget.note.content,
md.ExtensionSet.gitHubFlavored.blockSyntaxes, extensionSet: md.ExtensionSet(
<md.InlineSyntax>[ md.ExtensionSet.gitHubFlavored.blockSyntaxes,
md.EmojiSyntax(), <md.InlineSyntax>[
...md.ExtensionSet.gitHubFlavored.inlineSyntaxes md.EmojiSyntax(),
], ...md.ExtensionSet.gitHubFlavored.inlineSyntaxes
), ],
styleSheet: MarkdownStyleSheet( ),
p: const TextStyle( styleSheet: MarkdownStyleSheet(
fontSize: 15.0, p: const TextStyle(
), fontSize: 15.0,
), ),
), ),
)
: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: Image.memory(
const Base64Decoder().convert(widget.note.content),
fit: BoxFit.contain,
gaplessPlayback: true,
),
),
), ),
// Expanded( // Expanded(
// child: Text( // child: Text(

View File

@@ -268,6 +268,7 @@ class NotesScreenState extends State<NotesScreen> {
Provider.of<HomeworkProvider>(context, listen: false) Provider.of<HomeworkProvider>(context, listen: false)
.fetch(from: DateTime.now().subtract(const Duration(days: 30))); .fetch(from: DateTime.now().subtract(const Duration(days: 30)));
Provider.of<SelfNoteProvider>(context, listen: false).restore(); Provider.of<SelfNoteProvider>(context, listen: false).restore();
Provider.of<SelfNoteProvider>(context, listen: false).restoreTodo();
return Future(() => null); return Future(() => null);
}, },

View File

@@ -18,6 +18,8 @@ extension SettingsLocalization on String {
"click_here": "Click here", "click_here": "Click here",
"select_image": "to select an image", "select_image": "to select an image",
"new_image": "New Image", "new_image": "New Image",
"image_note": "Image",
"title": "Image title...",
}, },
"hu_hu": { "hu_hu": {
"notes": "Füzet", "notes": "Füzet",
@@ -34,6 +36,8 @@ extension SettingsLocalization on String {
"click_here": "Kattints ide", "click_here": "Kattints ide",
"select_image": "kép kiválasztásához", "select_image": "kép kiválasztásához",
"new_image": "Új kép", "new_image": "Új kép",
"image_note": "Kép",
"title": "Kép címe...",
}, },
"de_de": { "de_de": {
"notes": "Broschüre", "notes": "Broschüre",
@@ -50,6 +54,8 @@ extension SettingsLocalization on String {
"click_here": "Klicken Sie hier", "click_here": "Klicken Sie hier",
"select_image": "um ein Bild auszuwählen", "select_image": "um ein Bild auszuwählen",
"new_image": "Neues Bild", "new_image": "Neues Bild",
"image_note": "Bild",
"title": "Bildtitel...",
}, },
}; };

View File

@@ -1,3 +1,6 @@
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'package:refilc/models/settings.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/utils/format.dart'; import 'package:refilc/utils/format.dart';
@@ -50,11 +53,26 @@ class _DayTitleState extends State<DayTitle> {
width: MediaQuery.of(context).size.width / 1.5, width: MediaQuery.of(context).size.width / 1.5,
child: Text( child: Text(
widget.dayTitle(index).capital(), widget.dayTitle(index).capital(),
style: TextStyle( style: Provider.of<SettingsProvider>(context)
color: .fontFamily !=
AppColors.of(context).text.withOpacity(opacity), '' &&
fontSize: 32.0, Provider.of<SettingsProvider>(context)
fontWeight: FontWeight.bold), .titleOnlyFont
? GoogleFonts.getFont(
Provider.of<SettingsProvider>(context).fontFamily,
textStyle: TextStyle(
color: AppColors.of(context)
.text
.withOpacity(opacity),
fontSize: 32.0,
fontWeight: FontWeight.bold),
)
: TextStyle(
color: AppColors.of(context)
.text
.withOpacity(opacity),
fontSize: 32.0,
fontWeight: FontWeight.bold),
), ),
); );
}, },

View File

@@ -1,5 +1,6 @@
import 'dart:math'; import 'dart:math';
import 'package:animations/animations.dart'; import 'package:animations/animations.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:i18n_extension/i18n_extension.dart'; import 'package:i18n_extension/i18n_extension.dart';
import 'package:refilc/api/providers/database_provider.dart'; import 'package:refilc/api/providers/database_provider.dart';
import 'package:refilc/api/providers/update_provider.dart'; import 'package:refilc/api/providers/update_provider.dart';
@@ -19,7 +20,7 @@ import 'package:refilc_mobile_ui/common/empty.dart';
import 'package:refilc_mobile_ui/common/profile_image/profile_button.dart'; import 'package:refilc_mobile_ui/common/profile_image/profile_button.dart';
import 'package:refilc_mobile_ui/common/profile_image/profile_image.dart'; import 'package:refilc_mobile_ui/common/profile_image/profile_image.dart';
import 'package:refilc_mobile_ui/common/system_chrome.dart'; import 'package:refilc_mobile_ui/common/system_chrome.dart';
import 'package:refilc_mobile_ui/common/widgets/lesson/lesson_view.dart'; // import 'package:refilc_mobile_ui/common/widgets/lesson/lesson_view.dart';
import 'package:refilc_kreta_api/controllers/timetable_controller.dart'; import 'package:refilc_kreta_api/controllers/timetable_controller.dart';
import 'package:refilc_mobile_ui/common/widgets/lesson/lesson_viewable.dart'; import 'package:refilc_mobile_ui/common/widgets/lesson/lesson_viewable.dart';
import 'package:refilc_mobile_ui/pages/timetable/day_title.dart'; import 'package:refilc_mobile_ui/pages/timetable/day_title.dart';
@@ -60,7 +61,11 @@ class TimetablePage extends StatefulWidget {
NavigationScreen.of(context)?.setPage("timetable"); NavigationScreen.of(context)?.setPage("timetable");
// Show initial Lesson // Show initial Lesson
if (lesson != null) LessonView.show(lesson, context: context); // if (lesson != null) LessonView.show(lesson, context: context);
// changed to new popup
if (lesson != null) {
TimetableLessonPopup.show(context: context, lesson: lesson);
}
} }
@override @override
@@ -316,6 +321,7 @@ class TimetablePageState extends State<TimetablePage>
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
), ),
), ),
), ),
@@ -374,11 +380,25 @@ class TimetablePageState extends State<TimetablePage>
} else { } else {
return Text( return Text(
"timetable".i18n, "timetable".i18n,
style: TextStyle( style: Provider.of<SettingsProvider>(context)
fontSize: 32.0, .fontFamily !=
fontWeight: FontWeight.bold, '' &&
color: AppColors.of(context).text, Provider.of<SettingsProvider>(context)
), .titleOnlyFont
? GoogleFonts.getFont(
Provider.of<SettingsProvider>(context)
.fontFamily,
textStyle: TextStyle(
fontSize: 32.0,
fontWeight: FontWeight.bold,
color: AppColors.of(context).text,
),
)
: TextStyle(
fontSize: 32.0,
fontWeight: FontWeight.bold,
color: AppColors.of(context).text,
),
); );
} }
}(), }(),

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:refilc/models/settings.dart';
import 'package:refilc_plus/providers/plus_provider.dart'; import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/plus/activation_view/activation_view.dart'; import 'package:refilc_plus/ui/mobile/plus/activation_view/activation_view.dart';
import 'package:refilc_mobile_ui/plus/plus_screen.i18n.dart'; import 'package:refilc_mobile_ui/plus/plus_screen.i18n.dart';
@@ -50,6 +51,20 @@ class PlusPlanCard extends StatelessWidget {
return; return;
} }
if (Provider.of<SettingsProvider>(context, listen: false).xFilcId ==
"none") {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text(
"Be kell kapcsolnod a Névtelen Analitikát a beállítások főoldalán, mielőtt reFilc+ előfizetést vásárolnál!",
style:
TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
),
backgroundColor: Colors.white,
));
return;
}
if (Provider.of<PlusProvider>(context, listen: false).hasPremium) { if (Provider.of<PlusProvider>(context, listen: false).hasPremium) {
if (!active) { if (!active) {
launchUrl( launchUrl(

View File

@@ -225,6 +225,7 @@ class PlusScreenState extends State<PlusScreen> {
['🎓', 'rfp_6'.i18n], ['🎓', 'rfp_6'.i18n],
['👕', 'rfp_14'.i18n], ['👕', 'rfp_14'.i18n],
['👑', 'rfp_15'.i18n], ['👑', 'rfp_15'.i18n],
['📩', 'rfp_17'.i18n],
['🔜', 'more_soon'.i18n], ['🔜', 'more_soon'.i18n],
], ],
docsAccepted: docsAccepted, docsAccepted: docsAccepted,

View File

@@ -45,6 +45,7 @@ extension SettingsLocalization on String {
"rfp_14": "Discount in reFilc Shop (soon)", "rfp_14": "Discount in reFilc Shop (soon)",
"rfp_15": "Subscriber role in our Discord community", "rfp_15": "Subscriber role in our Discord community",
"rfp_16": "Private leaks and informations about upcoming features", "rfp_16": "Private leaks and informations about upcoming features",
"rfp_17": "Grade exporting",
// other // other
"and": " and ", "and": " and ",
"every": "Every ", "every": "Every ",
@@ -96,6 +97,7 @@ extension SettingsLocalization on String {
"rfp_14": "Kedvezmény a reFilc Shop-ban (hamarosan)", "rfp_14": "Kedvezmény a reFilc Shop-ban (hamarosan)",
"rfp_15": "Előfizetői rang a Discord szerverünkön", "rfp_15": "Előfizetői rang a Discord szerverünkön",
"rfp_16": "Privát betekintések és információk közelgő újításokról", "rfp_16": "Privát betekintések és információk közelgő újításokról",
"rfp_17": "Jegy exportálás",
// other // other
"and": " és ", "and": " és ",
"every": "Minden ", "every": "Minden ",
@@ -133,30 +135,32 @@ extension SettingsLocalization on String {
"Der Preis wird in Euro angegeben im Bezug zum aktuellen Wechselkurs. 1 EUR ≈ 390 HUF", "Der Preis wird in Euro angegeben im Bezug zum aktuellen Wechselkurs. 1 EUR ≈ 390 HUF",
"active": "Aktiv", "active": "Aktiv",
// benefits // benefits
"rfp_1": "Előzetes hozzáférés új verziókhoz", "rfp_1": "Frühzeitiger Zugriff auf Updates",
"rfp_2": "2 fiók használata egyszerre", "rfp_2": "Verwendung von zwei Konten gleichzeitig",
"rfp_3": "Egyedi üdvözlő üzenet", "rfp_3": "Individuelle Begrüßungsnachricht",
"rfp_4": "Korlátlan saját jegyzet és feladat a füzet oldalon", "rfp_4":
"rfp_5": "Egyedi jegy ritkaságok", "Unbegrenzte eigene Notizen und Aufgaben auf der Notizbuchseite",
"rfp_6": "Összesített átlagszámoló", "rfp_5": "Individuelle Notenraritäten",
"rfp_7": "Órarend jegyzetek", "rfp_6": "Gesamtdurchschnittsberechner",
"rfp_8": "Egyedi betütípusok", "rfp_7": "Stundenplan-Notizen",
"rfp_9": "Korlátlan fiók használata egyszerre", "rfp_8": "Individuelle Schriftarten",
"rfp_10": "Alkalmazás ikonjának megváltoztatása (v5.1-től)", "rfp_9": "Unbegrenzte Konten",
"rfp_11": "Live Activity szín", "rfp_10": "Anpassung des App-Symbols (ab v5.1)",
"rfp_12": "Fejlettebb cél kitűzés", "rfp_11": "Änderung der Live-Aktivitätsfarbe",
"rfp_13": "Naptár szinkronizálás", "rfp_12": "Verbesserter Zielplaner",
"rfp_14": "Kedvezmény a reFilc Shop-ban (hamarosan)", "rfp_13": "Importieren Sie Ihren Stundenplan in Ihre Kalender-App",
"rfp_15": "Előfizetői rang a Discord szerverünkön", "rfp_14": "Rabatt im reFilc Shop (bald)",
"rfp_16": "Privát betekintések és információk közelgő újításokról", "rfp_15": "Abonnentenrolle in unserer Discord-Community",
"rfp_16": "Private Leaks und Informationen über kommende Funktionen",
"rfp_17": "Notenexport",
// other // other
"and": " és ", "and": " und ",
"every": "Minden ", "every": "Jeder ",
"benefit": " előny", "benefit": " Vorteil",
"show_lifetime": "Für immer Pakete", "show_lifetime": "Für immer Pakete",
"more_soon": "Mehr folgt bald...", "more_soon": "Mehr folgt bald...",
"faq_dc": "faq_dc":
"Az előnyök beváltásához írj nekünk Discord-on privát üzenetet!", "Um Ihre Vorteile einzulösen, schreiben Sie uns eine private Nachricht auf Discord!",
"reactivate": "Bestehendes Abonnement reaktivieren", "reactivate": "Bestehendes Abonnement reaktivieren",
}, },
}; };

View File

@@ -276,4 +276,4 @@ class ErrorDetail extends StatelessWidget {
), ),
); );
} }
} }

View File

@@ -5,7 +5,7 @@ extension SettingsLocalization on String {
{ {
"en_en": { "en_en": {
"ekretaYou": "e-KRÉTA, you", "ekretaYou": "e-KRÉTA, you",
"description": "An error occurred!", "description": "Unexpected error while using the application!",
"submit": "Submit", "submit": "Submit",
"goback": "Go back", "goback": "Go back",
"details": "Details", "details": "Details",
@@ -15,11 +15,11 @@ extension SettingsLocalization on String {
"stack": "Stack Trace", "stack": "Stack Trace",
"done": "Done", "done": "Done",
"smth_went_wrong": "smth_went_wrong":
"Something went wrong, it is of course the fault of Educational Development Informatikai Zrt. (e-KRÉTA) in any case! /s", "An unexpected error occurred while using the app.",
}, },
"hu_hu": { "hu_hu": {
"ekretaYou": "e-KRÉTA, te", "ekretaYou": "e-KRÉTA, te",
"description": "Fasz-emulátor hivatásos balfasz!", "description": "Váratlan hiba az alkalmazás használata közben!",
"submit": "Hiba jelentése", "submit": "Hiba jelentése",
"goback": "Vissza", "goback": "Vissza",
"details": "Részletek", "details": "Részletek",
@@ -29,11 +29,11 @@ extension SettingsLocalization on String {
"stack": "Stacktrace", "stack": "Stacktrace",
"done": "Kész", "done": "Kész",
"smth_went_wrong": "smth_went_wrong":
"Valami probléma történt, ez természetesen az Educational Development Informatikai Zrt. (e-KRÉTA) hibája minden esetben! /s", "Nem várt hiba következett be az alkalmazás használata közben.",
}, },
"de_de": { "de_de": {
"ekretaYou": "e-KRÉTA, du", "ekretaYou": "e-KRÉTA, du",
"description": "Ein Fehler ist aufgetreten!", "description": "Unerwarteter Fehler bei der Benutzung der Anwendung!",
"submit": "Abschicken", "submit": "Abschicken",
"goback": "Zurück", "goback": "Zurück",
"details": "Details", "details": "Details",
@@ -43,7 +43,7 @@ extension SettingsLocalization on String {
"stack": "Stack Trace", "stack": "Stack Trace",
"done": "Fertig", "done": "Fertig",
"smth_went_wrong": "smth_went_wrong":
"Irgendetwas ist schief gelaufen, es ist natürlich auf jeden Fall die Schuld der Educational Development Informatikai Zrt. (e-KRÉTA)! /s", "Bei der Benutzung der Anwendung ist ein unerwarteter Fehler aufgetreten.",
}, },
}; };

View File

@@ -0,0 +1,183 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:refilc_kreta_api/client/api.dart';
import 'package:refilc_kreta_api/client/client.dart';
import 'package:webview_flutter/webview_flutter.dart';
class KretenLoginScreen extends StatefulWidget {
const KretenLoginScreen({super.key});
@override
State<KretenLoginScreen> createState() => _KretenLoginScreenState();
}
class _KretenLoginScreenState extends State<KretenLoginScreen> {
late final WebViewController controller;
var loadingPercentage = 0;
var currentUrl = '';
@override
void initState() {
super.initState();
controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(NavigationDelegate(
onPageStarted: (url) async {
setState(() {
loadingPercentage = 0;
currentUrl = url;
});
List<String> requiredThings = url
.replaceAll(
'https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect?code=',
'')
.replaceAll(
'&scope=openid email offline_access kreta-ellenorzo-webapi.public kreta-eugyintezes-webapi.public kreta-fileservice-webapi.public kreta-mobile-global-webapi.public kreta-dkt-webapi.public kreta-ier-webapi.public&state=refilc_student_mobile&session_state=',
':')
.split(':');
String code = requiredThings[0];
// String sessionState = requiredThings[1];
debugPrint('url: $url');
// actual login (token grant) logic
Map<String, String> headers = {
"content-type": "application/x-www-form-urlencoded",
"accept": "*/*",
"user-agent":
"eKretaStudent/264745 CFNetwork/1494.0.7 Darwin/23.4.0",
"code_verifier": "THDUSddKOOndwCkqBtVHvRjh2LK0V2kMyLP2QirqVWQ",
};
Map? res = await Provider.of<KretaClient>(context, listen: false)
.postAPI(KretaAPI.login, headers: headers, body: {
"code": code,
"redirect_uri":
"https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect",
"client_id": "kreta-ellenorzo-student-mobile-ios",
"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"];
// Map? studentJson =
// await Provider.of<KretaClient>(context, listen: false)
// .getAPI(KretaAPI.student(instituteCode));
// Student student = Student.fromJson(studentJson!);
// var user = User(
// username: username,
// password: password,
// instituteCode: instituteCode,
// name: student.name,
// student: student,
// role: JwtUtils.getRoleFromJWT(res["access_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;
// }
// }
// }
}
},
onProgress: (progress) {
setState(() {
loadingPercentage = progress;
});
},
onPageFinished: (url) {
setState(() {
loadingPercentage = 100;
});
},
))
..loadRequest(
Uri.parse(
'https://idp.e-kreta.hu/connect/authorize?prompt=login&nonce=refilc&response_type=code&code_challenge_method=S256&scope=openid%20email%20offline_access%20kreta-ellenorzo-webapi.public%20kreta-eugyintezes-webapi.public%20kreta-fileservice-webapi.public%20kreta-mobile-global-webapi.public%20kreta-dkt-webapi.public%20kreta-ier-webapi.public&code_challenge=Oj_aVMRJHYsv00mrtGJY72NJa7HY54lVnU2Cb4CWbWw&redirect_uri=https://mobil.e-kreta.hu/ellenorzo-student/prod/oauthredirect&client_id=kreta-ellenorzo-student-mobile-ios&state=refilc_student_mobile'),
);
}
// Future<void> loadLoginUrl() async {
// String nonceStr = await Provider.of<KretaClient>(context, listen: false)
// .getAPI(KretaAPI.nonce, json: false);
// Nonce nonce = getNonce(nonceStr, );
// }
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: const BackButton(),
title: const Text('e-KRÉTA Bejelentkezés'),
),
body: Stack(
children: [
WebViewWidget(
controller: controller,
),
if (loadingPercentage < 100)
LinearProgressIndicator(
value: loadingPercentage / 100.0,
),
],
),
);
}
}

View File

@@ -56,6 +56,9 @@ class AccountView extends StatelessWidget {
Detail( Detail(
title: "parents".plural(user.student.parents.length), title: "parents".plural(user.student.parents.length),
description: user.student.parents.join(", ")), description: user.student.parents.join(", ")),
const SizedBox(
height: 10.0,
),
], ],
), ),
); );

View File

@@ -8,21 +8,22 @@ extension Localization on String {
"school": "School", "school": "School",
"class": "Class", "class": "Class",
"address": "Home address", "address": "Home address",
"parents": "Parents".one("Parent"), "parents": "Parent(s)",
"parents_phone": "Parents' phone number: ",
}, },
"hu_hu": { "hu_hu": {
"birthdate": "Születési dátum", "birthdate": "Születési dátum",
"school": "Iskola", "school": "Iskola",
"class": "Osztály", "class": "Osztály",
"address": "Lakcím", "address": "Lakcím",
"parents": "Szülők".one("Szülő"), "parents": "Szülő(k)",
}, },
"de_de": { "de_de": {
"birthdate": "Geburtsdatum", "birthdate": "Geburtsdatum",
"school": "Schule", "school": "Schule",
"class": "Klasse", "class": "Klasse",
"address": "Wohnanschrift", "address": "Wohnanschrift",
"parents": "Eltern", "parents": "Elter(n)",
}, },
}; };

View File

@@ -37,6 +37,9 @@ import 'package:flutter_material_color_picker/flutter_material_color_picker.dart
import 'package:refilc/models/icon_pack.dart'; import 'package:refilc/models/icon_pack.dart';
import 'package:refilc/utils/format.dart'; import 'package:refilc/utils/format.dart';
import 'package:refilc_mobile_ui/screens/settings/theme_screen.dart'; import 'package:refilc_mobile_ui/screens/settings/theme_screen.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 '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/plus/upsell.dart'; // import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
@@ -900,6 +903,15 @@ class _LiveActivityColorSettingState extends State<LiveActivityColorSetting> {
allowShades: false, allowShades: false,
selectedColor: settings.liveActivityColor, selectedColor: settings.liveActivityColor,
onMainColorChange: (k) { onMainColorChange: (k) {
if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.liveActivityColor)) {
PlusLockedFeaturePopup.show(
context: context,
feature: PremiumFeature.liveActivity,
);
return;
}
setState(() { setState(() {
currentColor = k as Color; currentColor = k as Color;
settings.update( settings.update(

View File

@@ -27,6 +27,7 @@ import 'package:refilc_mobile_ui/common/bottom_sheet_menu/bottom_sheet_menu.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/panel/panel_button.dart'; import 'package:refilc_mobile_ui/common/panel/panel_button.dart';
import 'package:refilc_mobile_ui/common/profile_image/profile_image.dart'; import 'package:refilc_mobile_ui/common/profile_image/profile_image.dart';
import 'package:refilc_mobile_ui/common/soon_alert/soon_alert.dart';
// import 'package:refilc_mobile_ui/common/soon_alert/soon_alert.dart'; // import 'package:refilc_mobile_ui/common/soon_alert/soon_alert.dart';
import 'package:refilc_mobile_ui/common/splitted_panel/splitted_panel.dart'; import 'package:refilc_mobile_ui/common/splitted_panel/splitted_panel.dart';
// import 'package:refilc_mobile_ui/common/system_chrome.dart'; // import 'package:refilc_mobile_ui/common/system_chrome.dart';
@@ -320,6 +321,7 @@ class SettingsScreenState extends State<SettingsScreen>
badge: updateProvider.available, badge: updateProvider.available,
role: user.role, role: user.role,
profilePictureString: user.picture, profilePictureString: user.picture,
gradeStreak: (user.gradeStreak ?? 0) > 1,
backgroundColor: Theme.of(context) backgroundColor: Theme.of(context)
.colorScheme .colorScheme
.tertiary, //!settings.presentationMode .tertiary, //!settings.presentationMode
@@ -702,6 +704,46 @@ class SettingsScreenState extends State<SettingsScreen>
], ],
), ),
if ((user.gradeStreak ?? 0) > 1)
SplittedPanel(
padding: const EdgeInsets.only(
bottom: 12.0, left: 24.0, right: 24.0),
children: [
GestureDetector(
onTap: () {
SoonAlert.show(context: context);
},
child: ListTile(
title: Text(
"grade_streak".i18n,
style: TextStyle(
color: AppColors.of(context).text.withOpacity(0.95),
fontWeight: FontWeight.w500,
),
),
subtitle: Text(
"grade_streak_subtitle".i18n,
style: TextStyle(
color: AppColors.of(context).text.withOpacity(0.75),
),
),
leading: const Text(
"🔥",
style: TextStyle(fontSize: 22.0),
),
trailing: Text(
"${user.gradeStreak}",
style: TextStyle(
color: AppColors.of(context).text.withOpacity(0.95),
fontWeight: FontWeight.w500,
fontSize: 18.0,
),
),
),
),
],
),
// plus subscribe inline // plus subscribe inline
const PlusSettingsInline(), const PlusSettingsInline(),

View File

@@ -4,6 +4,8 @@ extension SettingsLocalization on String {
static final _t = Translations.byLocale("hu_hu") + static final _t = Translations.byLocale("hu_hu") +
{ {
"en_en": { "en_en": {
"heads_up": "Heads up!",
"export_warning": "Exported grades are currently not yet viewable in reFilc, you'll only be able to view them manually in JSON format. In the future, this functionality will be extended and you will be able to view the tickets in the app interface.",
"personal_details": "Personal Details", "personal_details": "Personal Details",
"open_dkt": "Open DCS", "open_dkt": "Open DCS",
"edit_nickname": "Edit Nickname", "edit_nickname": "Edit Nickname",
@@ -116,8 +118,18 @@ extension SettingsLocalization on String {
"exp_settings": "Export Settings", "exp_settings": "Export Settings",
"manage_subs": "Manage Subscription", "manage_subs": "Manage Subscription",
"copy_plus_id": "Copy reFilc+ ID", "copy_plus_id": "Copy reFilc+ ID",
// grade streak
"grade_streak": "Grade 5 Streak",
"grade_streak_subtitle": "So many 5s in a row?!",
// other
"only_ch_title_font": "Font Only for Titles",
"new_popups": "New Popups",
"export_method": "Export Method",
"grade_exporting": "Grade Exporting",
}, },
"hu_hu": { "hu_hu": {
"heads_up": "Figyelem!",
"export_warning": "Az exportált jegyek jelenleg még nem megtekinthetők a reFilc-ben, csak te magad tudod átnézni őket JSON formátumban. A jövőben ez a funkció bővülni fog, és a jegyeket meg is tekintheted majd a reFilc felületén.",
"personal_details": "Személyes információk", "personal_details": "Személyes információk",
"open_dkt": "DKT megnyitása", "open_dkt": "DKT megnyitása",
"edit_nickname": "Becenév szerkesztése", "edit_nickname": "Becenév szerkesztése",
@@ -230,8 +242,18 @@ extension SettingsLocalization on String {
"exp_settings": "Beállítások exportálása", "exp_settings": "Beállítások exportálása",
"manage_subs": "Előfizetés kezelése", "manage_subs": "Előfizetés kezelése",
"copy_plus_id": "reFilc+ ID másolása", "copy_plus_id": "reFilc+ ID másolása",
// grade streak
"grade_streak": "5-ös sorozat",
"grade_streak_subtitle": "Egymás után ennyi 5-ös?!",
// other
"only_ch_title_font": "Betűtípus csak címekre",
"new_popups": "Új felugró ablakok",
"export_method": "Exportálási mód",
"grade_exporting": "Jegy exportálás",
}, },
"de_de": { "de_de": {
"heads_up": "Achtung!",
"export_warning": "Exportierte Tickets sind derzeit noch nicht in reFilc einsehbar, Sie können sie nur selbst im JSON- Format überprüfen. In Zukunft wird diese Funktionalität erweitert und Sie werden die Tickets in der reFilc-Oberfläche anzeigen können",
"personal_details": "Persönliche Angaben", "personal_details": "Persönliche Angaben",
"open_dkt": "Öffnen RDZ", "open_dkt": "Öffnen RDZ",
"edit_nickname": "Spitznamen bearbeiten", "edit_nickname": "Spitznamen bearbeiten",
@@ -344,6 +366,14 @@ extension SettingsLocalization on String {
"exp_settings": "Einstellungen exportieren", "exp_settings": "Einstellungen exportieren",
"manage_subs": "Abonnement verwalten", "manage_subs": "Abonnement verwalten",
"copy_plus_id": "reFilc+ ID kopieren", "copy_plus_id": "reFilc+ ID kopieren",
// grade streak
"grade_streak": "5er-Streak",
"grade_streak_subtitle": "So viele 5er in Folge?!",
// other
"only_ch_title_font": "Schriftart nur für Titel",
"new_popups": "Neue Popups",
"export_method": "Exportmethode",
"grade_exporting": "Noten exportieren",
}, },
}; };

View File

@@ -10,6 +10,7 @@ import 'package:flutter/material.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/settings/submenu/calendar_sync.dart'; import 'package:refilc_plus/ui/mobile/settings/submenu/calendar_sync.dart';
import 'package:refilc_plus/ui/mobile/settings/submenu/grade_exporting.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/plus/upsell.dart'; import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
@@ -158,6 +159,16 @@ class ExtrasSettingsScreenState extends State<ExtrasSettingsScreen> {
), ),
], ],
), ),
SplittedPanel(
padding: const EdgeInsets.only(top: 9.0),
cardPadding: const EdgeInsets.all(4.0),
isSeparated: true,
children: [
MenuGradeExporting(
borderRadius: BorderRadius.circular(12.0),
),
],
),
], ],
), ),
), ),

View File

@@ -0,0 +1,381 @@
import 'package:refilc/models/settings.dart';
import 'package:refilc/theme/colors/colors.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:refilc/ui/flutter_colorpicker/colorpicker.dart';
import 'package:refilc/ui/widgets/grade/grade_tile.dart';
import 'package:refilc_kreta_api/models/grade.dart';
import 'package:refilc_mobile_ui/screens/settings/theme_screen.dart';
import 'submenu_screen.i18n.dart';
enum SelectedGrade { one, two, three, four, five }
class GradeColorsSettingsScreen extends StatefulWidget {
const GradeColorsSettingsScreen({super.key});
@override
GradeColorsSettingsScreenState createState() =>
GradeColorsSettingsScreenState();
}
class GradeColorsSettingsScreenState extends State<GradeColorsSettingsScreen> {
late SettingsProvider settingsProvider;
SelectedGrade currentEditGrade = SelectedGrade.one;
@override
Widget build(BuildContext context) {
SettingsProvider settingsProvider = Provider.of<SettingsProvider>(context);
return Scaffold(
appBar: AppBar(
surfaceTintColor: Theme.of(context).scaffoldBackgroundColor,
leading: BackButton(
color: AppColors.of(context).text,
onPressed: () {
setState(() {
// made this cuz else it will be ugly
currentEditGrade = SelectedGrade.one;
});
Navigator.of(context).pop();
},
),
title: Text(
"grade_colors".i18n,
style: TextStyle(color: AppColors.of(context).text),
),
actions: [
IconButton(
onPressed: () {
List<Color> colors = List.castFrom(settingsProvider.gradeColors);
var defaultColors =
SettingsProvider.defaultSettings().gradeColors;
colors[currentEditGrade.index] =
defaultColors[currentEditGrade.index];
settingsProvider.update(gradeColors: colors);
},
icon: const Icon(
Icons.restore,
size: 26.0,
),
),
const SizedBox(
width: 10.0,
),
],
),
body: SizedBox(
width: double.infinity,
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
SizedBox(
height: MediaQuery.of(context).size.height * 0.14,
),
Stack(
children: [
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
borderRadius: BorderRadius.circular(75.0),
boxShadow: [
BoxShadow(
color: Theme.of(context)
.colorScheme
.shadow
.withOpacity(.1),
blurRadius: 10.0,
offset: const Offset(0, 5),
),
],
),
padding: const EdgeInsets.all(6.0),
child: GradeValueWidget(
GradeValue(currentEditGrade.index + 1, '', '', 100),
fill: true,
size: 75.0,
// color:
// settingsProvider.gradeColors[currentEditGrade.index],
),
),
// before grades
if (currentEditGrade.index > 0)
Transform.translate(
offset: const Offset(-110, 16.5),
child: GradeValueWidget(
GradeValue(currentEditGrade.index, '', '', 100),
fill: true,
size: 60.0,
// color:
// settingsProvider.gradeColors[currentEditGrade.index],
),
),
if (currentEditGrade.index > 1)
Transform.translate(
offset: const Offset(-200, 23),
child: GradeValueWidget(
GradeValue(currentEditGrade.index - 1, '', '', 100),
fill: true,
size: 50.0,
// color:
// settingsProvider.gradeColors[currentEditGrade.index],
),
),
// after grades
if (currentEditGrade.index < 4)
Transform.translate(
offset: const Offset(142, 16.5),
child: GradeValueWidget(
GradeValue(currentEditGrade.index + 2, '', '', 100),
fill: true,
size: 60.0,
// color:
// settingsProvider.gradeColors[currentEditGrade.index],
),
),
if (currentEditGrade.index < 3)
Transform.translate(
offset: const Offset(245, 23),
child: GradeValueWidget(
GradeValue(currentEditGrade.index + 3, '', '', 100),
fill: true,
size: 50.0,
// color:
// settingsProvider.gradeColors[currentEditGrade.index],
),
),
],
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.14,
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: SafeArea(
child: FilcColorPicker(
colorMode: CustomColorMode.grade,
pickerColor:
settingsProvider.gradeColors[currentEditGrade.index],
onColorChanged: (c) {
setState(() {
// update grade color
settingsProvider.update(
gradeColors: settingsProvider.gradeColors
..[currentEditGrade.index] = c);
});
},
onColorChangeEnd: (c, {adaptive}) {
// update grade color
},
onThemeIdProvided: (t) {},
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 20.0, top: 16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () => setState(() {
currentEditGrade = SelectedGrade.one;
}),
child: Container(
width: 45.0,
height: 45.0,
decoration: BoxDecoration(
border: Border.all(
color: currentEditGrade == SelectedGrade.one
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.2),
width: 1.0,
),
borderRadius: BorderRadius.circular(50.0),
color: currentEditGrade == SelectedGrade.one
? Theme.of(context).colorScheme.secondary
: null,
),
child: Center(
child: Text(
'1',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: currentEditGrade == SelectedGrade.one
? Colors.white
: null,
),
),
),
),
),
const SizedBox(width: 10.0),
GestureDetector(
onTap: () => setState(() {
currentEditGrade = SelectedGrade.two;
}),
child: Container(
width: 45.0,
height: 45.0,
decoration: BoxDecoration(
border: Border.all(
color: currentEditGrade == SelectedGrade.two
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.2),
width: 1.0,
),
borderRadius: BorderRadius.circular(50.0),
color: currentEditGrade == SelectedGrade.two
? Theme.of(context).colorScheme.secondary
: null,
),
child: Center(
child: Text(
'2',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: currentEditGrade == SelectedGrade.two
? Colors.white
: null,
),
),
),
),
),
const SizedBox(width: 10.0),
GestureDetector(
onTap: () => setState(() {
currentEditGrade = SelectedGrade.three;
}),
child: Container(
width: 45.0,
height: 45.0,
decoration: BoxDecoration(
border: Border.all(
color: currentEditGrade == SelectedGrade.three
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.2),
width: 1.0,
),
borderRadius: BorderRadius.circular(50.0),
color: currentEditGrade == SelectedGrade.three
? Theme.of(context).colorScheme.secondary
: null,
),
child: Center(
child: Text(
'3',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: currentEditGrade == SelectedGrade.three
? Colors.white
: null,
),
),
),
),
),
const SizedBox(width: 10.0),
GestureDetector(
onTap: () => setState(() {
currentEditGrade = SelectedGrade.four;
}),
child: Container(
width: 45.0,
height: 45.0,
decoration: BoxDecoration(
border: Border.all(
color: currentEditGrade == SelectedGrade.four
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.2),
width: 1.0,
),
borderRadius: BorderRadius.circular(50.0),
color: currentEditGrade == SelectedGrade.four
? Theme.of(context).colorScheme.secondary
: null,
),
child: Center(
child: Text(
'4',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: currentEditGrade == SelectedGrade.four
? Colors.white
: null,
),
),
),
),
),
const SizedBox(width: 10.0),
GestureDetector(
onTap: () => setState(() {
currentEditGrade = SelectedGrade.five;
}),
child: Container(
width: 45.0,
height: 45.0,
decoration: BoxDecoration(
border: Border.all(
color: currentEditGrade == SelectedGrade.five
? Theme.of(context).colorScheme.secondary
: Theme.of(context)
.colorScheme
.secondary
.withOpacity(.2),
width: 1.0,
),
borderRadius: BorderRadius.circular(50.0),
color: currentEditGrade == SelectedGrade.five
? Theme.of(context).colorScheme.secondary
: null,
),
child: Center(
child: Text(
'5',
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w600,
color: currentEditGrade == SelectedGrade.five
? Colors.white
: null,
),
),
),
),
),
],
),
),
],
),
],
),
),
);
}
}

View File

@@ -16,6 +16,7 @@ import 'package:flutter/material.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_mobile_ui/screens/settings/settings_screen.i18n.dart'; import 'package:refilc_mobile_ui/screens/settings/settings_screen.i18n.dart';
import 'package:refilc_mobile_ui/screens/settings/submenu/share_theme_popup.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
class MenuPaintList extends StatelessWidget { class MenuPaintList extends StatelessWidget {
@@ -251,18 +252,7 @@ class PaintListScreenState extends State<PaintListScreen>
subject: 'share_subj_theme'.i18n, subject: 'share_subj_theme'.i18n,
); );
} else { } else {
SharedGradeColors gradeColors = await shareProvider ShareThemeDialog.show(context);
.shareCurrentGradeColors(context);
SharedTheme theme =
await shareProvider.shareCurrentTheme(
context,
gradeColors: gradeColors,
);
Share.share(
theme.id,
subject: 'share_subj_theme'.i18n,
);
} }
}, },
longPressInstead: true, longPressInstead: true,

View File

@@ -30,6 +30,8 @@ import 'package:refilc_plus/providers/plus_provider.dart';
import 'package:refilc_plus/ui/mobile/plus/upsell.dart'; import 'package:refilc_plus/ui/mobile/plus/upsell.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'grade_colors.dart';
class MenuPersonalizeSettings extends StatelessWidget { class MenuPersonalizeSettings extends StatelessWidget {
const MenuPersonalizeSettings({ const MenuPersonalizeSettings({
super.key, super.key,
@@ -459,6 +461,49 @@ class PersonalizeSettingsScreenState extends State<PersonalizeSettingsScreen>
), ),
], ],
), ),
// new popup toggle
SplittedPanel(
padding: const EdgeInsets.only(top: 9.0),
cardPadding: const EdgeInsets.all(4.0),
isSeparated: true,
children: [
PanelButton(
padding: const EdgeInsets.only(left: 14.0, right: 6.0),
onPressed: () async {
settingsProvider.update(
newPopups: !settingsProvider.newPopups);
setState(() {});
},
title: Text(
"new_popups".i18n,
style: TextStyle(
color: AppColors.of(context).text.withOpacity(
settingsProvider.newPopups ? .95 : .25),
),
),
leading: Icon(
FeatherIcons.alertOctagon,
size: 22.0,
color: AppColors.of(context).text.withOpacity(
settingsProvider.newPopups ? .95 : .25),
),
trailing: Switch(
onChanged: (v) async {
settingsProvider.update(newPopups: v);
setState(() {});
},
value: settingsProvider.newPopups,
activeColor: Theme.of(context).colorScheme.secondary,
),
borderRadius: const BorderRadius.vertical(
top: Radius.circular(12.0),
bottom: Radius.circular(12.0),
),
),
],
),
// change subject icons // change subject icons
// SplittedPanel( // SplittedPanel(
// padding: const EdgeInsets.only(top: 9.0), // padding: const EdgeInsets.only(top: 9.0),
@@ -499,8 +544,14 @@ class PersonalizeSettingsScreenState extends State<PersonalizeSettingsScreen>
children: [ children: [
PanelButton( PanelButton(
onPressed: () { onPressed: () {
SettingsHelper.gradeColors(context); // SettingsHelper.gradeColors(context);
setState(() {}); // setState(() {});
Navigator.of(context, rootNavigator: true).push(
CupertinoPageRoute(
builder: (context) =>
const GradeColorsSettingsScreen(),
),
);
}, },
title: Text( title: Text(
"grade_colors".i18n, "grade_colors".i18n,
@@ -670,16 +721,6 @@ class PersonalizeSettingsScreenState extends State<PersonalizeSettingsScreen>
children: [ children: [
PanelButton( PanelButton(
onPressed: () { onPressed: () {
if (!Provider.of<PlusProvider>(context,
listen: false)
.hasScope(PremiumScopes.liveActivityColor)) {
PlusLockedFeaturePopup.show(
context: context,
feature: PremiumFeature.liveActivity,
);
return;
}
SettingsHelper.liveActivityColor(context); SettingsHelper.liveActivityColor(context);
setState(() {}); setState(() {});
}, },
@@ -882,7 +923,7 @@ class PersonalizeSettingsScreenState extends State<PersonalizeSettingsScreen>
title: Text('fonts'.i18n), title: Text('fonts'.i18n),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
cardPadding: const EdgeInsets.all(4.0), cardPadding: const EdgeInsets.all(4.0),
isSeparated: true, isSeparated: false,
children: [ children: [
PanelButton( PanelButton(
onPressed: () { onPressed: () {
@@ -920,11 +961,72 @@ class PersonalizeSettingsScreenState extends State<PersonalizeSettingsScreen>
), ),
borderRadius: const BorderRadius.vertical( borderRadius: const BorderRadius.vertical(
top: Radius.circular(12.0), top: Radius.circular(12.0),
bottom: Radius.circular(6.0),
),
),
PanelButton(
padding: const EdgeInsets.only(left: 14.0, right: 6.0),
onPressed: () async {
if (!Provider.of<PlusProvider>(context, listen: false)
.hasScope(PremiumScopes.customFont)) {
PlusLockedFeaturePopup.show(
context: context,
feature: PremiumFeature.fontChange);
return;
}
settingsProvider.update(
titleOnlyFont: !settingsProvider.titleOnlyFont);
Provider.of<ThemeModeObserver>(context, listen: false)
.changeTheme(settingsProvider.theme,
updateNavbarColor: false);
setState(() {});
},
title: Text(
"only_ch_title_font".i18n,
style: TextStyle(
color: AppColors.of(context).text.withOpacity(
settingsProvider.titleOnlyFont ? .95 : .25),
),
),
leading: Icon(
Icons.text_increase_rounded,
size: 22.0,
color: AppColors.of(context).text.withOpacity(
settingsProvider.titleOnlyFont ? .95 : .25),
),
trailing: Switch(
onChanged: (v) async {
if (!Provider.of<PlusProvider>(context,
listen: false)
.hasScope(PremiumScopes.customFont)) {
PlusLockedFeaturePopup.show(
context: context,
feature: PremiumFeature.fontChange);
return;
}
settingsProvider.update(titleOnlyFont: v);
Provider.of<ThemeModeObserver>(context,
listen: false)
.changeTheme(settingsProvider.theme,
updateNavbarColor: false);
setState(() {});
},
value: settingsProvider.titleOnlyFont,
activeColor: Theme.of(context).colorScheme.secondary,
),
borderRadius: const BorderRadius.vertical(
top: Radius.circular(4.0),
bottom: Radius.circular(12.0), bottom: Radius.circular(12.0),
), ),
), ),
], ],
), ),
// bottom padding
const SizedBox(
height: 20.0,
),
], ],
), ),
), ),

View File

@@ -0,0 +1,160 @@
// ignore_for_file: use_build_context_synchronously, deprecated_member_use
import 'package:flutter/material.dart';
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart';
// import 'package:refilc/models/settings.dart';
import 'package:refilc/models/shared_theme.dart';
import 'package:refilc_kreta_api/providers/share_provider.dart';
import 'package:refilc_mobile_ui/common/action_button.dart';
import 'package:refilc_mobile_ui/common/splitted_panel/splitted_panel.dart';
import 'package:share_plus/share_plus.dart';
import 'submenu_screen.i18n.dart';
class ShareThemeDialog extends StatefulWidget {
const ShareThemeDialog({super.key});
static void show(BuildContext context) {
showDialog(
context: context,
builder: (context) => AlertDialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)),
title: Text("attention".i18n),
content: Text("share_disclaimer".i18n),
actions: [
ActionButton(
label: "understand".i18n,
onTap: () async {
Navigator.of(context).pop();
showDialog(
context: context,
builder: (context) => const ShareThemeDialog());
},
),
],
),
);
}
@override
ShareThemeDialogState createState() => ShareThemeDialogState();
}
class ShareThemeDialogState extends State<ShareThemeDialog> {
final _title = TextEditingController();
bool isPublic = false;
late ShareProvider shareProvider;
@override
void initState() {
super.initState();
shareProvider = Provider.of<ShareProvider>(context, listen: false);
}
@override
Widget build(BuildContext context) {
return AlertDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(14.0))),
contentPadding: const EdgeInsets.only(top: 10.0),
title: Text("share_theme".i18n),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding:
const EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0),
child: TextField(
controller: _title,
onEditingComplete: () async {},
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: 'paint_title'.i18n,
suffixIcon: IconButton(
icon: const Icon(
FeatherIcons.x,
color: Colors.grey,
),
onPressed: () {
setState(() {
_title.text = '';
});
},
),
),
),
),
SplittedPanel(
children: [
SwitchListTile(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16.0),
),
value: isPublic,
onChanged: (value) {
setState(() {
isPublic = value;
});
},
title: Text("is_public".i18n),
contentPadding: const EdgeInsets.only(left: 15.0, right: 10.0),
),
],
),
],
),
actions: [
TextButton(
child: Text(
"cancel".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () {
Navigator.of(context).maybePop();
},
),
TextButton(
child: Text(
"share_it".i18n,
style: const TextStyle(fontWeight: FontWeight.w500),
),
onPressed: () async {
// share the fucking theme
SharedGradeColors gradeColors =
await shareProvider.shareCurrentGradeColors(context);
SharedTheme theme = await shareProvider.shareCurrentTheme(
context,
gradeColors: gradeColors,
isPublic: isPublic,
displayName: _title.text,
);
// save theme id in settings
// Provider.of<SettingsProvider>(context, listen: false)
// .update(currentThemeId: theme.id);
// close this popup shit
Navigator.of(context).pop(true);
// show the share popup
Share.share(
theme.id,
subject: 'share_subj_theme'.i18n,
);
},
),
],
);
}
}

View File

@@ -17,6 +17,17 @@ extension SettingsLocalization on String {
"rare": "Rare", "rare": "Rare",
"epic": "Epic", "epic": "Epic",
"legendary": "Legendary", "legendary": "Legendary",
// grade colors
"grade_colors": "Grade Colors",
// theme share popup
"share_theme": "Share Paint",
"paint_title": "Paint title...",
"share_it": "Share it!",
"is_public": "Public Paint",
"attention": "Attention!",
"share_disclaimer":
"By sharing the theme, you agree that the nickname you set and all settings of the theme will be shared publicly.",
"understand": "I understand",
}, },
"hu_hu": { "hu_hu": {
"general": "Általános", "general": "Általános",
@@ -32,6 +43,17 @@ extension SettingsLocalization on String {
"rare": "Ritka", "rare": "Ritka",
"epic": "Epikus", "epic": "Epikus",
"legendary": "Legendás", "legendary": "Legendás",
// grade colors
"grade_colors": "Jegyek színei",
// theme share popup
"share_theme": "Téma megosztása",
"paint_title": "Téma neve...",
"share_it": "Megosztás!",
"is_public": "Nyilvános téma",
"attention": "Figyelem!",
"share_disclaimer":
"A téma megosztásával elfogadod, hogy az általad beállított becenév és a téma minden beállítása nyilvánosan megosztásra kerüljön.",
"understand": "Értem",
}, },
"de_de": { "de_de": {
"general": "Allgemeine", "general": "Allgemeine",
@@ -47,6 +69,17 @@ extension SettingsLocalization on String {
"rare": "Selten", "rare": "Selten",
"epic": "Episch", "epic": "Episch",
"legendary": "Legendär", "legendary": "Legendär",
// grade colors
"grade_colors": "Notenfarben",
// theme share popup
"share_theme": "Thema teilen",
"paint_title": "Thema Titel...",
"share_it": "Teilen!",
"is_public": "Öffentliches Thema",
"attention": "Achtung!",
"share_disclaimer":
"Durch das Teilen des Themes erklären Sie sich damit einverstanden, dass der von Ihnen festgelegte Spitzname und alle Einstellungen des Themes öffentlich geteilt werden.",
"understand": "Ich verstehe",
}, },
}; };

View File

@@ -1,7 +1,7 @@
// ignore_for_file: use_build_context_synchronously, deprecated_member_use // ignore_for_file: use_build_context_synchronously, deprecated_member_use
import 'package:refilc/models/settings.dart'; import 'package:refilc/models/settings.dart';
import 'package:refilc/models/shared_theme.dart'; // import 'package:refilc/models/shared_theme.dart';
import 'package:refilc/theme/colors/accent.dart'; import 'package:refilc/theme/colors/accent.dart';
import 'package:refilc/theme/colors/colors.dart'; import 'package:refilc/theme/colors/colors.dart';
import 'package:refilc/theme/observer.dart'; import 'package:refilc/theme/observer.dart';
@@ -10,7 +10,7 @@ import 'package:refilc/ui/widgets/message/message_tile.dart';
import 'package:refilc_kreta_api/models/grade.dart'; import 'package:refilc_kreta_api/models/grade.dart';
import 'package:refilc_kreta_api/models/homework.dart'; import 'package:refilc_kreta_api/models/homework.dart';
import 'package:refilc_kreta_api/models/message.dart'; import 'package:refilc_kreta_api/models/message.dart';
import 'package:refilc_mobile_ui/common/action_button.dart'; // import 'package:refilc_mobile_ui/common/action_button.dart';
import 'package:refilc_mobile_ui/common/filter_bar.dart'; import 'package:refilc_mobile_ui/common/filter_bar.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/widgets/grade/new_grades.dart'; import 'package:refilc_mobile_ui/common/widgets/grade/new_grades.dart';
@@ -24,6 +24,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.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_mobile_ui/screens/settings/submenu/share_theme_popup.dart';
import 'theme_screen.i18n.dart'; import 'theme_screen.i18n.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
@@ -44,6 +45,7 @@ enum CustomColorMode {
text, text,
icon, icon,
enterId, enterId,
grade,
} }
class _PremiumCustomAccentColorSettingState class _PremiumCustomAccentColorSettingState
@@ -158,6 +160,9 @@ class _PremiumCustomAccentColorSettingState
case CustomColorMode.enterId: case CustomColorMode.enterId:
// do nothing here lol // do nothing here lol
break; break;
case CustomColorMode.grade:
// do nothing here as well
break;
} }
} }
@@ -218,6 +223,9 @@ class _PremiumCustomAccentColorSettingState
settings.update(customAccentColor: accent, store: store); settings.update(customAccentColor: accent, store: store);
settings.update(customIconColor: icon, store: store); settings.update(customIconColor: icon, store: store);
break; break;
case CustomColorMode.grade:
// do nothing
break;
} }
} }
@@ -297,40 +305,48 @@ class _PremiumCustomAccentColorSettingState
// ), // ),
// ), // ),
// ); // );
showDialog( // showDialog(
context: context, // context: context,
builder: (context) => WillPopScope( // builder: (context) => WillPopScope(
onWillPop: () async => false, // onWillPop: () async => false,
child: AlertDialog( // child: AlertDialog(
shape: RoundedRectangleBorder( // shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0)), // borderRadius: BorderRadius.circular(12.0)),
title: Text("attention".i18n), // title: Text("attention".i18n),
content: Text("share_disclaimer".i18n), // content: Text("share_disclaimer".i18n),
actions: [ // actions: [
ActionButton( // ActionButton(
label: "understand".i18n, // label: "understand".i18n,
onTap: () async { // onTap: () async {
Navigator.of(context).pop(); // Navigator.of(context).pop();
SharedGradeColors gradeColors = // SharedGradeColors gradeColors =
await shareProvider // await shareProvider
.shareCurrentGradeColors(context); // .shareCurrentGradeColors(context);
SharedTheme theme = // SharedTheme theme =
await shareProvider.shareCurrentTheme( // await shareProvider.shareCurrentTheme(
context, // context,
gradeColors: gradeColors, // gradeColors: gradeColors,
); // );
Share.share( // Share.share(
theme.id, // theme.id,
subject: 'share_subj_theme'.i18n, // subject: 'share_subj_theme'.i18n,
); // );
}, // },
), // ),
], // ],
), // ),
), // ),
); // );
if (settings.currentThemeId != '') {
Share.share(
settings.currentThemeId,
subject: 'share_subj_theme'.i18n,
);
} else {
ShareThemeDialog.show(context);
}
}, },
icon: const Icon( icon: const Icon(
FeatherIcons.share2, FeatherIcons.share2,

View File

@@ -24,26 +24,17 @@ extension SettingsLocalization on String {
"dontfelt": "You didn't like this...", "dontfelt": "You didn't like this...",
"youlate": "You're late!", "youlate": "You're late!",
// allsum page // allsum page
"test": "tests" "test": "test(s)",
.one("test"), "closingtest": "module test(s)",
"closingtest": "module tests" "grade": "grade(s)",
.one("module test"), "hw": "homework(s)",
"grade": "grades" "subject": "subject(s)",
.one("grade"), "lesson": "lesson(s)",
"hw": "homeworks" "absence_sum": "absence(s)",
.one("homework"),
"subject": "subjects"
.one("subject"),
"lesson": "lessons"
.one("lesson"),
"absence_sum": "absences"
.one("absence"),
"excused": "excused", "excused": "excused",
"unexcused": "unexcused", "unexcused": "unexcused",
"delay_sum": "delays" "delay_sum": "delay(s)",
.one("delay"), "min": "minute(s)",
"min": "minutes"
.one("minute"),
// personality page // personality page
"click_reveal": "Click to reveal...", "click_reveal": "Click to reveal...",
}, },

View File

@@ -71,6 +71,8 @@ dependencies:
markdown: ^7.2.2 markdown: ^7.2.2
carousel_slider: ^4.2.1 carousel_slider: ^4.2.1
flutter_portal: ^1.1.4 flutter_portal: ^1.1.4
webview_flutter: ^4.8.0
file_picker: ^6.2.1
dev_dependencies: dev_dependencies:
flutter_lints: ^3.0.1 flutter_lints: ^3.0.1

0
upgrade-pub.sh Normal file → Executable file
View File