Compare commits

...

202 Commits
4.2.3 ... 4.5.1

Author SHA1 Message Date
Márton Kiss
88717d5925 Merge pull request #82 from refilc/dev
Dev
2023-12-26 00:21:09 +01:00
Kima
6cb86245cb fixed little thingies 2023-12-26 00:15:29 +01:00
Kima
8f393cd9c5 changed version string 2023-12-26 00:12:45 +01:00
Kima
38d892d9a1 temp removed app icon change button 2023-12-26 00:07:49 +01:00
Márton Kiss
fb70b2be38 Merge pull request #81 from refilc/dev
Dev
2023-12-26 00:06:19 +01:00
Kima
a5e368d983 added back everything to refilc+ submodule 2023-12-26 00:05:45 +01:00
Kima
de3fa0c71d added submodule back 2023-12-26 00:00:45 +01:00
Kima
cbece0e841 temp removed submodule 2023-12-25 23:51:36 +01:00
Kima
ac77f26eb2 idk test 2023-12-25 23:43:41 +01:00
Kima
52b4a9429b fixed message sending error 2023-12-25 23:36:51 +01:00
Márton Kiss
588bc2567e Merge pull request #80 from refilc/dev
Dev
2023-12-25 22:09:31 +01:00
Márton Kiss
d2d36c3d0f Merge branch 'master' into dev 2023-12-25 22:09:22 +01:00
Kima
8ef2bee62e why 2023-12-25 21:59:12 +01:00
Kima
30bde8b040 Merge branch 'dev' of github.com:refilc/naplo into dev 2023-12-25 21:59:00 +01:00
Kima
042522dc5a idk windows something 2023-12-25 21:58:58 +01:00
ReinerRego
fdc9276170 what 2023-12-23 02:16:44 +01:00
ReinerRego
413494a9ac Merge branch 'dev' of github.com:refilc/naplo into dev 2023-12-23 02:15:56 +01:00
Kima
8e3996e2f0 hide bottom sheet after msg sent 2023-12-23 00:05:51 +01:00
Kima
f46610314d fixed msg sending and added error handler 2023-12-23 00:05:12 +01:00
Kima
fdc6209656 updated version string (probably last time before update) 2023-12-22 22:22:53 +01:00
Kima
6def864b1f fixed renamed subjects italic font 2023-12-22 22:04:11 +01:00
Kima
fc40793534 fixed goal planner limit 2023-12-22 21:54:35 +01:00
Kima
f533c5d4f5 changed open_file to open_filex fort (fixed some issues maybe) 2023-12-22 21:31:59 +01:00
Kima
3a44a2f9bc fixed teacher rename error 2023-12-22 21:01:57 +01:00
Kima
1bf512991b fixed teacher rename error 2023-12-22 21:01:47 +01:00
ReinerRego
fb8b3ae73f changed login screen desktop 2023-12-22 19:21:18 +01:00
Kima
50d2d44ac2 fixed smth in message sending 2023-12-21 21:55:34 +01:00
Kima
b929766b14 something idk 2023-12-21 21:17:49 +01:00
Kima
d34371bfff finally "fixed" all shit issues in vscode 2023-12-21 21:17:38 +01:00
Kima
6bac82f7d6 fixed warnings (super.key, etc) 2023-12-12 22:57:16 +01:00
Kima
fc3f538e6b added translation to message sending 2023-12-12 22:42:22 +01:00
Kima
939e33feeb almost finished send message ui and functionality 2023-12-12 21:55:30 +01:00
Kima
a175a9ea1c fixed warnings and added bottom sheet to message sending 2023-12-12 20:39:17 +01:00
Kima
969aec0f11 finished message sending api ig 2023-12-12 19:45:51 +01:00
Kima
871c93050c added almost everything to provider 2023-12-12 19:07:39 +01:00
Kima
7f9c22bdcd added db shit to recipient storing 2023-12-12 19:01:01 +01:00
Kima
c06e9bc807 fixed warnings 2023-12-10 22:49:55 +01:00
Kima
7b7f603d9c finished sendable message base class gn 2023-12-10 22:47:25 +01:00
Kima
f4a6a0ceb0 lot of work in message sending thing 2023-12-10 22:42:39 +01:00
Kima
adc8deffa9 startend msg sending api thingie 2023-12-10 20:37:40 +01:00
Kima
3484230ced commented dropdown cuz not used currently 2023-12-10 19:33:25 +01:00
ReinerRego
40740b80d0 done i think 2023-12-09 21:12:14 +01:00
ReinerRego
20f20218e0 updated and added dropdownbutton 2023-12-09 20:03:58 +01:00
Kima
68c9745ce0 added gitignore to git 2023-12-09 19:59:46 +01:00
ReinerRego
70c8ac1876 added exam filter finally 2023-12-09 19:58:43 +01:00
Kima
bdfec4230b fixed app close on back button 2023-12-09 18:05:17 +01:00
Kima
093063b438 updated version string 2023-12-09 17:53:12 +01:00
Kima
bcab128332 fixed another weird shit 2023-12-09 17:39:56 +01:00
Kima
56500406e5 fixed things that were fucked up by pub upgrade 2023-12-09 17:23:21 +01:00
Kima
9f5e57eec6 fixed other shit 2023-12-09 17:01:00 +01:00
Kima
5079e0cb29 fixed weird warnings 2023-12-09 16:52:52 +01:00
Kima
646948012d fixed translation 2023-12-09 16:48:33 +01:00
Kima
399069537f maybe fixed timetable clear bug on kreten api error 2023-12-09 16:13:36 +01:00
Kima
1c49ffd57f temp removed app icon shit 2023-12-09 16:02:31 +01:00
Kima
8df3623d91 Merge branch 'dev' of github.com:refilc/naplo into dev 2023-12-09 15:42:24 +01:00
Kima
61ad26e047 updatet smth 2023-12-09 15:42:22 +01:00
Kima
51a6492477 CONVERT KEY TO SUPER PARAMETER KYS 2023-12-09 15:42:02 +01:00
ReinerRego
7d26a8bc33 changed gitmodules 2023-12-09 14:07:36 +01:00
Kima
e243b5c186 added adfghsdhg 2023-12-08 21:22:03 +01:00
Kima
043785fe35 why the hell was widget code in gitignore 2023-12-08 21:19:29 +01:00
Kima
72332b5000 remove unused temp files 2023-12-08 21:17:53 +01:00
Kima
e73aa6c1b0 fixed build shit 2023-12-08 21:16:21 +01:00
Kima
3410e410d2 fully finished total grade calculator 2023-11-21 21:47:09 +01:00
Kima
aba39505d9 half-working total average calculator done :3 2023-11-19 23:21:10 +01:00
Kima
ebf9c8526d icon 2023-11-18 22:35:25 +01:00
Kima
f5ab4bbc98 perfect 2023-11-18 22:01:36 +01:00
Kima
1764bb0f01 refilc+ smth 2023-11-18 21:28:54 +01:00
Kima
271e47619e idk smth old commit 2023-11-18 10:59:06 +01:00
ReinerRego
cd0c821bae wrong api lol 2023-11-14 22:43:16 +01:00
ReinerRego
6a1cb9f3eb made linux and uncommnented login from desktop ui 2023-11-14 22:42:55 +01:00
Kima
c6c5759a2c finished custom app icon option 2023-10-23 19:43:13 +02:00
Kima
b94ed46c8a app icon db and other things 2023-10-23 17:54:16 +02:00
Kima
b0eb78218a updated gitignore 2023-10-23 16:08:15 +02:00
Kima
1ac618c29f some progress in custom app icon thingie 2023-10-21 23:49:21 +02:00
Kima
7840a07c95 added gitignore to rfplus 2023-10-21 22:33:21 +02:00
Kima
3f5b8ab607 started doing app icon change 2023-10-21 22:20:16 +02:00
Kima
41fe5a3d05 csinaltam ezt meg azt pusz 2023-10-21 21:39:02 +02:00
Kima
af87e5ed36 smth 2023-10-21 21:33:58 +02:00
Kima
797963e63d removed shit 2023-10-21 21:22:59 +02:00
Kima
6a1eafe980 added submodule 2023-10-21 21:22:43 +02:00
Kima
5e7414ada8 renamed folder so i can add it as a submodule 2023-10-21 21:17:27 +02:00
Kima
8e391c9c7f Merge branch 'dev' of github.com:refilc/naplo into dev 2023-10-21 21:11:42 +02:00
Kima
316039463f moved non-premium features from premium folder 2023-10-21 21:11:39 +02:00
Márton Kiss
8e320b235c removed sebrhq from readme 2023-10-21 11:23:05 +02:00
Pearoo
be28c50ffc Make room number bigger for live card 2023-10-19 09:39:52 +02:00
Márton Kiss
82db2e2091 Merge pull request #75 from refilc/dev
added gitignore
2023-10-15 20:57:27 +02:00
Kima
774f63aa89 added gitignore 2023-10-15 20:57:00 +02:00
Márton Kiss
8375e1877a Merge pull request #74 from refilc/dev
changed build number to final
2023-10-15 20:34:10 +02:00
Kima
b00fab090c changed build number to final 2023-10-15 20:33:31 +02:00
Márton Kiss
382961971d Merge pull request #73 from refilc/dev
Dev
2023-10-15 20:29:14 +02:00
Kima
04c5c819f8 remove trailing from app icon option 2023-10-15 19:59:00 +02:00
Kima
6249015bef Revert "Some localization changes"
This reverts commit be4737f9db.
2023-10-15 19:54:17 +02:00
Kima
2fade7117b Merge branch 'dev' of github.com:refilc/naplo into dev 2023-10-15 19:48:23 +02:00
Kima
49c396e746 fixed error reporting 2023-10-15 19:48:20 +02:00
Pearoo
be4737f9db Some localization changes 2023-10-15 18:43:29 +02:00
Kima
d27c059b23 fixed height glitch on grades page 2023-10-15 17:20:08 +02:00
Kima
21a5771211 temp removed icon color tab 2023-10-15 16:35:50 +02:00
Kima
501d83c229 Merge branch 'dev' of github.com:refilc/naplo into dev 2023-10-15 16:08:26 +02:00
Kima
6651bbf14a fixed typo 2023-10-15 16:08:23 +02:00
Pearoo
ddf1944883 Fix typo in failure_warning 2023-10-15 16:03:02 +02:00
Kima
bf0eeb83e4 changed "default" to "dynamic" at welcome message 2023-10-15 15:15:13 +02:00
Kima
d41c39849b changed build number 2023-10-15 15:14:07 +02:00
Kima
25294dd4a7 added "soon alert" widget 2023-10-15 15:03:09 +02:00
Kima
d0f347c80d added app icon change option to settings 2023-10-15 15:02:59 +02:00
Kima
44464e1946 moved "secret settings" after account list 2023-10-15 14:41:31 +02:00
Kima
5a371d7200 added "send message" button to messages screen 2023-10-15 14:36:43 +02:00
Kima
27fefb4c27 fixed homework provider finally 2023-10-15 14:29:25 +02:00
Kima
efe58eeea9 added clear goal button to goal planning 2023-10-15 13:46:58 +02:00
Kima
8e629ef596 added textfield clear to enterid in theme menu 2023-10-15 13:18:25 +02:00
Kima
d188cefc07 fixed theme share with new options 2023-10-15 13:15:55 +02:00
Kima
c5b6f92b0e commented subject provider 2023-10-15 12:55:14 +02:00
Kima
2d5cbe8799 changed old subject type to gradesubject 2023-10-15 12:14:06 +02:00
Pearoo
c7c3b421f4 Added subjects API endpoint
Also added JSON structure in comments
No implementation yet, will be used in the future
Kudos @sleddev
2023-10-15 11:42:35 +02:00
Kima
adfa653062 changed version string 2023-10-12 21:48:16 +02:00
Kima
86f7cf3b2e fixed subject icon things 2023-10-12 21:10:14 +02:00
Kima
1cc885e4b7 fixed exam subject rename thing 2023-10-12 21:06:53 +02:00
Kima
a4207b8348 fixed livecard italic font bug 2023-10-12 20:58:23 +02:00
Kima
3e600f69f0 fix shadow thing on timetable 2023-10-12 20:54:07 +02:00
Kima
205d90523c added check everywhere to shadow effect 2023-10-12 20:38:32 +02:00
Kima
906de6dd45 changed shadow effect toggle icon to moon 2023-10-12 20:10:04 +02:00
Kima
3ff0927834 added toggle for shadow effect to settings screen 2023-10-12 20:08:23 +02:00
Kima
14e5614adc done icon color changer in settings 2023-10-12 19:51:41 +02:00
Kima
6ed89b2a1e added missing translation 2023-10-12 19:26:41 +02:00
Kima
5272ac5a01 added icon color changer everywhere 2023-10-12 19:24:40 +02:00
Kima
46e6120af3 added things to db and theme share 2023-10-12 19:14:40 +02:00
Kima
600bf7d763 removed import dsklfjnu 2023-10-12 19:10:54 +02:00
Kima
10750f898f added shadow effect and icon color option to sp 2023-10-12 19:10:32 +02:00
Pearoo
1d5ebe7bbd Fix cancelled vs. delayed card
Fixes https://discord.com/channels/1111649116020285532/1154687576758829097
Implements 9845a35 from `cancelled-bugfix` branch
Deletes `cancelled-bugfix` branch
2023-10-10 07:01:57 +02:00
Pearoo
2aa8db8f42 Merge pull request #70 from refilc/dev
Implement 6388932
2023-10-10 06:47:55 +02:00
Pearoo
f95d4582be Implement 6388932 2023-10-09 07:37:40 +02:00
Pearoo
63889325cf Add good student disclaimer german localisation
Fixes https://discord.com/channels/1111649116020285532/1160698590033870848
2023-10-09 07:26:29 +02:00
Márton Kiss
acbffd6d72 Merge pull request #69 from refilc/dev
69-es szamu pr haha 😏
2023-10-08 17:00:13 +02:00
Kima
b19da9cb66 finally fixed kreten error shit sdfadfsdfhsdfgh 2023-10-08 16:55:06 +02:00
Kima
fd80aec51f added upgrade-pub.sh to upgrade pub packages 2023-10-08 16:24:59 +02:00
Kima
5776622276 settings account tiles now showing nickname 2023-10-08 12:44:45 +02:00
Kima
69ea3e1a7f update version string 2023-10-08 12:03:08 +02:00
Kima
3d451f6f91 fixed the fix lol 2023-10-08 11:52:39 +02:00
Kima
387e2e46db fixed i18n error spam on home screen (welcome msg) 2023-10-08 11:51:09 +02:00
Kima
a7f1681902 someone commented birthday greeting, fuck yourself 2023-10-08 11:48:09 +02:00
Kima
4b127bdf56 fixed homewrok not showing up 2023-10-08 11:46:00 +02:00
Kima
dbb6125ab5 fixed live card not showing on android 2023-10-08 11:42:27 +02:00
Kima
b6d4ac6168 maybe fixed error shit 2023-10-08 11:33:09 +02:00
Kima
9d20d08838 fixed goal planner done popup 2023-10-07 19:41:33 +02:00
Kima
f39ac80770 fixed app bricking with welcome message thing 2023-10-05 21:54:57 +02:00
Kima
41991b3b66 change log message bc livecard is shit but idk why 2023-10-05 21:30:24 +02:00
ReinerRego
53ec3e567a Merge pull request #68 from TMarccci/dev
Xcode 15, iOS 17 - Bug Fix+Others
2023-10-05 00:07:41 +02:00
Tihanyi Marcell
176608bfc5 Xcode 15, iOS 17 - Bug Fix+Others 2023-10-04 23:25:00 +02:00
ReinerRego
92b4094550 started fixing desktop ui 2023-10-04 14:10:17 +02:00
Márton Kiss
45c6fccb89 Merge pull request #66 from TMarccci/master
Added a few subjects to helper
2023-09-28 21:37:56 +02:00
Tihanyi Marcell
014329d7fe Added a few subjects to helper 2023-09-28 21:28:30 +02:00
Márton Kiss
dca01d0ed0 Merge pull request #65 from sleddev/dev
timetable italics + instituteCode search + theme preview background color
2023-09-28 21:17:50 +02:00
SledDev
493adaa5f2 fixed background color in theme preview 2023-09-28 20:15:09 +02:00
SledDev
8451983163 find schools by instituteCode 2023-09-28 19:41:43 +02:00
SledDev
2b7e143812 fixed fullscreen timetable italics 2023-09-28 19:12:56 +02:00
Pearoo
9845a35c6e Fix english absence error + comment bugreports 2023-09-28 18:17:24 +02:00
Márton Kiss
b92ac9ffbc Merge pull request #63 from TMarccci/master
oopsie
2023-09-27 23:17:42 +02:00
Tihanyi Marcell
f435f31523 oopsie 2023-09-27 23:16:52 +02:00
Márton Kiss
6abc61db7b Merge pull request #62 from TMarccci/master
Live Activity Fixes
2023-09-27 23:06:39 +02:00
Márton Kiss
cd8ab8bfdb Merge pull request #61 from refilc/dev
Dev
2023-09-27 23:04:56 +02:00
Kima
24a6393aca changed version number 2023-09-27 23:04:21 +02:00
Kima
64fb22de74 grade colors sharing works fine ahh 2023-09-27 23:02:28 +02:00
Kima
14ce4c82fb fixed test account crash 2023-09-27 21:56:19 +02:00
Tihanyi Marcell
7d1f4e992c Fixes 2023-09-27 21:47:24 +02:00
Kima
17b8b96767 commented shit in desktop code 2023-09-27 21:38:48 +02:00
Kima
7ac5d64d19 Merge branch 'dev' of github.com:refilc/naplo into dev 2023-09-27 21:36:21 +02:00
Kima
d9bd555e6a added grade colors to theme share 2023-09-27 21:36:18 +02:00
Márton Kiss
b5bf994b8d Merge pull request #59 from refilc/dev
Dev
2023-09-26 23:01:10 +02:00
ReinerRego
8b216bd27b desktop fix 2023-09-26 22:48:52 +02:00
Kima
a9bd11a4d7 fixed profile crash 2023-09-26 22:11:27 +02:00
ReinerRego
129a95f359 Merge branch 'dev' of github.com:refilc/naplo into dev 2023-09-26 21:54:42 +02:00
ReinerRego
8b65d4d519 desktop login fix 2023-09-26 21:53:58 +02:00
Kima
353297bc90 changed version string 2023-09-26 21:16:19 +02:00
Kima
63d24f7e89 removed dev releases from auto-update 2023-09-26 21:01:47 +02:00
Márton Kiss
4b93c891c8 Merge pull request #58 from refilc/dev
Dev
2023-09-26 20:32:21 +02:00
Kima
6f85a4ebc1 fixed settings top padding 2023-09-26 18:04:44 +02:00
Kima
b37af9f5a5 fixed kreten status shit maybe idk 2023-09-25 22:46:24 +02:00
ReinerRego
3a26fd9ec9 changed the fucking linix title 2023-09-25 22:45:28 +02:00
Kima
9cda8c5d29 added custom welcome message to home screen 2023-09-25 18:31:32 +02:00
Kima
6212489001 added translation for dkt 2023-09-25 18:30:20 +02:00
Kima
b4ff2fa815 added welcome message to settings 2023-09-24 20:12:10 +02:00
Kima
a11ebce6fb also added test accounts to dev branch 2023-09-22 21:50:26 +02:00
Kima
fa75c1ec06 fixed share alert text 2023-09-22 20:52:13 +02:00
Kima
79677d657e updated version string 2023-09-19 19:12:28 +02:00
Kima
50d1803a18 added token revoke to logout 2023-09-19 18:58:08 +02:00
Kima
34f9929b16 removed "add spaces" text bc not relevant anymore 2023-09-19 18:57:57 +02:00
Pearoo
7b517b333a Revert "Rename everything filcnaplo-related to refilc"
This reverts commit d1a9625d93.
2023-09-19 18:16:57 +02:00
Pearoo
d1a9625d93 Rename everything filcnaplo-related to refilc 2023-09-19 18:16:03 +02:00
Kima
056bf7ab58 made ad tile image circular 2023-09-18 20:33:20 +02:00
Kima
c4dc03f41d fixed warns and timetable thing again 2023-09-18 20:22:42 +02:00
Kima
6d7a21dc02 fixed theme share warn dialog 2023-09-18 19:42:36 +02:00
Márton Kiss
9406efee8d Merge pull request #54 from refilc/master
master back to dev bc idiots modified things in it
2023-09-18 19:37:33 +02:00
Márton Kiss
151e97b243 Merge pull request #53 from refilc/dev
Dev
2023-09-18 19:36:20 +02:00
Kima
1ba0f4d8d3 handle timetable shit better ig 2023-09-18 19:33:29 +02:00
Kima
4b8dbf0691 Merge branch 'dev' of github.com:refilc/naplo into dev 2023-09-18 19:30:01 +02:00
Kima
98d7468f24 tried to fix timetable and handle kreten api error 2023-09-18 19:29:55 +02:00
ReinerRego
fa46d6cbd3 Merge branch 'dev' of github.com:refilc/naplo into dev 2023-09-18 19:20:35 +02:00
Márton Kiss
a0c68a4e5a nem 2023-09-18 17:53:10 +02:00
Pearoo
f2f35b2fbd Add smurfcat 2023-09-18 10:18:04 +02:00
Pearoo
a782dbd22f Add smurfcat 2023-09-18 10:16:58 +02:00
ReinerRego
6293bb4017 aligment again 2023-09-17 17:05:04 +02:00
ReinerRego
03a5057269 changed aligment bc stupid and color 2023-09-17 17:03:07 +02:00
ReinerRego
4a15514ba0 changed dependency idk 2023-09-17 17:01:54 +02:00
285 changed files with 4252 additions and 5642 deletions

85
.gitignore vendored
View File

@@ -1,52 +1,39 @@
# See https://www.dartlang.org/guides/libraries/private-files
.gitignore filcnaplo/.flutter-plugins
filcnaplo/.flutter-plugins-dependencies
filcnaplo/pubspec.lock
filcnaplo/.dart_tool/
filcnaplo/android/
filcnaplo/ios/
filcnaplo/windows/
filcnaplo/linux/
filcnaplo/macos/
filcnaplo/build/
termek.txt filcnaplo_desktop_ui/.flutter-plugins
filcnaplo_desktop_ui/.flutter-plugins-dependencies
filcnaplo_desktop_ui/pubspec.lock
filcnaplo_desktop_ui/.dart_tool/
filcnaplo_kreta_api/.flutter-plugins
filcnaplo_kreta_api/.flutter-plugins-dependencies
filcnaplo_kreta_api/pubspec.lock
filcnaplo_kreta_api/.dart_tool/
filcnaplo_mobile_ui/.flutter-plugins
filcnaplo_mobile_ui/.flutter-plugins-dependencies
filcnaplo_mobile_ui/pubspec.lock
filcnaplo_mobile_ui/.dart_tool/
filcnaplo_premium/.flutter-plugins
filcnaplo_premium/.flutter-plugins-dependencies
filcnaplo_premium/pubspec.lock
filcnaplo_premium/.dart_tool/
.vscode
.github
.idea
.gitmodules
filcnaplo/.DS_Store
.DS_Store .DS_Store
filc3.properties
local.properties
# Files and directories created by pub
.dart_tool/
.packages
build/
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/
# Avoid committing generated Javascript files:
*.dart.js
*.info.json # Produced by the --dump-info flag.
*.js # When generated by dart2js. Don't specify *.js if your
# project includes source files written in JavaScript.
*.js_
*.js.deps
*.js.map
*.txt
filcnaplo/macos/Flutter/GeneratedPluginRegistrant.swift
filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/connectivity_plus
filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/dynamic_color
filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/flutter_acrylic
filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows
filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows
filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/share_plus_windows
filcnaplo/windows/flutter/ephemeral/.plugin_symlinks/url_launcher_windows
filcnaplo/windows/flutter/ephemeral/generated_config.cmake
filcnaplo/windows/flutter/generated_plugin_registrant.cc
filcnaplo/windows/flutter/generated_plugin_registrant.h
filcnaplo/windows/flutter/generated_plugins.cmake
filcnaplo/linux/flutter/generated_plugin_registrant.cc
filcnaplo/linux/flutter/generated_plugin_registrant.h
filcnaplo/linux/flutter/generated_plugins.cmake
filcnaplo/macos/Flutter/*
filcnaplo/ios/Podfile.lock
.vscode/
key.properties
.flutter-plugins*
filcnaplo/ios/Flutter/flutter_export_environment 4.sh
filcnaplo/ios/Flutter/Generated 4.xcconfig

3
.gitmodules vendored
View File

@@ -0,0 +1,3 @@
[submodule "naplo-plus"]
path = filcnaplo_premium
url = git@github.com:refilc/naplo-plus.git

3
.idea/.gitignore generated vendored
View File

@@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

40
.vscode/launch.json vendored
View File

@@ -1,40 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "filcnaplo",
"cwd": "filcnaplo",
"request": "launch",
"type": "dart",
"toolArgs": [
"--dart-define=APPVER=$(cat pubspec.yaml | grep version: | cut -d' ' -f2 | cut -d+ -f1)"
]
},
// {
// "name": "filcnaplo release",
// "cwd": "filcnaplo release",
// "request": "launch",
// "type": "dart",
// "program": "lib/main.dart",
// "toolArgs": [
// "--dart-define=APPVER=$(cat pubspec.yaml | grep version: | cut -d' ' -f2 | cut -d+ -f1)"
// ]
// },
{
"name": "Flutter",
"program": "lib/main.dart",
"cwd": "filcnaplo",
"request": "launch",
"type": "dart",
"flutterMode": "debug"
},
{
"name": "Flutter (release)",
"program": "lib/main.dart",
"cwd": "filcnaplo",
"request": "launch",
"type": "dart",
"flutterMode": "release"
}
]
}

View File

@@ -43,7 +43,7 @@ Az összes (ugyan azon verzióhoz tartozó) contribution meg fog jelenni a relea
**vrolandd, TMarccci:** head developer **vrolandd, TMarccci:** head developer
**dwe., xou, SebRHQ:** designer **dwe., xou:** designer
**Péter:** video editor **Péter:** video editor

View File

@@ -8,6 +8,7 @@
.buildlog/ .buildlog/
.history .history
.svn/ .svn/
migrate_working_dir/
# IntelliJ related # IntelliJ related
*.iml *.iml
@@ -31,9 +32,6 @@
.pub/ .pub/
/build/ /build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related # Symbolication related
app.*.symbols app.*.symbols
@@ -44,4 +42,3 @@ app.*.map.json
/android/app/debug /android/app/debug
/android/app/profile /android/app/profile
/android/app/release /android/app/release
key.properties

View File

@@ -1,11 +1,11 @@
# This file tracks properties of this Flutter project. # This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc. # Used by Flutter tool to assess capabilities and perform upgrades etc.
# #
# This file should be version controlled. # This file should be version controlled and should not be manually edited.
version: version:
revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 revision: "b0366e0a3f089e15fd89c97604ab402fe26b724c"
channel: stable channel: "stable"
project_type: app project_type: app
@@ -13,11 +13,17 @@ project_type: app
migration: migration:
platforms: platforms:
- platform: root - platform: root
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: b0366e0a3f089e15fd89c97604ab402fe26b724c
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: b0366e0a3f089e15fd89c97604ab402fe26b724c
- platform: web - platform: linux
create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 create_revision: b0366e0a3f089e15fd89c97604ab402fe26b724c
base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: b0366e0a3f089e15fd89c97604ab402fe26b724c
- platform: macos
create_revision: b0366e0a3f089e15fd89c97604ab402fe26b724c
base_revision: b0366e0a3f089e15fd89c97604ab402fe26b724c
- platform: windows
create_revision: b0366e0a3f089e15fd89c97604ab402fe26b724c
base_revision: b0366e0a3f089e15fd89c97604ab402fe26b724c
# User provided section # User provided section

View File

@@ -1,12 +0,0 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
.project

View File

@@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" package="hu.refilc.naplo"> xmlns:tools="http://schemas.android.com/tools" package="hu.refilc.naplo">
<application android:name="${applicationName}" android:label="reFilc" tools:replace="android:label" android:icon="@mipmap/ic_launcher" <application android:name="${applicationName}" android:label="reFilc" tools:replace="android:label" android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true"> android:requestLegacyExternalStorage="true" android:enableOnBackInvokedCallback="false">
<activity android:exported="true" android:name="hu.refilc.naplo.MainActivity" <activity android:exported="true" android:name="hu.refilc.naplo.MainActivity"
android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:launchMode="singleTop" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
@@ -13,6 +13,7 @@
<meta-data android:name="io.flutter.embedding.android.NormalTheme" <meta-data android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" /> android:resource="@style/NormalTheme" />
<intent-filter> <intent-filter>
<!-- commented bc of dynamic app icons -->
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
@@ -39,6 +40,69 @@
</activity> </activity>
<meta-data android:name="flutterEmbedding" android:value="2" /> <meta-data android:name="flutterEmbedding" android:value="2" />
<!-- custom app icon thingies from here -->
<!-- <activity-alias
android:label="reFilc"
android:icon="@drawable/launch_ic_refilc_default"
android:name=".MainActivityAlias"
android:enabled="true"
android:exported="true"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:label="reFilc"
android:icon="@drawable/launch_ic_refilc_default"
android:name=".MainActivityAliasrefilc_default"
android:enabled="false"
android:exported="true"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:label="reFilc"
android:icon="@drawable/launch_ic_refilc_overcomplicated"
android:name=".MainActivityAliasrefilc_overcomplicated"
android:enabled="false"
android:exported="true"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:label="reFilc"
android:icon="@drawable/launch_ic_refilc_concept"
android:name=".MainActivityAliasrefilc_concept"
android:enabled="false"
android:exported="true"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:label="reFilc"
android:icon="@drawable/launch_ic_refilc_pride"
android:name=".MainActivityAliasrefilc_pride"
android:enabled="false"
android:exported="true"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias> -->
<!-- end of custom app icon thingies -->
<receiver android:name="hu.refilc.naplo.widget_timetable.WidgetTimetable" <receiver android:name="hu.refilc.naplo.widget_timetable.WidgetTimetable"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -136,7 +136,7 @@
android:layout_below="@id/iv_1" android:layout_below="@id/iv_1"
android:layout_marginHorizontal="15dp" android:layout_marginHorizontal="15dp"
android:fontFamily="@font/montserrat_medium" android:fontFamily="@font/montserrat_medium"
android:text="A widget használatához, bejelentkezés szükséges." android:text="A widget használatához bejelentkezés szükséges."
android:textColor="@color/black" android:textColor="@color/black"
android:paddingTop="10dp" android:paddingTop="10dp"
android:textSize="17sp" android:textSize="17sp"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,93 +0,0 @@
Copyright 2011 The Montserrat Project Authors (https://github.com/JulietaUla/Montserrat)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

View File

@@ -1,33 +0,0 @@
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
Flutter/ephemeral/
Flutter/app.flx
Flutter/app.zip
Flutter/flutter_assets/
Flutter/flutter_export_environment.sh
ServiceDefinitions.json
Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!default.mode1v3
!default.mode2v3
!default.pbxuser
!default.perspectivev3

View File

@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
# platform :ios, '11.0' platform :ios, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'
@@ -39,5 +39,8 @@ end
post_install do |installer| post_install do |installer|
installer.pods_project.targets.each do |target| installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target) flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET'
end
end end
end end

View File

@@ -17,6 +17,14 @@
3127F7A828EAEE8500C2EFB3 /* lesson_model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3127F7A728EAEE8500C2EFB3 /* lesson_model.swift */; }; 3127F7A828EAEE8500C2EFB3 /* lesson_model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3127F7A728EAEE8500C2EFB3 /* lesson_model.swift */; };
373A6ECB5FC71FE9D8AF2EDB /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F0ADD56276103500A3016C8 /* Pods_Runner.framework */; }; 373A6ECB5FC71FE9D8AF2EDB /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F0ADD56276103500A3016C8 /* Pods_Runner.framework */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B4461282AE6E0FF00AAE6FD /* refilc_default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B4461202AE6E0FF00AAE6FD /* refilc_default@2x.png */; };
3B4461292AE6E0FF00AAE6FD /* refilc_concept@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B4461212AE6E0FF00AAE6FD /* refilc_concept@2x.png */; };
3B44612A2AE6E0FF00AAE6FD /* refilc_concept@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B4461222AE6E0FF00AAE6FD /* refilc_concept@3x.png */; };
3B44612B2AE6E0FF00AAE6FD /* refilc_overcomplicated@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B4461232AE6E0FF00AAE6FD /* refilc_overcomplicated@2x.png */; };
3B44612C2AE6E0FF00AAE6FD /* refilc_default@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B4461242AE6E0FF00AAE6FD /* refilc_default@3x.png */; };
3B44612D2AE6E0FF00AAE6FD /* refilc_overcomplicated@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B4461252AE6E0FF00AAE6FD /* refilc_overcomplicated@3x.png */; };
3B44612E2AE6E0FF00AAE6FD /* refilc_pride@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B4461262AE6E0FF00AAE6FD /* refilc_pride@2x.png */; };
3B44612F2AE6E0FF00AAE6FD /* refilc_pride@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3B4461272AE6E0FF00AAE6FD /* refilc_pride@3x.png */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
@@ -73,6 +81,14 @@
3127F7A728EAEE8500C2EFB3 /* lesson_model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = lesson_model.swift; sourceTree = "<group>"; }; 3127F7A728EAEE8500C2EFB3 /* lesson_model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = lesson_model.swift; sourceTree = "<group>"; };
317DE77A294F6FFB002E323E /* livecard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = livecard.entitlements; sourceTree = "<group>"; }; 317DE77A294F6FFB002E323E /* livecard.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = livecard.entitlements; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B4461202AE6E0FF00AAE6FD /* refilc_default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "refilc_default@2x.png"; path = "../../../../../../../../../Downloads/iloveimg-resized/refilc_default@2x.png"; sourceTree = "<group>"; };
3B4461212AE6E0FF00AAE6FD /* refilc_concept@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "refilc_concept@2x.png"; path = "../../../../../../../../../Downloads/iloveimg-resized/refilc_concept@2x.png"; sourceTree = "<group>"; };
3B4461222AE6E0FF00AAE6FD /* refilc_concept@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "refilc_concept@3x.png"; path = "../../../../../../../../../Downloads/iloveimg-resized (1)/refilc_concept@3x.png"; sourceTree = "<group>"; };
3B4461232AE6E0FF00AAE6FD /* refilc_overcomplicated@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "refilc_overcomplicated@2x.png"; path = "../../../../../../../../../Downloads/iloveimg-resized/refilc_overcomplicated@2x.png"; sourceTree = "<group>"; };
3B4461242AE6E0FF00AAE6FD /* refilc_default@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "refilc_default@3x.png"; path = "../../../../../../../../../Downloads/iloveimg-resized (1)/refilc_default@3x.png"; sourceTree = "<group>"; };
3B4461252AE6E0FF00AAE6FD /* refilc_overcomplicated@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "refilc_overcomplicated@3x.png"; path = "../../../../../../../../../Downloads/iloveimg-resized (1)/refilc_overcomplicated@3x.png"; sourceTree = "<group>"; };
3B4461262AE6E0FF00AAE6FD /* refilc_pride@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "refilc_pride@2x.png"; path = "../../../../../../../../../Downloads/iloveimg-resized/refilc_pride@2x.png"; sourceTree = "<group>"; };
3B4461272AE6E0FF00AAE6FD /* refilc_pride@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "refilc_pride@3x.png"; path = "../../../../../../../../../Downloads/iloveimg-resized (1)/refilc_pride@3x.png"; sourceTree = "<group>"; };
707F8089D970F81C480F73C4 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; }; 707F8089D970F81C480F73C4 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -122,6 +138,21 @@
path = livecard; path = livecard;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
3B44611F2AE6DF7200AAE6FD /* App Icons */ = {
isa = PBXGroup;
children = (
3B4461212AE6E0FF00AAE6FD /* refilc_concept@2x.png */,
3B4461222AE6E0FF00AAE6FD /* refilc_concept@3x.png */,
3B4461202AE6E0FF00AAE6FD /* refilc_default@2x.png */,
3B4461242AE6E0FF00AAE6FD /* refilc_default@3x.png */,
3B4461232AE6E0FF00AAE6FD /* refilc_overcomplicated@2x.png */,
3B4461252AE6E0FF00AAE6FD /* refilc_overcomplicated@3x.png */,
3B4461262AE6E0FF00AAE6FD /* refilc_pride@2x.png */,
3B4461272AE6E0FF00AAE6FD /* refilc_pride@3x.png */,
);
path = "App Icons";
sourceTree = "<group>";
};
6640A963014A9D4F31026053 /* Frameworks */ = { 6640A963014A9D4F31026053 /* Frameworks */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -178,6 +209,7 @@
97C146F01CF9000F007C117D /* Runner */ = { 97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
3B44611F2AE6DF7200AAE6FD /* App Icons */,
3127F73928EAEC3200C2EFB3 /* Runner.entitlements */, 3127F73928EAEC3200C2EFB3 /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FD1CF9000F007C117D /* Assets.xcassets */,
@@ -221,9 +253,9 @@
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3127F74F28EAEC8A00C2EFB3 /* Embed Foundation Extensions */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
71459C0EB905E05018E3D78F /* [CP] Embed Pods Frameworks */, 71459C0EB905E05018E3D78F /* [CP] Embed Pods Frameworks */,
3127F74F28EAEC8A00C2EFB3 /* Embed Foundation Extensions */,
); );
buildRules = ( buildRules = (
); );
@@ -286,10 +318,18 @@
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
3B44612A2AE6E0FF00AAE6FD /* refilc_concept@3x.png in Resources */,
3B44612F2AE6E0FF00AAE6FD /* refilc_pride@3x.png in Resources */,
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B44612E2AE6E0FF00AAE6FD /* refilc_pride@2x.png in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
3B44612C2AE6E0FF00AAE6FD /* refilc_default@3x.png in Resources */,
3B4461292AE6E0FF00AAE6FD /* refilc_concept@2x.png in Resources */,
3B4461282AE6E0FF00AAE6FD /* refilc_default@2x.png in Resources */,
3B44612D2AE6E0FF00AAE6FD /* refilc_overcomplicated@3x.png in Resources */,
3B44612B2AE6E0FF00AAE6FD /* refilc_overcomplicated@2x.png in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -478,7 +518,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 195; CURRENT_PROJECT_VERSION = 195;
DEVELOPMENT_TEAM = 48XS7JAZB7; DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = reFilc; INFOPLIST_KEY_CFBundleDisplayName = reFilc;
@@ -488,7 +528,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 3.6.0; MARKETING_VERSION = 3.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo; PRODUCT_BUNDLE_IDENTIFIER = com.refilc2.naplo;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@@ -510,7 +550,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 48XS7JAZB7; DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = livecard/Info.plist; INFOPLIST_FILE = livecard/Info.plist;
@@ -526,7 +566,7 @@
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo.livecardpro; PRODUCT_BUNDLE_IDENTIFIER = com.refilc2.naplo.livecardpro;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@@ -552,7 +592,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 48XS7JAZB7; DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = livecard/Info.plist; INFOPLIST_FILE = livecard/Info.plist;
@@ -567,7 +607,7 @@
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo.livecardpro; PRODUCT_BUNDLE_IDENTIFIER = com.refilc2.naplo.livecardpro;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@@ -592,7 +632,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 48XS7JAZB7; DEVELOPMENT_TEAM = 4DKAF249F3;
GCC_C_LANGUAGE_STANDARD = gnu11; GCC_C_LANGUAGE_STANDARD = gnu11;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = livecard/Info.plist; INFOPLIST_FILE = livecard/Info.plist;
@@ -607,7 +647,7 @@
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo.livecardpro; PRODUCT_BUNDLE_IDENTIFIER = com.refilc2.naplo.livecardpro;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@@ -736,7 +776,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 195; CURRENT_PROJECT_VERSION = 195;
DEVELOPMENT_TEAM = 48XS7JAZB7; DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = reFilc; INFOPLIST_KEY_CFBundleDisplayName = reFilc;
@@ -746,7 +786,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 3.6.0; MARKETING_VERSION = 3.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo; PRODUCT_BUNDLE_IDENTIFIER = com.refilc2.naplo;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -764,7 +804,7 @@
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 195; CURRENT_PROJECT_VERSION = 195;
DEVELOPMENT_TEAM = 48XS7JAZB7; DEVELOPMENT_TEAM = 4DKAF249F3;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = reFilc; INFOPLIST_KEY_CFBundleDisplayName = reFilc;
@@ -774,7 +814,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 3.6.0; MARKETING_VERSION = 3.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo; PRODUCT_BUNDLE_IDENTIFIER = com.refilc2.naplo;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;

View File

@@ -2,6 +2,59 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>refilc_pride</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>refilc_pride</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>refilc_overcomplicated</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>refilc_overcomplicated</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>refilc_concept</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>refilc_concept</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>refilc_default</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>refilc_default</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundleIcons</key>
<dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconName</key>
<string></string>
<key>CFBundleIconFiles</key>
<array>
<string></string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>BGTaskSchedulerPermittedIdentifiers</key> <key>BGTaskSchedulerPermittedIdentifiers</key>
<array> <array>
<string>com.transistorsoft.fetch</string> <string>com.transistorsoft.fetch</string>

View File

@@ -6,7 +6,7 @@
<string>development</string> <string>development</string>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array> <array>
<string>group.refilcnaplo.livecard</string> <string>group.refilc2.livecard</string>
</array> </array>
</dict> </dict>
</plist> </plist>

View File

@@ -14,7 +14,7 @@ class LessonData {
var nextRoom: String var nextRoom: String
init?() { init?() {
let sharedDefault = UserDefaults(suiteName: "group.refilc.livecard")! let sharedDefault = UserDefaults(suiteName: "group.refilc2.livecard")!
self.color = sharedDefault.string(forKey: "color")! self.color = sharedDefault.string(forKey: "color")!
self.icon = sharedDefault.string(forKey: "icon")! self.icon = sharedDefault.string(forKey: "icon")!

View File

@@ -6,7 +6,7 @@
<string>development</string> <string>development</string>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array> <array>
<string>group.refilcnaplo.livecard</string> <string>group.refilc2.livecard</string>
</array> </array>
</dict> </dict>
</plist> </plist>

View File

@@ -91,14 +91,15 @@ struct LockScreenLiveActivityView: View {
Text(timerInterval: lesson!.date, countsDown: true) Text(timerInterval: lesson!.date, countsDown: true)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.frame(width: 85) .frame(width: 85)
.font(.title) .font(.title2)
.monospacedDigit() .monospacedDigit()
.padding(.trailing, CGFloat(24)) .padding(.trailing, CGFloat(24))
} }
.activityBackgroundTint( .activityBackgroundTint(
lesson!.color == "#676767" lesson!.color != "#676767"
? nil ? Color(hex: lesson!.color)
: Color(hex: lesson!.color) // Ha nem megy hat nem megy
: Color.clear
) )
} }
} }
@@ -118,12 +119,22 @@ struct LiveCardWidget: Widget {
DynamicIslandExpandedRegion(.leading) { DynamicIslandExpandedRegion(.leading) {
VStack { VStack {
Spacer() Spacer()
Image(systemName: lesson!.icon) ProgressView(
.resizable() timerInterval: lesson!.date,
.aspectRatio(contentMode: .fit) countsDown: true,
.frame(width: CGFloat(30), height: CGFloat(30)) label: {
.padding(.leading, CGFloat(6)) Image(systemName: lesson!.icon)
.padding(.bottom, CGFloat(6)) .resizable()
.aspectRatio(contentMode: .fit)
.frame(width: CGFloat(32), height: CGFloat(32))
},
currentValueLabel: {
Image(systemName: lesson!.icon)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: CGFloat(32), height: CGFloat(32))
}
).progressViewStyle(.circular)
} }
} }
DynamicIslandExpandedRegion(.center) { DynamicIslandExpandedRegion(.center) {
@@ -136,7 +147,7 @@ struct LiveCardWidget: Widget {
Text(lesson!.description) Text(lesson!.description)
.lineLimit(2) .lineLimit(2)
.font(.caption) .font(.caption)
} }.padding(EdgeInsets(top: 0.0, leading: 5.0, bottom: 0.0, trailing: 0.0))
} }
DynamicIslandExpandedRegion(.trailing) { DynamicIslandExpandedRegion(.trailing) {
VStack { VStack {
@@ -156,7 +167,8 @@ struct LiveCardWidget: Widget {
Image(systemName: lesson!.icon) Image(systemName: lesson!.icon)
} }
.font(.caption2) .font(.caption2)
} compactTrailing: { }
compactTrailing: {
Text(timerInterval: lesson!.date, countsDown: true) Text(timerInterval: lesson!.date, countsDown: true)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.frame(width: 40) .frame(width: 40)
@@ -164,22 +176,29 @@ struct LiveCardWidget: Widget {
/// Collapsed /// Collapsed
} minimal: { } minimal: {
VStack(alignment: .center) { VStack(alignment: .center, content: {
Image(systemName: lesson!.icon) ProgressView(
.resizable() timerInterval: lesson!.date,
.aspectRatio(contentMode: .fit) countsDown: true,
.frame(width: CGFloat(12), height: CGFloat(12)) label: {
Image(systemName: lesson!.icon)
Text(timerInterval: lesson!.date, countsDown: true) .resizable()
.multilineTextAlignment(.center) .aspectRatio(contentMode: .fit)
.monospacedDigit() .frame(width: CGFloat(12), height: CGFloat(12))
.font(.system(size: CGFloat(10))) },
} currentValueLabel: {
Image(systemName: lesson!.icon)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: CGFloat(12), height: CGFloat(12))
}
).progressViewStyle(.circular)
})
} }
.keylineTint( .keylineTint(
lesson!.color == "#676767" lesson!.color != "#676767"
? nil ? Color(hex: lesson!.color)
: Color(hex: lesson!.color) : Color.clear
) )
} }
} }

View File

@@ -40,6 +40,11 @@ class FilcAPI {
static const allThemes = "$themeGet/all"; static const allThemes = "$themeGet/all";
static const themeByID = "$themeGet/"; static const themeByID = "$themeGet/";
static const gradeColorsShare = "$baseUrl/v2/shared/grade-colors/add";
static const gradeColorsGet = "$baseUrl/v2/shared/grade-colors/get";
static const allGradeColors = "$gradeColorsGet/all";
static const gradeColorsByID = "$gradeColorsGet/";
static Future<bool> checkConnectivity() async => static Future<bool> checkConnectivity() async =>
(await Connectivity().checkConnectivity()) != ConnectivityResult.none; (await Connectivity().checkConnectivity()) != ConnectivityResult.none;
@@ -53,9 +58,14 @@ class FilcAPI {
.map((json) => School.fromJson(json)) .map((json) => School.fromJson(json))
.toList(); .toList();
schools.add(School( schools.add(School(
city: "Tiszabura", city: "Stockholm",
instituteCode: "supporttest-reni-tiszabura-teszt01", instituteCode: "refilc-test-sweden",
name: "FILC Éles Reni tiszabura-teszt", name: "reFilc Test SE - Leo Ekström High School",
));
schools.add(School(
city: "Madrid",
instituteCode: "refilc-test-spain",
name: "reFilc Test ES - Emilio Obrero University",
)); ));
return schools; return schools;
} else { } else {
@@ -180,12 +190,22 @@ class FilcAPI {
static Future<void> sendReport(ErrorReport report) async { static Future<void> sendReport(ErrorReport report) async {
try { try {
http.Response res = await http.post(Uri.parse(reportApi), body: { Map body = {
"os": report.os, "os": report.os,
"version": report.version, "version": report.version,
"error": report.error, "error": report.error,
"stack_trace": report.stack, "stack_trace": report.stack,
}); };
var client = http.Client();
http.Response res = await client.post(
Uri.parse(reportApi),
body: body,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
);
if (res.statusCode != 200) { if (res.statusCode != 200) {
throw "HTTP ${res.statusCode}: ${res.body}"; throw "HTTP ${res.statusCode}: ${res.body}";
@@ -203,6 +223,11 @@ class FilcAPI {
theme.json['background_color'] = theme.backgroundColor.value.toString(); theme.json['background_color'] = theme.backgroundColor.value.toString();
theme.json['panels_color'] = theme.panelsColor.value.toString(); theme.json['panels_color'] = theme.panelsColor.value.toString();
theme.json['accent_color'] = theme.accentColor.value.toString(); theme.json['accent_color'] = theme.accentColor.value.toString();
theme.json['icon_color'] = theme.iconColor.value.toString();
theme.json['shadow_effect'] = theme.shadowEffect.toString();
// set linked grade colors
theme.json['grade_colors_id'] = theme.gradeColors.id;
http.Response res = await http.post( http.Response res = await http.post(
Uri.parse(themeShare), Uri.parse(themeShare),
@@ -230,7 +255,49 @@ class FilcAPI {
throw "HTTP ${res.statusCode}: ${res.body}"; throw "HTTP ${res.statusCode}: ${res.body}";
} }
} on Exception catch (error, stacktrace) { } on Exception catch (error, stacktrace) {
log("ERROR: FilcAPI.addSharedTheme: $error $stacktrace"); log("ERROR: FilcAPI.getSharedTheme: $error $stacktrace");
}
return null;
}
static Future<void> addSharedGradeColors(
SharedGradeColors gradeColors) async {
try {
gradeColors.json.remove('json');
gradeColors.json['is_public'] = gradeColors.isPublic.toString();
gradeColors.json['five_color'] = gradeColors.fiveColor.value.toString();
gradeColors.json['four_color'] = gradeColors.fourColor.value.toString();
gradeColors.json['three_color'] = gradeColors.threeColor.value.toString();
gradeColors.json['two_color'] = gradeColors.twoColor.value.toString();
gradeColors.json['one_color'] = gradeColors.oneColor.value.toString();
http.Response res = await http.post(
Uri.parse(gradeColorsShare),
body: gradeColors.json,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
);
if (res.statusCode != 201) {
throw "HTTP ${res.statusCode}: ${res.body}";
}
log('Shared grade colors successfully with ID: ${gradeColors.id}');
} on Exception catch (error, stacktrace) {
log("ERROR: FilcAPI.addSharedGradeColors: $error $stacktrace");
}
}
static Future<Map?> getSharedGradeColors(String id) async {
try {
http.Response res = await http.get(Uri.parse(gradeColorsByID + id));
if (res.statusCode == 200) {
return (jsonDecode(res.body) as Map);
} else {
throw "HTTP ${res.statusCode}: ${res.body}";
}
} on Exception catch (error, stacktrace) {
log("ERROR: FilcAPI.getSharedGradeColors: $error $stacktrace");
} }
return null; return null;
} }

View File

@@ -1,6 +1,7 @@
// ignore_for_file: avoid_print, use_build_context_synchronously // ignore_for_file: avoid_print, use_build_context_synchronously
import 'package:filcnaplo/utils/jwt.dart'; import 'package:filcnaplo/utils/jwt.dart';
import 'package:filcnaplo_kreta_api/models/school.dart';
import 'package:filcnaplo_kreta_api/providers/absence_provider.dart'; import 'package:filcnaplo_kreta_api/providers/absence_provider.dart';
import 'package:filcnaplo_kreta_api/providers/event_provider.dart'; import 'package:filcnaplo_kreta_api/providers/event_provider.dart';
import 'package:filcnaplo_kreta_api/providers/exam_provider.dart'; import 'package:filcnaplo_kreta_api/providers/exam_provider.dart';
@@ -20,6 +21,7 @@ import 'package:filcnaplo_kreta_api/models/week.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:filcnaplo/api/nonce.dart'; import 'package:filcnaplo/api/nonce.dart';
import 'package:uuid/uuid.dart';
enum LoginState { enum LoginState {
missingFields, missingFields,
@@ -47,87 +49,143 @@ Future loginAPI({
void Function(User)? onLogin, void Function(User)? onLogin,
void Function()? onSuccess, void Function()? onSuccess,
}) async { }) async {
Provider.of<KretaClient>(context, listen: false).userAgent = Future testLogin(School school) async {
Provider.of<SettingsProvider>(context, listen: false).config.userAgent; var user = User(
username: username,
password: password,
instituteCode: instituteCode,
name: 'Teszt Lajos',
student: Student(
birth: DateTime.now(),
id: const Uuid().v4(),
name: 'Teszt Lajos',
school: school,
yearId: '1',
parents: ['Teszt András', 'Teszt Linda'],
json: {"a": "b"},
address: '1117 Budapest, Gábor Dénes utca 4.',
),
role: Role.parent,
);
Map<String, String> headers = { if (onLogin != null) onLogin(user);
"content-type": "application/x-www-form-urlencoded",
};
String nonceStr = await Provider.of<KretaClient>(context, listen: false) // store test user in db
.getAPI(KretaAPI.nonce, json: false); 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);
Nonce nonce = getNonce(nonceStr, username, instituteCode); if (onSuccess != null) onSuccess();
headers.addAll(nonce.header());
Map? res = await Provider.of<KretaClient>(context, listen: false) return LoginState.success;
.postAPI(KretaAPI.login, }
headers: headers,
body: User.loginBody(
username: username,
password: password,
instituteCode: instituteCode,
));
if (res != null) {
if (res.containsKey("error")) {
if (res["error"] == "invalid_grant") {
return LoginState.invalidGrant;
}
} 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); // if institute matches one of test things do test login
if (instituteCode == 'refilc-test-sweden') {
School school = School(
city: "Stockholm",
instituteCode: "refilc-test-sweden",
name: "reFilc Test SE - Leo Ekström High School",
);
// Store User in the database await testLogin(school);
await Provider.of<DatabaseProvider>(context, listen: false) } else if (instituteCode == 'refilc-test-spain') {
.store School school = School(
.storeUser(user); city: "Madrid",
Provider.of<UserProvider>(context, listen: false).addUser(user); instituteCode: "refilc-test-spain",
Provider.of<UserProvider>(context, listen: false).setUser(user.id); name: "reFilc Test ES - Emilio Obrero University",
);
// Get user data await testLogin(school);
} else {
// normal login from here
Provider.of<KretaClient>(context, listen: false).userAgent =
Provider.of<SettingsProvider>(context, listen: false).config.userAgent;
Map<String, String> headers = {
"content-type": "application/x-www-form-urlencoded",
};
String nonceStr = await Provider.of<KretaClient>(context, listen: false)
.getAPI(KretaAPI.nonce, json: false);
Nonce nonce = getNonce(nonceStr, username, instituteCode);
headers.addAll(nonce.header());
Map? res = await Provider.of<KretaClient>(context, listen: false)
.postAPI(KretaAPI.login,
headers: headers,
body: User.loginBody(
username: username,
password: password,
instituteCode: instituteCode,
));
if (res != null) {
if (res.containsKey("error")) {
if (res["error"] == "invalid_grant") {
return LoginState.invalidGrant;
}
} else {
if (res.containsKey("access_token")) {
try { try {
await Future.wait([ Provider.of<KretaClient>(context, listen: false).accessToken =
Provider.of<GradeProvider>(context, listen: false).fetch(), res["access_token"];
Provider.of<TimetableProvider>(context, listen: false) Map? studentJson =
.fetch(week: Week.current()), await Provider.of<KretaClient>(context, listen: false)
Provider.of<ExamProvider>(context, listen: false).fetch(), .getAPI(KretaAPI.student(instituteCode));
Provider.of<HomeworkProvider>(context, listen: false).fetch(), Student student = Student.fromJson(studentJson!);
Provider.of<MessageProvider>(context, listen: false).fetchAll(), var user = User(
Provider.of<NoteProvider>(context, listen: false).fetch(), username: username,
Provider.of<EventProvider>(context, listen: false).fetch(), password: password,
Provider.of<AbsenceProvider>(context, listen: false).fetch(), 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) { } catch (error) {
print("WARNING: failed to fetch user data: $error"); print("ERROR: loginAPI: $error");
// maybe check debug mode
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("ERROR: $error")));
return LoginState.failed;
} }
if (onSuccess != null) onSuccess();
return LoginState.success;
} catch (error) {
print("ERROR: loginAPI: $error");
// maybe check debug mode
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("ERROR: $error")));
return LoginState.failed;
} }
} }
} }
} }
return LoginState.failed; return LoginState.failed;
} }

View File

@@ -51,24 +51,24 @@ class LiveCardProvider extends ChangeNotifier {
_liveActivitiesPlugin.areActivitiesEnabled().then((value) { _liveActivitiesPlugin.areActivitiesEnabled().then((value) {
// Console log // Console log
if (kDebugMode) { if (kDebugMode) {
print("Live card enabled: $value"); print("iOS LiveActivity enabled: $value");
} }
if (value) { if (value) {
_liveActivitiesPlugin.init(appGroupId: "group.refilc.livecard"); _liveActivitiesPlugin.init(appGroupId: "group.refilc2.livecard");
_liveActivitiesPlugin.getAllActivitiesIds().then((value) { _liveActivitiesPlugin.getAllActivitiesIds().then((value) {
_latestActivityId = value.isNotEmpty ? value.first : null; _latestActivityId = value.isNotEmpty ? value.first : null;
}); });
} }
}); });
_timer = Timer.periodic(const Duration(seconds: 1), (timer) => update());
_delay = settings.bellDelayEnabled
? Duration(seconds: settings.bellDelay)
: Duration.zero;
update();
} }
_timer = Timer.periodic(const Duration(seconds: 1), (timer) => update());
_delay = settings.bellDelayEnabled
? Duration(seconds: settings.bellDelay)
: Duration.zero;
update();
} }
@override @override
@@ -88,7 +88,7 @@ class LiveCardProvider extends ChangeNotifier {
// Debugging // Debugging
static DateTime _now() { static DateTime _now() {
// return DateTime(2023, 8, 31, 8, 0); // return DateTime(2023, 9, 27, 9, 30);
return DateTime.now(); return DateTime.now();
} }
@@ -120,7 +120,7 @@ class LiveCardProvider extends ChangeNotifier {
"index": "index":
currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "", currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
"title": currentLesson != null "title": currentLesson != null
? ShortSubject.resolve(subject: currentLesson?.subject).capital() ? currentLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: currentLesson?.subject).capital()
: "", : "",
"subtitle": currentLesson?.room.replaceAll("_", " ") ?? "", "subtitle": currentLesson?.room.replaceAll("_", " ") ?? "",
"description": currentLesson?.description ?? "", "description": currentLesson?.description ?? "",
@@ -131,7 +131,7 @@ class LiveCardProvider extends ChangeNotifier {
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": nextLesson != null "nextSubject": nextLesson != null
? ShortSubject.resolve(subject: nextLesson?.subject).capital() ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "", : "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
@@ -160,7 +160,7 @@ class LiveCardProvider extends ChangeNotifier {
_delay.inMilliseconds) _delay.inMilliseconds)
.toString(), .toString(),
"nextSubject": (nextLesson != null "nextSubject": (nextLesson != null
? ShortSubject.resolve(subject: nextLesson?.subject) ? nextLesson?.subject.renamedTo ?? ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "") : "")
.capital(), .capital(),
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
@@ -196,7 +196,7 @@ class LiveCardProvider extends ChangeNotifier {
} }
} catch (e) { } catch (e) {
if (kDebugMode) { if (kDebugMode) {
print('ERROR: Unable to create or update iOS LiveCard!'); print('ERROR: Unable to create or update iOS LiveActivity!');
} }
} }
} }

View File

@@ -1,8 +1,10 @@
import 'dart:io';
import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
enum Status { network, maintenance, syncing } enum Status { network, maintenance, syncing, apiError }
class StatusProvider extends ChangeNotifier { class StatusProvider extends ChangeNotifier {
final List<Status> _stack = []; final List<Status> _stack = [];
@@ -12,6 +14,7 @@ class StatusProvider extends ChangeNotifier {
StatusProvider() { StatusProvider() {
_handleNetworkChanges(); _handleNetworkChanges();
_handleDNSFailure();
Connectivity().checkConnectivity().then((value) => _networkType = value); Connectivity().checkConnectivity().then((value) => _networkType = value);
} }
@@ -24,6 +27,7 @@ class StatusProvider extends ChangeNotifier {
_networkType = event; _networkType = event;
if (event == ConnectivityResult.none) { if (event == ConnectivityResult.none) {
if (!_stack.contains(Status.network)) { if (!_stack.contains(Status.network)) {
_stack.remove(Status.apiError);
_stack.insert(0, Status.network); _stack.insert(0, Status.network);
notifyListeners(); notifyListeners();
} }
@@ -36,8 +40,34 @@ class StatusProvider extends ChangeNotifier {
}); });
} }
void _handleDNSFailure() {
try {
InternetAddress.lookup('api.refilc.hu').then((status) {
if (status.isEmpty) {
if (!_stack.contains(Status.network)) {
_stack.remove(Status.apiError);
_stack.insert(0, Status.network);
notifyListeners();
}
} else {
if (_stack.contains(Status.network)) {
_stack.remove(Status.network);
notifyListeners();
}
}
});
} on SocketException catch (_) {
if (!_stack.contains(Status.network)) {
_stack.remove(Status.apiError);
_stack.insert(0, Status.network);
notifyListeners();
}
}
}
void triggerRequest(http.Response res) { void triggerRequest(http.Response res) {
if (res.headers.containsKey("x-maintenance-mode") || res.statusCode == 503) { if (res.headers.containsKey("x-maintenance-mode") ||
res.statusCode == 503) {
if (!_stack.contains(Status.maintenance)) { if (!_stack.contains(Status.maintenance)) {
_stack.insert(0, Status.maintenance); _stack.insert(0, Status.maintenance);
notifyListeners(); notifyListeners();
@@ -48,6 +78,23 @@ class StatusProvider extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
} }
if (res.body == 'invalid_grant' ||
res.body.replaceAll(' ', '') == '' ||
res.statusCode == 400) {
if (!_stack.contains(Status.apiError) &&
!_stack.contains(Status.network)) {
if (res.statusCode == 401) return;
_stack.insert(0, Status.apiError);
notifyListeners();
}
} else {
if (_stack.contains(Status.apiError) &&
res.request?.url.path != '/nonce') {
_stack.remove(Status.apiError);
notifyListeners();
}
}
} }
void triggerSync({required int current, required int max}) { void triggerSync({required int current, required int max}) {

View File

@@ -34,7 +34,8 @@ Future<void> syncAll(BuildContext context) {
print("INFO Syncing all"); print("INFO Syncing all");
UserProvider user = Provider.of<UserProvider>(context, listen: false); UserProvider user = Provider.of<UserProvider>(context, listen: false);
StatusProvider statusProvider = Provider.of<StatusProvider>(context, listen: false); StatusProvider statusProvider =
Provider.of<StatusProvider>(context, listen: false);
List<Future<void>> tasks = []; List<Future<void>> tasks = [];
int taski = 0; int taski = 0;
@@ -47,10 +48,14 @@ Future<void> syncAll(BuildContext context) {
tasks = [ tasks = [
syncStatus(Provider.of<GradeProvider>(context, listen: false).fetch()), syncStatus(Provider.of<GradeProvider>(context, listen: false).fetch()),
syncStatus(Provider.of<TimetableProvider>(context, listen: false).fetch(week: Week.current())), syncStatus(Provider.of<TimetableProvider>(context, listen: false)
.fetch(week: Week.current())),
syncStatus(Provider.of<ExamProvider>(context, listen: false).fetch()), syncStatus(Provider.of<ExamProvider>(context, listen: false).fetch()),
syncStatus(Provider.of<HomeworkProvider>(context, listen: false).fetch(from: DateTime.now().subtract(const Duration(days: 30)))), syncStatus(Provider.of<HomeworkProvider>(context, listen: false)
.fetch(from: DateTime.now().subtract(const Duration(days: 30)))),
syncStatus(Provider.of<MessageProvider>(context, listen: false).fetchAll()), syncStatus(Provider.of<MessageProvider>(context, listen: false).fetchAll()),
syncStatus(
Provider.of<MessageProvider>(context, listen: false).fetchAllRecipients()),
syncStatus(Provider.of<NoteProvider>(context, listen: false).fetch()), syncStatus(Provider.of<NoteProvider>(context, listen: false).fetch()),
syncStatus(Provider.of<EventProvider>(context, listen: false).fetch()), syncStatus(Provider.of<EventProvider>(context, listen: false).fetch()),
syncStatus(Provider.of<AbsenceProvider>(context, listen: false).fetch()), syncStatus(Provider.of<AbsenceProvider>(context, listen: false).fetch()),
@@ -58,14 +63,17 @@ Future<void> syncAll(BuildContext context) {
// Sync student // Sync student
syncStatus(() async { syncStatus(() async {
if (user.user == null) return; if (user.user == null) return;
Map? studentJson = await Provider.of<KretaClient>(context, listen: false).getAPI(KretaAPI.student(user.instituteCode!)); Map? studentJson = await Provider.of<KretaClient>(context, listen: false)
.getAPI(KretaAPI.student(user.instituteCode!));
if (studentJson == null) return; if (studentJson == null) return;
Student student = Student.fromJson(studentJson); Student student = Student.fromJson(studentJson);
user.user?.name = student.name; user.user?.name = student.name;
// Store user // Store user
await Provider.of<DatabaseProvider>(context, listen: false).store.storeUser(user.user!); await Provider.of<DatabaseProvider>(context, listen: false)
.store
.storeUser(user.user!);
}()), }()),
]; ];

View File

@@ -33,9 +33,12 @@ class UpdateProvider extends ChangeNotifier {
// Check for new releases // Check for new releases
if (_releases.isNotEmpty) { if (_releases.isNotEmpty) {
_available = _releases.first.version if (!_releases.first.prerelease) {
.compareTo(Version.fromString(currentVersion)) == _available = _releases.first.version
1; .compareTo(Version.fromString(currentVersion)) ==
1;
}
// ignore: avoid_print // ignore: avoid_print
if (_available) print("INFO: New update: ${releases.first.version}"); if (_available) print("INFO: New update: ${releases.first.version}");
notifyListeners(); notifyListeners();

View File

@@ -1,3 +1,5 @@
// ignore_for_file: deprecated_member_use
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
@@ -14,7 +16,7 @@ import 'package:filcnaplo/theme/theme.dart';
import 'package:filcnaplo_kreta_api/client/client.dart'; import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart'; import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:filcnaplo_premium/providers/goal_provider.dart'; import 'package:filcnaplo_premium/providers/goal_provider.dart';
import 'package:filcnaplo_premium/providers/share_provider.dart'; import 'package:filcnaplo_kreta_api/providers/share_provider.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -62,11 +64,10 @@ class App extends StatelessWidget {
final DatabaseProvider database; final DatabaseProvider database;
const App( const App(
{Key? key, {super.key,
required this.database, required this.database,
required this.settings, required this.settings,
required this.user}) required this.user});
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -131,6 +132,7 @@ class App extends StatelessWidget {
create: (context) => HomeworkProvider( create: (context) => HomeworkProvider(
context: context, context: context,
database: database, database: database,
user: user,
), ),
), ),
ChangeNotifierProvider<MessageProvider>( ChangeNotifierProvider<MessageProvider>(

View File

@@ -15,7 +15,8 @@ const settingsDB = DatabaseStruct("settings", {
"accent_color": int, "news": int, "seen_news": String, "accent_color": int, "news": int, "seen_news": String,
"developer_mode": int, "developer_mode": int,
"update_channel": int, "config": String, "custom_accent_color": int, "update_channel": int, "config": String, "custom_accent_color": int,
"custom_background_color": int, "custom_highlight_color": int, // general "custom_background_color": int, "custom_highlight_color": int,
"custom_icon_color": int, "shadow_effect": int, // general
"grade_color1": int, "grade_color2": int, "grade_color3": int, "grade_color1": int, "grade_color2": int, "grade_color3": int,
"grade_color4": int, "grade_color5": int, // grade colors "grade_color4": int, "grade_color5": int, // grade colors
"vibration_strength": int, "ab_weeks": int, "swap_ab_weeks": int, "vibration_strength": int, "ab_weeks": int, "swap_ab_weeks": int,
@@ -33,6 +34,7 @@ const settingsDB = DatabaseStruct("settings", {
"renamed_subjects_italics": int, "renamed_teachers_enabled": int, "renamed_subjects_italics": int, "renamed_teachers_enabled": int,
"renamed_teachers_italics": int, "renamed_teachers_italics": int,
"live_activity_color": String, "live_activity_color": String,
"welcome_message": String, "app_icon": String,
}); });
// DON'T FORGET TO UPDATE DEFAULT VALUES IN `initDB` MIGRATION OR ELSE PARENTS WILL COMPLAIN ABOUT THEIR CHILDREN MISSING // DON'T FORGET TO UPDATE DEFAULT VALUES IN `initDB` MIGRATION OR ELSE PARENTS WILL COMPLAIN ABOUT THEIR CHILDREN MISSING
// YOU'VE BEEN WARNED!!! // YOU'VE BEEN WARNED!!!
@@ -43,7 +45,7 @@ const usersDB = DatabaseStruct("users", {
}); });
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,
"homework": String, "messages": String, "notes": String, "homework": String, "messages": String, "recipients": String, "notes": String,
"events": String, "absences": String, "group_averages": String, "events": String, "absences": String, "group_averages": String,
// renamed subjects // non kreta data // renamed subjects // non kreta data
"renamed_subjects": String, "renamed_subjects": String,
@@ -99,7 +101,8 @@ Future<Database> initDB(DatabaseProvider database) async {
); );
await migrateDB(db, struct: userDataDB, defaultValues: { await migrateDB(db, struct: userDataDB, defaultValues: {
"grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]", "grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]",
"messages": "[]", "notes": "[]", "events": "[]", "absences": "[]", "messages": "[]", "recipients": "[]", "notes": "[]", "events": "[]",
"absences": "[]",
"group_averages": "[]", "group_averages": "[]",
// renamed subjects // non kreta data // renamed subjects // non kreta data
"renamed_subjects": "{}", "renamed_subjects": "{}",

View File

@@ -122,6 +122,19 @@ class UserDatabaseQuery {
return messages; return messages;
} }
Future<List<SendRecipient>> getRecipients({required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return [];
String? recipientsJson = userData.elementAt(0)["recipients"] as String?;
if (recipientsJson == null) return [];
List<SendRecipient> recipients = (jsonDecode(recipientsJson) as List)
.map((e) =>
SendRecipient.fromJson(e, SendRecipientType.fromJson(e['tipus'])))
.toList();
return recipients;
}
Future<List<Note>> getNotes({required String userId}) async { Future<List<Note>> getNotes({required String userId}) async {
List<Map> userData = List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]); await db.query("user_data", where: "id = ?", whereArgs: [userId]);

View File

@@ -86,6 +86,13 @@ class UserDatabaseStore {
where: "id = ?", whereArgs: [userId]); where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeRecipients(List<SendRecipient> recipients,
{required String userId}) async {
String recipientsJson = jsonEncode(recipients.map((e) => e.json).toList());
await db.update("user_data", {"recipients": recipientsJson},
where: "id = ?", whereArgs: [userId]);
}
Future<void> storeNotes(List<Note> notes, {required String userId}) async { Future<void> storeNotes(List<Note> notes, {required String userId}) async {
String notesJson = jsonEncode(notes.map((e) => e.json).toList()); String notesJson = jsonEncode(notes.map((e) => e.json).toList());
await db.update("user_data", {"notes": notesJson}, await db.update("user_data", {"notes": notesJson},

View File

@@ -9,16 +9,20 @@ import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/models/attachment.dart'; import 'package:filcnaplo_kreta_api/models/attachment.dart';
import 'package:filcnaplo_kreta_api/models/homework.dart'; import 'package:filcnaplo_kreta_api/models/homework.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:open_file/open_file.dart'; import 'package:open_filex/open_filex.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
extension AttachmentHelper on Attachment { extension AttachmentHelper on Attachment {
Future<String> download(BuildContext context, {bool overwrite = false}) async { Future<String> download(BuildContext context,
{bool overwrite = false}) async {
String downloads = await StorageHelper.downloadsPath(); String downloads = await StorageHelper.downloadsPath();
if (!overwrite && await File("$downloads/$name").exists()) return "$downloads/$name"; if (!overwrite && await File("$downloads/$name").exists()) {
return "$downloads/$name";
}
Uint8List data = await Provider.of<KretaClient>(context, listen: false).getAPI(downloadUrl, rawResponse: true); Uint8List data = await Provider.of<KretaClient>(context, listen: false)
.getAPI(downloadUrl, rawResponse: true);
if (!await StorageHelper.write("$downloads/$name", data)) return ""; if (!await StorageHelper.write("$downloads/$name", data)) return "";
return "$downloads/$name"; return "$downloads/$name";
@@ -28,19 +32,24 @@ extension AttachmentHelper on Attachment {
String downloads = await StorageHelper.downloadsPath(); String downloads = await StorageHelper.downloadsPath();
if (!await File("$downloads/$name").exists()) await download(context); if (!await File("$downloads/$name").exists()) await download(context);
var result = await OpenFile.open("$downloads/$name"); var result = await OpenFilex.open("$downloads/$name");
return result.type == ResultType.done; return result.type == ResultType.done;
} }
} }
extension HomeworkAttachmentHelper on HomeworkAttachment { extension HomeworkAttachmentHelper on HomeworkAttachment {
Future<String> download(BuildContext context, {bool overwrite = false}) async { Future<String> download(BuildContext context,
{bool overwrite = false}) async {
String downloads = await StorageHelper.downloadsPath(); String downloads = await StorageHelper.downloadsPath();
if (!overwrite && await File("$downloads/$name").exists()) return "$downloads/$name"; if (!overwrite && await File("$downloads/$name").exists()) {
return "$downloads/$name";
}
String url = downloadUrl(Provider.of<UserProvider>(context, listen: false).instituteCode ?? ""); String url = downloadUrl(
Uint8List data = await Provider.of<KretaClient>(context, listen: false).getAPI(url, rawResponse: true); Provider.of<UserProvider>(context, listen: false).instituteCode ?? "");
Uint8List data = await Provider.of<KretaClient>(context, listen: false)
.getAPI(url, rawResponse: true);
if (!await StorageHelper.write("$downloads/$name", data)) return ""; if (!await StorageHelper.write("$downloads/$name", data)) return "";
return "$downloads/$name"; return "$downloads/$name";
@@ -50,7 +59,7 @@ extension HomeworkAttachmentHelper on HomeworkAttachment {
String downloads = await StorageHelper.downloadsPath(); String downloads = await StorageHelper.downloadsPath();
if (!await File("$downloads/$name").exists()) await download(context); if (!await File("$downloads/$name").exists()) await download(context);
var result = await OpenFile.open("$downloads/$name"); var result = await OpenFilex.open("$downloads/$name");
return result.type == ResultType.done; return result.type == ResultType.done;
} }
} }

View File

@@ -195,7 +195,7 @@ class NotificationsHelper {
if (userProvider.getUsers().length == 1) { if (userProvider.getUsers().length == 1) {
await flutterLocalNotificationsPlugin.show( await flutterLocalNotificationsPlugin.show(
absence.id.hashCode, absence.id.hashCode,
"title_absence".i18n, "title_absence".i18n, // https://discord.com/channels/1111649116020285532/1153273625206591528
"body_absence".i18n.fill( "body_absence".i18n.fill(
[ [
DateFormat("yyyy-MM-dd").format(absence.date), DateFormat("yyyy-MM-dd").format(absence.date),
@@ -210,7 +210,7 @@ class NotificationsHelper {
} else { } else {
await flutterLocalNotificationsPlugin.show( await flutterLocalNotificationsPlugin.show(
absence.id.hashCode, absence.id.hashCode,
"title_absence".i18n, "title_absence".i18n, // https://discord.com/channels/1111649116020285532/1153273625206591528
"body_absence_multiuser".i18n.fill( "body_absence_multiuser".i18n.fill(
[ [
userProvider.displayName!, userProvider.displayName!,

View File

@@ -22,7 +22,8 @@ class SubjectIconData {
}); });
} }
SubjectIconVariants createIcon({required IconData material, required IconData cupertino}) { SubjectIconVariants createIcon(
{required IconData material, required IconData cupertino}) {
return { return {
IconPack.material: material, IconPack.material: material,
IconPack.cupertino: cupertino, IconPack.cupertino: cupertino,
@@ -30,82 +31,224 @@ SubjectIconVariants createIcon({required IconData material, required IconData cu
} }
class SubjectIcon { class SubjectIcon {
static String resolveName({Subject? subject, String? subjectName}) => _resolve(subject: subject, subjectName: subjectName).name; static String resolveName({GradeSubject? subject, String? subjectName}) =>
static IconData resolveVariant({Subject? subject, String? subjectName, required BuildContext context}) => _resolve(subject: subject, subjectName: subjectName).name;
_resolve(subject: subject, subjectName: subjectName).data[Provider.of<SettingsProvider>(context, listen: false).iconPack]!; static IconData resolveVariant(
{GradeSubject? subject,
String? subjectName,
required BuildContext context}) =>
_resolve(subject: subject, subjectName: subjectName).data[
Provider.of<SettingsProvider>(context, listen: false).iconPack]!;
static SubjectIconData _resolve({Subject? subject, String? subjectName}) { static SubjectIconData _resolve(
{GradeSubject? subject, String? subjectName}) {
assert(!(subject == null && subjectName == null)); assert(!(subject == null && subjectName == null));
String name = (subject?.name ?? subjectName ?? "").toLowerCase().specialChars().trim(); String name = (subject?.name ?? subjectName ?? "")
String category = subject?.category.description.toLowerCase().specialChars() ?? ""; .toLowerCase()
.specialChars()
.trim();
String category =
subject?.category.description.toLowerCase().specialChars() ?? "";
// todo: check for categories // todo: check for categories
if (RegExp("mate(k|matika)").hasMatch(name) || category == "matematika") { if (RegExp("mate(k|matika)").hasMatch(name) || category == "matematika") {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.function, material: Icons.calculate_outlined), name: "function");
} else if (RegExp("magyar nyelv|nyelvtan").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.textformat_alt, material: Icons.spellcheck_outlined), name: "textformat.alt");
} else if (RegExp("irodalom").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.book, material: Icons.menu_book_outlined), name: "book");
} else if (RegExp("tor(i|tenelem)").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.compass, material: Icons.hourglass_empty_outlined), name: "safari");
} else if (RegExp("foldrajz").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.map, material: Icons.public_outlined), name: "map");
} else if (RegExp("rajz|muvtori|muveszet|vizualis").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.paintbrush, material: Icons.palette_outlined), name: "paintbrush");
} else if (RegExp("fizika").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.lightbulb, material: Icons.emoji_objects_outlined), name: "lightbulb");
} else if (RegExp("^enek|zene|szolfezs|zongora|korus").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.music_note, material: Icons.music_note_outlined), name: "music.note");
} else if (RegExp("^tes(i|tneveles)|sport").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.sportscourt, material: Icons.sports_soccer_outlined), name: "sportscourt");
} else if (RegExp("kemia").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.lab_flask, material: Icons.science_outlined), name: "testtube.2");
} else if (RegExp("biologia").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.paw, material: Icons.pets_outlined), name: "pawprint");
} else if (RegExp("kornyezet|termeszet ?(tudomany|ismeret)|hon( es nep)?ismeret").hasMatch(name)) {
return SubjectIconData( return SubjectIconData(
data: createIcon(cupertino: CupertinoIcons.arrow_3_trianglepath, material: Icons.eco_outlined), name: "arrow.3.trianglepath"); data: createIcon(
cupertino: CupertinoIcons.function,
material: Icons.calculate_outlined),
name: "function");
} else if (RegExp("magyar nyelv|nyelvtan").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.textformat_alt,
material: Icons.spellcheck_outlined),
name: "textformat.alt");
} else if (RegExp("irodalom").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.book,
material: Icons.menu_book_outlined),
name: "book");
} else if (RegExp("tor(i|tenelem)").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.compass,
material: Icons.hourglass_empty_outlined),
name: "safari");
} else if (RegExp("foldrajz").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.map, material: Icons.public_outlined),
name: "map");
} else if (RegExp("rajz|muvtori|muveszet|vizualis").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.paintbrush,
material: Icons.palette_outlined),
name: "paintbrush");
} else if (RegExp("fizika").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.lightbulb,
material: Icons.emoji_objects_outlined),
name: "lightbulb");
} else if (RegExp("^enek|zene|szolfezs|zongora|korus").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.music_note,
material: Icons.music_note_outlined),
name: "music.note");
} else if (RegExp("^tes(i|tneveles)|sport").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.sportscourt,
material: Icons.sports_soccer_outlined),
name: "sportscourt");
} else if (RegExp("kemia").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.lab_flask,
material: Icons.science_outlined),
name: "testtube.2");
} else if (RegExp("biologia").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.paw, material: Icons.pets_outlined),
name: "pawprint");
} else if (RegExp(
"kornyezet|termeszet ?(tudomany|ismeret)|hon( es nep)?ismeret")
.hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.arrow_3_trianglepath,
material: Icons.eco_outlined),
name: "arrow.3.trianglepath");
} else if (RegExp("(hit|erkolcs)tan|vallas|etika").hasMatch(name)) { } else if (RegExp("(hit|erkolcs)tan|vallas|etika").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.heart, material: Icons.favorite_border_outlined), name: "heart"); return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.heart,
material: Icons.favorite_border_outlined),
name: "heart");
} else if (RegExp("penzugy").hasMatch(name)) { } else if (RegExp("penzugy").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.money_dollar, material: Icons.savings_outlined), name: "dollarsign"); return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.money_dollar,
material: Icons.savings_outlined),
name: "dollarsign");
} else if (RegExp("informatika|szoftver|iroda|digitalis").hasMatch(name)) { } else if (RegExp("informatika|szoftver|iroda|digitalis").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.device_laptop, material: Icons.computer_outlined), name: "laptopcomputer"); return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.device_laptop,
material: Icons.computer_outlined),
name: "laptopcomputer");
} else if (RegExp("prog").hasMatch(name)) { } else if (RegExp("prog").hasMatch(name)) {
return SubjectIconData( return SubjectIconData(
data: createIcon(cupertino: CupertinoIcons.chevron_left_slash_chevron_right, material: Icons.code_outlined), data: createIcon(
cupertino: CupertinoIcons.chevron_left_slash_chevron_right,
material: Icons.code_outlined),
name: "chevron.left.forwardslash.chevron.right"); name: "chevron.left.forwardslash.chevron.right");
} else if (RegExp("halozat").hasMatch(name)) { } else if (RegExp("halozat").hasMatch(name)) {
return SubjectIconData( return SubjectIconData(
data: createIcon(cupertino: CupertinoIcons.antenna_radiowaves_left_right, material: Icons.wifi_tethering_outlined), data: createIcon(
cupertino: CupertinoIcons.antenna_radiowaves_left_right,
material: Icons.wifi_tethering_outlined),
name: "antenna.radiowaves.left.and.right"); name: "antenna.radiowaves.left.and.right");
} else if (RegExp("szinhaz").hasMatch(name)) { } else if (RegExp("szinhaz").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.hifispeaker, material: Icons.theater_comedy_outlined), name: "hifispeaker"); return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.hifispeaker,
material: Icons.theater_comedy_outlined),
name: "hifispeaker");
} else if (RegExp("film|media").hasMatch(name)) { } else if (RegExp("film|media").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.film, material: Icons.theaters_outlined), name: "film"); return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.film,
material: Icons.theaters_outlined),
name: "film");
} else if (RegExp("elektro(tech)?nika").hasMatch(name)) { } else if (RegExp("elektro(tech)?nika").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.bolt, material: Icons.electrical_services_outlined), name: "bolt"); return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.bolt,
material: Icons.electrical_services_outlined),
name: "bolt");
} else if (RegExp("gepesz|mernok|ipar").hasMatch(name)) { } else if (RegExp("gepesz|mernok|ipar").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.wrench, material: Icons.precision_manufacturing_outlined), name: "wrench"); return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.wrench,
material: Icons.precision_manufacturing_outlined),
name: "wrench");
} else if (RegExp("technika").hasMatch(name)) { } else if (RegExp("technika").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.hammer, material: Icons.build_outlined), name: "hammer"); return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.hammer, material: Icons.build_outlined),
name: "hammer");
} else if (RegExp("tanc").hasMatch(name)) { } else if (RegExp("tanc").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.music_mic, material: Icons.speaker_outlined), name: "music.mic"); return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.music_mic,
material: Icons.speaker_outlined),
name: "music.mic");
} else if (RegExp("filozofia").hasMatch(name)) { } else if (RegExp("filozofia").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.bubble_left, material: Icons.psychology_outlined), name: "bubble.left"); return SubjectIconData(
} else if (RegExp("osztaly(fonoki|kozosseg)").hasMatch(name) || name == "ofo") { data: createIcon(
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.group, material: Icons.groups_outlined), name: "person.3"); cupertino: CupertinoIcons.bubble_left,
material: Icons.psychology_outlined),
name: "bubble.left");
} else if (RegExp("osztaly(fonoki|kozosseg)").hasMatch(name) ||
name == "ofo") {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.group, material: Icons.groups_outlined),
name: "person.3");
} else if (RegExp("gazdasag").hasMatch(name)) { } else if (RegExp("gazdasag").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.chart_pie, material: Icons.account_balance_outlined), name: "chart.pie"); return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.chart_pie,
material: Icons.account_balance_outlined),
name: "chart.pie");
} else if (RegExp("szorgalom").hasMatch(name)) { } else if (RegExp("szorgalom").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.checkmark_seal, material: Icons.verified_outlined), name: "checkmark.seal"); return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.checkmark_seal,
material: Icons.verified_outlined),
name: "checkmark.seal");
} else if (RegExp("magatartas").hasMatch(name)) { } else if (RegExp("magatartas").hasMatch(name)) {
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.smiley, material: Icons.emoji_people_outlined), name: "face.smiling"); return SubjectIconData(
} else if (RegExp("angol|nemet|francia|olasz|orosz|spanyol|latin|kinai|nyelv").hasMatch(name)) { data: createIcon(
return SubjectIconData(data: createIcon(cupertino: CupertinoIcons.globe, material: Icons.translate_outlined), name: "globe"); cupertino: CupertinoIcons.smiley,
material: Icons.emoji_people_outlined),
name: "face.smiling");
} else if (RegExp(
"angol|nemet|francia|olasz|orosz|spanyol|latin|kinai|nyelv")
.hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.globe,
material: Icons.translate_outlined),
name: "globe");
} else if (RegExp("linux").hasMatch(name)) { } else if (RegExp("linux").hasMatch(name)) {
return SubjectIconData(data: createIcon(material: FilcIcons.linux, cupertino: FilcIcons.linux)); return SubjectIconData(
data: createIcon(
material: FilcIcons.linux, cupertino: FilcIcons.linux));
} else if (RegExp("adatbazis").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.table_badge_more,
material: Icons.table_chart),
name: "table.badge.more");
} else if (RegExp("asztali alkalmazasok").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.macwindow,
material: Icons.desktop_windows_outlined),
name: "macwindow");
} else if (RegExp("projekt").hasMatch(name)) {
return SubjectIconData(
data: createIcon(
cupertino: CupertinoIcons.person_3_fill,
material: Icons.groups_3),
name: "person.3.fill");
} }
return SubjectIconData(); return SubjectIconData();
@@ -113,10 +256,13 @@ class SubjectIcon {
} }
class ShortSubject { class ShortSubject {
static String resolve({Subject? subject, String? subjectName}) { static String resolve({GradeSubject? subject, String? subjectName}) {
assert(!(subject == null && subjectName == null)); assert(!(subject == null && subjectName == null));
String name = (subject?.name ?? subjectName ?? "").toLowerCase().specialChars().trim(); String name = (subject?.name ?? subjectName ?? "")
.toLowerCase()
.specialChars()
.trim();
// String category = subject?.category.description.toLowerCase().specialChars() ?? ""; // String category = subject?.category.description.toLowerCase().specialChars() ?? "";
if (RegExp("magyar irodalom").hasMatch(name)) { if (RegExp("magyar irodalom").hasMatch(name)) {
@@ -131,7 +277,9 @@ class ShortSubject {
return "Tesi"; return "Tesi";
} else if (RegExp("tortenelem").hasMatch(name)) { } else if (RegExp("tortenelem").hasMatch(name)) {
return "Töri"; return "Töri";
} else if (RegExp("(angol|nemet|francia|olasz|orosz|spanyol|latin|kinai) nyelv").hasMatch(name)) { } else if (RegExp(
"(angol|nemet|francia|olasz|orosz|spanyol|latin|kinai) nyelv")
.hasMatch(name)) {
return (subject?.name ?? subjectName ?? "?").replaceAll(" nyelv", ""); return (subject?.name ?? subjectName ?? "?").replaceAll(" nyelv", "");
} else if (RegExp("informatika").hasMatch(name)) { } else if (RegExp("informatika").hasMatch(name)) {
return "Infó"; return "Infó";

View File

@@ -5,7 +5,7 @@ import 'dart:typed_data';
import 'package:filcnaplo/api/client.dart'; import 'package:filcnaplo/api/client.dart';
import 'package:filcnaplo/helpers/storage_helper.dart'; import 'package:filcnaplo/helpers/storage_helper.dart';
import 'package:filcnaplo/models/release.dart'; import 'package:filcnaplo/models/release.dart';
import 'package:open_file/open_file.dart'; import 'package:open_filex/open_filex.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
enum UpdateState { none, preparing, downloading, installing } enum UpdateState { none, preparing, downloading, installing }
@@ -37,7 +37,7 @@ extension UpdateHelper on Release {
(await Permission.manageExternalStorage.request().isGranted && (await Permission.manageExternalStorage.request().isGranted &&
await Permission.requestInstallPackages.request().isGranted); await Permission.requestInstallPackages.request().isGranted);
if (installPerms) { if (installPerms) {
var result = await OpenFile.open(apk.path); var result = await OpenFilex.open(apk.path);
if (result.type != ResultType.done) { if (result.type != ResultType.done) {
// ignore: avoid_print // ignore: avoid_print

View File

@@ -17,6 +17,7 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
void main() async { void main() async {
// Initalize // Initalize
WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized(); WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized();
// ignore: deprecated_member_use
binding.renderView.automaticSystemUiAdjustment = false; binding.renderView.automaticSystemUiAdjustment = false;
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
// Startup // Startup
@@ -63,7 +64,7 @@ class Startup {
await flutterLocalNotificationsPlugin await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation< .resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()! AndroidFlutterLocalNotificationsPlugin>()!
.requestPermission(); .requestNotificationsPermission();
} else if (Platform.isIOS) { } else if (Platform.isIOS) {
await flutterLocalNotificationsPlugin await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation< .resolvePlatformSpecificImplementation<

View File

@@ -20,7 +20,6 @@ class Ad {
}); });
factory Ad.fromJson(Map json) { factory Ad.fromJson(Map json) {
print(json);
return Ad( return Ad(
title: json['title'] ?? 'Ad', title: json['title'] ?? 'Ad',
description: json['description'] ?? '', description: json['description'] ?? '',

View File

@@ -67,6 +67,8 @@ class SettingsProvider extends ChangeNotifier {
Color _customAccentColor; Color _customAccentColor;
Color _customBackgroundColor; Color _customBackgroundColor;
Color _customHighlightColor; Color _customHighlightColor;
Color _customIconColor;
bool _shadowEffect;
List<String> _premiumScopes; List<String> _premiumScopes;
String _premiumAccessToken; String _premiumAccessToken;
String _premiumLogin; String _premiumLogin;
@@ -76,6 +78,8 @@ class SettingsProvider extends ChangeNotifier {
bool _renamedTeachersEnabled; bool _renamedTeachersEnabled;
bool _renamedTeachersItalics; bool _renamedTeachersItalics;
Color _liveActivityColor; Color _liveActivityColor;
String _welcomeMessage;
String _appIcon;
SettingsProvider({ SettingsProvider({
DatabaseProvider? database, DatabaseProvider? database,
@@ -111,6 +115,8 @@ class SettingsProvider extends ChangeNotifier {
required Color customAccentColor, required Color customAccentColor,
required Color customBackgroundColor, required Color customBackgroundColor,
required Color customHighlightColor, required Color customHighlightColor,
required Color customIconColor,
required bool shadowEffect,
required List<String> premiumScopes, required List<String> premiumScopes,
required String premiumAccessToken, required String premiumAccessToken,
required String premiumLogin, required String premiumLogin,
@@ -120,6 +126,8 @@ class SettingsProvider extends ChangeNotifier {
required bool renameTeachersEnabled, required bool renameTeachersEnabled,
required bool renameTeachersItalics, required bool renameTeachersItalics,
required Color liveActivityColor, required Color liveActivityColor,
required String welcomeMessage,
required String appIcon,
}) : _database = database, }) : _database = database,
_language = language, _language = language,
_startPage = startPage, _startPage = startPage,
@@ -153,6 +161,8 @@ class SettingsProvider extends ChangeNotifier {
_customAccentColor = customAccentColor, _customAccentColor = customAccentColor,
_customBackgroundColor = customBackgroundColor, _customBackgroundColor = customBackgroundColor,
_customHighlightColor = customHighlightColor, _customHighlightColor = customHighlightColor,
_customIconColor = customIconColor,
_shadowEffect = shadowEffect,
_premiumScopes = premiumScopes, _premiumScopes = premiumScopes,
_premiumAccessToken = premiumAccessToken, _premiumAccessToken = premiumAccessToken,
_premiumLogin = premiumLogin, _premiumLogin = premiumLogin,
@@ -161,7 +171,9 @@ class SettingsProvider extends ChangeNotifier {
_renamedSubjectsItalics = renameSubjectsItalics, _renamedSubjectsItalics = renameSubjectsItalics,
_renamedTeachersEnabled = renameTeachersEnabled, _renamedTeachersEnabled = renameTeachersEnabled,
_renamedTeachersItalics = renameTeachersItalics, _renamedTeachersItalics = renameTeachersItalics,
_liveActivityColor = liveActivityColor; _liveActivityColor = liveActivityColor,
_welcomeMessage = welcomeMessage,
_appIcon = appIcon;
factory SettingsProvider.fromMap(Map map, factory SettingsProvider.fromMap(Map map,
{required DatabaseProvider database}) { {required DatabaseProvider database}) {
@@ -214,6 +226,8 @@ class SettingsProvider extends ChangeNotifier {
customAccentColor: Color(map["custom_accent_color"]), customAccentColor: Color(map["custom_accent_color"]),
customBackgroundColor: Color(map["custom_background_color"]), customBackgroundColor: Color(map["custom_background_color"]),
customHighlightColor: Color(map["custom_highlight_color"]), customHighlightColor: Color(map["custom_highlight_color"]),
customIconColor: Color(map["custom_icon_color"]),
shadowEffect: map["shadow_effect"] == 1,
premiumScopes: jsonDecode(map["premium_scopes"]).cast<String>(), premiumScopes: jsonDecode(map["premium_scopes"]).cast<String>(),
premiumAccessToken: map["premium_token"], premiumAccessToken: map["premium_token"],
premiumLogin: map["premium_login"], premiumLogin: map["premium_login"],
@@ -223,6 +237,8 @@ class SettingsProvider extends ChangeNotifier {
renameTeachersEnabled: map["renamed_teachers_enabled"] == 1, renameTeachersEnabled: map["renamed_teachers_enabled"] == 1,
renameTeachersItalics: map["renamed_teachers_italics"] == 1, renameTeachersItalics: map["renamed_teachers_italics"] == 1,
liveActivityColor: Color(map["live_activity_color"]), liveActivityColor: Color(map["live_activity_color"]),
welcomeMessage: map["welcome_message"],
appIcon: map["app_icon"],
); );
} }
@@ -263,6 +279,8 @@ class SettingsProvider extends ChangeNotifier {
"custom_accent_color": _customAccentColor.value, "custom_accent_color": _customAccentColor.value,
"custom_background_color": _customBackgroundColor.value, "custom_background_color": _customBackgroundColor.value,
"custom_highlight_color": _customHighlightColor.value, "custom_highlight_color": _customHighlightColor.value,
"custom_icon_color": _customIconColor.value,
"shadow_effect": _shadowEffect ? 1 : 0,
"premium_scopes": jsonEncode(_premiumScopes), "premium_scopes": jsonEncode(_premiumScopes),
"premium_token": _premiumAccessToken, "premium_token": _premiumAccessToken,
"premium_login": _premiumLogin, "premium_login": _premiumLogin,
@@ -272,6 +290,8 @@ class SettingsProvider extends ChangeNotifier {
"renamed_teachers_enabled": _renamedTeachersEnabled ? 1 : 0, "renamed_teachers_enabled": _renamedTeachersEnabled ? 1 : 0,
"renamed_teachers_italics": _renamedTeachersItalics ? 1 : 0, "renamed_teachers_italics": _renamedTeachersItalics ? 1 : 0,
"live_activity_color": _liveActivityColor.value, "live_activity_color": _liveActivityColor.value,
"welcome_message": _welcomeMessage,
"app_icon": _appIcon,
}; };
} }
@@ -316,6 +336,8 @@ class SettingsProvider extends ChangeNotifier {
customAccentColor: const Color(0xff3D7BF4), customAccentColor: const Color(0xff3D7BF4),
customBackgroundColor: const Color(0xff000000), customBackgroundColor: const Color(0xff000000),
customHighlightColor: const Color(0xff222222), customHighlightColor: const Color(0xff222222),
customIconColor: const Color(0x00000000),
shadowEffect: true,
premiumScopes: [PremiumScopes.all], premiumScopes: [PremiumScopes.all],
premiumAccessToken: "igen", premiumAccessToken: "igen",
premiumLogin: "igen", premiumLogin: "igen",
@@ -325,6 +347,8 @@ class SettingsProvider extends ChangeNotifier {
renameTeachersEnabled: false, renameTeachersEnabled: false,
renameTeachersItalics: false, renameTeachersItalics: false,
liveActivityColor: const Color(0xFF676767), liveActivityColor: const Color(0xFF676767),
welcomeMessage: '',
appIcon: 'refilc_default',
); );
} }
@@ -364,6 +388,8 @@ class SettingsProvider extends ChangeNotifier {
: _customAccentColor; : _customAccentColor;
Color? get customBackgroundColor => _customBackgroundColor; Color? get customBackgroundColor => _customBackgroundColor;
Color? get customHighlightColor => _customHighlightColor; Color? get customHighlightColor => _customHighlightColor;
Color? get customIconColor => _customIconColor;
bool get shadowEffect => _shadowEffect;
List<String> get premiumScopes => _premiumScopes; List<String> get premiumScopes => _premiumScopes;
String get premiumAccessToken => _premiumAccessToken; String get premiumAccessToken => _premiumAccessToken;
String get premiumLogin => _premiumLogin; String get premiumLogin => _premiumLogin;
@@ -373,6 +399,8 @@ class SettingsProvider extends ChangeNotifier {
bool get renamedTeachersEnabled => _renamedTeachersEnabled; bool get renamedTeachersEnabled => _renamedTeachersEnabled;
bool get renamedTeachersItalics => _renamedTeachersItalics; bool get renamedTeachersItalics => _renamedTeachersItalics;
Color get liveActivityColor => _liveActivityColor; Color get liveActivityColor => _liveActivityColor;
String get welcomeMessage => _welcomeMessage;
String get appIcon => _appIcon;
Future<void> update({ Future<void> update({
bool store = true, bool store = true,
@@ -408,6 +436,8 @@ class SettingsProvider extends ChangeNotifier {
Color? customAccentColor, Color? customAccentColor,
Color? customBackgroundColor, Color? customBackgroundColor,
Color? customHighlightColor, Color? customHighlightColor,
Color? customIconColor,
bool? shadowEffect,
List<String>? premiumScopes, List<String>? premiumScopes,
String? premiumAccessToken, String? premiumAccessToken,
String? premiumLogin, String? premiumLogin,
@@ -417,6 +447,8 @@ class SettingsProvider extends ChangeNotifier {
bool? renamedTeachersEnabled, bool? renamedTeachersEnabled,
bool? renamedTeachersItalics, bool? renamedTeachersItalics,
Color? liveActivityColor, Color? liveActivityColor,
String? welcomeMessage,
String? appIcon,
}) async { }) async {
if (language != null && language != _language) _language = language; if (language != null && language != _language) _language = language;
if (startPage != null && startPage != _startPage) _startPage = startPage; if (startPage != null && startPage != _startPage) _startPage = startPage;
@@ -503,6 +535,12 @@ class SettingsProvider extends ChangeNotifier {
customHighlightColor != _customHighlightColor) { customHighlightColor != _customHighlightColor) {
_customHighlightColor = customHighlightColor; _customHighlightColor = customHighlightColor;
} }
if (customIconColor != null && customIconColor != _customIconColor) {
_customIconColor = customIconColor;
}
if (shadowEffect != null && shadowEffect != _shadowEffect) {
_shadowEffect = shadowEffect;
}
if (premiumScopes != null && premiumScopes != _premiumScopes) { if (premiumScopes != null && premiumScopes != _premiumScopes) {
_premiumScopes = premiumScopes; _premiumScopes = premiumScopes;
} }
@@ -535,6 +573,13 @@ class SettingsProvider extends ChangeNotifier {
if (liveActivityColor != null && liveActivityColor != _liveActivityColor) { if (liveActivityColor != null && liveActivityColor != _liveActivityColor) {
_liveActivityColor = liveActivityColor; _liveActivityColor = liveActivityColor;
} }
if (welcomeMessage != null && welcomeMessage != _welcomeMessage) {
_welcomeMessage = welcomeMessage;
}
if (appIcon != null && appIcon != _appIcon) {
_appIcon = appIcon;
}
// store or not
if (store) await _database?.store.storeSettings(this); if (store) await _database?.store.storeSettings(this);
notifyListeners(); notifyListeners();
} }

View File

@@ -8,6 +8,9 @@ class SharedTheme {
Color backgroundColor; Color backgroundColor;
Color panelsColor; Color panelsColor;
Color accentColor; Color accentColor;
Color iconColor;
bool shadowEffect;
SharedGradeColors gradeColors;
SharedTheme({ SharedTheme({
required this.json, required this.json,
@@ -17,9 +20,12 @@ class SharedTheme {
required this.backgroundColor, required this.backgroundColor,
required this.panelsColor, required this.panelsColor,
required this.accentColor, required this.accentColor,
required this.iconColor,
required this.shadowEffect,
required this.gradeColors,
}); });
factory SharedTheme.fromJson(Map json) { factory SharedTheme.fromJson(Map json, SharedGradeColors gradeColors) {
return SharedTheme( return SharedTheme(
json: json, json: json,
id: json['public_id'], id: json['public_id'],
@@ -28,6 +34,47 @@ class SharedTheme {
backgroundColor: Color(json['background_color']), backgroundColor: Color(json['background_color']),
panelsColor: Color(json['panels_color']), panelsColor: Color(json['panels_color']),
accentColor: Color(json['accent_color']), accentColor: Color(json['accent_color']),
iconColor: Color(json['icon_color']),
shadowEffect: json['shadow_effect'] ?? true,
gradeColors: gradeColors,
);
}
}
class SharedGradeColors {
Map json;
String id;
bool isPublic;
String nickname;
Color fiveColor;
Color fourColor;
Color threeColor;
Color twoColor;
Color oneColor;
SharedGradeColors({
required this.json,
required this.id,
this.isPublic = false,
this.nickname = 'Anonymous',
required this.fiveColor,
required this.fourColor,
required this.threeColor,
required this.twoColor,
required this.oneColor,
});
factory SharedGradeColors.fromJson(Map json) {
return SharedGradeColors(
json: json,
id: json['public_id'],
isPublic: json['is_public'] ?? false,
nickname: json['nickname'] ?? 'Anonymous',
fiveColor: Color(json['five_color']),
fourColor: Color(json['four_color']),
threeColor: Color(json['three_color']),
twoColor: Color(json['two_color']),
oneColor: Color(json['one_color']),
); );
} }
} }

View File

@@ -5,17 +5,21 @@ enum SubjectLessonCountUpdateState { ready, updating }
class SubjectLessonCount { class SubjectLessonCount {
DateTime lastUpdated; DateTime lastUpdated;
Map<Subject, int> subjects; Map<GradeSubject, int> subjects;
SubjectLessonCountUpdateState state; SubjectLessonCountUpdateState state;
SubjectLessonCount({required this.lastUpdated, required this.subjects, this.state = SubjectLessonCountUpdateState.ready}); SubjectLessonCount(
{required this.lastUpdated,
required this.subjects,
this.state = SubjectLessonCountUpdateState.ready});
factory SubjectLessonCount.fromMap(Map json) { factory SubjectLessonCount.fromMap(Map json) {
return SubjectLessonCount( return SubjectLessonCount(
lastUpdated: DateTime.fromMillisecondsSinceEpoch(json["last_updated"] ?? 0), lastUpdated:
DateTime.fromMillisecondsSinceEpoch(json["last_updated"] ?? 0),
subjects: ((json["subjects"] as Map?) ?? {}).map( subjects: ((json["subjects"] as Map?) ?? {}).map(
(key, value) => MapEntry( (key, value) => MapEntry(
Subject(id: key, name: "", category: Category.fromJson({})), GradeSubject(id: key, name: "", category: Category.fromJson({})),
value, value,
), ),
), ),

View File

@@ -1,5 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:filcnaplo_kreta_api/client/api.dart'; import 'package:filcnaplo_kreta_api/client/api.dart';
import 'package:filcnaplo_kreta_api/models/school.dart';
import 'package:filcnaplo_kreta_api/models/student.dart'; import 'package:filcnaplo_kreta_api/models/student.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
@@ -43,7 +44,16 @@ class User {
username: map["username"], username: map["username"],
password: map["password"], password: map["password"],
name: map["name"].trim(), name: map["name"].trim(),
student: Student.fromJson(jsonDecode(map["student"])), student: map["student"] != 'null'
? Student.fromJson(jsonDecode(map["student"]))
: Student(
id: const Uuid().v4(),
name: 'Ismeretlen Diák',
school: School(instituteCode: '', name: '', city: ''),
birth: DateTime.now(),
yearId: '1',
parents: [],
),
role: Role.values[map["role"] ?? 0], role: Role.values[map["role"] ?? 0],
nickname: map["nickname"] ?? "", nickname: map["nickname"] ?? "",
picture: map["picture"] ?? "", picture: map["picture"] ?? "",
@@ -93,4 +103,13 @@ class User {
"refresh_user_data": "false", "refresh_user_data": "false",
}; };
} }
static Map<String, Object?> logoutBody({
required String refreshToken,
}) {
return {
"refresh_token": refreshToken,
"client_id": KretaAPI.clientId,
};
}
} }

View File

@@ -35,6 +35,7 @@ import 'package:provider/provider.dart';
const List<FilterType> homeFilters = [ const List<FilterType> homeFilters = [
FilterType.all, FilterType.all,
FilterType.grades, FilterType.grades,
FilterType.exams,
FilterType.messages, FilterType.messages,
FilterType.absences FilterType.absences
]; ];
@@ -101,6 +102,7 @@ Future<List<DateWidget>> getFilterWidgets(FilterType activeData,
gradeProvider.grades, gradeProvider.lastSeenDate); gradeProvider.grades, gradeProvider.lastSeenDate);
if (settingsProvider.gradeOpeningFun) { if (settingsProvider.gradeOpeningFun) {
items.addAll( items.addAll(
// ignore: use_build_context_synchronously
await getFilterWidgets(FilterType.newGrades, context: context)); await getFilterWidgets(FilterType.newGrades, context: context));
} }
break; break;
@@ -213,19 +215,21 @@ Widget filterItemBuilder(
child: DecoratedBox( child: DecoratedBox(
decoration: BoxDecoration( decoration: BoxDecoration(
boxShadow: [ boxShadow: [
BoxShadow( if (Provider.of<SettingsProvider>(context, listen: false)
offset: const Offset(0, 21), .shadowEffect)
blurRadius: 23.0, BoxShadow(
color: Theme.of(context).shadowColor.withOpacity( offset: const Offset(0, 21),
Theme.of(context).shadowColor.opacity * blurRadius: 23.0,
CurvedAnimation( color: Theme.of(context).shadowColor.withOpacity(
parent: CurvedAnimation( Theme.of(context).shadowColor.opacity *
parent: animation, CurvedAnimation(
curve: Curves.easeInOutCubic), parent: CurvedAnimation(
curve: const Interval(2 / 3, 1.0), parent: animation,
).value, curve: Curves.easeInOutCubic),
), curve: const Interval(2 / 3, 1.0),
), ).value,
),
),
], ],
), ),
child: child, child: child,

View File

@@ -87,13 +87,13 @@ Widget _defaultItemBuilder(Color color, bool isCurrentColor, void Function() cha
// The blocky color picker you can alter the layout and shape. // The blocky color picker you can alter the layout and shape.
class BlockPicker extends StatefulWidget { class BlockPicker extends StatefulWidget {
BlockPicker({ BlockPicker({
Key? key, super.key,
required this.pickerColor, required this.pickerColor,
required this.onColorChanged, required this.onColorChanged,
this.useInShowDialog = true, this.useInShowDialog = true,
this.layoutBuilder = _defaultLayoutBuilder, this.layoutBuilder = _defaultLayoutBuilder,
this.itemBuilder = _defaultItemBuilder, this.itemBuilder = _defaultItemBuilder,
}) : super(key: key); });
final Color? pickerColor; final Color? pickerColor;
final ValueChanged<Color> onColorChanged; final ValueChanged<Color> onColorChanged;

View File

@@ -7,16 +7,18 @@
/// ///
/// You can create your own layout by importing `picker.dart`. /// You can create your own layout by importing `picker.dart`.
// ignore_for_file: use_build_context_synchronously
library hsv_picker; library hsv_picker;
import 'package:filcnaplo/models/shared_theme.dart'; import 'package:filcnaplo/models/shared_theme.dart';
import 'package:filcnaplo_mobile_ui/common/custom_snack_bar.dart'; import 'package:filcnaplo_mobile_ui/common/custom_snack_bar.dart';
import 'package:filcnaplo_premium/providers/share_provider.dart'; import 'package:filcnaplo_kreta_api/providers/share_provider.dart';
import 'package:filcnaplo_premium/ui/mobile/flutter_colorpicker/block_picker.dart'; import 'package:filcnaplo/ui/flutter_colorpicker/block_picker.dart';
import 'package:filcnaplo_premium/ui/mobile/flutter_colorpicker/palette.dart'; import 'package:filcnaplo/ui/flutter_colorpicker/palette.dart';
import 'package:filcnaplo_premium/ui/mobile/flutter_colorpicker/utils.dart'; import 'package:filcnaplo/ui/flutter_colorpicker/utils.dart';
import 'package:filcnaplo_premium/ui/mobile/settings/theme.dart'; import 'package:filcnaplo_mobile_ui/screens/settings/theme_screen.dart';
import 'package:filcnaplo_premium/ui/mobile/settings/theme.i18n.dart'; import 'package:filcnaplo_mobile_ui/screens/settings/theme_screen.i18n.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:filcnaplo/theme/colors/colors.dart'; import 'package:filcnaplo/theme/colors/colors.dart';
@@ -24,7 +26,7 @@ import 'package:provider/provider.dart';
class FilcColorPicker extends StatefulWidget { class FilcColorPicker extends StatefulWidget {
const FilcColorPicker({ const FilcColorPicker({
Key? key, super.key,
required this.colorMode, required this.colorMode,
required this.pickerColor, required this.pickerColor,
required this.onColorChanged, required this.onColorChanged,
@@ -53,7 +55,7 @@ class FilcColorPicker extends StatefulWidget {
this.colorHistory, this.colorHistory,
this.onHistoryChanged, this.onHistoryChanged,
required this.onThemeIdProvided, required this.onThemeIdProvided,
}) : super(key: key); });
final CustomColorMode colorMode; final CustomColorMode colorMode;
final Color pickerColor; final Color pickerColor;
@@ -78,10 +80,10 @@ class FilcColorPicker extends StatefulWidget {
final void Function(SharedTheme theme) onThemeIdProvided; final void Function(SharedTheme theme) onThemeIdProvided;
@override @override
_FilcColorPickerState createState() => _FilcColorPickerState(); FilcColorPickerState createState() => FilcColorPickerState();
} }
class _FilcColorPickerState extends State<FilcColorPicker> { class FilcColorPickerState extends State<FilcColorPicker> {
final idController = TextEditingController(); final idController = TextEditingController();
late final ShareProvider shareProvider; late final ShareProvider shareProvider;
@@ -262,6 +264,7 @@ class _FilcColorPickerState extends State<FilcColorPicker> {
if (theme != null) { if (theme != null) {
widget.onThemeIdProvided(theme); widget.onThemeIdProvided(theme);
idController.clear();
} else { } else {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
CustomSnackBar( CustomSnackBar(

View File

@@ -3,6 +3,7 @@
// FROM: https://pub.dev/packages/flutter_colorpicker // FROM: https://pub.dev/packages/flutter_colorpicker
// FROM: https://pub.dev/packages/flutter_colorpicker // FROM: https://pub.dev/packages/flutter_colorpicker
// ignore: dangling_library_doc_comments
/// The components of HSV Color Picker /// The components of HSV Color Picker
/// ///
/// Try to create a Color Picker with other layout on your own :) /// Try to create a Color Picker with other layout on your own :)
@@ -317,11 +318,11 @@ class ColorPickerInput extends StatefulWidget {
const ColorPickerInput( const ColorPickerInput(
this.color, this.color,
this.onColorChanged, { this.onColorChanged, {
Key? key, super.key,
this.enableAlpha = true, this.enableAlpha = true,
this.embeddedText = false, this.embeddedText = false,
this.disable = false, this.disable = false,
}) : super(key: key); });
final Color color; final Color color;
final ValueChanged<Color> onColorChanged; final ValueChanged<Color> onColorChanged;
@@ -330,10 +331,10 @@ class ColorPickerInput extends StatefulWidget {
final bool disable; final bool disable;
@override @override
_ColorPickerInputState createState() => _ColorPickerInputState(); ColorPickerInputState createState() => ColorPickerInputState();
} }
class _ColorPickerInputState extends State<ColorPickerInput> { class ColorPickerInputState extends State<ColorPickerInput> {
TextEditingController textEditingController = TextEditingController(); TextEditingController textEditingController = TextEditingController();
int inputColor = 0; int inputColor = 0;
@@ -346,11 +347,7 @@ class _ColorPickerInputState extends State<ColorPickerInput> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (inputColor != widget.color.value) { if (inputColor != widget.color.value) {
textEditingController.text = '#' + textEditingController.text = '#${widget.color.red.toRadixString(16).toUpperCase().padLeft(2, '0')}${widget.color.green.toRadixString(16).toUpperCase().padLeft(2, '0')}${widget.color.blue.toRadixString(16).toUpperCase().padLeft(2, '0')}${widget.enableAlpha ? widget.color.alpha.toRadixString(16).toUpperCase().padLeft(2, '0') : ''}';
widget.color.red.toRadixString(16).toUpperCase().padLeft(2, '0') +
widget.color.green.toRadixString(16).toUpperCase().padLeft(2, '0') +
widget.color.blue.toRadixString(16).toUpperCase().padLeft(2, '0') +
(widget.enableAlpha ? widget.color.alpha.toRadixString(16).toUpperCase().padLeft(2, '0') : '');
} }
return Padding( return Padding(
padding: const EdgeInsets.only(top: 6.0, left: 12.0, right: 12.0), padding: const EdgeInsets.only(top: 6.0, left: 12.0, right: 12.0),
@@ -516,10 +513,10 @@ class ColorPickerSlider extends StatelessWidget {
this.onColorChanged, this.onColorChanged,
this.onColorChangeEnd, this.onColorChangeEnd,
this.onProblem, { this.onProblem, {
Key? key, super.key,
this.displayThumbColor = false, this.displayThumbColor = false,
this.fullThumbColor = false, this.fullThumbColor = false,
}) : super(key: key); });
final TrackType trackType; final TrackType trackType;
final HSVColor hsvColor; final HSVColor hsvColor;
@@ -657,13 +654,13 @@ class ColorPickerSlider extends StatelessWidget {
class ColorIndicator extends StatelessWidget { class ColorIndicator extends StatelessWidget {
const ColorIndicator( const ColorIndicator(
this.hsvColor, { this.hsvColor, {
Key? key, super.key,
this.currentHsvColor, this.currentHsvColor,
this.icon, this.icon,
this.width = 50.0, this.width = 50.0,
this.height = 50.0, this.height = 50.0,
this.adaptive = false, this.adaptive = false,
}) : super(key: key); });
final HSVColor hsvColor; final HSVColor hsvColor;
final HSVColor? currentHsvColor; final HSVColor? currentHsvColor;
@@ -711,8 +708,8 @@ class ColorPickerArea extends StatelessWidget {
this.onColorChanged, this.onColorChanged,
this.onChangeEnd, this.onChangeEnd,
this.paletteType, { this.paletteType, {
Key? key, super.key,
}) : super(key: key); });
final HSVColor hsvColor; final HSVColor hsvColor;
final ValueChanged<HSVColor> onColorChanged; final ValueChanged<HSVColor> onColorChanged;

View File

@@ -3,6 +3,7 @@
// FROM: https://pub.dev/packages/flutter_colorpicker // FROM: https://pub.dev/packages/flutter_colorpicker
// FROM: https://pub.dev/packages/flutter_colorpicker // FROM: https://pub.dev/packages/flutter_colorpicker
// ignore: dangling_library_doc_comments
/// Common function lib /// Common function lib
import 'dart:math'; import 'dart:math';

View File

@@ -10,14 +10,20 @@ import 'package:flutter_feather_icons/flutter_feather_icons.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class GradeTile extends StatelessWidget { class GradeTile extends StatelessWidget {
const GradeTile(this.grade, const GradeTile(
{Key? key, this.onTap, this.padding, this.censored = false}) this.grade, {
: super(key: key); super.key,
this.onTap,
this.padding,
this.censored = false,
this.viewOverride = false,
});
final Grade grade; final Grade grade;
final void Function()? onTap; final void Function()? onTap;
final EdgeInsetsGeometry? padding; final EdgeInsetsGeometry? padding;
final bool censored; final bool censored;
final bool viewOverride;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -26,7 +32,8 @@ class GradeTile extends StatelessWidget {
bool isTitleItalic = false; bool isTitleItalic = false;
bool isSubtitleItalic = false; bool isSubtitleItalic = false;
EdgeInsets leadingPadding = EdgeInsets.zero; EdgeInsets leadingPadding = EdgeInsets.zero;
bool isSubjectView = SubjectGradesContainer.of(context) != null; bool isSubjectView =
SubjectGradesContainer.of(context) != null || viewOverride;
String subjectName = String subjectName =
grade.subject.renamedTo ?? grade.subject.name.capital(); grade.subject.renamedTo ?? grade.subject.name.capital();
String modeDescription = grade.mode.description.capital(); String modeDescription = grade.mode.description.capital();
@@ -34,8 +41,7 @@ class GradeTile extends StatelessWidget {
GradeCalculatorProvider calculatorProvider = GradeCalculatorProvider calculatorProvider =
Provider.of<GradeCalculatorProvider>(context, listen: false); Provider.of<GradeCalculatorProvider>(context, listen: false);
SettingsProvider settingsProvider = SettingsProvider settingsProvider = Provider.of<SettingsProvider>(context);
Provider.of<SettingsProvider>(context);
// Test order: // Test order:
// description // description
// mode // mode
@@ -50,7 +56,8 @@ class GradeTile extends StatelessWidget {
} }
} else { } else {
title = subjectName; title = subjectName;
isTitleItalic = grade.subject.isRenamed && settingsProvider.renamedSubjectsItalics; isTitleItalic =
grade.subject.isRenamed && settingsProvider.renamedSubjectsItalics;
} }
// Test order: // Test order:
@@ -62,7 +69,9 @@ class GradeTile extends StatelessWidget {
? modeDescription ? modeDescription
: "" : ""
: subjectName; : subjectName;
isSubtitleItalic = isSubjectView ? false : grade.subject.isRenamed && settingsProvider.renamedSubjectsItalics; isSubtitleItalic = isSubjectView
? false
: grade.subject.isRenamed && settingsProvider.renamedSubjectsItalics;
} else { } else {
subtitle = grade.value.valueName.split("(")[0]; subtitle = grade.value.valueName.split("(")[0];
} }
@@ -127,9 +136,7 @@ class GradeTile extends StatelessWidget {
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
fontStyle: isTitleItalic fontStyle: isTitleItalic ? FontStyle.italic : null),
? FontStyle.italic
: null),
), ),
subtitle: subtitle != "" subtitle: subtitle != ""
? censored ? censored
@@ -149,7 +156,10 @@ class GradeTile extends StatelessWidget {
subtitle, subtitle,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle(fontWeight: FontWeight.w500, fontStyle: isSubtitleItalic ? FontStyle.italic : null), style: TextStyle(
fontWeight: FontWeight.w500,
fontStyle:
isSubtitleItalic ? FontStyle.italic : null),
) )
: null, : null,
trailing: isSubjectView trailing: isSubjectView
@@ -184,7 +194,7 @@ class GradeTile extends StatelessWidget {
class GradeValueWidget extends StatelessWidget { class GradeValueWidget extends StatelessWidget {
const GradeValueWidget( const GradeValueWidget(
this.value, { this.value, {
Key? key, super.key,
this.size = 38.0, this.size = 38.0,
this.fill = false, this.fill = false,
this.contrast = false, this.contrast = false,
@@ -193,7 +203,7 @@ class GradeValueWidget extends StatelessWidget {
this.complemented = false, this.complemented = false,
this.nocolor = false, this.nocolor = false,
this.color, this.color,
}) : super(key: key); });
final GradeValue value; final GradeValue value;
final double size; final double size;
@@ -210,8 +220,8 @@ class GradeValueWidget extends StatelessWidget {
GradeValue value = this.value; GradeValue value = this.value;
bool isSubjectView = SubjectGradesContainer.of(context) != null; bool isSubjectView = SubjectGradesContainer.of(context) != null;
Color color = Color color = this.color ??
this.color ?? gradeColor(context: context, value: value.value, nocolor: nocolor); gradeColor(context: context, value: value.value, nocolor: nocolor);
Widget valueText; Widget valueText;
final percentage = value.percentage; final percentage = value.percentage;
@@ -283,7 +293,9 @@ class GradeValueWidget extends StatelessWidget {
color: color.withOpacity(contrast ? 1.0 : .25), color: color.withOpacity(contrast ? 1.0 : .25),
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ boxShadow: [
if (shadow) if (shadow &&
Provider.of<SettingsProvider>(context, listen: false)
.shadowEffect)
BoxShadow( BoxShadow(
color: color, color: color,
blurRadius: 62.0, blurRadius: 62.0,

View File

@@ -16,8 +16,7 @@ import 'package:provider/provider.dart';
import 'lesson_tile.i18n.dart'; import 'lesson_tile.i18n.dart';
class LessonTile extends StatelessWidget { class LessonTile extends StatelessWidget {
const LessonTile(this.lesson, {Key? key, this.onTap, this.swapDesc = false}) const LessonTile(this.lesson, {super.key, this.onTap, this.swapDesc = false});
: super(key: key);
final Lesson lesson; final Lesson lesson;
final bool swapDesc; final bool swapDesc;
@@ -287,8 +286,7 @@ enum LessonSubtileType { homework, exam, absence }
class LessonSubtile extends StatelessWidget { class LessonSubtile extends StatelessWidget {
const LessonSubtile( const LessonSubtile(
{Key? key, this.onPressed, required this.title, required this.type}) {super.key, this.onPressed, required this.title, required this.type});
: super(key: key);
final Function()? onPressed; final Function()? onPressed;
final String title; final String title;

View File

@@ -11,12 +11,12 @@ import 'package:provider/provider.dart';
class MessageTile extends StatelessWidget { class MessageTile extends StatelessWidget {
const MessageTile( const MessageTile(
this.message, { this.message, {
Key? key, super.key,
this.messages, this.messages,
this.padding, this.padding,
this.onTap, this.onTap,
this.censored = false, this.censored = false,
}) : super(key: key); });
final Message message; final Message message;
final List<Message>? messages; final List<Message>? messages;

View File

@@ -1 +0,0 @@
flutter/ephemeral

View File

@@ -1,116 +0,0 @@
cmake_minimum_required(VERSION 3.10)
project(runner LANGUAGES CXX)
set(BINARY_NAME "filcnaplo")
set(APPLICATION_ID "hu.filc.filcnaplo")
cmake_policy(SET CMP0063 NEW)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
# Root filesystem for cross-building.
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()
# Configure build options.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
# Compilation settings that should be applied to most targets.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_14)
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
endfunction()
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
# Flutter library and tool build rules.
add_subdirectory(${FLUTTER_MANAGED_DIR})
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
# Application build
add_executable(${BINARY_NAME}
"main.cc"
"my_application.cc"
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
)
apply_standard_settings(${BINARY_NAME})
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
add_dependencies(${BINARY_NAME} flutter_assemble)
# Only the install-generated bundle's copy of the executable will launch
# correctly, since the resources must in the right relative locations. To avoid
# people trying to run the unbundled copy, put it in a subdirectory instead of
# the default top-level location.
set_target_properties(${BINARY_NAME}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
)
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# By default, "installing" just makes a relocatable bundle in the build
# directory.
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
# Start with a clean build bundle directory every time.
install(CODE "
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
" COMPONENT Runtime)
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
if(PLUGIN_BUNDLED_LIBRARIES)
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()

View File

@@ -1,87 +0,0 @@
cmake_minimum_required(VERSION 3.10)
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
# Configuration provided via flutter tool.
include(${EPHEMERAL_DIR}/generated_config.cmake)
# TODO: Move the rest of this into files in ephemeral. See
# https://github.com/flutter/flutter/issues/57146.
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
# which isn't available in 3.10.
function(list_prepend LIST_NAME PREFIX)
set(NEW_LIST "")
foreach(element ${${LIST_NAME}})
list(APPEND NEW_LIST "${PREFIX}${element}")
endforeach(element)
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
endfunction()
# === Flutter Library ===
# System-level dependencies.
find_package(PkgConfig REQUIRED)
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
# Published to parent scope for install step.
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
list(APPEND FLUTTER_LIBRARY_HEADERS
"fl_basic_message_channel.h"
"fl_binary_codec.h"
"fl_binary_messenger.h"
"fl_dart_project.h"
"fl_engine.h"
"fl_json_message_codec.h"
"fl_json_method_codec.h"
"fl_message_codec.h"
"fl_method_call.h"
"fl_method_channel.h"
"fl_method_codec.h"
"fl_method_response.h"
"fl_plugin_registrar.h"
"fl_plugin_registry.h"
"fl_standard_message_codec.h"
"fl_standard_method_codec.h"
"fl_string_codec.h"
"fl_value.h"
"fl_view.h"
"flutter_linux.h"
)
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
add_library(flutter INTERFACE)
target_include_directories(flutter INTERFACE
"${EPHEMERAL_DIR}"
)
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
target_link_libraries(flutter INTERFACE
PkgConfig::GTK
PkgConfig::GLIB
PkgConfig::GIO
)
add_dependencies(flutter flutter_assemble)
# === Flutter tool backend ===
# _phony_ is a non-existent file to force this command to run every time,
# since currently there's no way to get a full input/output list from the
# flutter tool.
add_custom_command(
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
${CMAKE_CURRENT_BINARY_DIR}/_phony_
COMMAND ${CMAKE_COMMAND} -E env
${FLUTTER_TOOL_ENVIRONMENT}
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
VERBATIM
)
add_custom_target(flutter_assemble DEPENDS
"${FLUTTER_LIBRARY}"
${FLUTTER_LIBRARY_HEADERS}
)

View File

@@ -40,11 +40,11 @@ static void my_application_activate(GApplication* application) {
if (use_header_bar) { if (use_header_bar) {
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar)); gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "Filc Napló"); gtk_header_bar_set_title(header_bar, "reFilc");
gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
} else { } else {
gtk_window_set_title(window, "Filc Napló"); gtk_window_set_title(window, "reFilc");
} }
gtk_window_set_default_size(window, 1280, 720); gtk_window_set_default_size(window, 1280, 720);

View File

@@ -1,7 +0,0 @@
# Flutter-related
**/Flutter/ephemeral/
**/Pods/
# Xcode-related
**/dgph
**/xcuserdata/

View File

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

View File

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

View File

@@ -3,7 +3,7 @@ description: "Nem hivatalos e-napló alkalmazás az e-Kréta rendszerhez"
homepage: https://refilc.hu homepage: https://refilc.hu
publish_to: "none" publish_to: "none"
version: 4.2.3+223 version: 4.5.1+238
environment: environment:
sdk: ">=2.17.0 <3.0.0" sdk: ">=2.17.0 <3.0.0"
@@ -25,26 +25,27 @@ dependencies:
flutter_localizations: flutter_localizations:
sdk: flutter sdk: flutter
i18n_extension: ^9.0.0 i18n_extension: ^10.0.1
sqflite: ^2.2.0+2 sqflite: ^2.2.0+2
intl: ^0.18.0 intl: ^0.18.0
provider: ^5.0.0 provider: ^5.0.0
http: ^0.13.3 http: ^0.13.3
uuid: ^3.0.4 uuid: ^4.2.1
html: ^0.15.0 html: ^0.15.0
open_file: open_filex: ^4.3.4
git: # open_file:
url: https://github.com/crazecoder/open_file # git:
ref: master # url: https://github.com/crazecoder/open_file
# ref: master
path_provider: ^2.0.2 path_provider: ^2.0.2
permission_handler: ^10.2.0 permission_handler: ^11.0.1
share_plus: ^7.0.2 share_plus: ^7.0.2
connectivity_plus: ^4.0.1 connectivity_plus: ^5.0.2
flutter_displaymode: ^0.6.0 flutter_displaymode: ^0.6.0
quick_actions: ^1.0.1 quick_actions: ^1.0.1
animated_list_plus: ^0.5.0 animated_list_plus: ^0.5.0
dynamic_color: ^1.2.2 dynamic_color: ^1.2.2
material_color_utilities: ^0.2.0 material_color_utilities: ^0.5.0
crypto: ^3.0.2 crypto: ^3.0.2
elegant_notification: ^1.6.1 elegant_notification: ^1.6.1
flutter_feather_icons: ^2.0.0+1 flutter_feather_icons: ^2.0.0+1
@@ -53,9 +54,9 @@ dependencies:
lottie: ^1.4.3 lottie: ^1.4.3
rive: ^0.9.1 rive: ^0.9.1
animated_background: ^2.0.0 animated_background: ^2.0.0
dropdown_button2: ^1.8.9 dropdown_button2: ^1.9.4
home_widget: ^0.1.6 home_widget: ^0.1.6
flutter_expandable_fab: ^1.8.1 flutter_expandable_fab: ^2.0.0
uni_links: ^0.5.1 uni_links: ^0.5.1
url_launcher: ^6.1.6 url_launcher: ^6.1.6
workmanager: ^0.5.1 workmanager: ^0.5.1
@@ -63,7 +64,7 @@ dependencies:
image_picker: ^0.8.6 image_picker: ^0.8.6
animations: ^2.0.1 animations: ^2.0.1
background_fetch: ^1.1.5 background_fetch: ^1.1.5
flutter_local_notifications: ^14.1.0 flutter_local_notifications: ^16.2.0
package_info_plus: ^4.0.2 package_info_plus: ^4.0.2
screenshot: ^2.1.0 screenshot: ^2.1.0
flutter_staggered_grid_view: ^0.7.0 flutter_staggered_grid_view: ^0.7.0
@@ -73,7 +74,7 @@ dependencies:
url: https://github.com/kimaah/image_crop.git url: https://github.com/kimaah/image_crop.git
dev_dependencies: dev_dependencies:
flutter_lints: ^2.0.1 flutter_lints: ^3.0.1
flutter_launcher_icons: "^0.13.1" flutter_launcher_icons: "^0.13.1"
flutter_native_splash: "^2.3.0" flutter_native_splash: "^2.3.0"
sqflite_common_ffi: ^2.0.0+3 sqflite_common_ffi: ^2.0.0+3
@@ -87,6 +88,7 @@ flutter:
- assets/animations/ - assets/animations/
- assets/images/ - assets/images/
- assets/images/subject_covers/ - assets/images/subject_covers/
- assets/launch_icons/
fonts: fonts:
- family: FilcIcons - family: FilcIcons

View File

@@ -1,17 +0,0 @@
flutter/ephemeral/
# Visual Studio user-specific files.
*.suo
*.user
*.userosscache
*.sln.docstates
# Visual Studio build-related files.
x64/
x86/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/

View File

@@ -31,6 +31,11 @@ bool FlutterWindow::OnCreate() {
this->Show(); this->Show();
}); });
// Flutter can complete the first frame before the "show window" callback is
// registered. The following call ensures a frame is pending to ensure the
// window is shown. It is a no-op if the first frame hasn't completed yet.
flutter_controller_->ForceRedraw();
return true; return true;
} }

View File

@@ -1,47 +0,0 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
pubspec.lock

View File

@@ -61,19 +61,26 @@ class FilterBar extends StatelessWidget implements PreferredSizeWidget {
// avoid fading over selected tab // avoid fading over selected tab
return ShaderMask( return ShaderMask(
shaderCallback: (Rect bounds) { shaderCallback: (Rect bounds) {
final Color bg = Theme.of(context).scaffoldBackgroundColor; final Color bg =
Theme.of(context).scaffoldBackgroundColor;
final double index = controller.animation!.value; final double index = controller.animation!.value;
return LinearGradient(begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ return LinearGradient(
index < 0.2 ? Colors.transparent : bg, begin: Alignment.topLeft,
Colors.transparent, end: Alignment.bottomRight,
Colors.transparent, colors: [
index > controller.length - 1.2 ? Colors.transparent : bg index < 0.2 ? Colors.transparent : bg,
], stops: const [ Colors.transparent,
0, Colors.transparent,
0.1, index > controller.length - 1.2
0.9, ? Colors.transparent
1 : bg
]).createShader(bounds); ],
stops: const [
0,
0.1,
0.9,
1
]).createShader(bounds);
}, },
blendMode: BlendMode.dstOut, blendMode: BlendMode.dstOut,
child: child); child: child);

View File

@@ -31,7 +31,7 @@ import 'absences_page.i18n.dart';
enum AbsenceFilter { absences, delays, misses } enum AbsenceFilter { absences, delays, misses }
class SubjectAbsence { class SubjectAbsence {
Subject subject; GradeSubject subject;
List<Absence> absences; List<Absence> absences;
double percentage; double percentage;
@@ -56,7 +56,7 @@ class _AbsencesPageState extends State<AbsencesPage>
late String firstName; late String firstName;
late TabController _tabController; late TabController _tabController;
late List<SubjectAbsence> absences = []; late List<SubjectAbsence> absences = [];
final Map<Subject, Lesson> _lessonCount = {}; final Map<GradeSubject, Lesson> _lessonCount = {};
@override @override
void initState() { void initState() {
@@ -87,7 +87,7 @@ class _AbsencesPageState extends State<AbsencesPage>
} }
void buildSubjectAbsences() { void buildSubjectAbsences() {
Map<Subject, SubjectAbsence> _absences = {}; Map<GradeSubject, SubjectAbsence> _absences = {};
for (final absence in absenceProvider.absences) { for (final absence in absenceProvider.absences) {
if (absence.delay != 0) continue; if (absence.delay != 0) continue;

View File

@@ -1,6 +1,7 @@
import 'dart:math'; import 'dart:math';
import 'package:animations/animations.dart'; import 'package:animations/animations.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/utils/format.dart'; import 'package:filcnaplo/utils/format.dart';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart'; import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:filcnaplo/helpers/average_helper.dart'; import 'package:filcnaplo/helpers/average_helper.dart';
@@ -32,7 +33,7 @@ class GradeSubjectView extends StatefulWidget {
const GradeSubjectView(this.subject, {Key? key, this.groupAverage = 0.0}) const GradeSubjectView(this.subject, {Key? key, this.groupAverage = 0.0})
: super(key: key); : super(key: key);
final Subject subject; final GradeSubject subject;
final double groupAverage; final double groupAverage;
void push(BuildContext context, {bool root = false}) { void push(BuildContext context, {bool root = false}) {
@@ -56,13 +57,14 @@ class _GradeSubjectViewState extends State<GradeSubjectView> {
// Providers // Providers
late GradeProvider gradeProvider; late GradeProvider gradeProvider;
late GradeCalculatorProvider calculatorProvider; late GradeCalculatorProvider calculatorProvider;
late SettingsProvider settingsProvider;
late double average; late double average;
late Widget gradeGraph; late Widget gradeGraph;
bool gradeCalcMode = false; bool gradeCalcMode = false;
List<Grade> getSubjectGrades(Subject subject) => !gradeCalcMode List<Grade> getSubjectGrades(GradeSubject subject) => !gradeCalcMode
? gradeProvider.grades.where((e) => e.subject == subject).toList() ? gradeProvider.grades.where((e) => e.subject == subject).toList()
: calculatorProvider.grades.where((e) => e.subject == subject).toList(); : calculatorProvider.grades.where((e) => e.subject == subject).toList();
@@ -142,6 +144,7 @@ class _GradeSubjectViewState extends State<GradeSubjectView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
gradeProvider = Provider.of<GradeProvider>(context); gradeProvider = Provider.of<GradeProvider>(context);
calculatorProvider = Provider.of<GradeCalculatorProvider>(context); calculatorProvider = Provider.of<GradeCalculatorProvider>(context);
settingsProvider = Provider.of<SettingsProvider>(context);
List<Grade> subjectGrades = getSubjectGrades(widget.subject).toList(); List<Grade> subjectGrades = getSubjectGrades(widget.subject).toList();
average = AverageHelper.averageEvals(subjectGrades); average = AverageHelper.averageEvals(subjectGrades);
@@ -244,7 +247,8 @@ class _GradeSubjectViewState extends State<GradeSubjectView> {
subject: widget.subject, context: context), subject: widget.subject, context: context),
scrollController: _scrollController, scrollController: _scrollController,
title: widget.subject.renamedTo ?? widget.subject.name.capital(), title: widget.subject.renamedTo ?? widget.subject.name.capital(),
italic: widget.subject.isRenamed, italic: widget.subject.isRenamed &&
settingsProvider.renamedSubjectsItalics,
child: SubjectGradesContainer( child: SubjectGradesContainer(
child: CupertinoScrollbar( child: CupertinoScrollbar(
child: ListView.builder( child: ListView.builder(

View File

@@ -21,7 +21,7 @@ import 'package:filcnaplo_desktop_ui/pages/grades/grade_subject_view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:filcnaplo/helpers/average_helper.dart'; import 'package:filcnaplo/helpers/average_helper.dart';
import 'package:filcnaplo_premium/ui/mobile/grades/average_selector.dart'; import 'package:filcnaplo_mobile_ui/pages/grades/average_selector.dart';
import 'grades_page.i18n.dart'; import 'grades_page.i18n.dart';
class GradesPage extends StatefulWidget { class GradesPage extends StatefulWidget {
@@ -41,24 +41,25 @@ class _GradesPageState extends State<GradesPage> {
int avgDropValue = 0; int avgDropValue = 0;
List<Grade> getSubjectGrades(Subject subject, {int days = 0}) => gradeProvider List<Grade> getSubjectGrades(GradeSubject subject, {int days = 0}) =>
.grades gradeProvider.grades
.where((e) => .where((e) =>
e.subject == subject && e.subject == subject &&
e.type == GradeType.midYear && e.type == GradeType.midYear &&
(days == 0 || (days == 0 ||
e.date.isBefore(DateTime.now().subtract(Duration(days: days))))) e.date
.toList(); .isBefore(DateTime.now().subtract(Duration(days: days)))))
.toList();
void generateTiles() { void generateTiles() {
List<Subject> subjects = gradeProvider.grades List<GradeSubject> subjects = gradeProvider.grades
.map((e) => e.subject) .map((e) => e.subject)
.toSet() .toSet()
.toList() .toList()
..sort((a, b) => a.name.compareTo(b.name)); ..sort((a, b) => a.name.compareTo(b.name));
List<Widget> tiles = []; List<Widget> tiles = [];
Map<Subject, double> subjectAvgs = {}; Map<GradeSubject, double> subjectAvgs = {};
tiles.addAll(subjects.map((subject) { tiles.addAll(subjects.map((subject) {
List<Grade> subjectGrades = getSubjectGrades(subject); List<Grade> subjectGrades = getSubjectGrades(subject);
@@ -145,6 +146,7 @@ class _GradesPageState extends State<GradesPage> {
child: StatisticsTile( child: StatisticsTile(
outline: true, outline: true,
title: AutoSizeText( title: AutoSizeText(
// https://discord.com/channels/1111649116020285532/1153397476578050130
"classavg".i18n, "classavg".i18n,
textAlign: TextAlign.center, textAlign: TextAlign.center,
maxLines: 2, maxLines: 2,
@@ -208,7 +210,7 @@ class _GradesPageState extends State<GradesPage> {
title: Row( title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
PremiumAverageSelector( AverageSelector(
value: avgDropValue, value: avgDropValue,
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {

View File

@@ -16,7 +16,7 @@ extension Localization on String {
"7_days_average": "Weekly Average", "7_days_average": "Weekly Average",
"subjectavg": "Subject Average", "subjectavg": "Subject Average",
"classavg": "Class Average", "classavg": "Class Average",
"fail_warning": "Faliure warning", "fail_warning": "Failure warning",
"fail_warning_description": "You are failing %d subject(s)", "fail_warning_description": "You are failing %d subject(s)",
}, },
"hu_hu": { "hu_hu": {

View File

@@ -7,7 +7,7 @@ import 'package:filcnaplo/api/client.dart';
import 'package:filcnaplo/api/login.dart'; import 'package:filcnaplo/api/login.dart';
import 'package:filcnaplo_mobile_ui/screens/login/login_button.dart'; import 'package:filcnaplo_mobile_ui/screens/login/login_button.dart';
import 'package:filcnaplo_mobile_ui/screens/login/login_input.dart'; import 'package:filcnaplo_mobile_ui/screens/login/login_input.dart';
import 'package:filcnaplo_mobile_ui/screens/login/school_input/school_input.dart'; import 'package:filcnaplo_desktop_ui/screens/login/school_input/school_input.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart'; import 'package:flutter_acrylic/flutter_acrylic.dart';
@@ -15,11 +15,11 @@ import 'login_screen.i18n.dart';
const LinearGradient _backgroundGradient = LinearGradient( const LinearGradient _backgroundGradient = LinearGradient(
colors: [ colors: [
Color.fromARGB(255, 0, 0, 0), Color.fromARGB(255, 61, 122, 244),
Color.fromARGB(255, 23, 77, 185), Color.fromARGB(255, 23, 77, 185),
Color.fromARGB(255, 7, 42, 112), Color.fromARGB(255, 7, 42, 112),
], ],
begin: Alignment(-0.8, -2), begin: Alignment(-0.8, -2.0),
end: Alignment(0.8, 1.0), end: Alignment(0.8, 1.0),
stops: [-1.0, 0.0, 1.0], stops: [-1.0, 0.0, 1.0],
); );
@@ -90,7 +90,7 @@ class _LoginScreenState extends State<LoginScreen> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: Container( body: Container(
decoration: BoxDecoration( decoration: const BoxDecoration(
gradient: _backgroundGradient, gradient: _backgroundGradient,
), ),
child: SafeArea( child: SafeArea(
@@ -320,8 +320,10 @@ class _LoginScreenState extends State<LoginScreen> {
String password = passwordController.text; String password = passwordController.text;
if (username == "" || if (username == "" ||
password == "" || password ==
schoolController.selectedSchool == null) { "" ||
schoolController.selectedSchool == null
) {
return setState(() => _loginState = LoginState.missingFields); return setState(() => _loginState = LoginState.missingFields);
} }

View File

@@ -0,0 +1,122 @@
import 'package:filcnaplo_mobile_ui/screens/login/login_input.dart';
import 'package:filcnaplo_mobile_ui/screens/login/school_input/school_input_overlay.dart';
import 'package:filcnaplo_desktop_ui/screens/login/school_input/school_input_tile.dart';
import 'package:filcnaplo_mobile_ui/screens/login/school_input/school_search.dart';
import 'package:flutter/material.dart';
import 'package:filcnaplo_kreta_api/models/school.dart';
class SchoolInput extends StatefulWidget {
const SchoolInput({Key? key, required this.controller, required this.scroll})
: super(key: key);
final SchoolInputController controller;
final ScrollController scroll;
@override
_SchoolInputState createState() => _SchoolInputState();
}
class _SchoolInputState extends State<SchoolInput> {
final _focusNode = FocusNode();
final _layerLink = LayerLink();
late SchoolInputOverlay overlay;
@override
void initState() {
super.initState();
widget.controller.update = (fn) {
if (mounted) setState(fn);
};
overlay = SchoolInputOverlay(layerLink: _layerLink);
// Show school list when focused
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
WidgetsBinding.instance
.addPostFrameCallback((_) => overlay.createOverlayEntry(context));
Future.delayed(const Duration(milliseconds: 100)).then((value) {
if (mounted && widget.scroll.hasClients) {
widget.scroll.animateTo(widget.scroll.offset + 500,
duration: const Duration(milliseconds: 500),
curve: Curves.ease);
}
});
} else {
overlay.entry?.remove();
}
});
// LoginInput TextField listener
widget.controller.textController.addListener(() {
String text = widget.controller.textController.text;
if (text.isEmpty) {
overlay.children = null;
return;
}
List<School> results =
searchSchools(widget.controller.schools ?? [], text);
setState(() {
overlay.children = results
.map((School e) => SchoolInputTile(
school: e,
onTap: () => _selectSchool(e),
))
.toList();
});
Overlay.of(context).setState(() {});
});
}
void _selectSchool(School school) {
FocusScope.of(context).requestFocus(FocusNode());
setState(() {
widget.controller.selectedSchool = school;
widget.controller.textController.text = school.name;
});
}
@override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: _layerLink,
child: widget.controller.schools == null
? Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 10.0),
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.15),
borderRadius: BorderRadius.circular(12.0),
),
child: const Center(
child: SizedBox(
height: 28.0,
width: 28.0,
child: CircularProgressIndicator(
color: Colors.white,
),
),
),
)
: LoginInput(
style: LoginInputStyle.school,
focusNode: _focusNode,
onClear: () {
widget.controller.selectedSchool = null;
FocusScope.of(context).requestFocus(_focusNode);
},
controller: widget.controller.textController,
),
);
}
}
class SchoolInputController {
final textController = TextEditingController();
School? selectedSchool;
List<School>? schools;
late void Function(void Function()) update;
}

View File

@@ -0,0 +1,65 @@
import 'package:filcnaplo_kreta_api/models/school.dart';
import 'package:flutter/material.dart';
class SchoolInputTile extends StatelessWidget {
const SchoolInputTile({Key? key, required this.school, this.onTap})
: super(key: key);
final School school;
final Function()? onTap;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: GestureDetector(
onPanDown: (e) {
onTap!();
},
child: InkWell(
onTapDown: (e) {},
borderRadius: BorderRadius.circular(6.0),
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// School name
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
school.name,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontWeight: FontWeight.w600),
),
),
Row(
children: [
// School id
Expanded(
child: Text(
school.instituteCode,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
// School city
Expanded(
child: Text(
school.city,
textAlign: TextAlign.right,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
],
),
),
),
),
);
}
}

View File

@@ -63,8 +63,12 @@ class NavigationScreenState extends State<NavigationScreen>
await Window.initialize(); await Window.initialize();
} catch (_) {} } catch (_) {}
// Transparent sidebar // Transparent sidebar
if (Platform.isLinux) return;
await Window.setEffect( await Window.setEffect(
effect: WindowEffect.acrylic, effect: Platform.isLinux
? WindowEffect.transparent
: WindowEffect.acrylic,
color: Platform.isMacOS color: Platform.isMacOS
? Colors.transparent ? Colors.transparent
: const Color.fromARGB(27, 27, 27, 27)); : const Color.fromARGB(27, 27, 27, 27));

View File

@@ -62,6 +62,8 @@ class _SidebarState extends State<Sidebar> {
Provider.of<ExamProvider>(context, listen: false).restore(), Provider.of<ExamProvider>(context, listen: false).restore(),
Provider.of<HomeworkProvider>(context, listen: false).restore(), Provider.of<HomeworkProvider>(context, listen: false).restore(),
Provider.of<MessageProvider>(context, listen: false).restore(), Provider.of<MessageProvider>(context, listen: false).restore(),
Provider.of<MessageProvider>(context, listen: false)
.restoreRecipients(),
Provider.of<NoteProvider>(context, listen: false).restore(), Provider.of<NoteProvider>(context, listen: false).restore(),
Provider.of<EventProvider>(context, listen: false).restore(), Provider.of<EventProvider>(context, listen: false).restore(),
Provider.of<AbsenceProvider>(context, listen: false).restore(), Provider.of<AbsenceProvider>(context, listen: false).restore(),
@@ -176,13 +178,16 @@ class _SidebarState extends State<Sidebar> {
String? userId = user.id; String? userId = user.id;
if (userId == null) return; if (userId == null) return;
// Delete User // revoke refresh token
await Provider.of<KretaClient>(context, listen: false).logout();
// delete user from app
user.removeUser(userId); user.removeUser(userId);
await Provider.of<DatabaseProvider>(context, listen: false) await Provider.of<DatabaseProvider>(context, listen: false)
.store .store
.removeUser(userId); .removeUser(userId);
// If no other Users left, go back to LoginScreen // if no other users left, go back to login screen
if (user.getUsers().isNotEmpty) { if (user.getUsers().isNotEmpty) {
user.setUser(user.getUsers().first.id); user.setUser(user.getUsers().first.id);
restore().then((_) => user.setUser(user.getUsers().first.id)); restore().then((_) => user.setUser(user.getUsers().first.id));

View File

@@ -38,8 +38,7 @@ import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'settings_screen.i18n.dart'; import 'settings_screen.i18n.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:filcnaplo_premium/ui/mobile/settings/nickname.dart'; import 'package:filcnaplo_mobile_ui/screens/settings/user/nickname.dart';
import 'package:filcnaplo_premium/ui/mobile/settings/icon_pack.dart';
class SettingsScreen extends StatefulWidget { class SettingsScreen extends StatefulWidget {
const SettingsScreen({Key? key}) : super(key: key); const SettingsScreen({Key? key}) : super(key: key);
@@ -68,6 +67,8 @@ class _SettingsScreenState extends State<SettingsScreen>
Provider.of<ExamProvider>(context, listen: false).restore(), Provider.of<ExamProvider>(context, listen: false).restore(),
Provider.of<HomeworkProvider>(context, listen: false).restore(), Provider.of<HomeworkProvider>(context, listen: false).restore(),
Provider.of<MessageProvider>(context, listen: false).restore(), Provider.of<MessageProvider>(context, listen: false).restore(),
Provider.of<MessageProvider>(context, listen: false)
.restoreRecipients(),
Provider.of<NoteProvider>(context, listen: false).restore(), Provider.of<NoteProvider>(context, listen: false).restore(),
Provider.of<EventProvider>(context, listen: false).restore(), Provider.of<EventProvider>(context, listen: false).restore(),
Provider.of<AbsenceProvider>(context, listen: false).restore(), Provider.of<AbsenceProvider>(context, listen: false).restore(),
@@ -400,9 +401,9 @@ class _SettingsScreenState extends State<SettingsScreen>
if (v) { if (v) {
showDialog( showDialog(
context: context, context: context,
builder: (context) => builder: (context) => PopScope(
WillPopScope( onPopInvoked: (didPop) =>
onWillPop: () async => false, false,
child: AlertDialog( child: AlertDialog(
shape: shape:
RoundedRectangleBorder( RoundedRectangleBorder(
@@ -586,7 +587,8 @@ class _SettingsScreenState extends State<SettingsScreen>
.secondary, .secondary,
), ),
), ),
const PremiumIconPackSelector(), // we need icon pack selector here
// const PremiumIconPackSelector(),
], ],
), ),
), ),

View File

@@ -5,7 +5,7 @@ extension SettingsLocalization on String {
{ {
"en_en": { "en_en": {
"personal_details": "Personal Details", "personal_details": "Personal Details",
"open_dkt": "Open DKT", "open_dkt": "Open DCS",
"edit_nickname": "Edit Nickname", "edit_nickname": "Edit Nickname",
"edit_profile_picture": "Edit Profile Picture", "edit_profile_picture": "Edit Profile Picture",
"remove_profile_picture": "Remove Profile Picture", "remove_profile_picture": "Remove Profile Picture",
@@ -39,7 +39,8 @@ extension SettingsLocalization on String {
"done": "Done", "done": "Done",
"reset": "Reset", "reset": "Reset",
"open": "Open", "open": "Open",
"data_collected": "Data collected: Platform (eg. Android), App version (eg. 3.0.0), Unique Install Identifier", "data_collected":
"Data collected: Platform (eg. Android), App version (eg. 3.0.0), Unique Install Identifier",
"Analytics": "Analytics", "Analytics": "Analytics",
"Anonymous Usage Analytics": "Anonymous Usage Analytics", "Anonymous Usage Analytics": "Anonymous Usage Analytics",
"graph_class_avg": "Class average on graph", "graph_class_avg": "Class average on graph",
@@ -98,7 +99,8 @@ extension SettingsLocalization on String {
"done": "Kész", "done": "Kész",
"reset": "Visszaállítás", "reset": "Visszaállítás",
"open": "Megnyitás", "open": "Megnyitás",
"data_collected": "Gyűjtött adat: Platform (pl. Android), App verzió (pl. 3.0.0), Egyedi telepítési azonosító", "data_collected":
"Gyűjtött adat: Platform (pl. Android), App verzió (pl. 3.0.0), Egyedi telepítési azonosító",
"Analytics": "Analitika", "Analytics": "Analitika",
"Anonymous Usage Analytics": "Névtelen használati analitika", "Anonymous Usage Analytics": "Névtelen használati analitika",
"graph_class_avg": "Osztályátlag a grafikonon", "graph_class_avg": "Osztályátlag a grafikonon",
@@ -123,7 +125,7 @@ extension SettingsLocalization on String {
}, },
"de_de": { "de_de": {
"personal_details": "Persönliche Angaben", "personal_details": "Persönliche Angaben",
"open_dkt": "Öffnen DKT", "open_dkt": "Öffnen RDZ",
"edit_nickname": "Spitznamen bearbeiten", "edit_nickname": "Spitznamen bearbeiten",
"edit_profile_picture": "Profilbild bearbeiten", "edit_profile_picture": "Profilbild bearbeiten",
"remove_profile_picture": "Profilbild entfernen", "remove_profile_picture": "Profilbild entfernen",
@@ -157,7 +159,8 @@ extension SettingsLocalization on String {
"done": "Fertig", "done": "Fertig",
"reset": "Zurücksetzen", "reset": "Zurücksetzen",
"open": "Öffnen", "open": "Öffnen",
"data_collected": "Erhobene Daten: Plattform (z.B. Android), App version (z.B. 3.0.0), Eindeutige Installationskennung", "data_collected":
"Erhobene Daten: Plattform (z.B. Android), App version (z.B. 3.0.0), Eindeutige Installationskennung",
"Analytics": "Analytik", "Analytics": "Analytik",
"Anonymous Usage Analytics": "Anonyme Nutzungsanalyse", "Anonymous Usage Analytics": "Anonyme Nutzungsanalyse",
"graph_class_avg": "Klassendurchschnitt in der Grafik", "graph_class_avg": "Klassendurchschnitt in der Grafik",

View File

@@ -1,47 +0,0 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
pubspec.lock

View File

@@ -3,6 +3,7 @@ import 'package:intl/intl.dart';
class KretaAPI { class KretaAPI {
// IDP API // IDP API
static const login = BaseKreta.kretaIdp + KretaApiEndpoints.token; static const login = BaseKreta.kretaIdp + KretaApiEndpoints.token;
static const logout = BaseKreta.kretaIdp + KretaApiEndpoints.revoke;
static const nonce = BaseKreta.kretaIdp + KretaApiEndpoints.nonce; static const nonce = BaseKreta.kretaIdp + KretaApiEndpoints.nonce;
static const clientId = "kreta-ellenorzo-mobile-android"; static const clientId = "kreta-ellenorzo-mobile-android";
@@ -20,23 +21,14 @@ class KretaAPI {
static String groups(String iss) => static String groups(String iss) =>
BaseKreta.kreta(iss) + KretaApiEndpoints.groups; BaseKreta.kreta(iss) + KretaApiEndpoints.groups;
static String groupAverages(String iss, String uid) => static String groupAverages(String iss, String uid) =>
BaseKreta.kreta(iss) + "${BaseKreta.kreta(iss)}${KretaApiEndpoints.groupAverages}?oktatasiNevelesiFeladatUid=$uid";
KretaApiEndpoints.groupAverages +
"?oktatasiNevelesiFeladatUid=" +
uid;
static String averages(String iss, String uid) => static String averages(String iss, String uid) =>
BaseKreta.kreta(iss) + "${BaseKreta.kreta(iss)}${KretaApiEndpoints.averages}?oktatasiNevelesiFeladatUid=$uid";
KretaApiEndpoints.averages +
"?oktatasiNevelesiFeladatUid=" +
uid;
static String timetable(String iss, {DateTime? start, DateTime? end}) => static String timetable(String iss, {DateTime? start, DateTime? end}) =>
BaseKreta.kreta(iss) + BaseKreta.kreta(iss) +
KretaApiEndpoints.timetable + KretaApiEndpoints.timetable +
(start != null && end != null (start != null && end != null
? "?datumTol=" + ? "?datumTol=${start.toUtc().toIso8601String()}&datumIg=${end.toUtc().toIso8601String()}"
start.toUtc().toIso8601String() +
"&datumIg=" +
end.toUtc().toIso8601String()
: ""); : "");
static String exams(String iss) => static String exams(String iss) =>
BaseKreta.kreta(iss) + KretaApiEndpoints.exams; BaseKreta.kreta(iss) + KretaApiEndpoints.exams;
@@ -45,7 +37,7 @@ class KretaAPI {
KretaApiEndpoints.homework + KretaApiEndpoints.homework +
(id != null ? "/$id" : "") + (id != null ? "/$id" : "") +
(id == null && start != null (id == null && start != null
? "?datumTol=" + DateFormat('yyyy-MM-dd').format(start) ? "?datumTol=${DateFormat('yyyy-MM-dd').format(start)}"
: ""); : "");
static String capabilities(String iss) => static String capabilities(String iss) =>
BaseKreta.kreta(iss) + KretaApiEndpoints.capabilities; BaseKreta.kreta(iss) + KretaApiEndpoints.capabilities;
@@ -53,6 +45,28 @@ class KretaAPI {
String iss, String uid, String type) => String iss, String uid, String type) =>
BaseKreta.kreta(iss) + BaseKreta.kreta(iss) +
KretaApiEndpoints.downloadHomeworkAttachments(uid, type); KretaApiEndpoints.downloadHomeworkAttachments(uid, type);
static String subjects(String iss, String uid) =>
"${BaseKreta.kreta(iss)}${KretaApiEndpoints.subjects}?oktatasiNevelesiFeladatUid=$uid";
// Structure:
// {
// "Uid": 000,
// "Tantargy": {
// "Uid": 000,
// "Nev": "Irodalom",
// "Kategoria": {
// "Uid": "000,magyar_nyelv_es_irodalom",
// "Nev": "magyar_nyelv_es_irodalom",
// "Leiras": "Magyar nyelv és irodalom"
// },
// "SortIndex": 0,
// },
// "Atlag": null, // float
// "AtlagAlakulasaIdoFuggvenyeben": Array[], // no idea what this is
// "SulyozottOsztalyzatOsszege": null, // int | float
// "SulyozottOsztalyzatSzama": null, // int | float
// "SortIndex": 0
// }
// refer to https://discord.com/channels/1111649116020285532/1111798771513303102/1148368925969612920
// ADMIN API // ADMIN API
static const sendMessage = static const sendMessage =
@@ -65,8 +79,10 @@ class KretaAPI {
BaseKreta.kretaAdmin + KretaAdminEndpoints.recipientCategories; BaseKreta.kretaAdmin + KretaAdminEndpoints.recipientCategories;
static const availableCategories = static const availableCategories =
BaseKreta.kretaAdmin + KretaAdminEndpoints.availableCategories; BaseKreta.kretaAdmin + KretaAdminEndpoints.availableCategories;
static const recipientsTeacher = static const recipientTeachers =
BaseKreta.kretaAdmin + KretaAdminEndpoints.recipientsTeacher; BaseKreta.kretaAdmin + KretaAdminEndpoints.recipientTeachers;
static const recipientDirectorate =
BaseKreta.kretaAdmin + KretaAdminEndpoints.recipientDirectorate;
static const uploadAttachment = static const uploadAttachment =
BaseKreta.kretaAdmin + KretaAdminEndpoints.uploadAttachment; BaseKreta.kretaAdmin + KretaAdminEndpoints.uploadAttachment;
static String downloadAttachment(String id) => static String downloadAttachment(String id) =>
@@ -86,6 +102,7 @@ class BaseKreta {
class KretaApiEndpoints { class KretaApiEndpoints {
static const token = "/connect/token"; static const token = "/connect/token";
static const revoke = "/connect/revocation";
static const nonce = "/nonce"; static const nonce = "/nonce";
static const notes = "/ellenorzo/V3/Sajat/Feljegyzesek"; static const notes = "/ellenorzo/V3/Sajat/Feljegyzesek";
static const events = "/ellenorzo/V3/Sajat/FaliujsagElemek"; static const events = "/ellenorzo/V3/Sajat/FaliujsagElemek";
@@ -103,6 +120,8 @@ class KretaApiEndpoints {
static const capabilities = "/ellenorzo/V3/Sajat/Intezmenyek"; static const capabilities = "/ellenorzo/V3/Sajat/Intezmenyek";
static String downloadHomeworkAttachments(String uid, String type) => static String downloadHomeworkAttachments(String uid, String type) =>
"/ellenorzo/V3/Sajat/Csatolmany/$uid"; "/ellenorzo/V3/Sajat/Csatolmany/$uid";
static const subjects =
"/ellenorzo/V3/Sajat/Ertekelesek/Atlagok/TantargyiAtlagok";
} }
class KretaAdminEndpoints { class KretaAdminEndpoints {
@@ -114,7 +133,8 @@ class KretaAdminEndpoints {
"/api/v1/kommunikacio/postaladaelemek/$id"; "/api/v1/kommunikacio/postaladaelemek/$id";
static const recipientCategories = "/api/v1/adatszotarak/cimzetttipusok"; static const recipientCategories = "/api/v1/adatszotarak/cimzetttipusok";
static const availableCategories = "/api/v1/kommunikacio/cimezhetotipusok"; static const availableCategories = "/api/v1/kommunikacio/cimezhetotipusok";
static const recipientsTeacher = "/api/v1/kreta/alkalmazottak/tanar"; static const recipientTeachers = "/api/v1/kreta/alkalmazottak/tanar";
static const recipientDirectorate = "/api/v1/kreta/alkalmazottak/igazgatosag";
static const uploadAttachment = "/ideiglenesfajlok"; static const uploadAttachment = "/ideiglenesfajlok";
static String downloadAttachment(String id) => static String downloadAttachment(String id) =>
"/api/v1/dokumentumok/uzenetek/$id"; "/api/v1/dokumentumok/uzenetek/$id";

View File

@@ -26,6 +26,8 @@ class KretaClient {
late final UserProvider _user; late final UserProvider _user;
late final StatusProvider _status; late final StatusProvider _status;
bool _loginRefreshing = false;
KretaClient({ KretaClient({
this.accessToken, this.accessToken,
required SettingsProvider settings, required SettingsProvider settings,
@@ -89,6 +91,9 @@ class KretaClient {
} }
if (res == null) throw "Login error"; if (res == null) throw "Login error";
if (res.body == 'invalid_grant' || res.body.replaceAll(' ', '') == '') {
throw "Auth error";
}
if (json) { if (json) {
return jsonDecode(res.body); return jsonDecode(res.body);
@@ -134,6 +139,9 @@ class KretaClient {
if (!headerMap.containsKey("content-type")) { if (!headerMap.containsKey("content-type")) {
headerMap["content-type"] = "application/json"; headerMap["content-type"] = "application/json";
} }
if (url.contains('kommunikacio/uzenetek')) {
headerMap["X-Uzenet-Lokalizacio"] = "hu-HU";
}
} }
res = await client.post(Uri.parse(url), headers: headerMap, body: body); res = await client.post(Uri.parse(url), headers: headerMap, body: body);
@@ -148,6 +156,7 @@ class KretaClient {
if (res == null) throw "Login error"; if (res == null) throw "Login error";
if (json) { if (json) {
print(jsonDecode(res.body));
return jsonDecode(res.body); return jsonDecode(res.body);
} else { } else {
return res.body; return res.body;
@@ -160,7 +169,73 @@ class KretaClient {
} }
} }
Future<dynamic> sendFilesAPI(
String url, {
Map<String, String>? headers,
bool autoHeader = true,
Map<String, String>? body,
}) async {
Map<String, String> headerMap;
if (headers != null) {
headerMap = headers;
} else {
headerMap = {};
}
try {
http.StreamedResponse? res;
for (int i = 0; i < 3; i++) {
if (autoHeader) {
if (!headerMap.containsKey("authorization") && accessToken != null) {
headerMap["authorization"] = "Bearer $accessToken";
}
if (!headerMap.containsKey("user-agent") && userAgent != null) {
headerMap["user-agent"] = "$userAgent";
}
if (!headerMap.containsKey("content-type")) {
headerMap["content-type"] = "multipart/form-data";
}
if (url.contains('kommunikacio/uzenetek')) {
headerMap["X-Uzenet-Lokalizacio"] = "hu-HU";
}
}
var request = http.MultipartRequest("POST", Uri.parse(url));
// request.files.add(value)
request.fields.addAll(body ?? {});
request.headers.addAll(headers ?? {});
res = await request.send();
if (res.statusCode == 401) {
await refreshLogin();
headerMap.remove("authorization");
} else {
break;
}
}
if (res == null) throw "Login error";
print(res.statusCode);
return res.statusCode;
} on http.ClientException catch (error) {
print(
"ERROR: KretaClient.postAPI ($url) ClientException: ${error.message}");
} catch (error) {
print("ERROR: KretaClient.postAPI ($url) ${error.runtimeType}: $error");
}
}
Future<void> refreshLogin() async { Future<void> refreshLogin() async {
if (_loginRefreshing) return;
_loginRefreshing = true;
User? loginUser = _user.user; User? loginUser = _user.user;
if (loginUser == null) return; if (loginUser == null) return;
@@ -179,13 +254,15 @@ class KretaClient {
print("DEBUG: refreshLogin: ${loginUser.id} ${loginUser.name}"); print("DEBUG: refreshLogin: ${loginUser.id} ${loginUser.name}");
} }
Map? loginRes = await postAPI(KretaAPI.login, Map? loginRes = await postAPI(
headers: headers, KretaAPI.login,
body: User.loginBody( headers: headers,
username: loginUser.username, body: User.loginBody(
password: loginUser.password, username: loginUser.username,
instituteCode: loginUser.instituteCode, password: loginUser.password,
)); instituteCode: loginUser.instituteCode,
),
);
if (loginRes != null) { if (loginRes != null) {
if (loginRes.containsKey("access_token")) { if (loginRes.containsKey("access_token")) {
@@ -212,5 +289,25 @@ class KretaClient {
} }
} }
} }
_loginRefreshing = false;
}
Future<void> logout() async {
User? loginUser = _user.user;
if (loginUser == null) return;
Map<String, String> headers = {
"content-type": "application/x-www-form-urlencoded",
};
await postAPI(
KretaAPI.logout,
headers: headers,
body: User.logoutBody(
refreshToken: refreshToken!,
),
json: false,
);
} }
} }

View File

@@ -1,4 +1,4 @@
// ignore_for_file: avoid_print // ignore_for_file: avoid_print, use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'dart:developer'; import 'dart:developer';
@@ -154,9 +154,9 @@ class TimetableController extends ChangeNotifier {
} }
for (int i = 0; i < days.length; i++) { for (int i = 0; i < days.length; i++) {
List<Lesson> _day = List.castFrom(days[i]); List<Lesson> day0 = List.castFrom(days[i]);
List<int> lessonIndexes = _getIndexes(_day); List<int> lessonIndexes = _getIndexes(day0);
int minIndex = 0, maxIndex = 0; int minIndex = 0, maxIndex = 0;
if (lessonIndexes.isNotEmpty) { if (lessonIndexes.isNotEmpty) {
@@ -170,7 +170,7 @@ class TimetableController extends ChangeNotifier {
// Fill missing indexes with empty spaces // Fill missing indexes with empty spaces
for (var i in List<int>.generate( for (var i in List<int>.generate(
maxIndex - minIndex + 1, (int i) => minIndex + i)) { maxIndex - minIndex + 1, (int i) => minIndex + i)) {
List<Lesson> indexLessons = _getLessonsByIndex(_day, i); List<Lesson> indexLessons = _getLessonsByIndex(day0, i);
// Empty lesson // Empty lesson
if (indexLessons.isEmpty) { if (indexLessons.isEmpty) {
@@ -193,13 +193,13 @@ class TimetableController extends ChangeNotifier {
} }
// Additional lessons // Additional lessons
day.addAll(_day.where((l) => day.addAll(day0.where((l) =>
int.tryParse(l.lessonIndex) == null && l.subject.id != '')); int.tryParse(l.lessonIndex) == null && l.subject.id != ''));
day.sort((a, b) => a.start.compareTo(b.start)); day.sort((a, b) => a.start.compareTo(b.start));
// Special Dates // Special Dates
for (var l in _day) { for (var l in day0) {
l.subject.id == '' ? day.insert(0, l) : null; l.subject.id == '' ? day.insert(0, l) : null;
} }

View File

@@ -13,7 +13,7 @@ class Absence {
Category? justification; Category? justification;
Category? type; Category? type;
Category? mode; Category? mode;
Subject subject; GradeSubject subject;
DateTime lessonStart; DateTime lessonStart;
DateTime lessonEnd; DateTime lessonEnd;
int? lessonIndex; int? lessonIndex;
@@ -83,7 +83,7 @@ class Absence {
: null, : null,
type: json["Tipus"] != null ? Category.fromJson(json["Tipus"]) : null, type: json["Tipus"] != null ? Category.fromJson(json["Tipus"]) : null,
mode: json["Mod"] != null ? Category.fromJson(json["Mod"]) : null, mode: json["Mod"] != null ? Category.fromJson(json["Mod"]) : null,
subject: Subject.fromJson(json["Tantargy"] ?? {}), subject: GradeSubject.fromJson(json["Tantargy"] ?? {}),
lessonStart: lessonStart, lessonStart: lessonStart,
lessonEnd: lessonEnd, lessonEnd: lessonEnd,
lessonIndex: lessonIndex, lessonIndex: lessonIndex,

View File

@@ -1,3 +1,5 @@
import 'package:filcnaplo_kreta_api/models/subject.dart';
import 'category.dart'; import 'category.dart';
import 'teacher.dart'; import 'teacher.dart';
@@ -6,8 +8,9 @@ class Exam {
DateTime date; DateTime date;
DateTime writeDate; DateTime writeDate;
Category? mode; Category? mode;
int? subjectIndex; // int? subjectIndex;
String subjectName; // String subjectName;
GradeSubject subject;
Teacher teacher; Teacher teacher;
String description; String description;
String group; String group;
@@ -18,8 +21,9 @@ class Exam {
required this.date, required this.date,
required this.writeDate, required this.writeDate,
this.mode, this.mode,
this.subjectIndex, // this.subjectIndex,
required this.subjectName, // required this.subjectName,
required this.subject,
required this.teacher, required this.teacher,
required this.description, required this.description,
required this.group, required this.group,
@@ -36,8 +40,9 @@ class Exam {
? DateTime.parse(json["Datum"]).toLocal() ? DateTime.parse(json["Datum"]).toLocal()
: DateTime(0), : DateTime(0),
mode: json["Modja"] != null ? Category.fromJson(json["Modja"]) : null, mode: json["Modja"] != null ? Category.fromJson(json["Modja"]) : null,
subjectIndex: json["OrarendiOraOraszama"], // subjectIndex: json["OrarendiOraOraszama"],
subjectName: json["TantargyNeve"] ?? "", // subjectName: json["TantargyNeve"] ?? "",
subject: GradeSubject.fromJson(json["Tantargy"] ?? {}),
teacher: Teacher.fromString((json["RogzitoTanarNeve"] ?? "").trim()), teacher: Teacher.fromString((json["RogzitoTanarNeve"] ?? "").trim()),
description: (json["Temaja"] ?? "").trim(), description: (json["Temaja"] ?? "").trim(),
group: json["OsztalyCsoport"] != null group: json["OsztalyCsoport"] != null

View File

@@ -1,3 +1,5 @@
// ignore_for_file: no_leading_underscores_for_local_identifiers
import 'package:filcnaplo/utils/format.dart'; import 'package:filcnaplo/utils/format.dart';
import 'category.dart'; import 'category.dart';
import 'subject.dart'; import 'subject.dart';
@@ -12,7 +14,7 @@ class Grade {
String description; String description;
GradeType type; GradeType type;
String groupId; String groupId;
Subject subject; GradeSubject subject;
Category? gradeType; Category? gradeType;
Category mode; Category mode;
DateTime writeDate; DateTime writeDate;
@@ -57,7 +59,7 @@ class Grade {
? Category.getGradeType(json["Tipus"]["Nev"]) ? Category.getGradeType(json["Tipus"]["Nev"])
: GradeType.unknown, : GradeType.unknown,
groupId: (json["OsztalyCsoport"] ?? {})["Uid"] ?? "", groupId: (json["OsztalyCsoport"] ?? {})["Uid"] ?? "",
subject: Subject.fromJson(json["Tantargy"] ?? {}), subject: GradeSubject.fromJson(json["Tantargy"] ?? {}),
gradeType: json["ErtekFajta"] != null gradeType: json["ErtekFajta"] != null
? Category.fromJson(json["ErtekFajta"]) ? Category.fromJson(json["ErtekFajta"])
: null, : null,

View File

@@ -3,7 +3,7 @@ import 'package:filcnaplo_kreta_api/models/subject.dart';
class GroupAverage { class GroupAverage {
String uid; String uid;
double average; double average;
Subject subject; GradeSubject subject;
Map json; Map json;
GroupAverage({required this.uid, required this.average, required this.subject, this.json = const {}}); GroupAverage({required this.uid, required this.average, required this.subject, this.json = const {}});
@@ -12,7 +12,7 @@ class GroupAverage {
return GroupAverage( return GroupAverage(
uid: json["Uid"] ?? "", uid: json["Uid"] ?? "",
average: json["OsztalyCsoportAtlag"] ?? 0, average: json["OsztalyCsoportAtlag"] ?? 0,
subject: Subject.fromJson(json["Tantargy"] ?? {}), subject: GradeSubject.fromJson(json["Tantargy"] ?? {}),
json: json, json: json,
); );
} }

View File

@@ -12,7 +12,7 @@ class Homework {
bool homeworkEnabled; bool homeworkEnabled;
Teacher teacher; Teacher teacher;
String content; String content;
Subject subject; GradeSubject subject;
String group; String group;
List<HomeworkAttachment> attachments; List<HomeworkAttachment> attachments;
String id; String id;
@@ -48,7 +48,7 @@ class Homework {
homeworkEnabled: json["IsTanuloHaziFeladatEnabled"] ?? false, homeworkEnabled: json["IsTanuloHaziFeladatEnabled"] ?? false,
teacher: Teacher.fromString((json["RogzitoTanarNeve"] ?? "").trim()), teacher: Teacher.fromString((json["RogzitoTanarNeve"] ?? "").trim()),
content: (json["Szoveg"] ?? "").trim(), content: (json["Szoveg"] ?? "").trim(),
subject: Subject.fromJson(json["Tantargy"] ?? {}), subject: GradeSubject.fromJson(json["Tantargy"] ?? {}),
group: json["OsztalyCsoport"] != null group: json["OsztalyCsoport"] != null
? json["OsztalyCsoport"]["Uid"] ?? "" ? json["OsztalyCsoport"]["Uid"] ?? ""
: "", : "",

View File

@@ -6,7 +6,7 @@ class Lesson {
Map? json; Map? json;
Category? status; Category? status;
DateTime date; DateTime date;
Subject subject; GradeSubject subject;
String lessonIndex; String lessonIndex;
int? lessonYearIndex; int? lessonYearIndex;
Teacher? substituteTeacher; Teacher? substituteTeacher;
@@ -68,7 +68,7 @@ class Lesson {
date: json["Datum"] != null date: json["Datum"] != null
? DateTime.parse(json["Datum"]).toLocal() ? DateTime.parse(json["Datum"]).toLocal()
: DateTime(0), : DateTime(0),
subject: Subject.fromJson(json["Tantargy"] ?? {}), subject: GradeSubject.fromJson(json["Tantargy"] ?? {}),
lessonIndex: json["Oraszam"] != null ? json["Oraszam"].toString() : "+", lessonIndex: json["Oraszam"] != null ? json["Oraszam"].toString() : "+",
lessonYearIndex: json["OraEvesSorszama"], lessonYearIndex: json["OraEvesSorszama"],
substituteTeacher: json["HelyettesTanarNeve"] != null substituteTeacher: json["HelyettesTanarNeve"] != null

View File

@@ -68,13 +68,21 @@ class Message {
messageId: message["azonosito"], messageId: message["azonosito"],
seen: json["isElolvasva"] ?? false, seen: json["isElolvasva"] ?? false,
deleted: json["isToroltElem"] ?? false, deleted: json["isToroltElem"] ?? false,
date: message["kuldesDatum"] != null ? DateTime.parse(message["kuldesDatum"]).toLocal() : DateTime(0), date: message["kuldesDatum"] != null
? DateTime.parse(message["kuldesDatum"]).toLocal()
: DateTime(0),
author: (message["feladoNev"] ?? "").trim(), author: (message["feladoNev"] ?? "").trim(),
content: message["szoveg"].replaceAll("\r", "") ?? "", content: message["szoveg"].replaceAll("\r", "") ?? "",
subject: message["targy"] ?? "", subject: message["targy"] ?? "",
type: type, type: type,
recipients: (message["cimzettLista"] as List).cast<Map>().map((Map recipient) => Recipient.fromJson(recipient)).toList(), recipients: (message["cimzettLista"] as List)
attachments: (message["csatolmanyok"] as List).cast<Map>().map((Map attachment) => Attachment.fromJson(attachment)).toList(), .cast<Map>()
.map((Map recipient) => Recipient.fromJson(recipient))
.toList(),
attachments: (message["csatolmanyok"] as List)
.cast<Map>()
.map((Map attachment) => Attachment.fromJson(attachment))
.toList(),
replyId: message["elozoUzenetAzonosito"], replyId: message["elozoUzenetAzonosito"],
conversationId: message["beszelgetesAzonosito"], conversationId: message["beszelgetesAzonosito"],
json: json, json: json,
@@ -105,3 +113,99 @@ class Conversation {
Message get newest => _messages.first; Message get newest => _messages.first;
} }
// sendable message object and it's things
class SendMessage {
Map? json;
int id;
int lastMessageId;
String? subject;
String text;
DateTime sentDate;
String senderRank;
String senderName;
List<Attachment>? attachments;
List<SendRecipient> recipients;
SendMessage({
required this.id,
required this.lastMessageId,
this.subject,
required this.text,
required this.sentDate,
required this.senderRank,
required this.senderName,
this.attachments,
required this.recipients,
});
}
class SendRecipient {
Map? json;
int? id;
int? kretaId;
String? name;
SendRecipientType type;
SendRecipient({
required this.id,
required this.kretaId,
required this.name,
required this.type,
this.json,
});
factory SendRecipient.fromJson(Map json, SendRecipientType type) {
return SendRecipient(
id: json['kretaAzonosito'] ?? 0,
kretaId: json['kretaAzonosito'],
name: json['nev'],
type: type,
json: json,
);
}
Object get kretaJson => {
'azonosito': kretaId ?? 0,
'kretaAzonosito': kretaId ?? 0,
'nev': name ?? 'Teszt Lajos',
'tipus': {
'azonosito': type.id,
'kod': type.code,
'leiras': type.description,
'nev': type.name,
'rovidNev': type.shortName,
}
};
}
class SendRecipientType {
Map? json;
int id;
String code;
String description;
String name;
String shortName;
SendRecipientType({
required this.id,
required this.code,
required this.description,
required this.name,
required this.shortName,
this.json,
});
factory SendRecipientType.fromJson(Map json) {
return SendRecipientType(
id: json['azonosito'],
code: json['kod'],
description: json['leiras'],
name: json['nev'],
shortName: json['rovidNev'],
json: json,
);
}
}
enum AddresseeType { teachers, directorate }

View File

@@ -1,6 +1,6 @@
import 'category.dart'; import 'category.dart';
class Subject { class GradeSubject {
String id; String id;
Category category; Category category;
String name; String name;
@@ -8,11 +8,16 @@ class Subject {
bool get isRenamed => renamedTo != null; bool get isRenamed => renamedTo != null;
Subject({required this.id, required this.category, required this.name, this.renamedTo}); GradeSubject({
required this.id,
required this.category,
required this.name,
this.renamedTo,
});
factory Subject.fromJson(Map json) { factory GradeSubject.fromJson(Map json) {
final id = json["Uid"] ?? ""; final id = json["Uid"] ?? "";
return Subject( return GradeSubject(
id: id, id: id,
category: Category.fromJson(json["Kategoria"] ?? {}), category: Category.fromJson(json["Kategoria"] ?? {}),
name: (json["Nev"] ?? "").trim(), name: (json["Nev"] ?? "").trim(),
@@ -21,7 +26,7 @@ class Subject {
@override @override
bool operator ==(other) { bool operator ==(other) {
if (other is! Subject) return false; if (other is! GradeSubject) return false;
return id == other.id; return id == other.id;
} }

View File

@@ -1,3 +1,5 @@
// ignore_for_file: no_leading_underscores_for_local_identifiers
import 'package:filcnaplo_kreta_api/controllers/timetable_controller.dart'; import 'package:filcnaplo_kreta_api/controllers/timetable_controller.dart';
class Week { class Week {

View File

@@ -1,3 +1,5 @@
// ignore_for_file: no_leading_underscores_for_local_identifiers
import 'package:filcnaplo/api/providers/user_provider.dart'; import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/models/user.dart'; import 'package:filcnaplo/models/user.dart';
@@ -43,12 +45,14 @@ class AbsenceProvider with ChangeNotifier {
(await _database.query.getSettings(_database)).renamedSubjectsEnabled (await _database.query.getSettings(_database)).renamedSubjectsEnabled
? await _database.userQuery.renamedSubjects( ? await _database.userQuery.renamedSubjects(
userId: userId:
// ignore: use_build_context_synchronously
Provider.of<UserProvider>(_context, listen: false).user!.id) Provider.of<UserProvider>(_context, listen: false).user!.id)
: {}; : {};
Map<String, String> renamedTeachers = Map<String, String> renamedTeachers =
(await _database.query.getSettings(_database)).renamedTeachersEnabled (await _database.query.getSettings(_database)).renamedTeachersEnabled
? await _database.userQuery.renamedTeachers( ? await _database.userQuery.renamedTeachers(
userId: userId:
// ignore: use_build_context_synchronously
Provider.of<UserProvider>(_context, listen: false).user!.id) Provider.of<UserProvider>(_context, listen: false).user!.id)
: {}; : {};

View File

@@ -27,19 +27,51 @@ class ExamProvider with ChangeNotifier {
// Load exams from the database // Load exams from the database
if (userId != null) { if (userId != null) {
var dbExams = await Provider.of<DatabaseProvider>(_context, listen: false).userQuery.getExams(userId: userId); var dbExams = await Provider.of<DatabaseProvider>(_context, listen: false)
.userQuery
.getExams(userId: userId);
_exams = dbExams; _exams = dbExams;
notifyListeners(); notifyListeners();
await convertBySettings();
} }
} }
// for renamed subjects
Future<void> convertBySettings() async {
final database = Provider.of<DatabaseProvider>(_context, listen: false);
Map<String, String> renamedSubjects =
(await database.query.getSettings(database)).renamedSubjectsEnabled
? await database.userQuery.renamedSubjects(
userId:
// ignore: use_build_context_synchronously
Provider.of<UserProvider>(_context, listen: false).user!.id)
: {};
Map<String, String> renamedTeachers =
(await database.query.getSettings(database)).renamedTeachersEnabled
? await database.userQuery.renamedTeachers(
userId:
// ignore: use_build_context_synchronously
Provider.of<UserProvider>(_context, listen: false).user!.id)
: {};
for (Exam exam in _exams) {
exam.subject.renamedTo =
renamedSubjects.isNotEmpty ? renamedSubjects[exam.subject.id] : null;
exam.teacher.renamedTo =
renamedTeachers.isNotEmpty ? renamedTeachers[exam.teacher.id] : null;
}
notifyListeners();
}
// Fetches Exams from the Kreta API then stores them in the database // Fetches Exams from the Kreta API then stores them in the database
Future<void> fetch() async { Future<void> fetch() async {
User? user = Provider.of<UserProvider>(_context, listen: false).user; User? user = Provider.of<UserProvider>(_context, listen: false).user;
if (user == null) throw "Cannot fetch Exams for User null"; if (user == null) throw "Cannot fetch Exams for User null";
String iss = user.instituteCode; String iss = user.instituteCode;
List? examsJson = await Provider.of<KretaClient>(_context, listen: false).getAPI(KretaAPI.exams(iss)); List? examsJson = await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.exams(iss));
if (examsJson == null) throw "Cannot fetch Exams for User ${user.id}"; if (examsJson == null) throw "Cannot fetch Exams for User ${user.id}";
List<Exam> exams = examsJson.map((e) => Exam.fromJson(e)).toList(); List<Exam> exams = examsJson.map((e) => Exam.fromJson(e)).toList();
@@ -52,8 +84,11 @@ class ExamProvider with ChangeNotifier {
if (user == null) throw "Cannot store Exams for User null"; if (user == null) throw "Cannot store Exams for User null";
String userId = user.id; String userId = user.id;
await Provider.of<DatabaseProvider>(_context, listen: false).userStore.storeExams(exams, userId: userId); await Provider.of<DatabaseProvider>(_context, listen: false)
.userStore
.storeExams(exams, userId: userId);
_exams = exams; _exams = exams;
notifyListeners(); notifyListeners();
await convertBySettings();
} }
} }

View File

@@ -1,16 +1,17 @@
import 'package:filcnaplo/api/providers/user_provider.dart'; import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/models/settings.dart'; // import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/models/user.dart'; import 'package:filcnaplo/models/user.dart';
import 'package:filcnaplo_kreta_api/client/api.dart'; import 'package:filcnaplo_kreta_api/client/api.dart';
import 'package:filcnaplo_kreta_api/client/client.dart'; import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/models/homework.dart'; import 'package:filcnaplo_kreta_api/models/homework.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
class HomeworkProvider with ChangeNotifier { class HomeworkProvider with ChangeNotifier {
// Private // Private
late final SettingsProvider _settings; // late final SettingsProvider _settings;
late final UserProvider _user; late final UserProvider _user;
late final DatabaseProvider _database; late final DatabaseProvider _database;
@@ -23,10 +24,12 @@ class HomeworkProvider with ChangeNotifier {
List<Homework> initialHomework = const [], List<Homework> initialHomework = const [],
required BuildContext context, required BuildContext context,
required DatabaseProvider database, required DatabaseProvider database,
required UserProvider user,
}) { }) {
_homework = List.castFrom(initialHomework); _homework = List.castFrom(initialHomework);
_context = context; _context = context;
_database = database; _database = database;
_user = user;
if (_homework.isEmpty) restore(); if (_homework.isEmpty) restore();
} }
@@ -77,27 +80,32 @@ class HomeworkProvider with ChangeNotifier {
List? homeworkJson = []; List? homeworkJson = [];
try { try {
homeworkJson = await Provider.of<KretaClient>(_context, listen: false) Iterable hwjson = await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.homework(iss, start: from)); .getAPI(KretaAPI.homework(iss, start: from));
homeworkJson = List.from(hwjson.map((model) => model));
} catch (e) { } catch (e) {
if (kDebugMode) print(e);
// error fetcing homework (unknown error) // error fetcing homework (unknown error)
} }
if (homeworkJson == null) throw "Cannot fetch Homework for User ${user.id}"; if (homeworkJson == null) {
if (kDebugMode) print("Cannot fetch Homework for User ${user.id}");
return;
}
List<Homework> homework = []; List<Homework> homework = [];
await Future.forEach(homeworkJson.cast<Map>(), (Map hw) async { await Future.forEach(homeworkJson.cast<Map>(), (Map hw) async {
Map? e = await Provider.of<KretaClient>(_context, listen: false) Map? e = await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.homework(iss, id: hw["Uid"])); .getAPI(KretaAPI.homework(iss, id: hw["Uid"]));
Map<String, String> renamedSubjects = _settings.renamedSubjectsEnabled // Map<String, String> renamedSubjects = _settings.renamedSubjectsEnabled
? await _database.userQuery.renamedSubjects(userId: _user.user!.id) // ? await _database.userQuery.renamedSubjects(userId: _user.user!.id)
: {}; // : {};
if (e != null) { if (e != null) {
Homework hw = Homework.fromJson(e); Homework hmwrk = Homework.fromJson(e);
hw.subject.renamedTo = // hw.subject.renamedTo =
renamedSubjects.isNotEmpty ? renamedSubjects[hw.subject.id] : null; // renamedSubjects.isNotEmpty ? renamedSubjects[hw.subject.id] : null;
homework.add(hw); homework.add(hmwrk);
} }
}); });
@@ -106,6 +114,7 @@ class HomeworkProvider with ChangeNotifier {
if (db) await store(homework); if (db) await store(homework);
_homework = homework; _homework = homework;
notifyListeners(); notifyListeners();
await convertBySettings();
} }
// Stores Homework in the database // Stores Homework in the database

View File

@@ -1,3 +1,7 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:convert';
import 'dart:math';
import 'package:filcnaplo/api/providers/user_provider.dart'; import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/models/user.dart'; import 'package:filcnaplo/models/user.dart';
@@ -9,17 +13,22 @@ import 'package:provider/provider.dart';
class MessageProvider with ChangeNotifier { class MessageProvider with ChangeNotifier {
late List<Message> _messages; late List<Message> _messages;
late List<SendRecipient> _recipients;
late BuildContext _context; late BuildContext _context;
List<Message> get messages => _messages; List<Message> get messages => _messages;
List<SendRecipient> get recipients => _recipients;
MessageProvider({ MessageProvider({
List<Message> initialMessages = const [], List<Message> initialMessages = const [],
required BuildContext context, required BuildContext context,
}) { }) {
_messages = List.castFrom(initialMessages); _messages = List.castFrom(initialMessages);
_recipients = [];
_context = context; _context = context;
if (_messages.isEmpty) restore(); if (_messages.isEmpty) restore();
if (_recipients.isEmpty) restoreRecipients();
} }
Future<void> restore() async { Future<void> restore() async {
@@ -27,27 +36,33 @@ class MessageProvider with ChangeNotifier {
// Load messages from the database // Load messages from the database
if (userId != null) { if (userId != null) {
var dbMessages = await Provider.of<DatabaseProvider>(_context, listen: false).userQuery.getMessages(userId: userId); var dbMessages =
await Provider.of<DatabaseProvider>(_context, listen: false)
.userQuery
.getMessages(userId: userId);
_messages = dbMessages; _messages = dbMessages;
notifyListeners(); notifyListeners();
} }
} }
// Fetches all types of Messages // Fetches all types of Messages
Future<void> fetchAll() => Future.forEach(MessageType.values, (MessageType v) => fetch(type: v)); Future<void> fetchAll() =>
Future.forEach(MessageType.values, (MessageType v) => fetch(type: v));
// Fetches Messages from the Kreta API then stores them in the database // Fetches Messages from the Kreta API then stores them in the database
Future<void> fetch({MessageType type = MessageType.inbox}) async { Future<void> fetch({MessageType type = MessageType.inbox}) async {
// Check Message Type // Check Message Type
if (type == MessageType.draft) return; if (type == MessageType.draft) return;
String messageType = ["beerkezett", "elkuldott", "torolt"].elementAt(type.index); String messageType =
["beerkezett", "elkuldott", "torolt"].elementAt(type.index);
// Check User // Check User
User? user = Provider.of<UserProvider>(_context, listen: false).user; User? user = Provider.of<UserProvider>(_context, listen: false).user;
if (user == null) throw "Cannot fetch Messages for User null"; if (user == null) throw "Cannot fetch Messages for User null";
// Get messages // Get messages
List? messagesJson = await Provider.of<KretaClient>(_context, listen: false).getAPI(KretaAPI.messages(messageType)); List? messagesJson = await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.messages(messageType));
if (messagesJson == null) throw "Cannot fetch Messages for User ${user.id}"; if (messagesJson == null) throw "Cannot fetch Messages for User ${user.id}";
// Parse messages // Parse messages
@@ -55,8 +70,12 @@ class MessageProvider with ChangeNotifier {
await Future.wait(List.generate(messagesJson.length, (index) { await Future.wait(List.generate(messagesJson.length, (index) {
return () async { return () async {
Map message = messagesJson.cast<Map>()[index]; Map message = messagesJson.cast<Map>()[index];
Map? messageJson = await Provider.of<KretaClient>(_context, listen: false).getAPI(KretaAPI.message(message["azonosito"].toString())); Map? messageJson =
if (messageJson != null) messages.add(Message.fromJson(messageJson, forceType: type)); await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.message(message["azonosito"].toString()));
if (messageJson != null) {
messages.add(Message.fromJson(messageJson, forceType: type));
}
}(); }();
})); }));
@@ -73,8 +92,177 @@ class MessageProvider with ChangeNotifier {
if (user == null) throw "Cannot store Messages for User null"; if (user == null) throw "Cannot store Messages for User null";
String userId = user.id; String userId = user.id;
await Provider.of<DatabaseProvider>(_context, listen: false).userStore.storeMessages(_messages, userId: userId); await Provider.of<DatabaseProvider>(_context, listen: false)
.userStore
.storeMessages(_messages, userId: userId);
notifyListeners(); notifyListeners();
} }
// restore recipients
Future<void> restoreRecipients() async {
String? userId = Provider.of<UserProvider>(_context, listen: false).id;
// Load messages from the database
if (userId != null) {
var dbRecipients =
await Provider.of<DatabaseProvider>(_context, listen: false)
.userQuery
.getRecipients(userId: userId);
_recipients = dbRecipients;
notifyListeners();
}
}
// fetch all recipients
Future<void> fetchAllRecipients() => Future.forEach(
AddresseeType.values, (AddresseeType v) => fetchRecipients(type: v));
// fetch recipients
Future<void> fetchRecipients(
{AddresseeType type = AddresseeType.teachers}) async {
Map<AddresseeType, SendRecipientType> addressable = {};
// check user
User? user = Provider.of<UserProvider>(_context, listen: false).user;
if (user == null) throw "Cannot fetch Messages for User null";
// get categories
List? availableCategoriesJson =
await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.recipientCategories);
// print(availableCategoriesJson);
// get recipients
List? recipientTeachersJson =
await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.recipientTeachers);
List? recipientDirectorateJson =
await Provider.of<KretaClient>(_context, listen: false)
.getAPI(KretaAPI.recipientDirectorate);
if (availableCategoriesJson == null ||
recipientTeachersJson == null ||
recipientDirectorateJson == null) {
throw "Cannot fetch Recipients for User ${user.id}";
}
for (var e in availableCategoriesJson) {
// print(e);
switch (e['kod']) {
case 'TANAR':
addressable
.addAll({AddresseeType.teachers: SendRecipientType.fromJson(e)});
break;
case 'IGAZGATOSAG':
addressable.addAll(
{AddresseeType.directorate: SendRecipientType.fromJson(e)});
break;
default:
break;
}
}
// parse recipients
List<SendRecipient> recipients = [];
if (addressable.containsKey(AddresseeType.teachers) &&
type == AddresseeType.teachers) {
recipients.addAll(recipientTeachersJson.map((e) =>
SendRecipient.fromJson(e, addressable[AddresseeType.teachers]!)));
}
if (addressable.containsKey(AddresseeType.directorate) &&
type == AddresseeType.directorate) {
recipients.addAll(recipientDirectorateJson.map((e) =>
SendRecipient.fromJson(e, addressable[AddresseeType.directorate]!)));
}
// if (kDebugMode) {
// print(addressable);
// print(recipients);
// print(recipients.first.json);
// }
await storeRecipients(recipients, type);
}
// store recipients
Future<void> storeRecipients(
List<SendRecipient> recipients, AddresseeType type) async {
_recipients.removeWhere((r) => (type == AddresseeType.teachers
? (r.type.code == 'TANAR')
: (type == AddresseeType.directorate
? (r.type.code == 'IGAZGATOSAG')
: r.type.code != '')));
_recipients.addAll(recipients);
User? user = Provider.of<UserProvider>(_context, listen: false).user;
if (user == null) throw "Cannot store Recipients for User null";
String userId = user.id;
await Provider.of<DatabaseProvider>(_context, listen: false)
.userStore
.storeRecipients(_recipients, userId: userId);
notifyListeners();
}
// send message
Future<String?> sendMessage({
required List<SendRecipient> recipients,
String subject = "Nincs tárgy",
required String messageText,
}) async {
List<Object> recipientList = [];
User? user = Provider.of<UserProvider>(_context, listen: false).user;
if (user == null) throw "Cannot send Message as User null";
// for (var r in recipients) {
// recipientList.add({
// "azonosito": r.id ?? "",
// "kretaAzonosito": r.kretaId ?? "",
// "nev": r.name ?? "Teszt Lajos",
// "tipus": {
// "kod": r.type.code,
// "leiras": r.type.description,
// "azonosito": r.type.id,
// "nev": r.type.name,
// "rovidNev": r.type.shortName,
// }
// });
// }
recipientList.addAll(recipients.map((e) => e.kretaJson));
Map body = {
"cimzettLista": recipientList,
"csatolmanyok": [],
"azonosito": (Random().nextInt(10000) + 10000),
"feladoNev": user.name,
"feladoTitulus": user.role == Role.parent ? "Szülő" : "Diák",
"kuldesDatum": DateTime.now().toIso8601String(),
"targy": subject,
"szoveg": messageText,
// "elozoUzenetAzonosito": 0,
};
Map<String, String> headers = {
"content-type": "application/json",
};
var res = await Provider.of<KretaClient>(_context, listen: false).postAPI(
KretaAPI.sendMessage,
autoHeader: true,
json: true,
body: json.encode(body),
headers: headers,
);
if (res!['hibakod'] == 'UzenetKuldesEngedelyRule') {
return 'send_permission_error';
}
return 'successfully_sent';
}
} }

View File

@@ -0,0 +1,112 @@
import 'package:filcnaplo/api/client.dart';
import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/models/shared_theme.dart';
// import 'package:filcnaplo/models/shared_theme.dart';
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
class ShareProvider extends ChangeNotifier {
final UserProvider _user;
ShareProvider({
required UserProvider user,
}) : _user = user;
// Future<void> shareTheme({required SharedTheme theme}) async {
// }
// themes
Future<SharedTheme> shareCurrentTheme(BuildContext context,
{bool isPublic = false,
bool shareNick = true,
required SharedGradeColors gradeColors}) async {
final SettingsProvider settings =
Provider.of<SettingsProvider>(context, listen: false);
Map themeJson = {
'public_id': const Uuid().v4(),
'is_public': isPublic,
'nickname': shareNick ? _user.nickname : 'Anonymous',
'background_color': (settings.customBackgroundColor ??
SettingsProvider.defaultSettings().customBackgroundColor)
?.value,
'panels_color': (settings.customHighlightColor ??
SettingsProvider.defaultSettings().customHighlightColor)
?.value,
'accent_color': (settings.customAccentColor ??
SettingsProvider.defaultSettings().customAccentColor)
?.value ??
const Color(0xFF3D7BF4).value,
'icon_color': (settings.customIconColor ??
SettingsProvider.defaultSettings().customIconColor)
?.value ??
const Color(0x00000000).value,
'shadow_effect': settings.shadowEffect,
};
SharedTheme theme = SharedTheme.fromJson(themeJson, gradeColors);
FilcAPI.addSharedTheme(theme);
return theme;
}
Future<SharedTheme?> getThemeById(BuildContext context,
{required String id}) async {
Map? themeJson = await FilcAPI.getSharedTheme(id);
if (themeJson != null) {
Map? gradeColorsJson =
await FilcAPI.getSharedGradeColors(themeJson['grade_colors_id']);
if (gradeColorsJson != null) {
SharedTheme theme = SharedTheme.fromJson(
themeJson, SharedGradeColors.fromJson(gradeColorsJson));
return theme;
}
}
return null;
}
// grade colors
Future<SharedGradeColors> shareCurrentGradeColors(
BuildContext context, {
bool isPublic = false,
bool shareNick = true,
}) async {
final SettingsProvider settings =
Provider.of<SettingsProvider>(context, listen: false);
Map gradeColorsJson = {
'public_id': const Uuid().v4(),
'is_public': isPublic,
'nickname': shareNick ? _user.nickname : 'Anonymous',
'five_color': settings.gradeColors[4].value,
'four_color': settings.gradeColors[3].value,
'three_color': settings.gradeColors[2].value,
'two_color': settings.gradeColors[1].value,
'one_color': settings.gradeColors[0].value,
};
SharedGradeColors gradeColors = SharedGradeColors.fromJson(gradeColorsJson);
FilcAPI.addSharedGradeColors(gradeColors);
return gradeColors;
}
Future<SharedGradeColors?> getGradeColorsById(BuildContext context,
{required String id}) async {
Map? gradeColorsJson = await FilcAPI.getSharedGradeColors(id);
if (gradeColorsJson != null) {
SharedGradeColors gradeColors =
SharedGradeColors.fromJson(gradeColorsJson);
return gradeColors;
}
return null;
}
}

View File

@@ -0,0 +1,165 @@
// import 'package:filcnaplo/api/providers/user_provider.dart';
// import 'package:filcnaplo/api/providers/database_provider.dart';
// import 'package:filcnaplo/models/settings.dart';
// import 'package:filcnaplo/models/user.dart';
// import 'package:filcnaplo_kreta_api/client/api.dart';
// import 'package:filcnaplo_kreta_api/client/client.dart';
// import 'package:filcnaplo_kreta_api/models/grade.dart';
// import 'package:filcnaplo_kreta_api/models/group_average.dart';
// import 'package:filcnaplo_kreta_api/providers/grade_provider.i18n.dart';
// import 'package:flutter/material.dart';
// class SubjectProvider with ChangeNotifier {
// // Private
// late List<Grade> _grades;
// late DateTime _lastSeen;
// late String _groups;
// List<GroupAverage> _groupAvg = [];
// late final SettingsProvider _settings;
// late final UserProvider _user;
// late final DatabaseProvider _database;
// late final KretaClient _kreta;
// // Public
// List<Grade> get grades => _grades;
// DateTime get lastSeenDate =>
// _settings.gradeOpeningFun ? _lastSeen : DateTime(3000);
// String get groups => _groups;
// List<GroupAverage> get groupAverages => _groupAvg;
// SubjectProvider({
// List<Grade> initialGrades = const [],
// required SettingsProvider settings,
// required UserProvider user,
// required DatabaseProvider database,
// required KretaClient kreta,
// }) {
// _settings = settings;
// _user = user;
// _database = database;
// _kreta = kreta;
// _grades = List.castFrom(initialGrades);
// _lastSeen = DateTime.now();
// if (_grades.isEmpty) restore();
// }
// Future<void> seenAll() async {
// String? userId = _user.id;
// if (userId != null) {
// final userStore = _database.userStore;
// userStore.storeLastSeenGrade(DateTime.now(), userId: userId);
// _lastSeen = DateTime.now();
// }
// }
// Future<void> restore() async {
// String? userId = _user.id;
// // Load grades from the database
// if (userId != null) {
// final userQuery = _database.userQuery;
// _grades = await userQuery.getGrades(userId: userId);
// await convertBySettings();
// _groupAvg = await userQuery.getGroupAverages(userId: userId);
// notifyListeners();
// DateTime lastSeenDB = await userQuery.lastSeenGrade(userId: userId);
// if (lastSeenDB.millisecondsSinceEpoch == 0 ||
// lastSeenDB.year == 0 ||
// !_settings.gradeOpeningFun) {
// _lastSeen = DateTime.now();
// await seenAll();
// } else {
// _lastSeen = lastSeenDB;
// }
// notifyListeners();
// }
// }
// // good student mode, renamed subjects
// Future<void> convertBySettings() async {
// Map<String, String> renamedSubjects = _settings.renamedSubjectsEnabled
// ? await _database.userQuery.renamedSubjects(userId: _user.user!.id)
// : {};
// Map<String, String> renamedTeachers = _settings.renamedTeachersEnabled
// ? await _database.userQuery.renamedTeachers(userId: _user.user!.id)
// : {};
// for (Grade grade in _grades) {
// grade.subject.renamedTo =
// renamedSubjects.isNotEmpty ? renamedSubjects[grade.subject.id] : null;
// grade.teacher.renamedTo =
// renamedTeachers.isNotEmpty ? renamedTeachers[grade.teacher.id] : null;
// grade.value.value =
// _settings.goodStudent ? 5 : grade.json!["SzamErtek"] ?? 0;
// grade.value.valueName = _settings.goodStudent
// ? "Jeles".i18n
// : '${grade.json!["SzovegesErtek"]}'
// .replaceAll(RegExp(r'[(]+[12345]?[)]'), '')
// .i18n;
// grade.value.shortName = _settings.goodStudent
// ? "Jeles".i18n
// : '${grade.json!["SzovegesErtekelesRovidNev"]}' != "null" &&
// '${grade.json!["SzovegesErtekelesRovidNev"]}' != "-" &&
// '${grade.json!["SzovegesErtekelesRovidNev"]}'
// .replaceAll(RegExp(r'[0123456789]+[%]?'), '') !=
// ""
// ? '${grade.json!["SzovegesErtekelesRovidNev"]}'.i18n
// : grade.value.valueName;
// }
// notifyListeners();
// }
// // fetch subjects from kreten then store them
// Future<void> fetch() async {
// User? user = _user.user;
// if (user == null) throw "Cannot fetch Subjects for User null";
// String iss = user.instituteCode;
// List? gradesJson = await _kreta.getAPI(KretaAPI.subjects(iss, ""));
// if (gradesJson == null) throw "Cannot fetch Subjects for User ${user.id}";
// List<Grade> grades = gradesJson.map((e) => Grade.fromJson(e)).toList();
// if (grades.isNotEmpty || _grades.isNotEmpty) await store(grades);
// List? groupsJson = await _kreta.getAPI(KretaAPI.groups(iss));
// if (groupsJson == null || groupsJson.isEmpty) {
// throw "Cannot fetch Groups for User ${user.id}";
// }
// _groups = (groupsJson[0]["OktatasNevelesiFeladat"] ?? {})["Uid"] ?? "";
// List? groupAvgJson =
// await _kreta.getAPI(KretaAPI.groupAverages(iss, _groups));
// if (groupAvgJson == null) {
// throw "Cannot fetch Class Averages for User ${user.id}";
// }
// final groupAvgs =
// groupAvgJson.map((e) => GroupAverage.fromJson(e)).toList();
// await storeGroupAvg(groupAvgs);
// }
// // store subjects in db
// Future<void> store(List<Grade> grades) async {
// User? user = _user.user;
// if (user == null) throw "Cannot store Grades for User null";
// String userId = user.id;
// await _database.userStore.storeGrades(grades, userId: userId);
// _grades = grades;
// await convertBySettings();
// }
// Future<void> storeGroupAvg(List<GroupAverage> groupAvgs) async {
// _groupAvg = groupAvgs;
// User? user = _user.user;
// if (user == null) throw "Cannot store Grades for User null";
// String userId = user.id;
// await _database.userStore.storeGroupAverages(groupAvgs, userId: userId);
// notifyListeners();
// }
// }

View File

@@ -5,7 +5,7 @@ import 'package:filcnaplo_kreta_api/client/api.dart';
import 'package:filcnaplo_kreta_api/client/client.dart'; import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/models/lesson.dart'; import 'package:filcnaplo_kreta_api/models/lesson.dart';
import 'package:filcnaplo_kreta_api/models/week.dart'; import 'package:filcnaplo_kreta_api/models/week.dart';
import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart';
class TimetableProvider with ChangeNotifier { class TimetableProvider with ChangeNotifier {
Map<Week, List<Lesson>> lessons = {}; Map<Week, List<Lesson>> lessons = {};
@@ -65,17 +65,29 @@ class TimetableProvider with ChangeNotifier {
User? user = _user.user; User? user = _user.user;
if (user == null) throw "Cannot fetch Lessons for User null"; if (user == null) throw "Cannot fetch Lessons for User null";
String iss = user.instituteCode; String iss = user.instituteCode;
List? lessonsJson = await _kreta
.getAPI(KretaAPI.timetable(iss, start: week.start, end: week.end));
if (lessonsJson == null) throw "Cannot fetch Lessons for User ${user.id}";
List<Lesson> lessonsList = lessonsJson.map((e) => Lesson.fromJson(e)).toList();
if (lessons.isEmpty && lessons.isEmpty) return; List? lessonsJson;
try {
lessonsJson = await _kreta
.getAPI(KretaAPI.timetable(iss, start: week.start, end: week.end));
} catch (e) {
lessonsJson = null;
}
lessons[week] = lessonsList; if (lessonsJson == null) {
if (kDebugMode) print('Cannot fetch Lessons for User ${user.id}');
await store(); return;
await convertBySettings(); // throw "Cannot fetch Lessons for User ${user.id}";
} else {
List<Lesson> lessonsList =
lessonsJson.map((e) => Lesson.fromJson(e)).toList();
lessons[week] = lessonsList;
await store();
await convertBySettings();
}
} }
// Stores Lessons in the database // Stores Lessons in the database

View File

@@ -11,7 +11,10 @@ dependencies:
path: ../filcnaplo/ path: ../filcnaplo/
http: ^0.13.3 http: ^0.13.3
provider: ^5.0.0 provider: ^5.0.0
file_picker: ^5.3.2 file_picker: ^6.1.1
intl: ^0.18.1
i18n_extension: ^10.0.1
uuid: ^4.2.1
dev_dependencies: dev_dependencies:
flutter_lints: ^1.0.0 flutter_lints: ^3.0.1

View File

@@ -1,47 +0,0 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Web related
lib/generated_plugin_registrant.dart
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
pubspec.lock

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ActionButton extends StatelessWidget { class ActionButton extends StatelessWidget {
const ActionButton({Key? key, required this.label, this.activeColor, this.onTap}) : super(key: key); const ActionButton({super.key, required this.label, this.activeColor, this.onTap});
final Color? activeColor; final Color? activeColor;
final void Function()? onTap; final void Function()? onTap;

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