Compare commits

..

240 Commits
4.0.1 ... 4.2.2

Author SHA1 Message Date
Márton Kiss
023329f021 Merge pull request #43 from refilc/dev
Dev
2023-09-05 22:06:51 +02:00
Kima
e66fdbaeac added expire date to ads 2023-09-05 21:59:53 +02:00
Kima
bbbaea9224 fixed ad isBefore 2023-09-05 21:55:51 +02:00
Márton Kiss
c7c18cf684 Merge pull request #42 from refilc/dev
changed version number
2023-09-05 21:23:48 +02:00
Kima
4d501fed3e changed version number 2023-09-05 21:23:30 +02:00
Márton Kiss
8168ef5329 Merge pull request #41 from refilc/dev
Dev
2023-09-05 21:18:27 +02:00
Kima
608bc58771 fixed padding on ad tile 2023-09-05 21:17:54 +02:00
Kima
2cba1ec286 ads api working 2023-09-05 21:08:06 +02:00
Kima
b6eb65814f Merge branch 'dev' of github.com:refilc/naplo into dev 2023-09-05 18:49:16 +02:00
Kima
a5a43ea0b9 added ad provider 2023-09-05 18:49:14 +02:00
Márton Kiss
da356bb212 Merge pull request #40 from refilc/dev
Dev
2023-09-04 23:15:01 +02:00
Márton Kiss
c29ab3de29 Merge pull request #39 from Monke14/dev
Android widget fix
2023-09-04 23:14:38 +02:00
Kima
fceb4e050f FINALLY FIXED AUTO UPDATE 2023-09-04 23:13:54 +02:00
Kima
8feea02f68 added api endpoint and auto update fix 2023-09-04 21:45:11 +02:00
hihihaha
939e4f4d48 widget fix 2023-09-04 21:31:50 +02:00
Kima
a401ff32d9 something 2023-09-04 20:17:38 +02:00
Márton Kiss
84e7fc60c2 Merge pull request #38 from refilc/dev
dev to master
2023-09-04 18:40:16 +02:00
Kima
6821887263 Merge branch 'dev' of github.com:refilc/naplo into dev 2023-09-04 18:39:53 +02:00
Kima
8f8ceb0597 removed prints 2023-09-04 18:39:49 +02:00
Márton Kiss
deb2403c23 Merge pull request #37 from refilc/master
master readme to dev branch
2023-09-04 18:38:06 +02:00
Márton Kiss
d65c722ef0 Merge pull request #36 from refilc/dev
dev minden is master-be
2023-09-04 18:37:18 +02:00
Kima
1bdc1409e4 updated version number 2023-09-04 18:33:24 +02:00
Kima
467eca6c14 fixed that shit timetable bug 2023-09-04 18:31:47 +02:00
Kima
da3abb7fb7 fixed school select (omfg nagyon szarul csinaltak) 2023-09-04 17:10:09 +02:00
Márton Kiss
a8a818225e modified readme 2023-09-03 23:53:28 +02:00
Kima
5e650869f2 added some hint for spaces after username 2023-09-03 22:13:39 +02:00
Kima
6e06d82b1a made goal planner modal dark mode compatible 2023-09-03 21:17:22 +02:00
Márton Kiss
79370f6a02 Merge pull request #31 from refilc/dev
everything from dev
2023-09-02 21:03:49 +02:00
Kima
d0dee1002d removed italic font toggle from teacher rename 2023-09-02 20:59:42 +02:00
Kima
7517fd976a removed asset image temporary 2023-09-02 20:54:50 +02:00
Kima
ac9e3e9ff3 removed reasonless test button lol 2023-09-02 20:53:09 +02:00
Kima
a8dce30022 modified app version 2023-09-02 20:47:55 +02:00
Kima
dac2e6e52e added translation for goal plan errors 2023-09-02 20:44:55 +02:00
Kima
b7c3534751 changed back temp goal planner things 2023-09-02 20:26:10 +02:00
Kima
2c04b7ca7c test subject icon 2023-09-02 15:45:18 +02:00
Kima
4a43f1607c added goal provider thing 2023-09-02 15:37:49 +02:00
Kima
fef0857050 worked on goal planner finish modal 2023-09-02 14:48:05 +02:00
Kima
9078634fb7 fixed live activity error message in console 2023-09-02 14:47:51 +02:00
Kima
e71c56a146 did things in goal planner 2023-08-31 00:51:52 +02:00
Kima
8f85116353 basically finished goal planner 2023-08-31 00:20:26 +02:00
Kima
1d6b9dd5d8 almost done with goal planning 2023-08-30 23:58:55 +02:00
Kima
2bd534fde9 fixed settings screen snapping 2023-08-30 01:30:11 +02:00
Kima
c05b358b49 fixed notification minden is 2023-08-30 01:22:41 +02:00
Márton Kiss
91255182d2 Merge pull request #29 from Monke14/notifications
Értesítések
2023-08-30 00:47:45 +02:00
Márton Kiss
5052f57ee6 Merge pull request #28 from TMarccci/dev
Tested functions, BugFixes, Key line tint around Dyn Island
2023-08-30 00:47:28 +02:00
hihihaha
d651f6acf0 fix typo 2023-08-29 15:43:34 +02:00
hihihaha
ea2b91ca15 add notification for lesson updates 2023-08-29 15:36:23 +02:00
hihihaha
e280227ee1 add notification for messages 2023-08-29 14:32:40 +02:00
hihihaha
bc4e4e9b5a add notification for absences 2023-08-29 13:45:52 +02:00
Tihanyi Marcell
e732b36cb8 Merge branch 'refilc:dev' into dev 2023-08-29 13:28:14 +02:00
Tihanyi Marcell
894f370dad Fixes 2023-08-29 13:27:25 +02:00
hihihaha
ec04a0ff81 Merge branch 'dev' into notifications 2023-08-29 11:27:27 +02:00
Kima
b4be0f66dc fixed warnings 2023-08-29 11:16:17 +02:00
Márton Kiss
8bfbaee1f5 Merge pull request #27 from TMarccci/dev
Added function: Live Activity Custom Color, Small Fixes
2023-08-29 11:11:13 +02:00
Kima
458cfdd8a7 added db col for live activity color 2023-08-29 11:10:37 +02:00
Tihanyi Marcell
2406e9a45d Added function Live Activity Color change, Fixes 2023-08-29 02:12:05 +02:00
Tihanyi Marcell
d952b23b85 Merge branch 'dev' of https://github.com/refilc/naplo into dev 2023-08-29 02:08:01 +02:00
Tihanyi Marcell
0245ddb99e Added function Live Activity Color change, Fixes 2023-08-29 02:06:18 +02:00
Kima
40dd967903 some progress in goal planner again 2023-08-29 00:24:57 +02:00
Kima
d524d452bd some progress in goal planner (started goal state) 2023-08-28 18:25:20 +02:00
Kima
0ac0586fba setted goal plans can be saved now 2023-08-28 02:33:39 +02:00
Kima
3e470981a8 made goal planner even better 2023-08-28 00:36:24 +02:00
Kima
09e416ab74 added rounded border icon (new style thing) 2023-08-27 23:58:32 +02:00
Kima
1314b2f068 fix import 2023-08-27 23:48:11 +02:00
Kima
4b70b6e035 added back pubspec xd 2023-08-27 21:42:47 +02:00
Kima
856b48675b Merge branch 'dev' of github.com:refilc/naplo into dev 2023-08-27 21:38:35 +02:00
ReinerRego
534a223cbf Update README.md
--recursive kiszedve mert nem kell
2023-08-27 21:10:25 +02:00
Kima
625c43d786 updated privacy policy 2023-08-26 21:12:17 +02:00
Kima
d1f79a63a1 added notifications to group 2023-08-26 20:25:01 +02:00
Kima
f4bf509fa7 fixed icon 2023-08-26 20:22:02 +02:00
Kima
8ff4f0b88f only show normal grade notifications 2023-08-26 20:19:05 +02:00
Kima
ee2a42bbe2 modified confetti 2023-08-26 20:08:32 +02:00
Kima
bc1ec45855 simplified news provider 2023-08-26 19:12:03 +02:00
Kima
6d4939d88a changed teacher rename ico 2023-08-26 17:24:47 +02:00
Kima
f7d263570d added beta chip, changed things 2023-08-26 17:21:34 +02:00
Kima
1ea0f95863 finished goal planner first half 2023-08-26 17:05:16 +02:00
Kima
6003f6fd2a actually finished teacher rename 2023-08-26 15:32:23 +02:00
Kima
ded029e4cb maybe finished teacher rename 2023-08-26 15:15:56 +02:00
Kima
e64ab75753 teacher rename base and settings done :orbnsmirk: 2023-08-26 14:56:57 +02:00
Kima
2d11c45972 added rounded expansion tile (fixed absence bug) 2023-08-26 13:50:03 +02:00
Kima
63e5ccb7c3 added rounded expansion tile (fixed absence bug) 2023-08-26 13:27:58 +02:00
Kima
568d4cb769 Merge branch 'dev' of github.com:refilc/naplo into dev 2023-08-26 12:59:35 +02:00
Kima
88297cc181 modified gitignore 2023-08-26 12:59:23 +02:00
Márton Kiss
e5ed6c33ed Delete generated_plugin_registrant.h 2023-08-26 12:58:16 +02:00
Márton Kiss
1e7fbfd0a4 Delete generated_plugin_registrant.cc 2023-08-26 12:58:09 +02:00
Márton Kiss
87cd1a40f4 Delete generated_plugins.cmake 2023-08-26 12:55:55 +02:00
Márton Kiss
0d7d6738df Delete Podfile.lock 2023-08-26 12:53:43 +02:00
Márton Kiss
c3dd4a3b7e Delete GeneratedPluginRegistrant.swift 2023-08-26 12:51:32 +02:00
Márton Kiss
76b2492ba8 Delete Podfile.lock 2023-08-26 12:51:03 +02:00
Kima
758bcda581 Merge branch 'master' into dev 2023-08-26 12:14:17 +02:00
Kima
520d2f2ce0 increased grade calculator limit to 50 grades 2023-08-26 11:30:36 +02:00
Kima
8855dc4820 commented out widget test 2023-08-26 11:24:34 +02:00
Kima
6fda457bbb added back profile picture crop functionality 2023-08-26 00:19:41 +02:00
Kima
360426d851 fixed some of the widget bugs and removed assets 2023-08-25 23:20:44 +02:00
Kima
bad9ed000b fixed some of the widget bugs and removed assets 2023-08-25 23:20:22 +02:00
Kima
18b1b00f45 Merge branch 'dev' 2023-08-25 21:30:43 +02:00
Márton Kiss
7bd5653a5f Delete .flutter-plugins-dependencies 2 2023-08-23 00:30:55 +02:00
Márton Kiss
fb4e0f644a Delete .flutter-plugins 2 2023-08-23 00:30:48 +02:00
Márton Kiss
7766832d5f Delete .flutter-plugins-dependencies 2 2023-08-23 00:30:35 +02:00
Márton Kiss
11ae42cb03 Delete .flutter-plugins 2 2023-08-23 00:30:24 +02:00
Márton Kiss
de6ddb42ae Delete .flutter-plugins-dependencies 2 2023-08-23 00:30:03 +02:00
Márton Kiss
c100a032d6 Delete .flutter-plugins 2 2023-08-23 00:29:52 +02:00
Márton Kiss
6b8eb120f0 Delete .flutter-plugins-dependencies 2 2023-08-23 00:29:26 +02:00
Márton Kiss
b9b79fdde2 Delete .flutter-plugins 2 2023-08-23 00:29:15 +02:00
Kima
40ca5fe0a1 Merge branch 'master' of github.com:refilc/naplo 2023-08-23 00:04:36 +02:00
Kima
e183c17c9f look at the changes 😏 2023-08-23 00:04:33 +02:00
Kima
d2003893e8 changed error message in api client (nothing lol) 2023-08-16 02:11:41 +02:00
Kima
22cd08165b added notification support on linux 2023-08-04 13:48:36 +02:00
Kima
1f62a71cd5 i'll never make this shit work on web lol, go nuxt 2023-08-01 21:13:40 +02:00
Kima
93fab8196d added web support 2023-08-01 18:47:10 +02:00
Kima
5523a2a919 fixed lot of ui things 2023-07-31 23:20:30 +02:00
kima
d79045e47f modified personality requirements 2023-06-27 20:38:52 +02:00
kima
cffd93bfe6 fixed auto update and changed build number 2023-06-27 18:22:00 +02:00
kima
d2c762d29a fixed error screen bug in summary maybe 2023-06-26 21:15:25 +02:00
kima
9d9f99a955 fixed long subject names in grades summary 2023-06-25 14:55:01 +02:00
kima
2c5939fab4 fixed misaligned text on final sum page 2023-06-25 14:50:54 +02:00
kima
95ed503e53 fixed 0 min delay thingies 2023-06-25 14:47:06 +02:00
kima
51e2c63134 fixed navigation and ui bugs in summary 2023-06-25 14:36:18 +02:00
kima
50bc03f403 updated version string 2023-06-25 00:11:44 +02:00
kima
f5bc16ba42 created translation for personality card 2023-06-24 23:58:06 +02:00
kima
f4501ce251 finished translation for summary 2023-06-24 21:41:18 +02:00
kima
3317472773 fixed end-year average 2023-06-23 11:20:18 +02:00
kima
acdd47a49a fixed style bug and added reveal check to buttons 2023-06-23 01:17:26 +02:00
kima
fa8be89aaf fixed some issues and added gallery save feature 2023-06-23 01:06:48 +02:00
kima
5034af2fb4 finished animations and started reveal/share 2023-06-23 00:54:56 +02:00
kima
87842de421 finished personality card style 2023-06-22 23:33:28 +02:00
kima
1f46a0509f fixed summary crash error 2023-06-22 21:55:57 +02:00
kima
8e9713e436 almost finished personality page 2023-06-22 21:12:34 +02:00
kima
fe0a7d81ae finished personalities map 2023-06-22 20:52:45 +02:00
kima
f9e14349b7 Merge branch 'master' of github.com:refilc/naplo 2023-06-22 19:44:09 +02:00
kima
a1f087758f started summary personality page 2023-06-22 19:15:02 +02:00
kima
4068abdb95 finished final summary style and fixed thingies 2023-06-22 16:45:57 +02:00
kima
9314c613bc added lessons/misses page and final summary page 2023-06-22 15:59:57 +02:00
Márton Kiss
458e93e19f Merge pull request #25 from Monke14/master
fix italics toggle bugs
2023-06-20 17:44:42 +02:00
hihihaha
ba8d26d250 fix italics toggle bugs 2023-06-20 16:19:49 +02:00
Márton Kiss
33e3495d9f Merge pull request #23 from Monke14/master
fix high network usage
2023-06-20 10:28:27 +02:00
Márton Kiss
f71e72e443 Merge pull request #24 from PredatorPotatoX/master
Contribution guide update
2023-06-20 10:26:28 +02:00
hihihaha
c615a33bd2 make variable private 2023-06-19 22:34:53 +02:00
PredatorPotatoX
7ad0ea26e2 Contributing guide update 2023-06-19 21:04:32 +02:00
hihihaha
0ad663beb3 fix network activity 2023-06-18 17:36:01 +02:00
kima
1366984c15 added start page to summary 2023-06-17 21:30:48 +02:00
kima
62d3895373 added next page button to summary 2023-06-17 20:41:30 +02:00
kima
3579c4e821 fixed grades page ui in summary 2023-06-17 20:04:11 +02:00
Kima
5c39865d40 commit 2023-06-17 16:37:24 +02:00
Kima
551b2849fe grade page done in summary 2023-06-16 01:30:17 +02:00
hihihaha
633601a0f3 absence notification 2023-06-15 18:31:27 +02:00
Márton Kiss
ce1c5eb0d8 fixed nonce login error 2023-06-15 09:33:36 +02:00
Márton Kiss
d929c804df Merge pull request #21 from TMarccci/master
LiveActivity
2023-06-14 23:53:17 +02:00
Tihanyi Marcell
19c128eecd LiveActivity 2023-06-14 23:46:21 +02:00
kima
57cf764804 updated version string 2023-06-14 23:08:54 +02:00
kima
ea812e0b67 fixed project problems 2023-06-13 23:37:35 +02:00
kima
1c517a99f2 fixed project problems 2023-06-13 23:37:25 +02:00
kima
2687cb146b gitignore changes 2023-06-13 23:35:11 +02:00
kima
1a9080dcc2 added event functionality and summary to livecard 2023-06-13 23:27:40 +02:00
Márton Kiss
580c92b13d Merge pull request #20 from TMarccci/master
On empty timetable block fullscreen mode.
2023-06-13 21:10:04 +02:00
Tihanyi Marcell
ae4c4aa89c Merge branch 'refilc:master' into master 2023-06-12 21:54:47 +02:00
Tihanyi Marcell
ded7c51f44 Block empty fullscreen timetable 2023-06-12 21:54:13 +02:00
Márton Kiss
485e85ddaa Merge pull request #19 from TMarccci/master
Fixes
2023-06-12 20:26:48 +02:00
Márton Kiss
3c0082a786 Merge pull request #18 from CroatianHusky/master
Developer Settings i18n + Notifications toggle color fix
2023-06-12 20:25:28 +02:00
Tihanyi Marcell
c474512088 Live Activity version update, build-ipa.sh 2023-06-12 20:11:15 +02:00
Tihanyi Marcell
f78a542be2 iOS notification permission fix 2023-06-12 20:09:48 +02:00
Tihanyi Marcell
131454b99d Notification Capabilitie 2023-06-12 20:09:27 +02:00
Tihanyi Marcell
e255182b93 Removed " " from login 2023-06-12 20:09:11 +02:00
Tihanyi Marcell
3857896d6c Ghost Grade title overflow fix 2023-06-12 20:08:53 +02:00
CroatianHusky
301e8cb638 Updated settings_screen.i18n.dart 2023-06-12 17:35:13 +02:00
CroatianHusky
ae7c724f65 notification toggle color fix 2023-06-12 17:33:00 +02:00
CroatianHusky
751cd04ce2 developer settings i18n 2023-06-12 17:14:42 +02:00
Márton Kiss
a88ccfa3fc Merge pull request #15 from Monke14/notifications
Értesítések
2023-06-10 22:47:03 +02:00
Márton Kiss
9e914974b7 Merge branch 'master' into notifications 2023-06-10 22:46:40 +02:00
Kima
9cfa8296b8 fixed some bugs 2023-06-10 22:38:01 +02:00
hihihaha
27ef942723 fix headless task 2023-06-10 21:46:53 +02:00
hihihaha
fe03554fbf backend changes 2023-06-10 21:19:49 +02:00
hihihaha
8c2227df73 update design 2023-06-10 21:03:01 +02:00
hihihaha
0274c2f070 start on boot 2023-06-10 20:43:03 +02:00
hihihaha
8f85c6a33b add timeout safety to headless task 2023-06-10 20:41:31 +02:00
hihihaha
cf81ca8207 add annotation to function 2023-06-10 20:39:06 +02:00
hihihaha
07bbafe7dd add toggle for notifications in settings 2023-06-10 20:34:01 +02:00
hihihaha
3eee2c7a55 set grade as seen 2023-06-10 19:55:40 +02:00
hihihaha
1cdde3b6ce add notification 2023-06-10 19:50:32 +02:00
Márton Kiss
67aea46c06 Update navigation_screen.dart 2023-06-10 13:59:03 +02:00
Márton Kiss
7adec7dfa5 maybe fixed dark mode bug 2023-06-10 13:57:11 +02:00
Kima
95fa819ed2 updatet things in pubspec 2023-06-10 13:26:28 +02:00
Kima
1e87d344e2 fixed versions in pubspec 2023-06-10 11:25:24 +02:00
Márton Kiss
9223375304 Merge pull request #11 from CroatianHusky/master
"Új jegyek" többesszám fix + verzió "v?" fix
2023-06-10 11:10:04 +02:00
Márton Kiss
bb862f15bd Merge pull request #10 from PredatorPotatoX/master
CONTRIBUTING.md link fix
2023-06-10 11:09:46 +02:00
CroatianHusky
261c94e9bb fixed version counter "v?" 2023-06-10 10:38:26 +02:00
CroatianHusky
06016514e5 new grade plurality fix 2023-06-10 09:32:21 +02:00
CroatianHusky
cead24b65a removed dead filc links from pubspec 2023-06-10 09:29:44 +02:00
PredatorPotatoX
6eaab57468 CONTRIBUTING.md link fix 2023-06-09 23:31:29 +02:00
Márton Kiss
5852fc233d Update AndroidManifest.xml 2023-06-09 21:15:25 +02:00
Márton Kiss
d7e21f6332 Update update_helper.dart 2023-06-09 21:13:38 +02:00
Márton Kiss
c78b8d3b97 Merge pull request #9 from Monke14/bug-fixes
Dőlt betűk toggle
2023-06-09 20:15:31 +02:00
hihihaha
940e3d8ca1 add toggle for italics 2023-06-09 17:29:03 +02:00
Márton Kiss
e31d0753d1 Merge pull request #8 from TMarccci/master
I think I fixed this
2023-06-09 16:55:05 +02:00
Tihanyi Marcell
526c66f358 I think I fixed this 2023-06-09 16:53:28 +02:00
Kima
d6833a952d changed version string 2023-06-09 16:40:53 +02:00
Kima
4760761bb7 Merge branch 'master' of github.com:refilc/naplo 2023-06-09 16:25:34 +02:00
Kima
a33e6dae3b fixed auto-update error bug 2023-06-09 16:25:31 +02:00
Márton Kiss
d393181f10 Update grade_provider.dart 2023-06-09 16:06:17 +02:00
Márton Kiss
12df8b82c7 Merge pull request #7 from TMarccci/master
Handle disabled Live Activity, i18n AverageSelector won't update, ...
2023-06-09 16:02:05 +02:00
Tihanyi Marcell
1c7eba7af3 Appgroup id: not refilc2 2023-06-09 15:44:37 +02:00
Tihanyi Marcell
d39cdaef10 Fixed i18n wont update to AverageSelector 2023-06-09 14:22:15 +02:00
Tihanyi Marcell
cc40fb9c0f Ignore disabled live activity 2023-06-09 11:13:35 +02:00
Tihanyi Marcell
85c6d548ad Ignore null and - i18n 2023-06-09 11:08:00 +02:00
Kima
8dbf605450 added black accent color 2023-06-08 21:28:28 +02:00
Kima
2f418a7c1a updated version string 2023-06-08 21:19:46 +02:00
Kima
5f0c82f54c added grade value translations 2023-06-08 21:18:20 +02:00
Kima
4e659308e5 fixed subject rename at homeworks 2023-06-08 20:38:10 +02:00
Kima
50e24bde17 added disable fading to all filter/tab bars 2023-06-08 20:07:17 +02:00
Márton Kiss
31f7c6a465 Merge pull request #6 from Monke14/bug-fixes
some fixes - by Monke14
2023-06-08 20:01:22 +02:00
Márton Kiss
e734579249 Merge branch 'master' into bug-fixes 2023-06-08 19:59:57 +02:00
Márton Kiss
2cff46d628 Merge pull request #5 from TMarccci/master
fixed lot of things - by TMarccci
2023-06-08 19:56:35 +02:00
Kima
87f3f93177 started creating end-year summary and stb 2023-06-08 19:53:50 +02:00
hihihaha
30733caa4a remove home screen tabbar fade 2023-06-08 16:18:39 +02:00
hihihaha
4e30a550e1 fix chart overflow 2023-06-08 16:18:08 +02:00
hihihaha
cb687d6b10 add themed icon 2023-06-08 16:17:56 +02:00
hihihaha
6c6d3a7cd8 fix english translations 2023-06-08 16:17:46 +02:00
Tihanyi Marcell
da06e400e1 Login add " ", Comment rename 2023-06-08 13:47:40 +02:00
Tihanyi Marcell
87b8cbb60f HotFix 2023-06-08 12:59:09 +02:00
Tihanyi Marcell
8bac300585 goalPlanner remove 2023-06-08 12:54:46 +02:00
Tihanyi Marcell
da7d2b9333 Fixed: Settings UI, Live Act, Class Avg 2023-06-08 12:44:47 +02:00
Kima
e1f84caf19 changed refilc bday strings 2023-06-07 21:27:56 +02:00
Kima
274da2b766 ok 2023-06-07 21:21:35 +02:00
Kima
35aba35801 Merge branch 'master' of github.com:refilc/naplo 2023-06-07 20:50:48 +02:00
Kima
964e002c46 added og filc color to accents 2023-06-07 20:50:45 +02:00
Márton Kiss
d3318e10ab fixed download counter in readme 2023-06-07 20:22:41 +02:00
Kima
4c43369d59 updated version string 2023-06-07 19:22:55 +02:00
Kima
176243b881 started uwu mode 2023-06-06 21:46:10 +02:00
Kima
ed02a340d0 ok 2023-06-06 21:11:52 +02:00
Kima
2877f4fc5c oke mostmar tenyleg fix 😭 vagy pedig mas baja 2023-06-06 21:03:30 +02:00
Kima
fceb3bf31a fixed settings screen version check 2023-06-06 20:58:33 +02:00
Kima
9883d081ff added back button to full-screen timetable 2023-06-06 20:27:37 +02:00
Kima
db5a9fb197 fixed translate bugs and subject name things 2023-06-06 19:18:56 +02:00
Kima
93438ce3df Merge branch 'master' of github.com:refilc/naplo 2023-06-05 21:21:48 +02:00
Kima
95bca64fb8 fixed quick actions colors 2023-06-05 21:21:45 +02:00
Pearoo
7821e10869 Update README.md 2023-06-01 10:58:53 +00:00
Pearoo
cede3c3129 Merge branch 'master' of https://github.com/refilc/naplo 2023-05-31 00:00:25 +02:00
Pearoo
528ee862b9 Update README.md - Squircle ikon 2023-05-30 21:28:25 +00:00
Pearoo
518932c260 Merge branch 'master' of https://github.com/refilc/naplo 2023-05-29 22:10:16 +02:00
Pearoo
281b9cf6c4 Update .gitignore 2023-05-29 13:31:03 +02:00
247 changed files with 13749 additions and 3984 deletions

24
.gitignore vendored
View File

@@ -1,5 +1,7 @@
# See https://www.dartlang.org/guides/libraries/private-files # See https://www.dartlang.org/guides/libraries/private-files
.gitignore
termek.txt termek.txt
.DS_Store .DS_Store
filc3.properties filc3.properties
@@ -25,3 +27,25 @@ doc/api/
*.js.map *.js.map
*.txt *.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

1286
.idea/libraries/Dart_Packages.xml generated Normal file

File diff suppressed because it is too large Load Diff

27
.idea/libraries/Dart_SDK.xml generated Normal file
View File

@@ -0,0 +1,27 @@
<component name="libraryTable">
<library name="Dart SDK">
<CLASSES>
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/async" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/cli" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/collection" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/convert" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/core" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/developer" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/ffi" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/html" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/indexed_db" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/io" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/isolate" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/js" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/js_util" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/math" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/mirrors" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/svg" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/typed_data" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/web_audio" />
<root url="file:///opt/flutter/bin/cache/dart-sdk/lib/web_gl" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

4
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Android API 33, extension level 3 Platform" project-jdk-type="Android SDK" />
</project>

60
.idea/naplo.iml generated
View File

@@ -2,7 +2,65 @@
<module type="JAVA_MODULE" version="4"> <module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true"> <component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output /> <exclude-output />
<content url="file://$MODULE_DIR$" /> <content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/flutter_acrylic/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/flutter_acrylic/example/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/flutter_acrylic/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_desktop_ui/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_desktop_ui/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_desktop_ui/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/share_plus/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/share_plus/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/share_plus/example/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/dynamic_color/example/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_premium/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_premium/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_premium/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/share_plus/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/share_plus/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/share_plus/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux/example/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/connectivity_plus/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/connectivity_plus/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/connectivity_plus/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/connectivity_plus/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/connectivity_plus/example/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/connectivity_plus/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_kreta_api/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_kreta_api/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_kreta_api/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_mobile_ui/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_mobile_ui/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo_mobile_ui/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus/example/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/flutter_acrylic/build" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/flutter_acrylic/.pub" />
<excludeFolder url="file://$MODULE_DIR$/filcnaplo/linux/flutter/ephemeral/.plugin_symlinks/flutter_acrylic/.dart_tool" />
</content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
</component> </component>

29
.vscode/launch.json vendored
View File

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

View File

@@ -1,39 +1,36 @@
# Contributing Guide # Contribution guide
Köszönjük, ha programozással segíted a munkánkat! Köszönjük, ha programozással segíted a munkánkat!
A folytatáshoz szükséged lesz egy Linuxot vagy Windowst futtató számítógépre, minimális programozási tapasztalatra és egy kis angoltudásra. A folytatáshoz szükséged lesz egy Linux-ot vagy Windows-t futtató számítógépre, minimális programozási tapasztalatra és egy kis angoltudásra.
Segít, ha nem csak kicsit tudsz programozni, és ha ismered a Gitet és a GitHubot ;) Segít, ha már gyakorlottabb vagy a programozásban, és ha ismered a [Git](https://git-scm.com/) és a [GitHub](https://github.com/) működését. ;)
## Miben segítsek? ## Miben segítsek?
Kérünk, **olyan dologgal járulj hozzá** a reFilchez, ami valószínűleg **sok embernek hasznos lesz** majd. Szeretnénk egy minél teljeskörűbb iskolai asszisztenst létrehozni, de az iskolaspecifikus, vagy külön neked hasznos funkciók helye inkább legyen a saját forkod. Kérünk, **olyan dologgal járulj hozzá** a **reFilc**hez, ami valószínűleg **sok embernek hasznos lehet**. Szeretnénk egy minél teljeskörűbb iskolai asszisztenst létrehozni, de az iskolaspecifikus, vagy külön neked hasznos funkciók helye inkább legyen a saját Fork-od.
Fontos, hogy **mielőtt egy nagy volumenű projektbe belekezdesz, futtasd meg ötletedet a [Discord szerverünkön](https://dc.refilc.hu/),** ahol még azelőtt tudunk tanácsot adni, mielőtt sok-sok órát beleöltél volna egy esetleg felesleges dologba. Fontos, hogy **mielőtt egy nagyobb méretű projektbe belekezdenél, futtasd meg ötletedet a [Discord szerverünkön](https://dc.refilc.hu/)**, ahol még azelőtt tudunk tanácsot adni, hogy sok-sok órát beleöltél volna egy esetleg felesleges dologba.
A legjobban annak örülünk, ha az [Issues](https://github.com/refilc/filcnaplo/issues) oldalról szemezgetsz, **ha lehet, a [priority taggel megjelöltekkel kezdd](https://github.com/refilc/filcnaplo/issues?q=is%3Aissue+is%3Aopen+label%3Apriority),** vagy ha új vagy a Flutterhez, ajánljuk figyelmedbe [ezeket a viszonylag könnyen javítható hibákat](https://github.com/refilc/filcnaplo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) (ha épp van ilyen). A legjobban annak örülünk, ha az [Issues](https://github.com/refilc/naplo/issues) oldalról szemezgetsz. Ha még új vagy a Flutterben, ajánljuk figyelmedbe ezeket a [viszonylag könnyen javítható hibákat](https://github.com/refilc/naplo/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22), ha éppen van ilyen.
## Hogyan segítsek? ## Hogyan segítsek?
Nem ígérhetünk itt sem programozás-, sem Git-kurzust, de a projektspecifikus dolgokat leírjuk, és segítünk a Flutter telepítésében.
Nem ígérhetünk itt sem programozás-, sem git-kurzust, de a projektspecifikus dolgokat leírjuk, és segítünk a Flutter feltelepítésében. A **reFilc** a Google által pár éve létrehozott **[Flutter](https://flutter.dev/)** keretrendszert használja, aminek nyelve a **[Dart](https://dart.dev/)**. Ha ismered a C#, Java, C++, vagy egyéb hasonló programnyelvek működését, **nem fog nagy gondot okozni a használata.** A felhasználói felület létrehozásában az is segíthet, ha foglalkoztál már korábban weboldalakkal vagy alkalmazásfejlesztéssel.
Ha még nem használtad a Flutter-t, mindenképp böngészd át a [YouTube csatornájukat](https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw).
Kód vagy UI teszteléséhez Flutter telepítése nélkül is használhatod a [DartPad](https://dartpad.dev/)-et.
A reFilc a Google által pár éve létrehozott **[Fluttert](https://flutter.dev/)** használja, aminek nyelve a **[Dart](https://dart.dev/)**. Ha ismered a C#-ot, Javát, C++t, vagy egyéb hasonló nyelvet, **nem fog gondot okozni a használata.** A felhasználói felület létrehozásában az is segíthet, ha foglalkoztál már korábban weboldalakkal. #### [Segítség a Flutter telepítéséhez](https://docs.flutter.dev/get-started/install)
Ha még nem használtál Fluttert, mindenképp böngészd át a [YouTube csatornájukat](https://www.youtube.com/channel/UCwXdFgeE9KYzlDdR7TG9cMw). **Használd a Flutter stable verzióját!** Írd be a terminálba: `flutter channel stable`
Könnyen tudsz kódot, vagy akár UI-t is tesztelni a [DartPad](https://dartpad.dev/) oldalon.
#### [Segítség a Flutter telepítéséhez és a forráskód futtatásához](/.github/SETUP.md) Ha nem értessz a Git-hez vagy a GitHub-hoz, ajánljuk figyelmedbe [ezt a cikket](https://medium.com/envienta-magyarorsz%C3%A1g/git-%C3%A9s-github-gyorstalpal%C3%B3-f2d78a732deb), viszont arra kérünk, hogy a használatukat ne a **reFilc**en próbáld ki először. Hozz létre egy saját Repo-t és abban tesztelgess. Ha már nagyjából kitapasztaltad, várjuk hozzájárulásodat.
Fontos: **Legyél a flutter beta verzióján!** Írd be: `flutter channel beta`
Készíts egy Fork-ot a saját GitHub fiókod alá.
A **reFilc** legfrissebb, **épp fejlesztés alatt álló verzióját a [master branch](https://github.com/refilc/naplo/tree/master)-en találod**. Kérjük ide Commit-olj és ide célozd a Fork-odból a Pull Request-edet. Írd le benne, hogy mit változtattál és ha lehet, csatolj képernyőképet is.
Ha nem értesz a Githez, ajánljuk figyelmedbe [ezt a cikket](https://medium.com/envienta-magyarorsz%C3%A1g/git-%C3%A9s-github-gyorstalpal%C3%B3-f2d78a732deb). Viszont arra kérünk, a Git használatát ne a reFilcen próbáld ki először, hozz létre előbb egy saját Repót, és abba tesztelgess. Ha már nagyjából kitapasztaltad, várjuk hozzájárulásodat. Minél gyakrabban készíts minél részletesebben elnevezett Commit-okat, hogy mások is el tudjanak igazodni az általad beküldött kódban.
Készíts egy forkot a saját fiókod alá.
A reFilc legfrissebb, épp fejlesztés alatt álló verzióját a [dev brancen](https://github.com/refilc/filcnaplo/tree/dev) találod, kérjük ide commitolj, és ide célozd a forkodból a Pull Requested. Írd le benne, mit változtattál, és ha lehet, csatolj képernyőképet is.
Minél gyakrabban készíts minél részletesebben elnevezett commitokat, hogy el tudjunk tájékozódni az általad beküldött kódon.
--- ---
Az általad fejlesztett funkciók mellé a changelogban odakerül GitHub felhasználóneved. Az általad fejlesztett funkciók mellé a Changelog-ba odakerül a GitHub felhasználóneved.
Ha jelentős és rendszeres hozzájáruló vagy, Discordon megkapod a `DEV` rangot. Ha jelentős és rendszeres hozzájáruló vagy, Discord-on megkaphatod a `DEV` rangot.
Ha bárhol elakadtál, keress minket Discordon. Ha bárhol elakadtál vagy kérdésed van, keress bátran Discordon!
Jó fejlesztést kívánunk! **Jó fejlesztést kívánunk!**

View File

@@ -1,18 +1,18 @@
<p align=center> <p align=center>
<img src="https://media.discordapp.net/attachments/1111727410677825596/1111790518964326510/reFilc_Logo2.png?width=671&height=671" width=150> <img src="https://media.discordapp.net/attachments/1111727410677825596/1113217167513624646/reFilc_Logo_Squircle.png?width=671&height=671" width=150>
<h1 align=center><b>reFilc</b></h1> <h1 align=center><b>reFilc</b></h1>
</p> </p>
#### Nem hivatalos e-napló alkalmazás az eKRÉTA rendszerhez - tanulóktól, tanulóknak. #### Nem hivatalos e-napló alkalmazás az e-KRÉTA rendszerhez - tanulóktól, tanulóknak.
[![Downloads](https://img.shields.io/github/downloads-pre/refilc/naplo/latest/total?color=%23&label=Downloads&logo=github&sort=semver)](https://github.com/refilc/naplo/releases) &nbsp; [![discord](https://img.shields.io/discord/1111649116020285532?label=Discord)](http://dc.refilc.hu) [![Downloads](https://img.shields.io/github/downloads-pre/refilc/naplo/total?&logo=github&label=Downloads)](https://github.com/refilc/naplo/releases) &nbsp; [![Discord](https://img.shields.io/discord/1111649116020285532?logo=discord&label=Discord)](https://dc.refilc.hu)
## Setup ## Setup
### Clone the project ### Clone the project
```sh ```sh
git clone --recursive https://github.com/refilc/naplo git clone https://github.com/refilc/naplo
cd naplo cd naplo
``` ```
@@ -29,14 +29,22 @@ flutter run
### Contribution ### Contribution
**Nézd meg a [Contribution guide](CONTRIBUTING.md)-ot!**
Az összes (ugyan azon verzióhoz tartozó) contribution meg fog jelenni a release-nél. Kérjük, írd le a Discord nevedet a Description-be, hogy adhassunk rangot. Az összes (ugyan azon verzióhoz tartozó) contribution meg fog jelenni a release-nél. Kérjük, írd le a Discord nevedet a Description-be, hogy adhassunk rangot.
------- -------
# Kudo # Team
**kima:** head developer / project manager
**Reiner, pdf, Pearoo:** community- and project manager / developer
**annon:** a Filc napló készítője (ez az app a Filcen alapul) **vrolandd, TMarccci:** head developer
**kima, chromium, peighter, mog, WolfY:** a fejlesztői csapat **dwe., xou:** designer
**Regő, Pearoo:** weboldal design és community management **Péter:** social media manager / video editor
**annon:** a régi Filc Napló fejlesztője (ez az app, ha bár sokban változott, alapjaiban a Filc-re épül)

View File

@@ -44,3 +44,4 @@ 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,30 +1,30 @@
# 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.
version: version:
revision: 3c0bee85b8e43b860877922bdc411a7333db4d32 revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
channel: beta channel: stable
project_type: app project_type: app
# Tracks metadata for the flutter migrate command # Tracks metadata for the flutter migrate command
migration: migration:
platforms: platforms:
- platform: root - platform: root
create_revision: 3c0bee85b8e43b860877922bdc411a7333db4d32 create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: 3c0bee85b8e43b860877922bdc411a7333db4d32 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
- platform: macos - platform: web
create_revision: 3c0bee85b8e43b860877922bdc411a7333db4d32 create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
base_revision: 3c0bee85b8e43b860877922bdc411a7333db4d32 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8
# User provided section # User provided section
# List of Local paths (relative to this file) that should be # List of Local paths (relative to this file) that should be
# ignored by the migrate tool. # ignored by the migrate tool.
# #
# Files that are not part of the templates will be ignored by default. # Files that are not part of the templates will be ignored by default.
unmanaged_files: unmanaged_files:
- 'lib/main.dart' - 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj' - 'ios/Runner.xcodeproj/project.pbxproj'

View File

@@ -1,13 +1,15 @@
<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: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">
<activity android:exported="true" android:name=".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"
android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"
android:showWhenLocked="true" android:showWhenLocked="true"
android:turnScreenOn="true"> android:turnScreenOn="true">
<meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background" />
<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>
@@ -18,16 +20,26 @@
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with https://api.filcnaplo.hu --> <!-- Accepts URIs that begin with https://api.refilcapp.hu -->
<data <data
android:scheme="https" android:scheme="https"
android:host="api.filcnaplo.hu" android:host="api.refilcapp.hu"
android:pathPrefix="/callback" /> android:pathPrefix="/v1/auth/callback" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with https://refilc.hu -->
<data
android:scheme="https"
android:host="refilc.hu"
android:pathPrefix="/app" />
</intent-filter> </intent-filter>
</activity> </activity>
<meta-data android:name="flutterEmbedding" android:value="2" /> <meta-data android:name="flutterEmbedding" android:value="2" />
<receiver android:name=".widget_timetable.WidgetTimetable" <receiver android:name="hu.refilc.naplo.widget_timetable.WidgetTimetable"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@@ -43,7 +55,7 @@
android:resource="@xml/home_widget_test_info" /> android:resource="@xml/home_widget_test_info" />
</receiver> </receiver>
<service android:name=".widget_timetable.WidgetTimetableService" <service android:name="hu.refilc.naplo.widget_timetable.WidgetTimetableService"
android:permission="android.permission.BIND_REMOTEVIEWS" /> android:permission="android.permission.BIND_REMOTEVIEWS" />
<receiver android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver" <receiver android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver"
@@ -57,14 +69,18 @@
android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" /> android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true" />
</application> </application>
<meta-data android:name="flutterEmbedding" android:value="2" />
<!-- Permissions --> <!-- Permissions -->
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" /> <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
</manifest> </manifest>

View File

@@ -1,18 +0,0 @@
package hu.refilc.naplo;
import android.os.Bundle;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.embedding.engine.FlutterEngine;
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(new FlutterEngine(this));
}
}

View File

@@ -1 +0,0 @@
../../../../../../../../../filcnaplo_premium/android/database

View File

@@ -1 +0,0 @@
../../../../../../../../../filcnaplo_premium/android/utils

View File

@@ -1 +0,0 @@
../../../../../../../../../filcnaplo_premium/android/widget_timetable

View File

@@ -0,0 +1,7 @@
package hu.refilc.naplo;
import io.flutter.embedding.android.FlutterActivity;
public class MainActivity extends FlutterActivity {
}

View File

@@ -1,119 +1,119 @@
package hu.refilc.naplo.database; package hu.refilc.naplo.database;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import java.sql.SQLException; import java.sql.SQLException;
import hu.refilc.naplo.database.SQLiteHelper; import hu.refilc.naplo.database.SQLiteHelper;
public class DBManager { public class DBManager {
private Context context; private Context context;
private SQLiteDatabase database; private SQLiteDatabase database;
private SQLiteHelper dbHelper; private SQLiteHelper dbHelper;
public DBManager(Context c) { public DBManager(Context c) {
this.context = c; this.context = c;
} }
public DBManager open() throws SQLException { public DBManager open() throws SQLException {
this.dbHelper = new SQLiteHelper(this.context); this.dbHelper = new SQLiteHelper(this.context);
this.database = this.dbHelper.getWritableDatabase(); this.database = this.dbHelper.getWritableDatabase();
return this; return this;
} }
public void close() { public void close() {
this.dbHelper.close(); this.dbHelper.close();
} }
public Cursor fetchWidget(int wid) { public Cursor fetchWidget(int wid) {
Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_WIDGETS, new String[]{SQLiteHelper._ID, SQLiteHelper.DAY_SEL}, SQLiteHelper._ID + " = " + wid, null, null, null, null); Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_WIDGETS, new String[]{SQLiteHelper._ID, SQLiteHelper.DAY_SEL}, SQLiteHelper._ID + " = " + wid, null, null, null, null);
if (cursor != null) { if (cursor != null) {
cursor.moveToFirst(); cursor.moveToFirst();
} }
return cursor; return cursor;
} }
public Cursor fetchTimetable() { public Cursor fetchTimetable() {
Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_USER_DATA, new String[]{SQLiteHelper.TIMETABLE}, null, null, null, null, null); Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_USER_DATA, new String[]{SQLiteHelper.TIMETABLE}, null, null, null, null, null);
if (cursor != null) { if (cursor != null) {
cursor.moveToFirst(); cursor.moveToFirst();
} }
return cursor; return cursor;
} }
public Cursor fetchLastUser() { public Cursor fetchLastUser() {
Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.LAST_ACCOUNT_ID}, null, null, null, null, null); Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.LAST_ACCOUNT_ID}, null, null, null, null, null);
if (cursor != null) { if (cursor != null) {
cursor.moveToFirst(); cursor.moveToFirst();
} }
return cursor; return cursor;
} }
public Cursor fetchTheme() { public Cursor fetchTheme() {
Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.THEME, SQLiteHelper.ACCENT_COLOR}, null, null, null, null, null); Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.THEME, SQLiteHelper.ACCENT_COLOR}, null, null, null, null, null);
if (cursor != null) { if (cursor != null) {
cursor.moveToFirst(); cursor.moveToFirst();
} }
return cursor; return cursor;
} }
public Cursor fetchPremiumToken() { public Cursor fetchPremiumToken() {
Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.PREMIUM_TOKEN}, null, null, null, null, null); Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.PREMIUM_TOKEN}, null, null, null, null, null);
if (cursor != null) { if (cursor != null) {
cursor.moveToFirst(); cursor.moveToFirst();
} }
return cursor; return cursor;
} }
public Cursor fetchPremiumScopes() { public Cursor fetchPremiumScopes() {
Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.PREMIUM_SCOPES}, null, null, null, null, null); Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.PREMIUM_SCOPES}, null, null, null, null, null);
if (cursor != null) { if (cursor != null) {
cursor.moveToFirst(); cursor.moveToFirst();
} }
return cursor; return cursor;
} }
public Cursor fetchLocale() { public Cursor fetchLocale() {
Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.LOCALE}, null, null, null, null, null); Cursor cursor = this.database.query(SQLiteHelper.TABLE_NAME_SETTINGS, new String[]{SQLiteHelper.LOCALE}, null, null, null, null, null);
if (cursor != null) { if (cursor != null) {
cursor.moveToFirst(); cursor.moveToFirst();
} }
return cursor; return cursor;
} }
public void deleteWidget(int _id) { public void deleteWidget(int _id) {
this.database.delete(SQLiteHelper.TABLE_NAME_WIDGETS, "_id=" + _id, null); this.database.delete(SQLiteHelper.TABLE_NAME_WIDGETS, "_id=" + _id, null);
} }
/*public void changeSettings(int _id, Map<String, String> map) { /*public void changeSettings(int _id, Map<String, String> map) {
ContentValues con = new ContentValues(); ContentValues con = new ContentValues();
for(Map.Entry<String, String> e: map.entrySet()){ for(Map.Entry<String, String> e: map.entrySet()){
con.put(e.getKey(), e.getValue()); con.put(e.getKey(), e.getValue());
} }
this.database.update(SQLiteHelper.TABLE_NAME_WIDGETS, con, "_id = " + _id, null); this.database.update(SQLiteHelper.TABLE_NAME_WIDGETS, con, "_id = " + _id, null);
} }
public void insertSettings(int _id, Map<String, String> map) { public void insertSettings(int _id, Map<String, String> map) {
ContentValues con = new ContentValues(); ContentValues con = new ContentValues();
for(Map.Entry<String, String> e: map.entrySet()){ for(Map.Entry<String, String> e: map.entrySet()){
con.put(e.getKey(), e.getValue()); con.put(e.getKey(), e.getValue());
//Log.d("Settings added", e.getKey() + " - " + e.getValue()); //Log.d("Settings added", e.getKey() + " - " + e.getValue());
} }
this.database.insert(SQLiteHelper.TABLE_NAME_WIDGETS, null, con); this.database.insert(SQLiteHelper.TABLE_NAME_WIDGETS, null, con);
}*/ }*/
public void insertSelDay(int _id, int day_sel) { public void insertSelDay(int _id, int day_sel) {
ContentValues con = new ContentValues(); ContentValues con = new ContentValues();
con.put(SQLiteHelper._ID, _id); con.put(SQLiteHelper._ID, _id);
con.put(SQLiteHelper.DAY_SEL, day_sel); con.put(SQLiteHelper.DAY_SEL, day_sel);
this.database.insert(SQLiteHelper.TABLE_NAME_WIDGETS, null, con); this.database.insert(SQLiteHelper.TABLE_NAME_WIDGETS, null, con);
} }
public int update(int _id, int day_sel) { public int update(int _id, int day_sel) {
ContentValues con = new ContentValues(); ContentValues con = new ContentValues();
con.put(SQLiteHelper.DAY_SEL, day_sel); con.put(SQLiteHelper.DAY_SEL, day_sel);
return this.database.update(SQLiteHelper.TABLE_NAME_WIDGETS, con, SQLiteHelper._ID + " = " + _id, null); return this.database.update(SQLiteHelper.TABLE_NAME_WIDGETS, con, SQLiteHelper._ID + " = " + _id, null);
} }
} }

View File

@@ -1,36 +1,36 @@
package hu.refilc.naplo.database; package hu.refilc.naplo.database;
import android.content.Context; import android.content.Context;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteOpenHelper;
public class SQLiteHelper extends SQLiteOpenHelper { public class SQLiteHelper extends SQLiteOpenHelper {
private static final String CREATE_TABLE_WIDGET = " create table widgets ( _id INTEGER NOT NULL, day_sel INTEGER NOT NULL);"; private static final String CREATE_TABLE_WIDGET = " create table widgets ( _id INTEGER NOT NULL, day_sel INTEGER NOT NULL);";
private static final String DB_NAME = "app.db"; private static final String DB_NAME = "app.db";
private static final int DB_VERSION = 1; private static final int DB_VERSION = 1;
public static final String _ID = "_id"; public static final String _ID = "_id";
public static final String DAY_SEL = "day_sel"; public static final String DAY_SEL = "day_sel";
public static final String TIMETABLE = "timetable"; public static final String TIMETABLE = "timetable";
public static final String LAST_ACCOUNT_ID = "last_account_id"; public static final String LAST_ACCOUNT_ID = "last_account_id";
public static final String THEME = "theme"; public static final String THEME = "theme";
public static final String PREMIUM_TOKEN = "premium_token"; public static final String PREMIUM_TOKEN = "premium_token";
public static final String PREMIUM_SCOPES = "premium_scopes"; public static final String PREMIUM_SCOPES = "premium_scopes";
public static final String LOCALE = "language"; public static final String LOCALE = "language";
public static final String ACCENT_COLOR = "accent_color"; public static final String ACCENT_COLOR = "accent_color";
public static final String TABLE_NAME_WIDGETS = "widgets"; public static final String TABLE_NAME_WIDGETS = "widgets";
public static final String TABLE_NAME_USER_DATA = "user_data"; public static final String TABLE_NAME_USER_DATA = "user_data";
public static final String TABLE_NAME_SETTINGS = "settings"; public static final String TABLE_NAME_SETTINGS = "settings";
public SQLiteHelper(Context context) { public SQLiteHelper(Context context) {
super(context, DB_NAME, null, 7); super(context, DB_NAME, null, 7);
} }
public void onCreate(SQLiteDatabase db) { public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE_WIDGET); db.execSQL(CREATE_TABLE_WIDGET);
} }
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS widgets"); db.execSQL("DROP TABLE IF EXISTS widgets");
onCreate(db); onCreate(db);
} }
} }

View File

@@ -1,36 +1,36 @@
package hu.refilc.naplo.utils; package hu.refilc.naplo.utils;
import android.content.Context; import android.content.Context;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
public class Utils { public class Utils {
public static boolean hasNetwork(Context context) { public static boolean hasNetwork(Context context) {
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo(); NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) { if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true; return true;
} }
return false; return false;
} }
public static Date getWeekStartDate() { public static Date getWeekStartDate() {
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) { while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
calendar.add(Calendar.DATE, -1); calendar.add(Calendar.DATE, -1);
} }
return calendar.getTime(); return calendar.getTime();
} }
public static Date getWeekEndDate() { public static Date getWeekEndDate() {
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) { while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
calendar.add(Calendar.DATE, 1); calendar.add(Calendar.DATE, 1);
} }
calendar.add(Calendar.DATE, -1); calendar.add(Calendar.DATE, -1);
return calendar.getTime(); return calendar.getTime();
} }
} }

View File

@@ -1,65 +1,65 @@
package hu.refilc.naplo.utils; package hu.refilc.naplo.utils;
import java.time.DayOfWeek; import java.time.DayOfWeek;
import java.time.Duration; import java.time.Duration;
import java.time.LocalDate; import java.time.LocalDate;
public class Week { public class Week {
private final LocalDate start; private final LocalDate start;
private final LocalDate end; private final LocalDate end;
private Week(LocalDate start, LocalDate end) { private Week(LocalDate start, LocalDate end) {
this.start = start; this.start = start;
this.end = end; this.end = end;
} }
public static Week current() { public static Week current() {
return fromDate(LocalDate.now()); return fromDate(LocalDate.now());
} }
public static Week fromId(int id) { public static Week fromId(int id) {
LocalDate _now = getYearStart().plusDays(id * 7L); LocalDate _now = getYearStart().plusDays(id * 7L);
return new Week(_now.minusDays(_now.getDayOfWeek().getValue() - 1), _now.plusDays(7 - _now.getDayOfWeek().getValue())); return new Week(_now.minusDays(_now.getDayOfWeek().getValue() - 1), _now.plusDays(7 - _now.getDayOfWeek().getValue()));
} }
public static Week fromDate(LocalDate date) { public static Week fromDate(LocalDate date) {
return new Week(date.minusDays(date.getDayOfWeek().getValue() - 1), date.plusDays(7 - date.getDayOfWeek().getValue())); return new Week(date.minusDays(date.getDayOfWeek().getValue() - 1), date.plusDays(7 - date.getDayOfWeek().getValue()));
} }
public Week next() { public Week next() {
return Week.fromDate(start.plusDays(8)); return Week.fromDate(start.plusDays(8));
} }
public int id() { public int id() {
return (int) Math.ceil(Duration.between(getYearStart().atStartOfDay(), start.atStartOfDay()).toDays() / 7f); return (int) Math.ceil(Duration.between(getYearStart().atStartOfDay(), start.atStartOfDay()).toDays() / 7f);
} }
private static LocalDate getYearStart() { private static LocalDate getYearStart() {
LocalDate now = LocalDate.now(); LocalDate now = LocalDate.now();
LocalDate start = getYearStart(now.getYear()); LocalDate start = getYearStart(now.getYear());
return start.isBefore(now) ? start : getYearStart(now.getYear() -1); return start.isBefore(now) ? start : getYearStart(now.getYear() -1);
} }
private static LocalDate getYearStart(int year) { private static LocalDate getYearStart(int year) {
LocalDate time = LocalDate.of(year, 9, 1); LocalDate time = LocalDate.of(year, 9, 1);
if (time.getDayOfWeek() == DayOfWeek.SATURDAY) if (time.getDayOfWeek() == DayOfWeek.SATURDAY)
return time.plusDays(2); return time.plusDays(2);
else if (time.getDayOfWeek() == DayOfWeek.SUNDAY) else if (time.getDayOfWeek() == DayOfWeek.SUNDAY)
return time.plusDays(1); return time.plusDays(1);
return time; return time;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; if (o == null || getClass() != o.getClass()) return false;
Week week = (Week) o; Week week = (Week) o;
return this.id() == week.id(); return this.id() == week.id();
} }
@Override @Override
public int hashCode() { public int hashCode() {
return id(); return id();
} }
} }

View File

@@ -1,397 +1,392 @@
package hu.refilc.naplo.widget_timetable; package hu.refilc.naplo.widget_timetable;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider; import android.appwidget.AppWidgetProvider;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import android.widget.Toast; import android.widget.Toast;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.time.DayOfWeek; import java.time.DayOfWeek;
import java.time.format.TextStyle; import java.time.format.TextStyle;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import hu.refilc.naplo.database.DBManager; import java.util.HashMap;
import hu.refilc.naplo.MainActivity; import java.text.ParseException;
import hu.refilc.naplo.R; import java.text.SimpleDateFormat;
import java.util.Date;
import hu.refilc.naplo.utils.Week;
import hu.refilc.naplo.database.DBManager;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT; import hu.refilc.naplo.MainActivity;
import hu.refilc.naplo.R;
import es.antonborri.home_widget.HomeWidgetBackgroundIntent;
import es.antonborri.home_widget.HomeWidgetLaunchIntent; import hu.refilc.naplo.utils.Week;
import es.antonborri.home_widget.HomeWidgetProvider;
import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
public class WidgetTimetable extends HomeWidgetProvider {
import es.antonborri.home_widget.HomeWidgetBackgroundIntent;
private static final String ACTION_WIDGET_CLICK_NAV_LEFT = "list_widget.ACTION_WIDGET_CLICK_NAV_LEFT"; import es.antonborri.home_widget.HomeWidgetLaunchIntent;
private static final String ACTION_WIDGET_CLICK_NAV_RIGHT = "list_widget.ACTION_WIDGET_CLICK_NAV_RIGHT"; import es.antonborri.home_widget.HomeWidgetProvider;
private static final String ACTION_WIDGET_CLICK_NAV_TODAY = "list_widget.ACTION_WIDGET_CLICK_NAV_TODAY";
private static final String ACTION_WIDGET_CLICK_NAV_REFRESH = "list_widget.ACTION_WIDGET_CLICK_NAV_REFRESH"; public class WidgetTimetable extends HomeWidgetProvider {
private static final String ACTION_WIDGET_CLICK_BUY_PREMIUM = "list_widget.ACTION_WIDGET_CLICK_BUY_PREMIUM";
private static final String ACTION_WIDGET_CLICK_NAV_LEFT = "list_widget.ACTION_WIDGET_CLICK_NAV_LEFT";
@Override private static final String ACTION_WIDGET_CLICK_NAV_RIGHT = "list_widget.ACTION_WIDGET_CLICK_NAV_RIGHT";
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, SharedPreferences widgetData) { private static final String ACTION_WIDGET_CLICK_NAV_TODAY = "list_widget.ACTION_WIDGET_CLICK_NAV_TODAY";
for (int i = 0; i < appWidgetIds.length; i++) { private static final String ACTION_WIDGET_CLICK_NAV_REFRESH = "list_widget.ACTION_WIDGET_CLICK_NAV_REFRESH";
RemoteViews views = generateView(context, appWidgetIds[i]); private static final String ACTION_WIDGET_CLICK_BUY_PREMIUM = "list_widget.ACTION_WIDGET_CLICK_BUY_PREMIUM";
if(premiumEnabled(context) && userLoggedIn(context)) { @Override
int rday = selectDay(context, appWidgetIds[i], 0, true); public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, SharedPreferences widgetData) {
views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday)); for (int i = 0; i < appWidgetIds.length; i++) {
} RemoteViews views = generateView(context, appWidgetIds[i]);
pushUpdate(context, views, appWidgetIds[i]); if(premiumEnabled(context) && userLoggedIn(context)) {
} int rday = selectDay(context, appWidgetIds[i], 0, true);
} views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday));
}
public static void pushUpdate(Context context, RemoteViews remoteViews, int appWidgetSingleId) {
AppWidgetManager manager = AppWidgetManager.getInstance(context); pushUpdate(context, views, appWidgetIds[i]);
}
manager.updateAppWidget(appWidgetSingleId, remoteViews); }
manager.notifyAppWidgetViewDataChanged(appWidgetSingleId, R.id.widget_list);
} public static void pushUpdate(Context context, RemoteViews remoteViews, int appWidgetSingleId) {
AppWidgetManager manager = AppWidgetManager.getInstance(context);
public static RemoteViews generateView(Context context, int appId) {
Intent serviceIntent = new Intent(context, WidgetTimetableService.class); manager.updateAppWidget(appWidgetSingleId, remoteViews);
serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appId); manager.notifyAppWidgetViewDataChanged(appWidgetSingleId, R.id.widget_list);
serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME))); }
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_timetable); public static RemoteViews generateView(Context context, int appId) {
Intent serviceIntent = new Intent(context, WidgetTimetableService.class);
views.setViewVisibility(R.id.need_premium, View.GONE); serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appId);
views.setViewVisibility(R.id.need_login, View.GONE); serviceIntent.setData(Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)));
views.setViewVisibility(R.id.tt_grid_cont, View.GONE);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_timetable);
if(!userLoggedIn(context)) {
views.setViewVisibility(R.id.need_login, View.VISIBLE); views.setViewVisibility(R.id.need_premium, View.GONE);
views.setOnClickPendingIntent(R.id.open_login, makePending(context, ACTION_WIDGET_CLICK_BUY_PREMIUM, appId)); views.setViewVisibility(R.id.need_login, View.GONE);
} else if(premiumEnabled(context)) { views.setViewVisibility(R.id.tt_grid_cont, View.GONE);
views.setViewVisibility(R.id.tt_grid_cont, View.VISIBLE);
views.setOnClickPendingIntent(R.id.nav_to_left, makePending(context, ACTION_WIDGET_CLICK_NAV_LEFT, appId)); if(!userLoggedIn(context)) {
views.setOnClickPendingIntent(R.id.nav_to_right, makePending(context, ACTION_WIDGET_CLICK_NAV_RIGHT, appId)); views.setViewVisibility(R.id.need_login, View.VISIBLE);
views.setOnClickPendingIntent(R.id.nav_current, makePending(context, ACTION_WIDGET_CLICK_NAV_TODAY, appId)); views.setOnClickPendingIntent(R.id.open_login, makePending(context, ACTION_WIDGET_CLICK_BUY_PREMIUM, appId));
views.setOnClickPendingIntent(R.id.nav_refresh, makePending(context, ACTION_WIDGET_CLICK_NAV_REFRESH, appId)); } else if(premiumEnabled(context)) {
views.setRemoteAdapter(R.id.widget_list, serviceIntent); views.setViewVisibility(R.id.tt_grid_cont, View.VISIBLE);
views.setEmptyView(R.id.widget_list, R.id.empty_view); views.setOnClickPendingIntent(R.id.nav_to_left, makePending(context, ACTION_WIDGET_CLICK_NAV_LEFT, appId));
} else { views.setOnClickPendingIntent(R.id.nav_to_right, makePending(context, ACTION_WIDGET_CLICK_NAV_RIGHT, appId));
views.setViewVisibility(R.id.need_premium, View.VISIBLE); views.setOnClickPendingIntent(R.id.nav_current, makePending(context, ACTION_WIDGET_CLICK_NAV_TODAY, appId));
views.setOnClickPendingIntent(R.id.buy_premium, makePending(context, ACTION_WIDGET_CLICK_BUY_PREMIUM, appId)); views.setOnClickPendingIntent(R.id.nav_refresh, makePending(context, ACTION_WIDGET_CLICK_NAV_REFRESH, appId));
} views.setRemoteAdapter(R.id.widget_list, serviceIntent);
views.setEmptyView(R.id.widget_list, R.id.empty_view);
return views; } else {
} views.setViewVisibility(R.id.need_premium, View.VISIBLE);
views.setOnClickPendingIntent(R.id.buy_premium, makePending(context, ACTION_WIDGET_CLICK_BUY_PREMIUM, appId));
static PendingIntent makePending(Context context, String action, int appWidgetId) { }
Intent activebtnnext = new Intent(context, WidgetTimetable.class);
activebtnnext.setAction(action); return views;
activebtnnext.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); }
return PendingIntent.getBroadcast(context, appWidgetId, activebtnnext , PendingIntent.FLAG_IMMUTABLE);
} static PendingIntent makePending(Context context, String action, int appWidgetId) {
Intent activebtnnext = new Intent(context, WidgetTimetable.class);
@Override activebtnnext.setAction(action);
public void onReceive(Context context, Intent intent) { activebtnnext.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
super.onReceive(context, intent); return PendingIntent.getBroadcast(context, appWidgetId, activebtnnext , PendingIntent.FLAG_IMMUTABLE);
}
if(intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
int appId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); @Override
RemoteViews views = generateView(context, appId); public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
try {
if(premiumEnabled(context) && userLoggedIn(context)) { if(intent.hasExtra(AppWidgetManager.EXTRA_APPWIDGET_ID)) {
if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_LEFT)) { int appId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
int rday = selectDay(context, appId, -1, false); RemoteViews views = generateView(context, appId);
views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday));
try {
pushUpdate(context, views, appId); if(premiumEnabled(context) && userLoggedIn(context)) {
} else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_RIGHT)) { if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_LEFT)) {
int rday = selectDay(context, appId, 1, false); int rday = selectDay(context, appId, -1, false);
views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday)); views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday));
pushUpdate(context, views, appId); pushUpdate(context, views, appId);
} else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_TODAY)) { } else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_RIGHT)) {
int rday = getToday(context); int rday = selectDay(context, appId, 1, false);
setSelectedDay(context, appId, rday); views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday));
views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday)); pushUpdate(context, views, appId);
} else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_TODAY)) {
pushUpdate(context, views, appId); int rday = getToday(context);
} else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_REFRESH)) { setSelectedDay(context, appId, rday);
PendingIntent pendingIntent = HomeWidgetLaunchIntent.INSTANCE.getActivity(context, MainActivity.class, Uri.parse("timetable://refresh"));
pendingIntent.send(); views.setTextViewText(R.id.nav_current, convertDayOfWeek(context, rday));
} else if (intent.getAction().equals("android.appwidget.action.APPWIDGET_DELETED")) {
DBManager dbManager = new DBManager(context.getApplicationContext()); pushUpdate(context, views, appId);
} else if (intent.getAction().equals(ACTION_WIDGET_CLICK_NAV_REFRESH)) {
try { PendingIntent pendingIntent = HomeWidgetLaunchIntent.INSTANCE.getActivity(context, MainActivity.class, Uri.parse("timetable://refresh"));
dbManager.open(); pendingIntent.send();
dbManager.deleteWidget(appId); } else if (intent.getAction().equals("android.appwidget.action.APPWIDGET_DELETED")) {
dbManager.close(); DBManager dbManager = new DBManager(context.getApplicationContext());
} catch (Exception e) {
e.printStackTrace(); try {
} dbManager.open();
} dbManager.deleteWidget(appId);
} dbManager.close();
} catch (Exception e) {
if(intent.getAction().equals(ACTION_WIDGET_CLICK_BUY_PREMIUM)) { e.printStackTrace();
PendingIntent pendingIntent = HomeWidgetLaunchIntent.INSTANCE.getActivity(context, MainActivity.class, Uri.parse("settings://premium")); }
pendingIntent.send(); }
} }
}
catch (Exception e) { if(intent.getAction().equals(ACTION_WIDGET_CLICK_BUY_PREMIUM)) {
e.printStackTrace(); PendingIntent pendingIntent = HomeWidgetLaunchIntent.INSTANCE.getActivity(context, MainActivity.class, Uri.parse("settings://premium"));
} pendingIntent.send();
} }
} }
catch (Exception e) {
public static String convertDayOfWeek(Context context, int rday) { e.printStackTrace();
}
/*if(rday == -1) return DayOfWeek.of(1).getDisplayName(TextStyle.FULL, new Locale("hu", "HU")); }
}
String dayOfWeek = DayOfWeek.of(rday + 1).getDisplayName(TextStyle.FULL, new Locale("hu", "HU"));*/
public static String convertDayOfWeek(Context context, int rday) {
String dayOfWeek = "Unknown";
/*if(rday == -1) return DayOfWeek.of(1).getDisplayName(TextStyle.FULL, new Locale("hu", "HU"));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Locale loc = getLocale(context); String dayOfWeek = DayOfWeek.of(rday + 1).getDisplayName(TextStyle.FULL, new Locale("hu", "HU"));*/
if (rday == -1) String dayOfWeek = "Unknown";
return DayOfWeek.of(1).getDisplayName(TextStyle.FULL, loc);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
dayOfWeek = DayOfWeek.of(rday + 1).getDisplayName(TextStyle.FULL, loc); Locale loc = getLocale(context);
}
if (rday == -1)
return dayOfWeek.substring(0, 1).toUpperCase() + dayOfWeek.substring(1).toLowerCase(); return DayOfWeek.of(1).getDisplayName(TextStyle.FULL, loc);
}
dayOfWeek = DayOfWeek.of(rday + 1).getDisplayName(TextStyle.FULL, loc);
public static void setSelectedDay(Context context, int wid, int day) { }
DBManager dbManager = new DBManager(context.getApplicationContext());
return dayOfWeek.substring(0, 1).toUpperCase() + dayOfWeek.substring(1).toLowerCase();
try { }
dbManager.open();
dbManager.update(wid, day); public static void setSelectedDay(Context context, int wid, int day) {
dbManager.close(); DBManager dbManager = new DBManager(context.getApplicationContext());
} catch (Exception e) {
e.printStackTrace(); try {
} dbManager.open();
} dbManager.update(wid, day);
dbManager.close();
public static int getToday(Context context) { } catch (Exception e) {
int rday = new DateTime().getDayOfWeek() - 1; e.printStackTrace();
List<JSONArray> s = genJsonDays(context); }
}
try {
if(checkIsAfter(s, rday)) rday += 1; public static int getToday(Context context) {
} catch (Exception e) { int rday = new DateTime().getDayOfWeek() - 1;
e.printStackTrace(); List<JSONArray> s = genJsonDays(context);
}
return retDay(rday, s.size()); try {
} if(checkIsAfter(s, rday)) rday += 1;
} catch (Exception e) {
public static int selectDay(Context context, int wid, int add, Boolean afterSubjects) { e.printStackTrace();
DBManager dbManager = new DBManager(context.getApplicationContext()); }
return retDay(rday, s.size());
try { }
dbManager.open();
Cursor cursor = dbManager.fetchWidget(wid); public static int selectDay(Context context, int wid, int add, Boolean afterSubjects) {
DBManager dbManager = new DBManager(context.getApplicationContext());
List<JSONArray> s = genJsonDays(context);
int retday = new DateTime().getDayOfWeek() - 1; try {
dbManager.open();
if(cursor.getCount() != 0) retday = retDay(cursor.getInt(1) + add, s.size()); Cursor cursor = dbManager.fetchWidget(wid);
if(afterSubjects) if(checkIsAfter(s, retday)) retday += 1; List<JSONArray> s = genJsonDays(context);
retday = retDay(retday, s.size()); int retday = new DateTime().getDayOfWeek() - 1;
if(cursor.getCount() == 0) dbManager.insertSelDay(wid, retday); if(cursor.getCount() != 0) retday = retDay(cursor.getInt(1) + add, s.size());
else dbManager.update(wid, retday);
if(afterSubjects) if(checkIsAfter(s, retday)) retday += 1;
dbManager.close(); retday = retDay(retday, s.size());
return retday; if(cursor.getCount() == 0) dbManager.insertSelDay(wid, retday);
} catch (Exception e) { else dbManager.update(wid, retday);
e.printStackTrace();
} dbManager.close();
return 0; return retday;
} } catch (Exception e) {
e.printStackTrace();
public static Boolean checkIsAfter(List<JSONArray> s, int retday) throws Exception { }
retday = retDay(retday, s.size());
return 0;
String vegIdopont = s.get(retday).getJSONObject(s.get(retday).length() - 1).getString("VegIdopont"); }
return new DateTime().isAfter(new DateTime(vegIdopont)); public static Boolean checkIsAfter(List<JSONArray> s, int retday) throws Exception {
} retday = retDay(retday, s.size());
public static int retDay(int retday, int size) { String vegIdopont = s.get(retday).getJSONObject(s.get(retday).length() - 1).getString("VegIdopont");
if (retday < 0) retday = size - 1;
else if (retday > size - 1) retday = 0; return new DateTime().isAfter(new DateTime(vegIdopont));
}
return retday;
} public static int retDay(int retday, int size) {
if (retday < 0) retday = size - 1;
public static List<JSONArray> genJsonDays(Context context) { else if (retday > size - 1) retday = 0;
List<JSONArray> gen_days = new ArrayList<>();
return retday;
DBManager dbManager = new DBManager(context.getApplicationContext()); }
try {
dbManager.open(); public static List<JSONArray> genJsonDays(Context context) {
Cursor ct = dbManager.fetchTimetable(); List<JSONArray> genDays = new ArrayList<>();
dbManager.close(); Map<String, JSONArray> dayMap = new HashMap<>();
if(ct.getCount() == 0) { DBManager dbManager = new DBManager(context.getApplicationContext());
return gen_days;
} try {
dbManager.open();
JSONObject fecthtt = new JSONObject(ct.getString(0)); Cursor ct = dbManager.fetchTimetable();
JSONArray dayArray = new JSONArray(); if (ct.getCount() == 0) {
String currday = ""; return genDays;
}
String currweek = String.valueOf(Week.current().id());
JSONObject fetchedTimetable = new JSONObject(ct.getString(0));
JSONArray week = fecthtt.getJSONArray(currweek); String currentWeek = String.valueOf(Week.current().id());
JSONArray week = fetchedTimetable.getJSONArray(currentWeek);
for (int i=0; i < week.length(); i++)
{ // Organize lessons into dates
try { for (int i = 0; i < week.length(); i++) {
if(i == 0) currday = week.getJSONObject(0).getString("Datum"); try {
JSONObject oraObj = week.getJSONObject(i); JSONObject entry = week.getJSONObject(i);
String date = entry.getString("Datum");
if(!currday.equals(oraObj.getString("Datum"))) { dayMap.computeIfAbsent(date, k -> new JSONArray()).put(entry);
gen_days.add(dayArray); } catch (JSONException e) {
currday = week.getJSONObject(i).getString("Datum"); e.printStackTrace();
dayArray = new JSONArray(); }
} }
dayArray.put(oraObj); genDays.addAll(dayMap.values());
if(i == week.length() - 1) {
gen_days.add(dayArray); // Sort the 'genDays' list of JSON based on the start time of the first entry
} genDays.sort((day1, day2) -> {
} catch (Exception e) { try {
e.printStackTrace(); // Extract the start time of the first entry in each day's JSON
} String startTime1 = day1.getJSONObject(0).getString("KezdetIdopont");
} String startTime2 = day2.getJSONObject(0).getString("KezdetIdopont");
} catch (Exception e) { // Compare the start times and return the result for sorting
e.printStackTrace(); return startTime1.compareTo(startTime2);
} } catch (JSONException e) {
e.printStackTrace();
Collections.sort(gen_days, new Comparator<JSONArray>() { return 0;
}
public int compare(JSONArray a, JSONArray b) { });
long valA = 0;
long valB = 0; } catch (Exception e) {
e.printStackTrace();
try { } finally {
valA = (long) new DateTime( a.getJSONObject(0).getString("Datum")).getMillis(); dbManager.close();
valB = (long) new DateTime( b.getJSONObject(0).getString("Datum")).getMillis(); }
}
catch (JSONException ignored) { return genDays;
} }
return (int) (valA - valB);
}
}); public static String zeroPad(int value, int padding){
StringBuilder b = new StringBuilder();
return gen_days; b.append(value);
} while(b.length() < padding){
b.insert(0,"0");
public static String zeroPad(int value, int padding){ }
StringBuilder b = new StringBuilder(); return b.toString();
b.append(value); }
while(b.length() < padding){
b.insert(0,"0"); public static Locale getLocale(Context context) {
} DBManager dbManager = new DBManager(context.getApplicationContext());
return b.toString();
} try {
dbManager.open();
public static Locale getLocale(Context context) { String loc = dbManager.fetchLocale().getString(0);
DBManager dbManager = new DBManager(context.getApplicationContext()); dbManager.close();
try { if(loc.equals("hu") || loc.equals("de")) {
dbManager.open(); return new Locale(loc, loc.toUpperCase());
String loc = dbManager.fetchLocale().getString(0); }
dbManager.close(); } catch (Exception e) {
e.printStackTrace();
if(loc.equals("hu") || loc.equals("de")) { }
return new Locale(loc, loc.toUpperCase());
} return new Locale("en", "GB");
} catch (Exception e) { }
e.printStackTrace();
} public static boolean premiumEnabled(Context context) {
DBManager dbManager = new DBManager(context.getApplicationContext());
return new Locale("en", "GB");
} try {
dbManager.open();
public static boolean premiumEnabled(Context context) { String premium_token = dbManager.fetchPremiumToken().getString(0);
DBManager dbManager = new DBManager(context.getApplicationContext()); String premium_scopes_raw = dbManager.fetchPremiumScopes().getString(0);
dbManager.close();
try {
dbManager.open(); JSONArray arr = new JSONArray(premium_scopes_raw);
String premium_token = dbManager.fetchPremiumToken().getString(0); List<String> premium_scopes = new ArrayList<>();
String premium_scopes_raw = dbManager.fetchPremiumScopes().getString(0); for(int i = 0; i < arr.length(); i++){
dbManager.close(); String scope = arr.getString(i);
premium_scopes.add(scope.substring(scope.lastIndexOf('.') + 1));
JSONArray arr = new JSONArray(premium_scopes_raw); }
List<String> premium_scopes = new ArrayList<>();
for(int i = 0; i < arr.length(); i++){ if(!premium_token.equals("") && (premium_scopes.contains("*") || premium_scopes.contains("TIMETALBE_WIDGET"))) {
String scope = arr.getString(i); return true;
premium_scopes.add(scope.substring(scope.lastIndexOf('.') + 1)); }
} } catch (Exception e) {
e.printStackTrace();
if(!premium_token.equals("") && (premium_scopes.contains("*") || premium_scopes.contains("TIMETALBE_WIDGET"))) { }
return true;
} return false;
} catch (Exception e) { }
e.printStackTrace();
} public static boolean userLoggedIn(Context context) {
return !lastUserId(context).equals("");
return false; }
}
public static String lastUserId(Context context) {
public static boolean userLoggedIn(Context context) { DBManager dbManager = new DBManager(context.getApplicationContext());
return !lastUserId(context).equals(""); try {
} dbManager.open();
Cursor cursor = dbManager.fetchLastUser();
public static String lastUserId(Context context) { dbManager.close();
DBManager dbManager = new DBManager(context.getApplicationContext());
try { if(cursor != null && !cursor.getString(0).equals("")) {
dbManager.open(); String last_user = cursor.getString(0);
Cursor cursor = dbManager.fetchLastUser(); return last_user;
dbManager.close(); }
} catch (Exception e) {
if(cursor != null && !cursor.getString(0).equals("")) { e.printStackTrace();
String last_user = cursor.getString(0); }
return last_user;
} return "";
} catch (Exception e) { }
e.printStackTrace();
} @Override
public void onEnabled(Context context) {
return ""; }
}
@Override
@Override public void onDisabled(Context context) {
public void onEnabled(Context context) { }
}
@Override
public void onDisabled(Context context) {
}
} }

View File

@@ -1,354 +1,356 @@
package hu.refilc.naplo.widget_timetable; package hu.refilc.naplo.widget_timetable;
import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.os.Build; import android.os.Build;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import android.widget.RemoteViewsService; import android.widget.RemoteViewsService;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import hu.refilc.naplo.database.DBManager; import hu.refilc.naplo.database.DBManager;
import hu.refilc.naplo.R; import hu.refilc.naplo.R;
public class WidgetTimetableDataProvider implements RemoteViewsService.RemoteViewsFactory { public class WidgetTimetableDataProvider implements RemoteViewsService.RemoteViewsFactory {
private Context context; private Context context;
private int appWidgetId; private int appWidgetId;
private int rday = 0; private int rday = 0;
private int theme; private int theme;
private Integer[] colorValues; private Integer[] colorValues;
List<Lesson> day_subjects = new ArrayList<>(); List<Lesson> day_subjects = new ArrayList<>();
List<Integer> lessonIndexes = new ArrayList<>(); List<Integer> lessonIndexes = new ArrayList<>();
Item witem; Item witem;
/* Default values */ /* Default values */
static class Item { static class Item {
int Layout; int Layout;
int NumVisibility; int NumVisibility;
int NameVisibility; int NameVisibility;
int NameNodescVisibility; int NameNodescVisibility;
int DescVisibility; int DescVisibility;
int RoomVisibility; int RoomVisibility;
int TimeVisibility; int TimeVisibility;
int NumColor; int NumColor;
int NameColor; int NameColor;
int NameNodescColor; int NameNodescColor;
int DescColor; int DescColor;
Integer[] NameNodescPadding = {0, 0, 0, 0}; Integer[] NameNodescPadding = {0, 0, 0, 0};
public Item(int Layout, int NumVisibility,int NameVisibility,int NameNodescVisibility,int DescVisibility,int RoomVisibility,int TimeVisibility,int NumColor,int NameColor,int NameNodescColor,int DescColor) { public Item(int Layout, int NumVisibility,int NameVisibility,int NameNodescVisibility,int DescVisibility,int RoomVisibility,int TimeVisibility,int NumColor,int NameColor,int NameNodescColor,int DescColor) {
this.Layout = Layout; this.Layout = Layout;
this.NumVisibility = NumVisibility; this.NumVisibility = NumVisibility;
this.NameVisibility = NameVisibility; this.NameVisibility = NameVisibility;
this.NameNodescVisibility = NameNodescVisibility; this.NameNodescVisibility = NameNodescVisibility;
this.DescVisibility = DescVisibility; this.DescVisibility = DescVisibility;
this.RoomVisibility = RoomVisibility; this.RoomVisibility = RoomVisibility;
this.TimeVisibility = TimeVisibility; this.TimeVisibility = TimeVisibility;
this.NumColor = NumColor; this.NumColor = NumColor;
this.NameColor = NameColor; this.NameColor = NameColor;
this.NameNodescColor = NameNodescColor; this.NameNodescColor = NameNodescColor;
this.DescColor = DescColor; this.DescColor = DescColor;
} }
} }
static class Lesson { static class Lesson {
String status; String status;
String lessonIndex; String lessonIndex;
String lessonName; String lessonName;
String lessonTopic; String lessonTopic;
String lessonRoom; String lessonRoom;
long lessonStart; long lessonStart;
long lessonEnd; long lessonEnd;
String substituteTeacher; String substituteTeacher;
public Lesson(String status, String lessonIndex,String lessonName,String lessonTopic, String lessonRoom,long lessonStart,long lessonEnd,String substituteTeacher) { public Lesson(String status, String lessonIndex,String lessonName,String lessonTopic, String lessonRoom,long lessonStart,long lessonEnd,String substituteTeacher) {
this.status = status; this.status = status;
this.lessonIndex = lessonIndex; this.lessonIndex = lessonIndex;
this.lessonName = lessonName; this.lessonName = lessonName;
this.lessonTopic = lessonTopic; this.lessonTopic = lessonTopic;
this.lessonRoom = lessonRoom; this.lessonRoom = lessonRoom;
this.lessonStart = lessonStart; this.lessonStart = lessonStart;
this.lessonEnd = lessonEnd; this.lessonEnd = lessonEnd;
this.substituteTeacher = substituteTeacher; this.substituteTeacher = substituteTeacher;
} }
} }
Integer[] itemNameNodescPadding = {0, 0, 0, 0}; Integer[] itemNameNodescPadding = {0, 0, 0, 0};
public WidgetTimetableDataProvider(Context context, Intent intent) { public WidgetTimetableDataProvider(Context context, Intent intent) {
this.context = context; this.context = context;
this.appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); this.appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
this.theme = getThemeAccent(context); this.theme = getThemeAccent(context);
this.colorValues = new Integer[]{R.color.filc, this.colorValues = new Integer[]{R.color.filc,
R.color.blue_shade300, R.color.blue_shade300,
R.color.green_shade300, R.color.green_shade300,
R.color.lime_shade300, R.color.lime_shade300,
R.color.yellow_shade300, R.color.yellow_shade300,
R.color.orange_shade300, R.color.orange_shade300,
R.color.red_shade300, R.color.red_shade300,
R.color.pink_shade300, R.color.pink_shade300,
R.color.purple_shade300}; R.color.purple_shade300};
} }
@Override @Override
public void onCreate() { public void onCreate() {
initData(); initData();
} }
@Override @Override
public void onDataSetChanged() { public void onDataSetChanged() {
initData(); initData();
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
} }
@Override @Override
public int getCount() { public int getCount() {
return day_subjects.size(); return day_subjects.size();
} }
public void setLayout(final RemoteViews view) { public void setLayout(final RemoteViews view) {
/* Visibilities */ /* Visibilities */
view.setViewVisibility(R.id.tt_item_num, witem.NumVisibility); view.setViewVisibility(R.id.tt_item_num, witem.NumVisibility);
view.setViewVisibility(R.id.tt_item_name, witem.NameVisibility); view.setViewVisibility(R.id.tt_item_name, witem.NameVisibility);
view.setViewVisibility(R.id.tt_item_name_nodesc, witem.NameNodescVisibility); view.setViewVisibility(R.id.tt_item_name_nodesc, witem.NameNodescVisibility);
view.setViewVisibility(R.id.tt_item_desc, witem.DescVisibility); view.setViewVisibility(R.id.tt_item_desc, witem.DescVisibility);
view.setViewVisibility(R.id.tt_item_room, witem.RoomVisibility); view.setViewVisibility(R.id.tt_item_room, witem.RoomVisibility);
view.setViewVisibility(R.id.tt_item_time, witem.TimeVisibility); view.setViewVisibility(R.id.tt_item_time, witem.TimeVisibility);
/* backgroundResources */ /* backgroundResources */
view.setInt(R.id.main_lay, "setBackgroundResource", witem.Layout); view.setInt(R.id.main_lay, "setBackgroundResource", witem.Layout);
/* Paddings */ /* Paddings */
view.setViewPadding(R.id.tt_item_name_nodesc, witem.NameNodescPadding[0], witem.NameNodescPadding[1], witem.NameNodescPadding[2], witem.NameNodescPadding[3]); view.setViewPadding(R.id.tt_item_name_nodesc, witem.NameNodescPadding[0], witem.NameNodescPadding[1], witem.NameNodescPadding[2], witem.NameNodescPadding[3]);
/* Text Colors */ /* Text Colors */
view.setInt(R.id.tt_item_num, "setTextColor", getColor(context, witem.NumColor)); view.setInt(R.id.tt_item_num, "setTextColor", getColor(context, witem.NumColor));
view.setInt(R.id.tt_item_name, "setTextColor", getColor(context, witem.NameColor)); view.setInt(R.id.tt_item_name, "setTextColor", getColor(context, witem.NameColor));
view.setInt(R.id.tt_item_name_nodesc, "setTextColor", getColor(context, witem.NameNodescColor)); view.setInt(R.id.tt_item_name_nodesc, "setTextColor", getColor(context, witem.NameNodescColor));
view.setInt(R.id.tt_item_desc, "setTextColor", getColor(context, witem.DescColor)); view.setInt(R.id.tt_item_desc, "setTextColor", getColor(context, witem.DescColor));
} }
public int getColor(Context context, int color) { public int getColor(Context context, int color) {
return context.getResources().getColor(color); return context.getResources().getColor(color);
} }
@Override @Override
public RemoteViews getViewAt(int position) { public RemoteViews getViewAt(int position) {
RemoteViews view = new RemoteViews(context.getPackageName(), R.layout.timetable_item); RemoteViews view = new RemoteViews(context.getPackageName(), R.layout.timetable_item);
witem = defaultItem(theme); witem = defaultItem(theme);
Lesson curr_subject = day_subjects.get(position); Lesson curr_subject = day_subjects.get(position);
if (curr_subject.status.equals("empty")) { if (curr_subject.status.equals("empty")) {
witem.NumColor = R.color.text_miss_num; witem.NumColor = R.color.text_miss_num;
witem.TimeVisibility = View.GONE; witem.TimeVisibility = View.GONE;
witem.RoomVisibility = View.GONE; witem.RoomVisibility = View.GONE;
witem.NameNodescColor = R.color.text_miss; witem.NameNodescColor = R.color.text_miss;
} }
if (!curr_subject.substituteTeacher.equals("null")) { if (!curr_subject.substituteTeacher.equals("null")) {
witem.NumColor = R.color.yellow; witem.NumColor = R.color.yellow;
witem.Layout = R.drawable.card_layout_tile_helyetesitett; witem.Layout = R.drawable.card_layout_tile_helyetesitett;
} }
if (curr_subject.status.equals("Elmaradt")) { if (curr_subject.status.equals("Elmaradt")) {
witem.NumColor = R.color.red; witem.NumColor = R.color.red;
witem.Layout = R.drawable.card_layout_tile_elmarad; witem.Layout = R.drawable.card_layout_tile_elmarad;
} else if (curr_subject.status.equals("TanevRendjeEsemeny")) { } else if (curr_subject.status.equals("TanevRendjeEsemeny")) {
witem.NumVisibility = View.GONE; witem.NumVisibility = View.GONE;
witem.TimeVisibility = View.GONE; witem.TimeVisibility = View.GONE;
witem.RoomVisibility = View.GONE; witem.RoomVisibility = View.GONE;
witem.NameNodescPadding[0] = 50; witem.NameNodescPadding[0] = 50;
witem.NameNodescPadding[2] = 50; witem.NameNodescPadding[2] = 50;
witem.NameNodescColor = R.color.text_miss; witem.NameNodescColor = R.color.text_miss;
} }
if (curr_subject.lessonTopic.equals("null")) { if (curr_subject.lessonTopic.equals("null")) {
witem.DescVisibility = View.GONE; witem.DescVisibility = View.GONE;
witem.NameVisibility = View.GONE; witem.NameVisibility = View.GONE;
witem.NameNodescVisibility = View.VISIBLE; witem.NameNodescVisibility = View.VISIBLE;
} }
setLayout(view); setLayout(view);
String lessonIndexTrailing = curr_subject.lessonIndex.equals("+") ? "" : "."; String lessonIndexTrailing = curr_subject.lessonIndex.equals("+") ? "" : ".";
view.setTextViewText(R.id.tt_item_num, curr_subject.lessonIndex + lessonIndexTrailing); view.setTextViewText(R.id.tt_item_num, curr_subject.lessonIndex + lessonIndexTrailing);
view.setTextViewText(R.id.tt_item_name, curr_subject.lessonName); view.setTextViewText(R.id.tt_item_name, curr_subject.lessonName);
view.setTextViewText(R.id.tt_item_name_nodesc, curr_subject.lessonName); view.setTextViewText(R.id.tt_item_name_nodesc, curr_subject.lessonName);
view.setTextViewText(R.id.tt_item_desc, curr_subject.lessonTopic); view.setTextViewText(R.id.tt_item_desc, curr_subject.lessonTopic);
view.setTextViewText(R.id.tt_item_room, curr_subject.lessonRoom); view.setTextViewText(R.id.tt_item_room, curr_subject.lessonRoom);
if(curr_subject.lessonStart != 0 && curr_subject.lessonEnd != 0) if(curr_subject.lessonStart != 0 && curr_subject.lessonEnd != 0)
view.setTextViewText(R.id.tt_item_time, WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonStart).getHourOfDay(), 2) + ":" + WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonStart).getMinuteOfHour(), 2) + view.setTextViewText(R.id.tt_item_time, WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonStart).getHourOfDay(), 2) + ":" + WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonStart).getMinuteOfHour(), 2) +
"\n" + WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonEnd).getHourOfDay(), 2) + ":" + WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonEnd).getMinuteOfHour(),2)); "\n" + WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonEnd).getHourOfDay(), 2) + ":" + WidgetTimetable.zeroPad(new DateTime(curr_subject.lessonEnd).getMinuteOfHour(),2));
return view; return view;
} }
@Override @Override
public RemoteViews getLoadingView() { public RemoteViews getLoadingView() {
return null; return null;
} }
@Override @Override
public int getViewTypeCount() { public int getViewTypeCount() {
return 1; return 1;
} }
@Override @Override
public long getItemId(int position) { public long getItemId(int position) {
return position; return position;
} }
@Override @Override
public boolean hasStableIds() { public boolean hasStableIds() {
return true; return true;
} }
private void initData() { private void initData() {
theme = getThemeAccent(context); theme = getThemeAccent(context);
rday = WidgetTimetable.selectDay(context, appWidgetId, 0, false); rday = WidgetTimetable.selectDay(context, appWidgetId, 0, false);
day_subjects.clear(); day_subjects.clear();
lessonIndexes.clear(); lessonIndexes.clear();
try { try {
List<JSONArray> arr = WidgetTimetable.genJsonDays(context); List<JSONArray> arr = WidgetTimetable.genJsonDays(context);
if(arr.isEmpty()) { if(arr.isEmpty()) {
return; return;
} }
JSONArray arr_lessons = WidgetTimetable.genJsonDays(context).get(rday); JSONArray arr_lessons = WidgetTimetable.genJsonDays(context).get(rday);
for (int i = 0; i < arr_lessons.length(); i++) { for (int i = 0; i < arr_lessons.length(); i++) {
JSONObject obj_lessons = arr_lessons.getJSONObject(i); JSONObject obj_lessons = arr_lessons.getJSONObject(i);
day_subjects.add(jsonToLesson(obj_lessons)); day_subjects.add(jsonToLesson(obj_lessons));
} }
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }
if(day_subjects.size() > 0) { if(day_subjects.size() > 0) {
Collections.sort(day_subjects, new Comparator<Lesson>() { Collections.sort(day_subjects, new Comparator<Lesson>() {
public int compare(Lesson o1, Lesson o2) { public int compare(Lesson o1, Lesson o2) {
return new DateTime(o1.lessonStart).compareTo(new DateTime(o2.lessonStart)); return new DateTime(o1.lessonStart).compareTo(new DateTime(o2.lessonStart));
} }
}); });
for (int i = 0; i < day_subjects.size(); i++) { for (int i = 0; i < day_subjects.size(); i++) {
if(!day_subjects.get(i).lessonIndex.equals("+")) { if(!day_subjects.get(i).lessonIndex.equals("+")) {
lessonIndexes.add(Integer.valueOf(day_subjects.get(i).lessonIndex)); lessonIndexes.add(Integer.valueOf(day_subjects.get(i).lessonIndex));
} }
} }
if(lessonIndexes.size() > 0) { if(lessonIndexes.size() > 0) {
int lessonsChecked = Collections.min(lessonIndexes); int lessonsChecked = Collections.min(lessonIndexes);
int i = 0; int i = 0;
while(lessonsChecked < Collections.max(lessonIndexes)) { while(lessonsChecked < Collections.max(lessonIndexes)) {
if(!lessonIndexes.contains(lessonsChecked)) { if(!lessonIndexes.contains(lessonsChecked)) {
day_subjects.add(i, emptyLesson(lessonsChecked)); day_subjects.add(i, emptyLesson(lessonsChecked));
} }
lessonsChecked++; lessonsChecked++;
i++; i++;
} }
} }
} }
} }
public static Integer getThemeAccent(Context context) { public static Integer getThemeAccent(Context context) {
DBManager dbManager = new DBManager(context.getApplicationContext()); DBManager dbManager = new DBManager(context.getApplicationContext());
try { try {
dbManager.open(); dbManager.open();
Cursor cursor = dbManager.fetchTheme(); Cursor cursor = dbManager.fetchTheme();
dbManager.close(); dbManager.close();
return cursor.getInt(1); return cursor.getInt(1);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
return 0; return 0;
} }
public Item defaultItem(int theme) { public Item defaultItem(int theme) {
return new Item( return new Item(
R.drawable.card_layout_tile, R.drawable.card_layout_tile,
View.VISIBLE, View.VISIBLE,
View.VISIBLE, View.VISIBLE,
View.INVISIBLE, View.INVISIBLE,
View.VISIBLE, View.VISIBLE,
View.VISIBLE, View.VISIBLE,
View.VISIBLE, View.VISIBLE,
colorValues[theme >= colorValues.length ? 0 : theme], colorValues[theme >= colorValues.length ? 0 : theme],
R.color.text, R.color.text,
R.color.text, R.color.text,
R.color.text_desc R.color.text_desc
); );
} }
public Lesson emptyLesson(int lessonIndex) { public Lesson emptyLesson(int lessonIndex) {
return new Lesson("empty", String.valueOf(lessonIndex), "Lyukasóra", "null", "null", 0, 0, "null"); return new Lesson("empty", String.valueOf(lessonIndex), "Lyukasóra", "null", "null", 0, 0, "null");
} }
public Lesson jsonToLesson(JSONObject json) { public Lesson jsonToLesson(JSONObject json) {
try { try {
return new Lesson( String name = json.getString("Nev");
json.getJSONObject("Allapot").getString("Nev"), name = name.substring(0, 1).toUpperCase() + name.substring(1); // Capitalize name
!json.getString("Oraszam").equals("null") ? json.getString("Oraszam") : "+", return new Lesson(
json.getString("Nev"), json.getJSONObject("Allapot").getString("Nev"),
json.getString("Tema"), !json.getString("Oraszam").equals("null") ? json.getString("Oraszam") : "+",
json.getString("TeremNeve"), name,
new DateTime(json.getString("KezdetIdopont")).getMillis(), json.getString("Tema"),
new DateTime(json.getString("VegIdopont")).getMillis(), json.getString("TeremNeve"),
json.getString("HelyettesTanarNeve") new DateTime(json.getString("KezdetIdopont")).getMillis(),
); new DateTime(json.getString("VegIdopont")).getMillis(),
}catch (Exception e) { json.getString("HelyettesTanarNeve")
Log.d("Filc", "exception: " + e); );
}; }catch (Exception e) {
Log.d("Filc", "exception: " + e);
return null; };
}
return null;
}
} }

View File

@@ -1,12 +1,12 @@
package hu.refilc.naplo.widget_timetable; package hu.refilc.naplo.widget_timetable;
import android.content.Intent; import android.content.Intent;
import android.os.Build; import android.os.Build;
import android.widget.RemoteViewsService; import android.widget.RemoteViewsService;
public class WidgetTimetableService extends RemoteViewsService { public class WidgetTimetableService extends RemoteViewsService {
@Override @Override
public RemoteViewsFactory onGetViewFactory(Intent intent) { public RemoteViewsFactory onGetViewFactory(Intent intent) {
return new WidgetTimetableDataProvider(getApplicationContext(), intent); return new WidgetTimetableDataProvider(getApplicationContext(), intent);
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:startColor="#123323"
android:endColor="#20AC9B"
android:angle="135" />
</shape>
</item>
</selector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/launch_gradient_background" />
<item>
<bitmap android:gravity="center" android:src="@mipmap/ic_splash"/>
</item>
</layer-list>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:startColor="#123323"
android:endColor="#20AC9B"
android:angle="135" />
</shape>
</item>
</selector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<gradient
android:startColor="#123323"
android:endColor="#20AC9B"
android:angle="135" />
</shape>
</item>
</selector>

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:id="@+id/main_lay" android:id="@+id/main_lay"
android:layout_height="50dp" android:layout_height="50dp"
@@ -15,12 +16,14 @@
android:id="@+id/tt_item_num" android:id="@+id/tt_item_num"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fontFamily="@font/montserrat_medium"
android:gravity="center"
android:text="1."
android:textColor="@color/filc"
android:textColorLink="#ff3D7BF4"
android:textSize="30sp" android:textSize="30sp"
android:textStyle="bold" android:textStyle="bold"
android:fontFamily="@font/montserrat_medium" tools:ignore="HardcodedText" />
android:text="1."
android:gravity="center"
android:textColor="@color/filc"></TextView>
<TextView <TextView
android:id="@+id/tt_item_name" android:id="@+id/tt_item_name"
@@ -33,10 +36,11 @@
android:text="Óra neve" android:text="Óra neve"
android:maxLines="1" android:maxLines="1"
android:ellipsize="end" android:ellipsize="end"
android:layout_toLeftOf="@id/tt_item_room" android:layout_toStartOf="@id/tt_item_room"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layout_toRightOf="@id/tt_item_num" android:layout_toEndOf="@id/tt_item_num"
android:textColor="@color/text"></TextView> android:textColor="@color/text"
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/tt_item_name_nodesc" android:id="@+id/tt_item_name_nodesc"
@@ -47,13 +51,14 @@
android:fontFamily="@font/montserrat_medium" android:fontFamily="@font/montserrat_medium"
android:visibility="gone" android:visibility="gone"
android:layout_marginTop="2.5dp" android:layout_marginTop="2.5dp"
android:layout_toLeftOf="@id/tt_item_room" android:layout_toStartOf="@id/tt_item_room"
android:text="Óra neve" android:text="Óra neve"
android:maxLines="1" android:maxLines="1"
android:ellipsize="end" android:ellipsize="end"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layout_toRightOf="@id/tt_item_num" android:layout_toEndOf="@id/tt_item_num"
android:textColor="@color/text"></TextView> android:textColor="@color/text"
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/tt_item_desc" android:id="@+id/tt_item_desc"
@@ -67,10 +72,11 @@
android:maxLines="1" android:maxLines="1"
android:ellipsize="end" android:ellipsize="end"
android:gravity="center_vertical" android:gravity="center_vertical"
android:layout_toRightOf="@id/tt_item_num" android:layout_toEndOf="@id/tt_item_num"
android:layout_toLeftOf="@id/tt_item_room" android:layout_toStartOf="@id/tt_item_room"
android:layout_below="@id/tt_item_name" android:layout_below="@id/tt_item_name"
android:textColor="@color/text_desc"></TextView> android:textColor="@color/text_desc"
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/tt_item_room" android:id="@+id/tt_item_room"
@@ -84,8 +90,9 @@
android:ellipsize="end" android:ellipsize="end"
android:maxLines="2" android:maxLines="2"
android:gravity="center" android:gravity="center"
android:layout_toLeftOf="@id/tt_item_time" android:layout_toStartOf="@id/tt_item_time"
android:textColor="@color/text_desc"></TextView> android:textColor="@color/text_desc"
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/tt_item_time" android:id="@+id/tt_item_time"
@@ -95,11 +102,12 @@
android:textFontWeight="500" android:textFontWeight="500"
android:fontFamily="@font/montserrat_medium" android:fontFamily="@font/montserrat_medium"
android:textStyle="bold" android:textStyle="bold"
android:layout_marginLeft="2dp" android:layout_marginStart="2dp"
android:layout_marginTop="-2dp" android:layout_marginTop="-2dp"
android:text="8:30\n9:10" android:text="8:30\n9:10"
android:gravity="center" android:gravity="center"
android:layout_alignParentRight="true" android:layout_alignParentEnd="true"
android:textColor="@color/white"></TextView> android:textColor="@color/white"
tools:ignore="HardcodedText" />
</RelativeLayout> </RelativeLayout>

View File

@@ -19,10 +19,12 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:gravity="center" android:gravity="center"
android:text="Empty" android:text="Üres / Empty"
android:background="@drawable/widget_card_bottom_dark"
android:textColor="@color/text" android:textColor="@color/text"
android:textSize="20sp" android:textSize="20sp"
android:textStyle="bold" /> android:textStyle="bold"
tools:ignore="HardcodedText" />
<ListView <ListView
android:id="@+id/widget_list" android:id="@+id/widget_list"
@@ -43,57 +45,63 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="45dp" android:layout_height="45dp"
android:background="@drawable/widget_card_top_dark"> android:background="@drawable/widget_card_top_dark">
<ImageView <ImageView
android:id="@+id/nav_refresh" android:id="@+id/nav_refresh"
android:layout_width="40dp" android:layout_width="40dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_toStartOf="@id/nav_to_left"
android:clickable="true" android:clickable="true"
android:foreground="?android:attr/selectableItemBackground" android:foreground="?android:attr/selectableItemBackground"
android:padding="10dp"
android:src="@drawable/ic_refresh_cw" android:src="@drawable/ic_refresh_cw"
android:layout_toLeftOf="@id/nav_to_left"
android:tint="@color/text_desc" android:tint="@color/text_desc"
tools:ignore="UseAppTint" tools:ignore="UseAppTint"
android:padding="10dp" /> android:focusable="true" />
<ImageView <ImageView
android:id="@+id/nav_to_left" android:id="@+id/nav_to_left"
android:layout_width="50dp" android:layout_width="45dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_toStartOf="@id/nav_to_right"
android:clickable="true" android:clickable="true"
android:foreground="?android:attr/selectableItemBackground" android:foreground="?android:attr/selectableItemBackground"
android:padding="10dp"
android:src="@drawable/ic_chevron_left" android:src="@drawable/ic_chevron_left"
android:layout_toLeftOf="@id/nav_to_right"
android:tint="@color/text_desc" android:tint="@color/text_desc"
tools:ignore="UseAppTint" tools:ignore="UseAppTint"
android:padding="10dp" /> android:focusable="true" />
<ImageView <ImageView
android:id="@+id/nav_to_right" android:id="@+id/nav_to_right"
android:layout_width="50dp" android:layout_width="45dp"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_marginEnd="5dp"
android:clickable="true" android:clickable="true"
android:foreground="?android:attr/selectableItemBackground" android:foreground="?android:attr/selectableItemBackground"
android:padding="10dp"
android:src="@drawable/ic_chevron_right" android:src="@drawable/ic_chevron_right"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp"
android:tint="@color/text_desc" android:tint="@color/text_desc"
tools:ignore="UseAppTint" tools:ignore="UseAppTint"
android:padding="10dp" /> android:focusable="true" />
<TextView <TextView
android:id="@+id/nav_current" android:id="@+id/nav_current"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_alignParentLeft="true" android:layout_alignParentStart="true"
android:layout_marginLeft="20sp" android:layout_marginStart="15sp"
android:layout_toLeftOf="@id/nav_refresh" android:layout_marginTop="2sp"
android:layout_toStartOf="@id/nav_refresh"
android:fontFamily="@font/montserrat_medium" android:fontFamily="@font/montserrat_medium"
android:gravity="center_vertical" android:gravity="center_vertical"
android:maxLines="1" android:maxLines="1"
android:text="Timetable" android:text="Órarend"
android:textColor="@color/text" android:textColor="@color/text"
android:textSize="24sp" android:textSize="22sp"
android:textStyle="bold" /> android:textStyle="bold"
tools:ignore="HardcodedText" />
</RelativeLayout> </RelativeLayout>
</RelativeLayout> </RelativeLayout>
@@ -131,8 +139,9 @@
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="17dp" android:textSize="17sp"
android:textStyle="bold" /> android:textStyle="bold"
tools:ignore="HardcodedText" />
<Button <Button
android:id="@+id/open_login" android:id="@+id/open_login"
@@ -145,8 +154,9 @@
android:layout_margin="10dp" android:layout_margin="10dp"
android:textColor="@color/white" android:textColor="@color/white"
android:fontFamily="@font/montserrat_medium" android:fontFamily="@font/montserrat_medium"
android:textSize="16dp" android:textSize="16sp"
android:textStyle="bold"/> android:textStyle="bold"
tools:ignore="HardcodedText" />
</RelativeLayout> </RelativeLayout>
@@ -185,8 +195,9 @@
android:text="Órák a kezdőképernyőd kényelméből." android:text="Órák a kezdőképernyőd kényelméből."
android:textColor="@color/black" android:textColor="@color/black"
android:paddingTop="10dp" android:paddingTop="10dp"
android:textSize="16dp" android:textSize="16sp"
android:textStyle="bold" /> android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -197,7 +208,8 @@
android:textColor="@color/black" android:textColor="@color/black"
android:layout_marginTop="0dp" android:layout_marginTop="0dp"
android:layout_marginHorizontal="15dp" android:layout_marginHorizontal="15dp"
android:textSize="14dp" /> android:textSize="14sp"
tools:ignore="HardcodedText" />
<Button <Button
android:id="@+id/buy_premium" android:id="@+id/buy_premium"
@@ -211,8 +223,9 @@
android:layout_margin="10dp" android:layout_margin="10dp"
android:textColor="#ff691A9B" android:textColor="#ff691A9B"
android:fontFamily="@font/montserrat_medium" android:fontFamily="@font/montserrat_medium"
android:textSize="16dp" android:textSize="16sp"
android:textStyle="bold"/> android:textStyle="bold"
tools:ignore="HardcodedText" />
</RelativeLayout> </RelativeLayout>

View File

@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/> <background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/> <foreground android:drawable="@drawable/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon> </adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 916 B

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,12 +0,0 @@
<resources>
<style name="Widget.Android.AppWidget.Container" parent="android:Widget">
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_background</item>
</style>
<style name="Widget.Android.AppWidget.InnerView" parent="android:Widget">
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_inner_view_background</item>
</style>
</resources>

View File

@@ -27,7 +27,7 @@
<color name="yellow_light">#ffFFCC00</color> <color name="yellow_light">#ffFFCC00</color>
<color name="light_yellow_light">#40FFD60A</color> <color name="light_yellow_light">#40FFD60A</color>
<color name="green_light">#ff34C759</color> <color name="green_light">#ff34C759</color>
<color name="filc_light">#ff247665</color> <color name="filc_light">#ff3D7BF4</color>
<color name="teal_light">#ff5AC8FA</color> <color name="teal_light">#ff5AC8FA</color>
<color name="blue_light">#ff007AFF</color> <color name="blue_light">#ff007AFF</color>
<color name="indigo_light">#ff5856D6</color> <color name="indigo_light">#ff5856D6</color>
@@ -49,7 +49,7 @@
<color name="yellow">#ffFFD60A</color> <color name="yellow">#ffFFD60A</color>
<color name="light_yellow">#40FFD60A</color> <color name="light_yellow">#40FFD60A</color>
<color name="green">#ff32D74B</color> <color name="green">#ff32D74B</color>
<color name="filc">#ff29826F</color> <color name="filc">#ff3D7BF4</color>
<color name="teal">#ff64D2FF</color> <color name="teal">#ff64D2FF</color>
<color name="blue">#ff0A84FF</color> <color name="blue">#ff0A84FF</color>
<color name="indigo">#ff5E5CE6</color> <color name="indigo">#ff5E5CE6</color>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 735 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -1,3 +1,7 @@
#!/bin/sh #!/bin/sh
flutter clean
dart pub get
flutter doctor -v
flutter build ipa --release --dart-define=APPVER=$(cat pubspec.yaml | grep version: | cut -d' ' -f2 | cut -d+ -f1) --no-tree-shake-icons flutter build ipa --release --dart-define=APPVER=$(cat pubspec.yaml | grep version: | cut -d' ' -f2 | cut -d+ -f1) --no-tree-shake-icons

View File

@@ -1,15 +1,14 @@
// This is a generated file; do not edit or check into version control. // This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/Users/kima/development/flutter FLUTTER_ROOT=/Users/kima/src/flutter
FLUTTER_APPLICATION_PATH=/Users/kima/Documents/refilc/app/naplo/filcnaplo FLUTTER_APPLICATION_PATH=/Users/kima/Documents/refilc/app/naplo/filcnaplo
COCOAPODS_PARALLEL_CODE_SIGN=true COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_TARGET=/Users/kima/Documents/refilc/app/naplo/filcnaplo/lib/main.dart FLUTTER_TARGET=lib/main.dart
FLUTTER_BUILD_DIR=build FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_NAME=3.5.1 FLUTTER_BUILD_NAME=4.2.0
FLUTTER_BUILD_NUMBER=197 FLUTTER_BUILD_NUMBER=220
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386 EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386
EXCLUDED_ARCHS[sdk=iphoneos*]=armv7 EXCLUDED_ARCHS[sdk=iphoneos*]=armv7
DART_DEFINES=RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ==,RkxVVFRFUl9XRUJfQ0FOVkFTS0lUX1VSTD1odHRwczovL3d3dy5nc3RhdGljLmNvbS9mbHV0dGVyLWNhbnZhc2tpdC9iNGZiMTEyMTRkZDJkZGE2Y2UwMTJkZDk4ZWE0OThlOWU4YjkxMjYyLw==
DART_OBFUSCATION=false DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=true TRACK_WIDGET_CREATION=true
TREE_SHAKE_ICONS=false TREE_SHAKE_ICONS=false
PACKAGE_CONFIG=/Users/kima/Documents/refilc/app/naplo/filcnaplo/.dart_tool/package_config.json PACKAGE_CONFIG=.dart_tool/package_config.json

View File

@@ -0,0 +1,14 @@
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/Users/kima/src/flutter
FLUTTER_APPLICATION_PATH=/Users/kima/Documents/refilc/app/naplo/filcnaplo
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_TARGET=lib/main.dart
FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_NAME=4.2.0
FLUTTER_BUILD_NUMBER=220
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386
EXCLUDED_ARCHS[sdk=iphoneos*]=armv7
DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=true
TREE_SHAKE_ICONS=false
PACKAGE_CONFIG=.dart_tool/package_config.json

View File

@@ -0,0 +1,13 @@
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/kima/src/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/kima/Documents/refilc/app/naplo/filcnaplo"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=4.2.0"
export "FLUTTER_BUILD_NUMBER=220"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.dart_tool/package_config.json"

View File

@@ -0,0 +1,13 @@
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/kima/src/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/kima/Documents/refilc/app/naplo/filcnaplo"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=4.2.0"
export "FLUTTER_BUILD_NUMBER=220"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.dart_tool/package_config.json"

View File

@@ -1,237 +0,0 @@
PODS:
- app_group_directory (1.0.0):
- Flutter
- background_fetch (1.1.6):
- Flutter
- connectivity_plus (0.0.1):
- Flutter
- ReachabilitySwift
- DKImagePickerController/Core (4.3.4):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.4)
- DKImagePickerController/PhotoGallery (4.3.4):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.4)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Flutter (1.0.0)
- flutter_custom_tabs (0.0.1):
- Flutter
- flutter_image_compress (1.0.0):
- Flutter
- Mantle
- SDWebImage
- SDWebImageWebPCoder
- flutter_local_notifications (0.0.1):
- Flutter
- flutter_native_image (0.0.1):
- Flutter
- flutter_native_splash (0.0.1):
- Flutter
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- home_widget (0.0.1):
- Flutter
- image_picker_ios (0.0.1):
- Flutter
- libwebp (1.2.4):
- libwebp/demux (= 1.2.4)
- libwebp/mux (= 1.2.4)
- libwebp/webp (= 1.2.4)
- libwebp/demux (1.2.4):
- libwebp/webp
- libwebp/mux (1.2.4):
- libwebp/demux
- libwebp/webp (1.2.4)
- live_activities (0.0.1):
- Flutter
- Mantle (2.2.0):
- Mantle/extobjc (= 2.2.0)
- Mantle/extobjc (2.2.0)
- open_file (0.0.1):
- Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- permission_handler_apple (9.0.4):
- Flutter
- quick_actions_ios (0.0.1):
- Flutter
- ReachabilitySwift (5.0.0)
- SDWebImage (5.13.2):
- SDWebImage/Core (= 5.13.2)
- SDWebImage/Core (5.13.2)
- SDWebImageWebPCoder (0.9.1):
- libwebp (~> 1.0)
- SDWebImage/Core (~> 5.13)
- share_plus (0.0.1):
- Flutter
- sqflite (0.0.3):
- Flutter
- FMDB (>= 2.7.5)
- SwiftyGif (5.4.3)
- uni_links (0.0.1):
- Flutter
- url_launcher_ios (0.0.1):
- Flutter
- workmanager (0.0.1):
- Flutter
DEPENDENCIES:
- app_group_directory (from `.symlinks/plugins/app_group_directory/ios`)
- background_fetch (from `.symlinks/plugins/background_fetch/ios`)
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- DKImagePickerController/PhotoGallery (from `https://github.com/zhangao0086/DKImagePickerController.git`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- Flutter (from `Flutter`)
- flutter_custom_tabs (from `.symlinks/plugins/flutter_custom_tabs/ios`)
- flutter_image_compress (from `.symlinks/plugins/flutter_image_compress/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- flutter_native_image (from `.symlinks/plugins/flutter_native_image/ios`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- home_widget (from `.symlinks/plugins/home_widget/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- live_activities (from `.symlinks/plugins/live_activities/ios`)
- open_file (from `.symlinks/plugins/open_file/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- quick_actions_ios (from `.symlinks/plugins/quick_actions_ios/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- uni_links (from `.symlinks/plugins/uni_links/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- workmanager (from `.symlinks/plugins/workmanager/ios`)
SPEC REPOS:
trunk:
- DKPhotoGallery
- FMDB
- libwebp
- Mantle
- ReachabilitySwift
- SDWebImage
- SDWebImageWebPCoder
- SwiftyGif
EXTERNAL SOURCES:
app_group_directory:
:path: ".symlinks/plugins/app_group_directory/ios"
background_fetch:
:path: ".symlinks/plugins/background_fetch/ios"
connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/ios"
DKImagePickerController:
:git: https://github.com/zhangao0086/DKImagePickerController.git
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
flutter_custom_tabs:
:path: ".symlinks/plugins/flutter_custom_tabs/ios"
flutter_image_compress:
:path: ".symlinks/plugins/flutter_image_compress/ios"
flutter_local_notifications:
:path: ".symlinks/plugins/flutter_local_notifications/ios"
flutter_native_image:
:path: ".symlinks/plugins/flutter_native_image/ios"
flutter_native_splash:
:path: ".symlinks/plugins/flutter_native_splash/ios"
home_widget:
:path: ".symlinks/plugins/home_widget/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
live_activities:
:path: ".symlinks/plugins/live_activities/ios"
open_file:
:path: ".symlinks/plugins/open_file/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
quick_actions_ios:
:path: ".symlinks/plugins/quick_actions_ios/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
uni_links:
:path: ".symlinks/plugins/uni_links/ios"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
workmanager:
:path: ".symlinks/plugins/workmanager/ios"
CHECKOUT OPTIONS:
DKImagePickerController:
:commit: a727e44718a67e300089174e5591166045815ba4
:git: https://github.com/zhangao0086/DKImagePickerController.git
SPEC CHECKSUMS:
app_group_directory: 7bf9f8f9819ead554de29da7c25fb7a680d6a9a0
background_fetch: bc9b44b0bf8b434e282a2ac9be8662800a0296ed
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_custom_tabs: 7a10a08686955cb748e5d26e0ae586d30689bf89
flutter_image_compress: 5a5e9aee05b6553048b8df1c3bc456d0afaac433
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
flutter_native_image: 9c0b7451838484458e5b0fae007b86a4c2d4bdfe
flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
home_widget: 2829415127ee92e876f816cbbe44c0b6601b8a37
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef
live_activities: 9ff56a06a2d43ecd68f56deeed13b18a8304789c
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
open_file: 02eb5cb6b21264bd3a696876f5afbfb7ca4f4b7d
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
quick_actions_ios: 9e80dcfadfbc5d47d9cf8f47bcf428b11cf383d4
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866
SDWebImageWebPCoder: 18503de6621dd2c420d680e33d46bf8e1d5169b0
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
PODFILE CHECKSUM: efe5e2e257c61a1c3d5be693ef1a8ea1c4b81d8f
COCOAPODS: 1.12.1

View File

@@ -198,9 +198,9 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 3127F79F28EAEDE300C2EFB3 /* Build configuration list for PBXNativeTarget "livecard" */; buildConfigurationList = 3127F79F28EAEDE300C2EFB3 /* Build configuration list for PBXNativeTarget "livecard" */;
buildPhases = ( buildPhases = (
3127F78A28EAEDE200C2EFB3 /* Resources */,
3127F78828EAEDE200C2EFB3 /* Sources */, 3127F78828EAEDE200C2EFB3 /* Sources */,
3127F78928EAEDE200C2EFB3 /* Frameworks */, 3127F78928EAEDE200C2EFB3 /* Frameworks */,
3127F78A28EAEDE200C2EFB3 /* Resources */,
); );
buildRules = ( buildRules = (
); );
@@ -299,7 +299,7 @@
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
buildActionMask = 2147483647; buildActionMask = 12;
files = ( files = (
); );
inputPaths = ( inputPaths = (
@@ -310,11 +310,11 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin\n";
}; };
71459C0EB905E05018E3D78F /* [CP] Embed Pods Frameworks */ = { 71459C0EB905E05018E3D78F /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 12;
files = ( files = (
); );
inputFileListPaths = ( inputFileListPaths = (
@@ -364,7 +364,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n";
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
@@ -488,7 +488,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 3.6.0; MARKETING_VERSION = 3.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo; PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.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;
@@ -526,7 +526,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.refilc.naplo.livecardpro; PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo.livecardpro;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@@ -567,7 +567,7 @@
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo.livecardpro; PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo.livecardpro;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@@ -607,7 +607,7 @@
); );
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo.livecardpro; PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.naplo.livecardpro;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@@ -746,7 +746,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 3.6.0; MARKETING_VERSION = 3.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo; PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.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";
@@ -774,7 +774,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 3.6.0; MARKETING_VERSION = 3.6.0;
PRODUCT_BUNDLE_IDENTIFIER = com.refilc.naplo; PRODUCT_BUNDLE_IDENTIFIER = com.refilctest.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,7 +2,11 @@
<!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>aps-environment</key>
<string>development</string>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array/> <array>
<string>group.refilcnaplo.livecard</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@@ -1,13 +1,14 @@
{ {
"images" : [ "images" : [
{ {
"idiom" : "universal", "filename" : "reFilc_Logo.png",
"platform" : "ios", "idiom" : "universal",
"size" : "1024x1024" "platform" : "ios",
} "size" : "1024x1024"
], }
"info" : { ],
"author" : "xcode", "info" : {
"version" : 1 "author" : "xcode",
} "version" : 1
} }
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 KiB

View File

@@ -1,6 +1,7 @@
import Foundation import Foundation
class LessonData { class LessonData {
var color: String
var icon: String var icon: String
var index: String var index: String
var title: String var title: String
@@ -13,8 +14,9 @@ class LessonData {
var nextRoom: String var nextRoom: String
init?() { init?() {
let sharedDefault = UserDefaults(suiteName: "group.filcnaplo.livecard")! let sharedDefault = UserDefaults(suiteName: "group.refilc.livecard")!
self.color = sharedDefault.string(forKey: "color")!
self.icon = sharedDefault.string(forKey: "icon")! self.icon = sharedDefault.string(forKey: "icon")!
self.index = sharedDefault.string(forKey: "index")! self.index = sharedDefault.string(forKey: "index")!
self.title = sharedDefault.string(forKey: "title")! self.title = sharedDefault.string(forKey: "title")!

View File

@@ -2,7 +2,11 @@
<!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>aps-environment</key>
<string>development</string>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array/> <array>
<string>group.refilcnaplo.livecard</string>
</array>
</dict> </dict>
</plist> </plist>

View File

@@ -11,6 +11,33 @@ struct Widgets: WidgetBundle {
} }
} }
// Color Converter
extension Color {
init(hex: String, alpha: Double = 1.0) {
var hexValue = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
if hexValue.hasPrefix("#") {
hexValue.remove(at: hexValue.startIndex)
}
var rgbValue: UInt64 = 0
Scanner(string: hexValue).scanHexInt64(&rgbValue)
let red = Double((rgbValue & 0xFF0000) >> 16) / 255.0
let green = Double((rgbValue & 0x00FF00) >> 8) / 255.0
let blue = Double(rgbValue & 0x0000FF) / 255.0
self.init(
.sRGB,
red: red,
green: green,
blue: blue,
opacity: alpha
)
}
}
// We need to redefined live activities pipe // We need to redefined live activities pipe
struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable { struct LiveActivitiesAppAttributes: ActivityAttributes, Identifiable {
public struct ContentState: Codable, Hashable { } public struct ContentState: Codable, Hashable { }
@@ -68,8 +95,11 @@ struct LockScreenLiveActivityView: View {
.monospacedDigit() .monospacedDigit()
.padding(.trailing, CGFloat(24)) .padding(.trailing, CGFloat(24))
} }
.activitySystemActionForegroundColor(.teal) .activityBackgroundTint(
.activityBackgroundTint(.teal) lesson!.color == "#676767"
? nil
: Color(hex: lesson!.color)
)
} }
} }
@@ -146,7 +176,11 @@ struct LiveCardWidget: Widget {
.font(.system(size: CGFloat(10))) .font(.system(size: CGFloat(10)))
} }
} }
.keylineTint(.accentColor) .keylineTint(
lesson!.color == "#676767"
? nil
: Color(hex: lesson!.color)
)
} }
} }
} }

View File

@@ -1,12 +1,14 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'package:filcnaplo/models/ad.dart';
import 'package:filcnaplo/models/config.dart'; import 'package:filcnaplo/models/config.dart';
import 'package:filcnaplo/models/news.dart'; import 'package:filcnaplo/models/news.dart';
import 'package:filcnaplo/models/release.dart'; import 'package:filcnaplo/models/release.dart';
import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/models/supporter.dart'; import 'package:filcnaplo/models/supporter.dart';
import 'package:filcnaplo_kreta_api/models/school.dart'; import 'package:filcnaplo_kreta_api/models/school.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:connectivity_plus/connectivity_plus.dart';
@@ -17,6 +19,7 @@ class FilcAPI {
static const supporters = "https://api.refilc.hu/v1/public/supporters"; static const supporters = "https://api.refilc.hu/v1/public/supporters";
// Private API // Private API
static const ads = "https://api.refilc.hu/v1/private/ads";
static const config = "https://api.refilc.hu/v1/private/config"; static const config = "https://api.refilc.hu/v1/private/config";
static const reportApi = "https://api.refilc.hu/v1/private/crash-report"; static const reportApi = "https://api.refilc.hu/v1/private/crash-report";
static const premiumApi = "https://api.filcnaplo.hu/premium/activate"; static const premiumApi = "https://api.filcnaplo.hu/premium/activate";
@@ -68,7 +71,9 @@ class FilcAPI {
http.Response res = await http.get(Uri.parse(config), headers: headers); http.Response res = await http.get(Uri.parse(config), headers: headers);
if (res.statusCode == 200) { if (res.statusCode == 200) {
print(jsonDecode(res.body)); if (kDebugMode) {
print(jsonDecode(res.body));
}
return Config.fromJson(jsonDecode(res.body)); return Config.fromJson(jsonDecode(res.body));
} else if (res.statusCode == 429) { } else if (res.statusCode == 429) {
res = await http.get(Uri.parse(config)); res = await http.get(Uri.parse(config));
@@ -114,6 +119,24 @@ class FilcAPI {
return null; return null;
} }
static Future<List<Ad>?> getAds() async {
try {
http.Response res = await http.get(Uri.parse(ads));
if (res.statusCode == 200) {
return (jsonDecode(res.body) as List)
.cast<Map>()
.map((e) => Ad.fromJson(e))
.toList();
} else {
throw "HTTP ${res.statusCode}: ${res.body}";
}
} on Exception catch (error, stacktrace) {
log("ERROR: FilcAPI.getAds: $error $stacktrace");
}
return null;
}
static Future<List<Release>?> getReleases() async { static Future<List<Release>?> getReleases() async {
try { try {
http.Response res = await http.get(Uri.parse(releases)); http.Response res = await http.get(Uri.parse(releases));

View File

@@ -27,7 +27,7 @@ enum LoginState {
failed, failed,
normal, normal,
inProgress, inProgress,
success success,
} }
Nonce getNonce(String nonce, String username, String instituteCode) { Nonce getNonce(String nonce, String username, String instituteCode) {
@@ -39,7 +39,7 @@ Nonce getNonce(String nonce, String username, String instituteCode) {
return nonceEncoder; return nonceEncoder;
} }
Future loginApi({ Future loginAPI({
required String username, required String username,
required String password, required String password,
required String instituteCode, required String instituteCode,
@@ -121,7 +121,7 @@ Future loginApi({
return LoginState.success; return LoginState.success;
} catch (error) { } catch (error) {
print("ERROR: loginApi: $error"); print("ERROR: loginAPI: $error");
// maybe check debug mode // maybe check debug mode
// ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("ERROR: $error"))); // ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text("ERROR: $error")));
return LoginState.failed; return LoginState.failed;

View File

@@ -0,0 +1,29 @@
import 'package:filcnaplo/api/client.dart';
import 'package:filcnaplo/models/ad.dart';
import 'package:flutter/material.dart';
class AdProvider extends ChangeNotifier {
// private
late List<Ad> _ads;
bool get available => _ads.isNotEmpty;
// public
List<Ad> get ads => _ads;
AdProvider({
List<Ad> initialAds = const [],
required BuildContext context,
}) {
_ads = List.castFrom(initialAds);
}
Future<void> fetch() async {
_ads = await FilcAPI.getAds() ?? [];
_ads.sort((a, b) => -a.date.compareTo(b.date));
// check for new ads
if (_ads.isNotEmpty) {
notifyListeners();
}
}
}

View File

@@ -2,7 +2,6 @@ import 'dart:io';
import 'package:filcnaplo/database/query.dart'; import 'package:filcnaplo/database/query.dart';
import 'package:filcnaplo/database/store.dart'; import 'package:filcnaplo/database/store.dart';
import 'package:sqflite/sqflite.dart';
// ignore: depend_on_referenced_packages // ignore: depend_on_referenced_packages
import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart';

View File

@@ -13,7 +13,15 @@ import 'package:flutter/foundation.dart';
import 'package:live_activities/live_activities.dart'; import 'package:live_activities/live_activities.dart';
import 'package:filcnaplo_mobile_ui/pages/home/live_card/live_card.i18n.dart'; import 'package:filcnaplo_mobile_ui/pages/home/live_card/live_card.i18n.dart';
enum LiveCardState { empty, duringLesson, duringBreak, morning, afternoon, night } enum LiveCardState {
empty,
duringLesson,
duringBreak,
morning,
afternoon,
night,
summary
}
class LiveCardProvider extends ChangeNotifier { class LiveCardProvider extends ChangeNotifier {
Lesson? currentLesson; Lesson? currentLesson;
@@ -32,29 +40,55 @@ class LiveCardProvider extends ChangeNotifier {
String? _latestActivityId; String? _latestActivityId;
Map<String, String> _lastActivity = {}; Map<String, String> _lastActivity = {};
bool _hasCheckedTimetable = false;
LiveCardProvider({ LiveCardProvider({
required TimetableProvider timetable, required TimetableProvider timetable,
required SettingsProvider settings, required SettingsProvider settings,
}) : _timetable = timetable, }) : _timetable = timetable,
_settings = settings { _settings = settings {
_liveActivitiesPlugin.init(appGroupId: "group.filcnaplo.livecard"); if (Platform.isIOS) {
_liveActivitiesPlugin.getAllActivitiesIds().then((value) { _liveActivitiesPlugin.areActivitiesEnabled().then((value) {
_latestActivityId = value.isNotEmpty ? value.first : null; // Console log
}); if (kDebugMode) {
_timer = Timer.periodic(const Duration(seconds: 1), (timer) => update()); print("Live card enabled: $value");
_delay = settings.bellDelayEnabled ? Duration(seconds: settings.bellDelay) : Duration.zero; }
update();
if (value) {
_liveActivitiesPlugin.init(appGroupId: "group.refilc.livecard");
_liveActivitiesPlugin.getAllActivitiesIds().then((value) {
_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();
}
} }
@override @override
void dispose() { void dispose() {
_timer.cancel(); _timer.cancel();
if (_latestActivityId != null && Platform.isIOS) _liveActivitiesPlugin.endActivity(_latestActivityId!); if (Platform.isIOS) {
_liveActivitiesPlugin.areActivitiesEnabled().then((value) {
if (value) {
if (_latestActivityId != null) {
_liveActivitiesPlugin.endActivity(_latestActivityId!);
}
}
});
}
super.dispose(); super.dispose();
} }
// Debugging // Debugging
static DateTime _now() { static DateTime _now() {
// return DateTime(2023, 8, 31, 8, 0);
return DateTime.now(); return DateTime.now();
} }
@@ -78,14 +112,27 @@ class LiveCardProvider extends ChangeNotifier {
switch (currentState) { switch (currentState) {
case LiveCardState.duringLesson: case LiveCardState.duringLesson:
return { return {
"icon": currentLesson != null ? SubjectIcon.resolveName(subject: currentLesson?.subject) : "book", "color":
"index": currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "", '#${_settings.liveActivityColor.toString().substring(10, 16)}',
"title": currentLesson != null ? ShortSubject.resolve(subject: currentLesson?.subject).capital() : "", "icon": currentLesson != null
? SubjectIcon.resolveName(subject: currentLesson?.subject)
: "book",
"index":
currentLesson != null ? '${currentLesson!.lessonIndex}. ' : "",
"title": currentLesson != null
? ShortSubject.resolve(subject: currentLesson?.subject).capital()
: "",
"subtitle": currentLesson?.room.replaceAll("_", " ") ?? "", "subtitle": currentLesson?.room.replaceAll("_", " ") ?? "",
"description": currentLesson?.description ?? "", "description": currentLesson?.description ?? "",
"startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(), "startDate": ((currentLesson?.start.millisecondsSinceEpoch ?? 0) -
"endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(), _delay.inMilliseconds)
"nextSubject": nextLesson != null ? ShortSubject.resolve(subject: nextLesson?.subject).capital() : "", .toString(),
"endDate": ((currentLesson?.end.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds)
.toString(),
"nextSubject": nextLesson != null
? ShortSubject.resolve(subject: nextLesson?.subject).capital()
: "",
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
}; };
case LiveCardState.duringBreak: case LiveCardState.duringBreak:
@@ -99,12 +146,23 @@ class LiveCardProvider extends ChangeNotifier {
final diff = getFloorDifference(); final diff = getFloorDifference();
return { return {
"color":
'#${_settings.liveActivityColor.toString().substring(10, 16)}',
"icon": iconFloorMap[diff] ?? "cup.and.saucer", "icon": iconFloorMap[diff] ?? "cup.and.saucer",
"title": "Szünet", "title": "Szünet",
"description": "go $diff".i18n.fill([diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room]), "description": "go $diff".i18n.fill([
"startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(), diff != "to room" ? (nextLesson!.getFloor() ?? 0) : nextLesson!.room
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) - _delay.inMilliseconds).toString(), ]),
"nextSubject": (nextLesson != null ? ShortSubject.resolve(subject: nextLesson?.subject) : "").capital(), "startDate": ((prevLesson?.end.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds)
.toString(),
"endDate": ((nextLesson?.start.millisecondsSinceEpoch ?? 0) -
_delay.inMilliseconds)
.toString(),
"nextSubject": (nextLesson != null
? ShortSubject.resolve(subject: nextLesson?.subject)
: "")
.capital(),
"nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "", "nextRoom": nextLesson?.room.replaceAll("_", " ") ?? "",
"index": "", "index": "",
"subtitle": "", "subtitle": "",
@@ -116,42 +174,66 @@ class LiveCardProvider extends ChangeNotifier {
void update() async { void update() async {
if (Platform.isIOS) { if (Platform.isIOS) {
final cmap = toMap(); _liveActivitiesPlugin.areActivitiesEnabled().then((value) {
if (!mapEquals(cmap, _lastActivity)) { if (value) {
_lastActivity = cmap; final cmap = toMap();
if (!mapEquals(cmap, _lastActivity)) {
if (_lastActivity.isNotEmpty) { _lastActivity = cmap;
if (_latestActivityId == null) { try {
_liveActivitiesPlugin.createActivity(_lastActivity).then((value) => _latestActivityId = value); if (_lastActivity.isNotEmpty) {
} else { if (_latestActivityId == null) {
_liveActivitiesPlugin.updateActivity(_latestActivityId!, _lastActivity); _liveActivitiesPlugin
.createActivity(_lastActivity)
.then((value) => _latestActivityId = value);
} else {
_liveActivitiesPlugin.updateActivity(
_latestActivityId!, _lastActivity);
}
} else {
if (_latestActivityId != null) {
_liveActivitiesPlugin.endActivity(_latestActivityId!);
}
}
} catch (e) {
if (kDebugMode) {
print('ERROR: Unable to create or update iOS LiveCard!');
}
}
} }
} else {
if (_latestActivityId != null) _liveActivitiesPlugin.endActivity(_latestActivityId!);
} }
} });
} }
List<Lesson> today = _today(_timetable); List<Lesson> today = _today(_timetable);
if (today.isEmpty) { if (today.isEmpty && !_hasCheckedTimetable) {
_hasCheckedTimetable = true;
await _timetable.fetch(week: Week.current()); await _timetable.fetch(week: Week.current());
today = _today(_timetable); today = _today(_timetable);
} }
_delay = _settings.bellDelayEnabled ? Duration(seconds: _settings.bellDelay) : Duration.zero; _delay = _settings.bellDelayEnabled
? Duration(seconds: _settings.bellDelay)
: Duration.zero;
final now = _now().add(_delay); final now = _now().add(_delay);
// Filter cancelled lessons #20 // Filter cancelled lessons #20
// Filter label lessons #128 // Filter label lessons #128
today = today.where((lesson) => lesson.status?.name != "Elmaradt" && lesson.subject.id != '' && !lesson.isEmpty).toList(); today = today
.where((lesson) =>
lesson.status?.name != "Elmaradt" &&
lesson.subject.id != '' &&
!lesson.isEmpty)
.toList();
if (today.isNotEmpty) { if (today.isNotEmpty) {
// sort // sort
today.sort((a, b) => a.start.compareTo(b.start)); today.sort((a, b) => a.start.compareTo(b.start));
final _lesson = today.firstWhere((l) => l.start.isBefore(now) && l.end.isAfter(now), orElse: () => Lesson.fromJson({})); final _lesson = today.firstWhere(
(l) => l.start.isBefore(now) && l.end.isAfter(now),
orElse: () => Lesson.fromJson({}));
if (_lesson.start.year != 0) { if (_lesson.start.year != 0) {
currentLesson = _lesson; currentLesson = _lesson;
@@ -159,7 +241,8 @@ class LiveCardProvider extends ChangeNotifier {
currentLesson = null; currentLesson = null;
} }
final _next = today.firstWhere((l) => l.start.isAfter(now), orElse: () => Lesson.fromJson({})); final _next = today.firstWhere((l) => l.start.isAfter(now),
orElse: () => Lesson.fromJson({}));
nextLessons = today.where((l) => l.start.isAfter(now)).toList(); nextLessons = today.where((l) => l.start.isAfter(now)).toList();
if (_next.start.year != 0) { if (_next.start.year != 0) {
@@ -168,7 +251,8 @@ class LiveCardProvider extends ChangeNotifier {
nextLesson = null; nextLesson = null;
} }
final _prev = today.lastWhere((l) => l.end.isBefore(now), orElse: () => Lesson.fromJson({})); final _prev = today.lastWhere((l) => l.end.isBefore(now),
orElse: () => Lesson.fromJson({}));
if (_prev.start.year != 0) { if (_prev.start.year != 0) {
prevLesson = _prev; prevLesson = _prev;
@@ -177,7 +261,10 @@ class LiveCardProvider extends ChangeNotifier {
} }
} }
if (currentLesson != null) { if (now.isBefore(DateTime(now.year, DateTime.august, 31)) &&
now.isAfter(DateTime(now.year, DateTime.june, 14))) {
currentState = LiveCardState.summary;
} else if (currentLesson != null) {
currentState = LiveCardState.duringLesson; currentState = LiveCardState.duringLesson;
} else if (nextLesson != null && prevLesson != null) { } else if (nextLesson != null && prevLesson != null) {
currentState = LiveCardState.duringBreak; currentState = LiveCardState.duringBreak;
@@ -198,7 +285,10 @@ class LiveCardProvider extends ChangeNotifier {
Duration get delay => _delay; Duration get delay => _delay;
bool _sameDate(DateTime a, DateTime b) => (a.year == b.year && a.month == b.month && a.day == b.day); bool _sameDate(DateTime a, DateTime b) =>
(a.year == b.year && a.month == b.month && a.day == b.day);
List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? []).where((l) => _sameDate(l.date, _now())).toList(); List<Lesson> _today(TimetableProvider p) => (p.getWeek(Week.current()) ?? [])
.where((l) => _sameDate(l.date, _now()))
.toList();
} }

View File

@@ -1,7 +1,4 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:math';
import 'package:filcnaplo/api/client.dart'; import 'package:filcnaplo/api/client.dart';
import 'package:filcnaplo/models/news.dart'; import 'package:filcnaplo/models/news.dart';
import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/models/settings.dart';
@@ -11,7 +8,7 @@ import 'package:provider/provider.dart';
class NewsProvider extends ChangeNotifier { class NewsProvider extends ChangeNotifier {
// Private // Private
late List<News> _news; late List<News> _news;
late int _state; //late int _state;
late int _fresh; late int _fresh;
bool show = false; bool show = false;
late BuildContext _context; late BuildContext _context;
@@ -30,56 +27,83 @@ class NewsProvider extends ChangeNotifier {
Future<void> restore() async { Future<void> restore() async {
// Load news state from the database // Load news state from the database
var state_ = Provider.of<SettingsProvider>(_context, listen: false).newsState; var seen_ = Provider.of<SettingsProvider>(_context, listen: false).seenNews;
if (state_ == -1) { if (seen_.isEmpty) {
var news_ = await FilcAPI.getNews(); var news_ = await FilcAPI.getNews();
if (news_ != null) { if (news_ != null) {
state_ = news_.length;
_news = news_; _news = news_;
show = true;
} }
} }
_state = state_; //_state = seen_;
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state); // Provider.of<SettingsProvider>(_context, listen: false)
// .update(seenNewsId: news_.id);
} }
Future<void> fetch() async { Future<void> fetch() async {
var news_ = await FilcAPI.getNews(); var news_ = await FilcAPI.getNews();
if (news_ == null) return; if (news_ == null) return;
show = false;
_news = news_; _news = news_;
_fresh = news_.length - _state;
if (_fresh < 0) { for (var news in news_) {
_state = news_.length; if (news.expireDate.isAfter(DateTime.now()) &&
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state); Provider.of<SettingsProvider>(_context, listen: false)
.seenNews
.contains(news.id) ==
false) {
show = true;
Provider.of<SettingsProvider>(_context, listen: false)
.update(seenNewsId: news.id);
notifyListeners();
}
} }
// print(news_.length);
// print(_state);
_fresh = max(_fresh, 0); // _news = news_;
// _fresh = news_.length - _state;
if (_fresh > 0) { // if (_fresh < 0) {
show = true; // _state = news_.length;
notifyListeners(); // Provider.of<SettingsProvider>(_context, listen: false)
} // .update(newsState: _state);
// }
// _fresh = max(_fresh, 0);
// if (_fresh > 0) {
// show = true;
// notifyListeners();
// }
// print(_fresh);
// print(_state);
// print(show);
} }
void lock() => show = false; void lock() => show = false;
void release() { void release() {
if (_fresh == 0) return; // if (_fresh == 0) return;
_fresh--; // _fresh--;
_state++; // //_state++;
Provider.of<SettingsProvider>(_context, listen: false).update(newsState: _state); // // Provider.of<SettingsProvider>(_context, listen: false)
// // .update(seenNewsId: _state);
if (_fresh > 0) { // if (_fresh > 0) {
show = true; // show = true;
} else { // } else {
show = false; // show = false;
} // }
notifyListeners(); // notifyListeners();
} }
} }

View File

@@ -3,6 +3,7 @@ import 'dart:math';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
import 'package:filcnaplo/api/client.dart'; import 'package:filcnaplo/api/client.dart';
import 'package:filcnaplo/api/providers/ad_provider.dart';
import 'package:filcnaplo/api/providers/live_card_provider.dart'; import 'package:filcnaplo/api/providers/live_card_provider.dart';
import 'package:filcnaplo/api/providers/news_provider.dart'; import 'package:filcnaplo/api/providers/news_provider.dart';
import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart';
@@ -11,7 +12,10 @@ import 'package:filcnaplo/models/config.dart';
import 'package:filcnaplo/theme/observer.dart'; import 'package:filcnaplo/theme/observer.dart';
import 'package:filcnaplo/theme/theme.dart'; 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_premium/providers/goal_provider.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:i18n_extension/i18n_widget.dart'; import 'package:i18n_extension/i18n_widget.dart';
@@ -22,13 +26,18 @@ import 'package:provider/provider.dart';
import 'package:filcnaplo_mobile_ui/common/system_chrome.dart' as mobile; import 'package:filcnaplo_mobile_ui/common/system_chrome.dart' as mobile;
import 'package:filcnaplo_mobile_ui/screens/login/login_route.dart' as mobile; import 'package:filcnaplo_mobile_ui/screens/login/login_route.dart' as mobile;
import 'package:filcnaplo_mobile_ui/screens/login/login_screen.dart' as mobile; import 'package:filcnaplo_mobile_ui/screens/login/login_screen.dart' as mobile;
import 'package:filcnaplo_mobile_ui/screens/navigation/navigation_screen.dart' as mobile; import 'package:filcnaplo_mobile_ui/screens/navigation/navigation_screen.dart'
import 'package:filcnaplo_mobile_ui/screens/settings/settings_route.dart' as mobile; as mobile;
import 'package:filcnaplo_mobile_ui/screens/settings/settings_screen.dart' as mobile; import 'package:filcnaplo_mobile_ui/screens/settings/settings_route.dart'
as mobile;
import 'package:filcnaplo_mobile_ui/screens/settings/settings_screen.dart'
as mobile;
// Desktop UI // Desktop UI
import 'package:filcnaplo_desktop_ui/screens/navigation/navigation_screen.dart' as desktop; import 'package:filcnaplo_desktop_ui/screens/navigation/navigation_screen.dart'
import 'package:filcnaplo_desktop_ui/screens/login/login_screen.dart' as desktop; as desktop;
import 'package:filcnaplo_desktop_ui/screens/login/login_screen.dart'
as desktop;
import 'package:filcnaplo_desktop_ui/screens/login/login_route.dart' as desktop; import 'package:filcnaplo_desktop_ui/screens/login/login_route.dart' as desktop;
// Providers // Providers
@@ -36,7 +45,6 @@ import 'package:filcnaplo/models/settings.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';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:filcnaplo_kreta_api/providers/homework_provider.dart'; import 'package:filcnaplo_kreta_api/providers/homework_provider.dart';
import 'package:filcnaplo_kreta_api/providers/message_provider.dart'; import 'package:filcnaplo_kreta_api/providers/message_provider.dart';
import 'package:filcnaplo_kreta_api/providers/note_provider.dart'; import 'package:filcnaplo_kreta_api/providers/note_provider.dart';
@@ -52,7 +60,12 @@ class App extends StatelessWidget {
final UserProvider user; final UserProvider user;
final DatabaseProvider database; final DatabaseProvider database;
const App({Key? key, required this.database, required this.settings, required this.user}) : super(key: key); const App(
{Key? key,
required this.database,
required this.settings,
required this.user})
: super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -65,7 +78,8 @@ class App extends StatelessWidget {
final status = StatusProvider(); final status = StatusProvider();
final kreta = KretaClient(user: user, settings: settings, status: status); final kreta = KretaClient(user: user, settings: settings, status: status);
final timetable = TimetableProvider(user: user, database: database, kreta: kreta); final timetable =
TimetableProvider(user: user, database: database, kreta: kreta);
final premium = PremiumProvider(settings: settings); final premium = PremiumProvider(settings: settings);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -77,29 +91,57 @@ class App extends StatelessWidget {
return MultiProvider( return MultiProvider(
providers: [ providers: [
// refilc providers
ChangeNotifierProvider<PremiumProvider>(create: (_) => premium), ChangeNotifierProvider<PremiumProvider>(create: (_) => premium),
ChangeNotifierProvider<SettingsProvider>(create: (_) => settings), ChangeNotifierProvider<SettingsProvider>(create: (_) => settings),
ChangeNotifierProvider<UserProvider>(create: (_) => user), ChangeNotifierProvider<UserProvider>(create: (_) => user),
ChangeNotifierProvider<StatusProvider>(create: (_) => status), ChangeNotifierProvider<StatusProvider>(create: (_) => status),
Provider<KretaClient>(create: (_) => kreta), Provider<KretaClient>(create: (_) => kreta),
Provider<DatabaseProvider>(create: (context) => database), Provider<DatabaseProvider>(create: (context) => database),
ChangeNotifierProvider<ThemeModeObserver>(create: (context) => ThemeModeObserver(initialTheme: settings.theme)), ChangeNotifierProvider<ThemeModeObserver>(
ChangeNotifierProvider<NewsProvider>(create: (context) => NewsProvider(context: context)), create: (context) =>
ChangeNotifierProvider<UpdateProvider>(create: (context) => UpdateProvider(context: context)), ThemeModeObserver(initialTheme: settings.theme)),
ChangeNotifierProvider<NewsProvider>(
create: (context) => NewsProvider(context: context)),
ChangeNotifierProvider<UpdateProvider>(
create: (context) => UpdateProvider(context: context)),
ChangeNotifierProvider<AdProvider>(
create: (context) => AdProvider(context: context)),
// User data providers // user data (kreten) providers
ChangeNotifierProvider<GradeProvider>(create: (_) => GradeProvider(settings: settings, user: user, database: database, kreta: kreta)), ChangeNotifierProvider<GradeProvider>(
create: (_) => GradeProvider(
settings: settings,
user: user,
database: database,
kreta: kreta)),
ChangeNotifierProvider<TimetableProvider>(create: (_) => timetable), ChangeNotifierProvider<TimetableProvider>(create: (_) => timetable),
ChangeNotifierProvider<ExamProvider>(create: (context) => ExamProvider(context: context)), ChangeNotifierProvider<ExamProvider>(
ChangeNotifierProvider<HomeworkProvider>(create: (context) => HomeworkProvider(context: context)), create: (context) => ExamProvider(context: context)),
ChangeNotifierProvider<MessageProvider>(create: (context) => MessageProvider(context: context)), ChangeNotifierProvider<HomeworkProvider>(
ChangeNotifierProvider<NoteProvider>(create: (context) => NoteProvider(context: context)), create: (context) =>
ChangeNotifierProvider<EventProvider>(create: (context) => EventProvider(context: context)), HomeworkProvider(context: context, database: database)),
ChangeNotifierProvider<AbsenceProvider>(create: (context) => AbsenceProvider(context: context)), ChangeNotifierProvider<MessageProvider>(
create: (context) => MessageProvider(context: context)),
ChangeNotifierProvider<NoteProvider>(
create: (context) => NoteProvider(context: context)),
ChangeNotifierProvider<EventProvider>(
create: (context) => EventProvider(context: context)),
ChangeNotifierProvider<AbsenceProvider>(
create: (context) => AbsenceProvider(context: context)),
// other providers
ChangeNotifierProvider<GradeCalculatorProvider>( ChangeNotifierProvider<GradeCalculatorProvider>(
create: (_) => GradeCalculatorProvider(settings: settings, user: user, database: database, kreta: kreta)), create: (_) => GradeCalculatorProvider(
ChangeNotifierProvider<LiveCardProvider>(create: (context) => LiveCardProvider(timetable: timetable, settings: settings)) settings: settings,
user: user,
database: database,
kreta: kreta)),
ChangeNotifierProvider<LiveCardProvider>(
create: (context) =>
LiveCardProvider(timetable: timetable, settings: settings)),
ChangeNotifierProvider<GoalProvider>(
create: (context) => GoalProvider(database: database, user: user)),
], ],
child: Consumer<ThemeModeObserver>( child: Consumer<ThemeModeObserver>(
builder: (context, themeMode, child) { builder: (context, themeMode, child) {
@@ -110,12 +152,15 @@ class App extends StatelessWidget {
return MaterialApp( return MaterialApp(
builder: (context, child) { builder: (context, child) {
// Limit font size scaling to 1.0 // Limit font size scaling to 1.0
double textScaleFactor = min(MediaQuery.of(context).textScaleFactor, 1.0); double textScaleFactor =
min(MediaQuery.of(context).textScaleFactor, 1.0);
return I18n( return I18n(
initialLocale: Locale(settings.language, settings.language.toUpperCase()), initialLocale: Locale(
settings.language, settings.language.toUpperCase()),
child: MediaQuery( child: MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor), data: MediaQuery.of(context)
.copyWith(textScaleFactor: textScaleFactor),
child: child ?? Container(), child: child ?? Container(),
), ),
); );
@@ -148,7 +193,8 @@ class App extends StatelessWidget {
return locale; return locale;
}, },
onGenerateRoute: (settings) => rootNavigator(settings), onGenerateRoute: (settings) => rootNavigator(settings),
initialRoute: user.getUsers().isNotEmpty ? "navigation" : "login", initialRoute:
user.getUsers().isNotEmpty ? "navigation" : "login",
); );
}, },
); );
@@ -158,11 +204,23 @@ class App extends StatelessWidget {
} }
Route? rootNavigator(RouteSettings route) { Route? rootNavigator(RouteSettings route) {
// if platform == android || platform == ios if (kIsWeb) {
if (Platform.isAndroid || Platform.isIOS) {
switch (route.name) { switch (route.name) {
case "login_back": case "login_back":
return CupertinoPageRoute(builder: (context) => const mobile.LoginScreen(back: true)); return CupertinoPageRoute(
builder: (context) => const desktop.LoginScreen(back: true));
case "login":
return _rootRoute(const desktop.LoginScreen());
case "navigation":
return _rootRoute(const desktop.NavigationScreen());
case "login_to_navigation":
return desktop.loginRoute(const desktop.NavigationScreen());
}
} else if (Platform.isAndroid || Platform.isIOS) {
switch (route.name) {
case "login_back":
return CupertinoPageRoute(
builder: (context) => const mobile.LoginScreen(back: true));
case "login": case "login":
return _rootRoute(const mobile.LoginScreen()); return _rootRoute(const mobile.LoginScreen());
case "navigation": case "navigation":
@@ -175,7 +233,8 @@ class App extends StatelessWidget {
} else if (Platform.isWindows || Platform.isMacOS || Platform.isLinux) { } else if (Platform.isWindows || Platform.isMacOS || Platform.isLinux) {
switch (route.name) { switch (route.name) {
case "login_back": case "login_back":
return CupertinoPageRoute(builder: (context) => const desktop.LoginScreen(back: true)); return CupertinoPageRoute(
builder: (context) => const desktop.LoginScreen(back: true));
case "login": case "login":
return _rootRoute(const desktop.LoginScreen()); return _rootRoute(const desktop.LoginScreen());
case "navigation": case "navigation":

View File

@@ -5,41 +5,68 @@ import 'dart:io';
import 'package:filcnaplo/api/providers/database_provider.dart'; import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/database/struct.dart'; import 'package:filcnaplo/database/struct.dart';
import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/models/settings.dart';
import 'package:sqflite/sqflite.dart'; import 'package:flutter/foundation.dart';
// ignore: depend_on_referenced_packages // ignore: depend_on_referenced_packages
import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart';
const settingsDB = DatabaseStruct("settings", { const settingsDB = DatabaseStruct("settings", {
"language": String, "start_page": int, "rounding": int, "theme": int, "accent_color": int, "news": int, "news_state": int, "developer_mode": int, "language": String, "start_page": int, "rounding": int, "theme": int,
"update_channel": int, "config": String, "custom_accent_color": int, "custom_background_color": int, "custom_highlight_color": int, // general "accent_color": int, "news": int, "seen_news": String,
"grade_color1": int, "grade_color2": int, "grade_color3": int, "grade_color4": int, "grade_color5": int, // grade colors "developer_mode": int,
"update_channel": int, "config": String, "custom_accent_color": int,
"custom_background_color": int, "custom_highlight_color": int, // general
"grade_color1": int, "grade_color2": int, "grade_color3": int,
"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,
"notifications": int, "notifications_bitfield": int, "notification_poll_interval": int, // notifications "notifications": int, "notifications_bitfield": int,
"x_filc_id": String, "graph_class_avg": int, "presentation_mode": int, "bell_delay": int, "bell_delay_enabled": int, "notification_poll_interval": int,
"grade_opening_fun": int, "icon_pack": String, "premium_scopes": String, "premium_token": String, "premium_login": String, "notifications_grades": int,
"notifications_absences": int,
"notifications_messages": int,
"notifications_lessons": int, // notifications
"x_filc_id": String, "graph_class_avg": int, "presentation_mode": int,
"bell_delay": int, "bell_delay_enabled": int,
"grade_opening_fun": int, "icon_pack": String, "premium_scopes": String,
"premium_token": String, "premium_login": String,
"last_account_id": String, "renamed_subjects_enabled": int, "last_account_id": String, "renamed_subjects_enabled": int,
"renamed_subjects_italics": int, "renamed_teachers_enabled": int,
"renamed_teachers_italics": int,
"live_activity_color": 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!!!
const usersDB = DatabaseStruct("users", { const usersDB = DatabaseStruct("users", {
"id": String, "name": String, "username": String, "password": String, "institute_code": String, "student": String, "role": int, "id": String, "name": String, "username": String, "password": String,
"institute_code": String, "student": String, "role": int,
"nickname": String, "picture": String // premium only "nickname": String, "picture": String // premium only
}); });
const userDataDB = DatabaseStruct("user_data", { const userDataDB = DatabaseStruct("user_data", {
"id": String, "grades": String, "timetable": String, "exams": String, "homework": String, "messages": String, "notes": String, "id": String, "grades": String, "timetable": String, "exams": String,
"homework": String, "messages": 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,
// renamed teachers // non kreta data
"renamed_teachers": String,
// "subject_lesson_count": String, // non kreta data // "subject_lesson_count": String, // non kreta data
"last_seen_grade": int, "last_seen_grade": int,
// goal planning // non kreta data
"goal_plans": String,
"goal_averages": String,
"goal_befores": String,
"goal_pin_dates": String,
}); });
Future<void> createTable(Database db, DatabaseStruct struct) => db.execute("CREATE TABLE IF NOT EXISTS ${struct.table} ($struct)"); Future<void> createTable(Database db, DatabaseStruct struct) =>
db.execute("CREATE TABLE IF NOT EXISTS ${struct.table} ($struct)");
Future<Database> initDB(DatabaseProvider database) async { Future<Database> initDB(DatabaseProvider database) async {
Database db; Database db;
if (Platform.isLinux || Platform.isWindows) { if (kIsWeb) {
db = await databaseFactoryFfiWeb.openDatabase("app.db");
} else if (Platform.isLinux || Platform.isWindows) {
sqfliteFfiInit(); sqfliteFfiInit();
db = await databaseFactoryFfi.openDatabase("app.db"); db = await databaseFactoryFfi.openDatabase("app.db");
} else { } else {
@@ -50,9 +77,11 @@ Future<Database> initDB(DatabaseProvider database) async {
await createTable(db, usersDB); await createTable(db, usersDB);
await createTable(db, userDataDB); await createTable(db, userDataDB);
if ((await db.rawQuery("SELECT COUNT(*) FROM settings"))[0].values.first == 0) { if ((await db.rawQuery("SELECT COUNT(*) FROM settings"))[0].values.first ==
0) {
// Set default values for table Settings // Set default values for table Settings
await db.insert("settings", SettingsProvider.defaultSettings(database: database).toMap()); await db.insert("settings",
SettingsProvider.defaultSettings(database: database).toMap());
} }
// Migrate Databases // Migrate Databases
@@ -60,7 +89,8 @@ Future<Database> initDB(DatabaseProvider database) async {
await migrateDB( await migrateDB(
db, db,
struct: settingsDB, struct: settingsDB,
defaultValues: SettingsProvider.defaultSettings(database: database).toMap(), defaultValues:
SettingsProvider.defaultSettings(database: database).toMap(),
); );
await migrateDB( await migrateDB(
db, db,
@@ -68,12 +98,20 @@ Future<Database> initDB(DatabaseProvider database) async {
defaultValues: {"role": 0, "nickname": "", "picture": ""}, defaultValues: {"role": 0, "nickname": "", "picture": ""},
); );
await migrateDB(db, struct: userDataDB, defaultValues: { await migrateDB(db, struct: userDataDB, defaultValues: {
"grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]", "messages": "[]", "notes": "[]", "events": "[]", "absences": "[]", "grades": "[]", "timetable": "[]", "exams": "[]", "homework": "[]",
"messages": "[]", "notes": "[]", "events": "[]", "absences": "[]",
"group_averages": "[]", "group_averages": "[]",
// renamed subjects // non kreta data // renamed subjects // non kreta data
"renamed_subjects": "{}", "renamed_subjects": "{}",
// renamed teachers // non kreta data
"renamed_teachers": "{}",
// "subject_lesson_count": "{}", // non kreta data // "subject_lesson_count": "{}", // non kreta data
"last_seen_grade": 0, "last_seen_grade": 0,
// goal planning // non kreta data
"goal_plans": "{}",
"goal_averages": "{}",
"goal_befores": "{}",
"goal_pin_dates": "{}",
}); });
} catch (error) { } catch (error) {
print("ERROR: migrateDB: $error"); print("ERROR: migrateDB: $error");
@@ -99,7 +137,8 @@ Future<void> migrateDB(
// go through each row and add missing keys or delete non existing keys // go through each row and add missing keys or delete non existing keys
await Future.forEach<Map<String, Object?>>(originalRows, (original) async { await Future.forEach<Map<String, Object?>>(originalRows, (original) async {
bool migrationRequired = struct.struct.keys.any((key) => !original.containsKey(key) || original[key] == null) || bool migrationRequired = struct.struct.keys.any(
(key) => !original.containsKey(key) || original[key] == null) ||
original.keys.any((key) => !struct.struct.containsKey(key)); original.keys.any((key) => !struct.struct.containsKey(key));
if (migrationRequired) { if (migrationRequired) {

View File

@@ -26,7 +26,8 @@ class DatabaseQuery {
Future<SettingsProvider> getSettings(DatabaseProvider database) async { Future<SettingsProvider> getSettings(DatabaseProvider database) async {
Map settingsMap = (await db.query("settings")).elementAt(0); Map settingsMap = (await db.query("settings")).elementAt(0);
SettingsProvider settings = SettingsProvider.fromMap(settingsMap, database: database); SettingsProvider settings =
SettingsProvider.fromMap(settingsMap, database: database);
return settings; return settings;
} }
@@ -36,7 +37,10 @@ class DatabaseQuery {
for (var user in usersMap) { for (var user in usersMap) {
userProvider.addUser(User.fromMap(user)); userProvider.addUser(User.fromMap(user));
} }
if (userProvider.getUsers().map((e) => e.id).contains(settings.lastAccountId)) { if (userProvider
.getUsers()
.map((e) => e.id)
.contains(settings.lastAccountId)) {
userProvider.setUser(settings.lastAccountId); userProvider.setUser(settings.lastAccountId);
} else { } else {
if (usersMap.isNotEmpty) { if (usersMap.isNotEmpty) {
@@ -54,100 +58,133 @@ class UserDatabaseQuery {
final Database db; final Database db;
Future<List<Grade>> getGrades({required String userId}) async { Future<List<Grade>> getGrades({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? gradesJson = userData.elementAt(0)["grades"] as String?; String? gradesJson = userData.elementAt(0)["grades"] as String?;
if (gradesJson == null) return []; if (gradesJson == null) return [];
List<Grade> grades = (jsonDecode(gradesJson) as List).map((e) => Grade.fromJson(e)).toList(); List<Grade> grades =
(jsonDecode(gradesJson) as List).map((e) => Grade.fromJson(e)).toList();
return grades; return grades;
} }
Future<Map<Week, List<Lesson>>> getLessons({required String userId}) async { Future<Map<Week, List<Lesson>>> getLessons({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return {}; if (userData.isEmpty) return {};
String? lessonsJson = userData.elementAt(0)["timetable"] as String?; String? lessonsJson = userData.elementAt(0)["timetable"] as String?;
if (lessonsJson == null) return {}; if (lessonsJson == null) return {};
if (jsonDecode(lessonsJson) is List) return {}; if (jsonDecode(lessonsJson) is List) return {};
Map<Week, List<Lesson>> lessons = (jsonDecode(lessonsJson) as Map).cast<String, List>().map((key, value) { Map<Week, List<Lesson>> lessons =
return MapEntry(Week.fromId(int.parse(key)), value.cast<Map<String, Object?>>().map((e) => Lesson.fromJson(e)).toList()); (jsonDecode(lessonsJson) as Map).cast<String, List>().map((key, value) {
return MapEntry(
Week.fromId(int.parse(key)),
value
.cast<Map<String, Object?>>()
.map((e) => Lesson.fromJson(e))
.toList());
}).cast(); }).cast();
return lessons; return lessons;
} }
Future<List<Exam>> getExams({required String userId}) async { Future<List<Exam>> getExams({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? examsJson = userData.elementAt(0)["exams"] as String?; String? examsJson = userData.elementAt(0)["exams"] as String?;
if (examsJson == null) return []; if (examsJson == null) return [];
List<Exam> exams = (jsonDecode(examsJson) as List).map((e) => Exam.fromJson(e)).toList(); List<Exam> exams =
(jsonDecode(examsJson) as List).map((e) => Exam.fromJson(e)).toList();
return exams; return exams;
} }
Future<List<Homework>> getHomework({required String userId}) async { Future<List<Homework>> getHomework({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? homeworkJson = userData.elementAt(0)["homework"] as String?; String? homeworkJson = userData.elementAt(0)["homework"] as String?;
if (homeworkJson == null) return []; if (homeworkJson == null) return [];
List<Homework> homework = (jsonDecode(homeworkJson) as List).map((e) => Homework.fromJson(e)).toList(); List<Homework> homework = (jsonDecode(homeworkJson) as List)
.map((e) => Homework.fromJson(e))
.toList();
return homework; return homework;
} }
Future<List<Message>> getMessages({required String userId}) async { Future<List<Message>> getMessages({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? messagesJson = userData.elementAt(0)["messages"] as String?; String? messagesJson = userData.elementAt(0)["messages"] as String?;
if (messagesJson == null) return []; if (messagesJson == null) return [];
List<Message> messages = (jsonDecode(messagesJson) as List).map((e) => Message.fromJson(e)).toList(); List<Message> messages = (jsonDecode(messagesJson) as List)
.map((e) => Message.fromJson(e))
.toList();
return messages; return messages;
} }
Future<List<Note>> getNotes({required String userId}) async { Future<List<Note>> getNotes({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? notesJson = userData.elementAt(0)["notes"] as String?; String? notesJson = userData.elementAt(0)["notes"] as String?;
if (notesJson == null) return []; if (notesJson == null) return [];
List<Note> notes = (jsonDecode(notesJson) as List).map((e) => Note.fromJson(e)).toList(); List<Note> notes =
(jsonDecode(notesJson) as List).map((e) => Note.fromJson(e)).toList();
return notes; return notes;
} }
Future<List<Event>> getEvents({required String userId}) async { Future<List<Event>> getEvents({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? eventsJson = userData.elementAt(0)["events"] as String?; String? eventsJson = userData.elementAt(0)["events"] as String?;
if (eventsJson == null) return []; if (eventsJson == null) return [];
List<Event> events = (jsonDecode(eventsJson) as List).map((e) => Event.fromJson(e)).toList(); List<Event> events =
(jsonDecode(eventsJson) as List).map((e) => Event.fromJson(e)).toList();
return events; return events;
} }
Future<List<Absence>> getAbsences({required String userId}) async { Future<List<Absence>> getAbsences({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? absencesJson = userData.elementAt(0)["absences"] as String?; String? absencesJson = userData.elementAt(0)["absences"] as String?;
if (absencesJson == null) return []; if (absencesJson == null) return [];
List<Absence> absences = (jsonDecode(absencesJson) as List).map((e) => Absence.fromJson(e)).toList(); List<Absence> absences = (jsonDecode(absencesJson) as List)
.map((e) => Absence.fromJson(e))
.toList();
return absences; return absences;
} }
Future<List<GroupAverage>> getGroupAverages({required String userId}) async { Future<List<GroupAverage>> getGroupAverages({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return []; if (userData.isEmpty) return [];
String? groupAveragesJson = userData.elementAt(0)["group_averages"] as String?; String? groupAveragesJson =
userData.elementAt(0)["group_averages"] as String?;
if (groupAveragesJson == null) return []; if (groupAveragesJson == null) return [];
List<GroupAverage> groupAverages = (jsonDecode(groupAveragesJson) as List).map((e) => GroupAverage.fromJson(e)).toList(); List<GroupAverage> groupAverages = (jsonDecode(groupAveragesJson) as List)
.map((e) => GroupAverage.fromJson(e))
.toList();
return groupAverages; return groupAverages;
} }
Future<SubjectLessonCount> getSubjectLessonCount({required String userId}) async { Future<SubjectLessonCount> getSubjectLessonCount(
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); {required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return SubjectLessonCount.fromMap({}); if (userData.isEmpty) return SubjectLessonCount.fromMap({});
String? lessonCountJson = userData.elementAt(0)["subject_lesson_count"] as String?; String? lessonCountJson =
userData.elementAt(0)["subject_lesson_count"] as String?;
if (lessonCountJson == null) return SubjectLessonCount.fromMap({}); if (lessonCountJson == null) return SubjectLessonCount.fromMap({});
SubjectLessonCount lessonCount = SubjectLessonCount.fromMap(jsonDecode(lessonCountJson) as Map); SubjectLessonCount lessonCount =
SubjectLessonCount.fromMap(jsonDecode(lessonCountJson) as Map);
return lessonCount; return lessonCount;
} }
Future<DateTime> lastSeenGrade({required String userId}) async { Future<DateTime> lastSeenGrade({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return DateTime(0); if (userData.isEmpty) return DateTime(0);
int? lastSeenDate = userData.elementAt(0)["last_seen_grade"] as int?; int? lastSeenDate = userData.elementAt(0)["last_seen_grade"] as int?;
if (lastSeenDate == null) return DateTime(0); if (lastSeenDate == null) return DateTime(0);
@@ -155,11 +192,71 @@ class UserDatabaseQuery {
return lastSeen; return lastSeen;
} }
// renamed things
Future<Map<String, String>> renamedSubjects({required String userId}) async { Future<Map<String, String>> renamedSubjects({required String userId}) async {
List<Map> userData = await db.query("user_data", where: "id = ?", whereArgs: [userId]); List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return {}; if (userData.isEmpty) return {};
String? renamedSubjectsJson = userData.elementAt(0)["renamed_subjects"] as String?; String? renamedSubjectsJson =
userData.elementAt(0)["renamed_subjects"] as String?;
if (renamedSubjectsJson == null) return {}; if (renamedSubjectsJson == null) return {};
return (jsonDecode(renamedSubjectsJson) as Map).map((key, value) => MapEntry(key.toString(), value.toString())); return (jsonDecode(renamedSubjectsJson) as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
}
Future<Map<String, String>> renamedTeachers({required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return {};
String? renamedTeachersJson =
userData.elementAt(0)["renamed_teachers"] as String?;
if (renamedTeachersJson == null) return {};
return (jsonDecode(renamedTeachersJson) as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
}
// goal planner
Future<Map<String, String>> subjectGoalPlans({required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return {};
String? goalPlansJson = userData.elementAt(0)["goal_plans"] as String?;
if (goalPlansJson == null) return {};
return (jsonDecode(goalPlansJson) as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
}
Future<Map<String, String>> subjectGoalAverages(
{required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return {};
String? goalAvgsJson = userData.elementAt(0)["goal_averages"] as String?;
if (goalAvgsJson == null) return {};
return (jsonDecode(goalAvgsJson) as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
}
Future<Map<String, String>> subjectGoalBefores(
{required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return {};
String? goalBeforesJson = userData.elementAt(0)["goal_befores"] as String?;
if (goalBeforesJson == null) return {};
return (jsonDecode(goalBeforesJson) as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
}
Future<Map<String, String>> subjectGoalPinDates(
{required String userId}) async {
List<Map> userData =
await db.query("user_data", where: "id = ?", whereArgs: [userId]);
if (userData.isEmpty) return {};
String? goalPinDatesJson =
userData.elementAt(0)["goal_pin_dates"] as String?;
if (goalPinDatesJson == null) return {};
return (jsonDecode(goalPinDatesJson) as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
} }
} }

View File

@@ -27,9 +27,11 @@ class DatabaseStore {
} }
Future<void> storeUser(User user) async { Future<void> storeUser(User user) async {
List userRes = await db.query("users", where: "id = ?", whereArgs: [user.id]); List userRes =
await db.query("users", where: "id = ?", whereArgs: [user.id]);
if (userRes.isNotEmpty) { if (userRes.isNotEmpty) {
await db.update("users", user.toMap(), where: "id = ?", whereArgs: [user.id]); await db
.update("users", user.toMap(), where: "id = ?", whereArgs: [user.id]);
} else { } else {
await db.insert("users", user.toMap()); await db.insert("users", user.toMap());
await db.insert("user_data", {"id": user.id}); await db.insert("user_data", {"id": user.id});
@@ -49,64 +51,123 @@ class UserDatabaseStore {
Future<void> storeGrades(List<Grade> grades, {required String userId}) async { Future<void> storeGrades(List<Grade> grades, {required String userId}) async {
String gradesJson = jsonEncode(grades.map((e) => e.json).toList()); String gradesJson = jsonEncode(grades.map((e) => e.json).toList());
await db.update("user_data", {"grades": gradesJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"grades": gradesJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeLessons(Map<Week, List<Lesson>?> lessons, {required String userId}) async { Future<void> storeLessons(Map<Week, List<Lesson>?> lessons,
{required String userId}) async {
final map = lessons.map<String, List<Map<String, Object?>>>( final map = lessons.map<String, List<Map<String, Object?>>>(
(k, v) => MapEntry(k.id.toString(), v!.where((e) => e.json != null).map((e) => e.json!).toList().cast()), (k, v) => MapEntry(k.id.toString(),
v!.where((e) => e.json != null).map((e) => e.json!).toList().cast()),
); );
String lessonsJson = jsonEncode(map); String lessonsJson = jsonEncode(map);
await db.update("user_data", {"timetable": lessonsJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"timetable": lessonsJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeExams(List<Exam> exams, {required String userId}) async { Future<void> storeExams(List<Exam> exams, {required String userId}) async {
String examsJson = jsonEncode(exams.map((e) => e.json).toList()); String examsJson = jsonEncode(exams.map((e) => e.json).toList());
await db.update("user_data", {"exams": examsJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"exams": examsJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeHomework(List<Homework> homework, {required String userId}) async { Future<void> storeHomework(List<Homework> homework,
{required String userId}) async {
String homeworkJson = jsonEncode(homework.map((e) => e.json).toList()); String homeworkJson = jsonEncode(homework.map((e) => e.json).toList());
await db.update("user_data", {"homework": homeworkJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"homework": homeworkJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeMessages(List<Message> messages, {required String userId}) async { Future<void> storeMessages(List<Message> messages,
{required String userId}) async {
String messagesJson = jsonEncode(messages.map((e) => e.json).toList()); String messagesJson = jsonEncode(messages.map((e) => e.json).toList());
await db.update("user_data", {"messages": messagesJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"messages": messagesJson},
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}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"notes": notesJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeEvents(List<Event> events, {required String userId}) async { Future<void> storeEvents(List<Event> events, {required String userId}) async {
String eventsJson = jsonEncode(events.map((e) => e.json).toList()); String eventsJson = jsonEncode(events.map((e) => e.json).toList());
await db.update("user_data", {"events": eventsJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"events": eventsJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeAbsences(List<Absence> absences, {required String userId}) async { Future<void> storeAbsences(List<Absence> absences,
{required String userId}) async {
String absencesJson = jsonEncode(absences.map((e) => e.json).toList()); String absencesJson = jsonEncode(absences.map((e) => e.json).toList());
await db.update("user_data", {"absences": absencesJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"absences": absencesJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeGroupAverages(List<GroupAverage> groupAverages, {required String userId}) async { Future<void> storeGroupAverages(List<GroupAverage> groupAverages,
String groupAveragesJson = jsonEncode(groupAverages.map((e) => e.json).toList()); {required String userId}) async {
await db.update("user_data", {"group_averages": groupAveragesJson}, where: "id = ?", whereArgs: [userId]); String groupAveragesJson =
jsonEncode(groupAverages.map((e) => e.json).toList());
await db.update("user_data", {"group_averages": groupAveragesJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeSubjectLessonCount(SubjectLessonCount lessonCount, {required String userId}) async { Future<void> storeSubjectLessonCount(SubjectLessonCount lessonCount,
{required String userId}) async {
String lessonCountJson = jsonEncode(lessonCount.toMap()); String lessonCountJson = jsonEncode(lessonCount.toMap());
await db.update("user_data", {"subject_lesson_count": lessonCountJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"subject_lesson_count": lessonCountJson},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeLastSeenGrade(DateTime date, {required String userId}) async { Future<void> storeLastSeenGrade(DateTime date,
{required String userId}) async {
int lastSeenDate = date.millisecondsSinceEpoch; int lastSeenDate = date.millisecondsSinceEpoch;
await db.update("user_data", {"last_seen_grade": lastSeenDate}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"last_seen_grade": lastSeenDate},
where: "id = ?", whereArgs: [userId]);
} }
Future<void> storeRenamedSubjects(Map<String, String> subjects, {required String userId}) async { // renamed things
Future<void> storeRenamedSubjects(Map<String, String> subjects,
{required String userId}) async {
String renamedSubjectsJson = jsonEncode(subjects); String renamedSubjectsJson = jsonEncode(subjects);
await db.update("user_data", {"renamed_subjects": renamedSubjectsJson}, where: "id = ?", whereArgs: [userId]); await db.update("user_data", {"renamed_subjects": renamedSubjectsJson},
where: "id = ?", whereArgs: [userId]);
}
Future<void> storeRenamedTeachers(Map<String, String> teachers,
{required String userId}) async {
String renamedTeachersJson = jsonEncode(teachers);
await db.update("user_data", {"renamed_teachers": renamedTeachersJson},
where: "id = ?", whereArgs: [userId]);
}
// goal planner
Future<void> storeSubjectGoalPlans(Map<String, String> plans,
{required String userId}) async {
String goalPlansJson = jsonEncode(plans);
await db.update("user_data", {"goal_plans": goalPlansJson},
where: "id = ?", whereArgs: [userId]);
}
Future<void> storeSubjectGoalAverages(Map<String, String> avgs,
{required String userId}) async {
String goalAvgsJson = jsonEncode(avgs);
await db.update("user_data", {"goal_averages": goalAvgsJson},
where: "id = ?", whereArgs: [userId]);
}
Future<void> storeSubjectGoalBefores(Map<String, String> befores,
{required String userId}) async {
String goalBeforesJson = jsonEncode(befores);
await db.update("user_data", {"goal_befores": goalBeforesJson},
where: "id = ?", whereArgs: [userId]);
}
Future<void> storeSubjectGoalPinDates(Map<String, String> dates,
{required String userId}) async {
String goalPinDatesJson = jsonEncode(dates);
await db.update("user_data", {"goal_pin_dates": goalPinDatesJson},
where: "id = ?", whereArgs: [userId]);
} }
} }

View File

@@ -0,0 +1,601 @@
import 'package:filcnaplo/api/providers/database_provider.dart';
import 'package:filcnaplo/api/providers/status_provider.dart';
import 'package:filcnaplo/api/providers/user_provider.dart';
import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/helpers/notification_helper.i18n.dart';
import 'package:filcnaplo_kreta_api/client/api.dart';
import 'package:filcnaplo_kreta_api/client/client.dart';
import 'package:filcnaplo_kreta_api/models/absence.dart';
import 'package:filcnaplo_kreta_api/models/grade.dart';
import 'package:filcnaplo_kreta_api/models/lesson.dart';
import 'package:filcnaplo_kreta_api/models/week.dart';
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
import 'package:filcnaplo_kreta_api/providers/timetable_provider.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'
hide Message;
import 'package:i18n_extension/i18n_widget.dart';
import 'package:intl/intl.dart';
import 'package:filcnaplo_kreta_api/models/message.dart';
class NotificationsHelper {
late DatabaseProvider database;
late SettingsProvider settingsProvider;
late UserProvider userProvider;
late KretaClient kretaClient;
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
List<T> combineLists<T, K>(
List<T> list1,
List<T> list2,
K Function(T) keyExtractor,
) {
Set<K> uniqueKeys = <K>{};
List<T> combinedList = [];
for (T item in list1) {
K key = keyExtractor(item);
if (!uniqueKeys.contains(key)) {
uniqueKeys.add(key);
combinedList.add(item);
}
}
for (T item in list2) {
K key = keyExtractor(item);
if (!uniqueKeys.contains(key)) {
uniqueKeys.add(key);
combinedList.add(item);
}
}
return combinedList;
}
String dayTitle(DateTime date) {
try {
return DateFormat("EEEE", I18n.locale.languageCode).format(date);
} catch (e) {
return "Unknown";
}
}
@pragma('vm:entry-point')
void backgroundJob() async {
// initialize providers
database = DatabaseProvider();
await database.init();
settingsProvider = await database.query.getSettings(database);
userProvider = await database.query.getUsers(settingsProvider);
if (userProvider.id != null && settingsProvider.notificationsEnabled) {
// refresh kreta login
final status = StatusProvider();
kretaClient = KretaClient(
user: userProvider, settings: settingsProvider, status: status);
kretaClient.refreshLogin();
if (settingsProvider.notificationsGradesEnabled) gradeNotification();
if (settingsProvider.notificationsAbsencesEnabled) absenceNotification();
if (settingsProvider.notificationsMessagesEnabled) messageNotification();
if (settingsProvider.notificationsLessonsEnabled) lessonNotification();
}
}
void gradeNotification() async {
// fetch grades
GradeProvider gradeProvider = GradeProvider(
settings: settingsProvider,
user: userProvider,
database: database,
kreta: kretaClient);
gradeProvider.fetch();
List<Grade> grades =
await database.userQuery.getGrades(userId: userProvider.id ?? "");
DateTime lastSeenGrade =
await database.userQuery.lastSeenGrade(userId: userProvider.id ?? "");
// loop through grades and see which hasn't been seen yet
for (Grade grade in grades) {
// if grade is not a normal grade (1-5), don't show it
if ([1, 2, 3, 4, 5].contains(grade.value.value)) {
// if the grade was added over a week ago, don't show it to avoid notification spam
if (grade.seenDate.isAfter(lastSeenGrade) &&
grade.date.difference(DateTime.now()).inDays * -1 < 7) {
// send notificiation about new grade
AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails(
'GRADES',
'Jegyek',
channelDescription: 'Értesítés jegyek beírásakor',
importance: Importance.max,
priority: Priority.max,
color: settingsProvider.customAccentColor,
ticker: 'Jegyek',
);
NotificationDetails notificationDetails =
NotificationDetails(android: androidNotificationDetails);
if (userProvider.getUsers().length == 1) {
await flutterLocalNotificationsPlugin.show(
grade.id.hashCode,
"title_grade".i18n,
"body_grade".i18n.fill(
[
grade.value.value.toString(),
grade.subject.isRenamed &&
settingsProvider.renamedSubjectsEnabled
? grade.subject.renamedTo!
: grade.subject.name
],
),
notificationDetails,
);
} else {
// multiple users are added, also display student name
await flutterLocalNotificationsPlugin.show(
grade.id.hashCode,
"title_grade".i18n,
"body_grade_multiuser".i18n.fill(
[
userProvider.displayName!,
grade.value.value.toString(),
grade.subject.isRenamed &&
settingsProvider.renamedSubjectsEnabled
? grade.subject.renamedTo!
: grade.subject.name
],
),
notificationDetails,
);
}
}
}
}
// set grade seen status
gradeProvider.seenAll();
}
void absenceNotification() async {
// get absences from api
List? absenceJson = await kretaClient
.getAPI(KretaAPI.absences(userProvider.instituteCode ?? ""));
List<Absence> storedAbsences =
await database.userQuery.getAbsences(userId: userProvider.id!);
if (absenceJson == null) {
return;
}
// format api absences to correct format while preserving isSeen value
List<Absence> absences = absenceJson.map((e) {
Absence apiAbsence = Absence.fromJson(e);
Absence storedAbsence = storedAbsences.firstWhere(
(stored) => stored.id == apiAbsence.id,
orElse: () => apiAbsence);
apiAbsence.isSeen = storedAbsence.isSeen;
return apiAbsence;
}).toList();
List<Absence> modifiedAbsences = [];
if (absences != storedAbsences) {
// remove absences that are not new
absences.removeWhere((element) => storedAbsences.contains(element));
for (Absence absence in absences) {
if (!absence.isSeen) {
absence.isSeen = true;
modifiedAbsences.add(absence);
AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails(
'ABSENCES',
'Hiányzások',
channelDescription: 'Értesítés hiányzások beírásakor',
importance: Importance.max,
priority: Priority.max,
color: settingsProvider.customAccentColor,
ticker: 'Hiányzások',
);
NotificationDetails notificationDetails =
NotificationDetails(android: androidNotificationDetails);
if (userProvider.getUsers().length == 1) {
await flutterLocalNotificationsPlugin.show(
absence.id.hashCode,
"title_absence".i18n,
"body_absence".i18n.fill(
[
DateFormat("yyyy-MM-dd").format(absence.date),
absence.subject.isRenamed &&
settingsProvider.renamedSubjectsEnabled
? absence.subject.renamedTo!
: absence.subject.name
],
),
notificationDetails,
);
} else {
await flutterLocalNotificationsPlugin.show(
absence.id.hashCode,
"title_absence".i18n,
"body_absence_multiuser".i18n.fill(
[
userProvider.displayName!,
DateFormat("yyyy-MM-dd").format(absence.date),
absence.subject.isRenamed &&
settingsProvider.renamedSubjectsEnabled
? absence.subject.renamedTo!
: absence.subject.name
],
),
notificationDetails,
);
}
}
}
}
// combine modified absences and storedabsences list and save them to the database
List<Absence> combinedAbsences = combineLists(
modifiedAbsences,
storedAbsences,
(Absence absence) => absence.id,
);
await database.userStore
.storeAbsences(combinedAbsences, userId: userProvider.id!);
}
void messageNotification() async {
// get messages from api
List? messageJson =
await kretaClient.getAPI(KretaAPI.messages("beerkezett"));
List<Message> storedmessages =
await database.userQuery.getMessages(userId: userProvider.id!);
if (messageJson == null) {
return;
}
// format api messages to correct format while preserving isSeen value
// Parse messages
List<Message> messages = [];
await Future.wait(List.generate(messageJson.length, (index) {
return () async {
Map message = messageJson.cast<Map>()[index];
Map? innerMessageJson = await kretaClient
.getAPI(KretaAPI.message(message["azonosito"].toString()));
if (innerMessageJson != null) {
messages.add(
Message.fromJson(innerMessageJson, forceType: MessageType.inbox));
}
}();
}));
for (Message message in messages) {
for (Message storedMessage in storedmessages) {
if (message.id == storedMessage.id) {
message.isSeen = storedMessage.isSeen;
}
}
}
List<Message> modifiedmessages = [];
if (messages != storedmessages) {
// remove messages that are not new
messages.removeWhere((element) => storedmessages.contains(element));
for (Message message in messages) {
if (!message.isSeen) {
message.isSeen = true;
modifiedmessages.add(message);
AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails(
'MESSAGES',
'Üzenetek',
channelDescription: 'Értesítés kapott üzenetekkor',
importance: Importance.max,
priority: Priority.max,
color: settingsProvider.customAccentColor,
ticker: 'Üzenetek',
);
NotificationDetails notificationDetails =
NotificationDetails(android: androidNotificationDetails);
if (userProvider.getUsers().length == 1) {
await flutterLocalNotificationsPlugin.show(
message.id.hashCode,
message.author,
message.content.replaceAll(RegExp(r'<[^>]*>'), ''),
notificationDetails,
);
} else {
await flutterLocalNotificationsPlugin.show(
message.id.hashCode,
"(${userProvider.displayName!}) ${message.author}",
message.content.replaceAll(RegExp(r'<[^>]*>'), ''),
notificationDetails,
);
}
}
}
}
// combine modified messages and storedmessages list and save them to the database
List<Message> combinedmessages = combineLists(
modifiedmessages,
storedmessages,
(Message message) => message.id,
);
await database.userStore
.storeMessages(combinedmessages, userId: userProvider.id!);
}
void lessonNotification() async {
// get lesson from api
TimetableProvider timetableProvider = TimetableProvider(
user: userProvider, database: database, kreta: kretaClient);
List<Lesson> storedlessons =
timetableProvider.lessons[Week.current()] ?? [];
List? apilessons = timetableProvider.getWeek(Week.current()) ?? [];
for (Lesson lesson in apilessons) {
for (Lesson storedLesson in storedlessons) {
if (lesson.id == storedLesson.id) {
lesson.isSeen = storedLesson.isSeen;
}
}
}
List<Lesson> modifiedlessons = [];
if (apilessons != storedlessons) {
// remove lessons that are not new
apilessons.removeWhere((element) => storedlessons.contains(element));
for (Lesson lesson in apilessons) {
if (!lesson.isSeen && lesson.isChanged) {
lesson.isSeen = true;
modifiedlessons.add(lesson);
AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails(
'LESSONS',
'Órák',
channelDescription:
'Értesítés órák elmaradásáról, helyettesítésről',
importance: Importance.max,
priority: Priority.max,
color: settingsProvider.customAccentColor,
ticker: 'Órák',
);
NotificationDetails notificationDetails =
NotificationDetails(android: androidNotificationDetails);
if (userProvider.getUsers().length == 1) {
if (lesson.status?.name == "Elmaradt") {
switch (I18n.localeStr) {
case "en_en":
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_canceled".i18n.fill(
[
lesson.lessonIndex,
lesson.name,
dayTitle(lesson.date)
],
),
notificationDetails,
);
break;
}
case "hu_hu":
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_canceled".i18n.fill(
[
dayTitle(lesson.date),
lesson.lessonIndex,
lesson.name
],
),
notificationDetails,
);
break;
}
default:
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_canceled".i18n.fill(
[
lesson.lessonIndex,
lesson.name,
dayTitle(lesson.date)
],
),
notificationDetails,
);
break;
}
}
} else if (lesson.substituteTeacher?.name != "") {
switch (I18n.localeStr) {
case "en_en":
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_substituted".i18n.fill(
[
lesson.lessonIndex,
lesson.name,
dayTitle(lesson.date),
lesson.substituteTeacher!.isRenamed
? lesson.substituteTeacher!.renamedTo!
: lesson.substituteTeacher!.name
],
),
notificationDetails,
);
break;
}
case "hu_hu":
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_substituted".i18n.fill(
[
dayTitle(lesson.date),
lesson.lessonIndex,
lesson.name,
lesson.substituteTeacher!.isRenamed
? lesson.substituteTeacher!.renamedTo!
: lesson.substituteTeacher!.name
],
),
notificationDetails,
);
break;
}
default:
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_substituted".i18n.fill(
[
lesson.lessonIndex,
lesson.name,
dayTitle(lesson.date),
lesson.substituteTeacher!.isRenamed
? lesson.substituteTeacher!.renamedTo!
: lesson.substituteTeacher!.name
],
),
notificationDetails,
);
break;
}
}
}
} else {
if (lesson.status?.name == "Elmaradt") {
switch (I18n.localeStr) {
case "en_en":
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_canceled".i18n.fill(
[
userProvider.displayName!,
lesson.lessonIndex,
lesson.name,
dayTitle(lesson.date)
],
),
notificationDetails,
);
break;
}
case "hu_hu":
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_canceled".i18n.fill(
[
userProvider.displayName!,
dayTitle(lesson.date),
lesson.lessonIndex,
lesson.name
],
),
notificationDetails,
);
break;
}
default:
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_canceled".i18n.fill(
[
userProvider.displayName!,
lesson.lessonIndex,
lesson.name,
dayTitle(lesson.date)
],
),
notificationDetails,
);
break;
}
}
} else if (lesson.substituteTeacher?.name != "") {
switch (I18n.localeStr) {
case "en_en":
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_substituted".i18n.fill(
[
userProvider.displayName!,
lesson.lessonIndex,
lesson.name,
dayTitle(lesson.date),
lesson.substituteTeacher!.isRenamed
? lesson.substituteTeacher!.renamedTo!
: lesson.substituteTeacher!.name
],
),
notificationDetails,
);
break;
}
case "hu_hu":
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_substituted".i18n.fill(
[
userProvider.displayName!,
dayTitle(lesson.date),
lesson.lessonIndex,
lesson.name,
lesson.substituteTeacher!.isRenamed
? lesson.substituteTeacher!.renamedTo!
: lesson.substituteTeacher!.name
],
),
notificationDetails,
);
break;
}
default:
{
await flutterLocalNotificationsPlugin.show(
lesson.id.hashCode,
"title_lesson".i18n,
"body_lesson_substituted".i18n.fill(
[
userProvider.displayName!,
lesson.lessonIndex,
lesson.name,
dayTitle(lesson.date),
lesson.substituteTeacher!.isRenamed
? lesson.substituteTeacher!.renamedTo!
: lesson.substituteTeacher!.name
],
),
notificationDetails,
);
break;
}
}
}
}
}
}
// combine modified lesson and storedlesson list and save them to the database
List<Lesson> combinedlessons = combineLists(
modifiedlessons,
storedlessons,
(Lesson message) => message.id,
);
Map<Week, List<Lesson>> timetableLessons = timetableProvider.lessons;
timetableLessons[Week.current()] = combinedlessons;
await database.userStore
.storeLessons(timetableLessons, userId: userProvider.id!);
}
}
}

View File

@@ -0,0 +1,51 @@
import 'package:i18n_extension/i18n_extension.dart';
extension Localization on String {
static final _t = Translations.byLocale("hu_hu") +
{
"en_en": {
"title_grade": "New grade",
"body_grade": "You got a %s in %s",
"body_grade_multiuser": "%s got a %s in %s",
"title_absence": "Absence recorded",
"body_absence": "An absence was recorded on %s for %s",
"body_absence_multiuser": "An absence was recorded for %s on %s for the subject %s",
"title_lesson": "Timetable modified",
"body_lesson_canceled": "Lesson #%s (%s) has been canceled on %s",
"body_lesson_canceled_multiuser": "(%s) Lesson #%s (%s) has been canceled on %s",
"body_lesson_substituted": "Lesson #%s (%s) on %s will be substituted by %s",
"body_lesson_substituted_multiuser": "(%s) Lesson #%s (%s) on %s will be substituted by %s"
},
"hu_hu": {
"title_grade": "Új jegy",
"body_grade": "%s-st kaptál %s tantárgyból",
"body_grade_multiuser": "%s tanuló %s-st kapott %s tantárgyból",
"title_absence": "Új hiányzás",
"body_absence": "Új hiányzást kaptál %s napon %s tantárgyból",
"body_absence_multiuser": "%s tanuló új hiányzást kapott %s napon %s tantárgyból",
"title_lesson": "Órarend szerkesztve",
"body_lesson_canceled": "%s-i %s. óra (%s) elmarad",
"body_lesson_canceled_multiuser": "(%s) %s-i %s. óra (%s) elmarad",
"body_lesson_substituted": "%s-i %s. (%s) órát %s helyettesíti",
"body_lesson_substituted_multiuser": "(%s) %s-i %s. (%s) órát %s helyettesíti"
},
"de_de": {
"title_grade": "Neue Note",
"body_grade": "Du hast eine %s in %s",
"body_grade_multiuser": "%s hast eine %s in %s",
"title_absence": "Abwesenheit aufgezeichnet",
"body_absence": "Auf %s für %s wurde eine Abwesenheit aufgezeichnet",
"body_absence_multiuser": "Für %s wurde am %s für das Thema Mathematik eine Abwesenheit aufgezeichnet",
"title_lesson": "Fahrplan geändert",
"body_lesson_canceled": "Lektion Nr. %s (%s) wurde am %s abgesagt",
"body_lesson_canceled_multiuser": "(%s) Lektion Nr. %s (%s) wurde am %s abgesagt",
"body_lesson_substituted": "Lektion Nr. %s (%s) wird am %s durch %s ersetzt",
"body_lesson_substituted_multiuser": "(%s) Lektion Nr. %s (%s) wird am %s durch %s ersetzt"
},
};
String get i18n => localize(this, _t);
String fill(List<Object> params) => localizeFill(this, params);
String plural(int value) => localizePlural(value, this, _t);
String version(Object modifier) => localizeVersion(modifier, this, _t);
}

View File

@@ -9,7 +9,7 @@ import 'package:permission_handler/permission_handler.dart';
class StorageHelper { class StorageHelper {
static Future<bool> write(String path, Uint8List data) async { static Future<bool> write(String path, Uint8List data) async {
try { try {
if (await Permission.storage.request().isGranted) { if (await Permission.manageExternalStorage.request().isGranted) {
await File(path).writeAsBytes(data); await File(path).writeAsBytes(data);
return true; return true;
} else { } else {
@@ -34,5 +34,6 @@ class StorageHelper {
} }
return downloads; return downloads;
// return (await getTemporaryDirectory()).path;
} }
} }

View File

@@ -6,6 +6,7 @@ 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_file/open_file.dart';
import 'package:permission_handler/permission_handler.dart';
enum UpdateState { none, preparing, downloading, installing } enum UpdateState { none, preparing, downloading, installing }
@@ -19,23 +20,30 @@ extension UpdateHelper on Release {
updateCallback!(-1, UpdateState.preparing); updateCallback!(-1, UpdateState.preparing);
String downloads = await StorageHelper.downloadsPath(); String downloads = await StorageHelper.downloadsPath();
File apk = File("$downloads/filcnaplo-$version.apk"); File apk = File("$downloads/refilc-v$version.apk");
if (!await apk.exists()) { if (!await apk.exists()) {
updateCallback(-1, UpdateState.downloading); updateCallback(-1, UpdateState.downloading);
var bytes = await download(updateCallback: updateCallback); var bytes = await download(updateCallback: updateCallback);
if (!await StorageHelper.write(apk.path, bytes)) throw "failed to write apk: permission denied"; if (!await StorageHelper.write(apk.path, bytes)) {
throw "failed to write apk: permission denied";
}
} }
updateCallback(-1, UpdateState.installing); updateCallback(-1, UpdateState.installing);
var result = await OpenFile.open(apk.path); var installPerms =
(await Permission.manageExternalStorage.request().isGranted &&
await Permission.requestInstallPackages.request().isGranted);
if (installPerms) {
var result = await OpenFile.open(apk.path);
if (result.type != ResultType.done) { if (result.type != ResultType.done) {
// ignore: avoid_print // ignore: avoid_print
print("ERROR: installUpdate.openFile: ${result.message}"); print("ERROR: installUpdate.openFile: ${result.message}");
throw result.message; throw result.message;
}
} }
updateCallback(-1, UpdateState.none); updateCallback(-1, UpdateState.none);
@@ -50,7 +58,8 @@ extension UpdateHelper on Release {
var completer = Completer<Uint8List>(); var completer = Completer<Uint8List>();
response?.stream.listen((List<int> chunk) { response?.stream.listen((List<int> chunk) {
updateCallback!(downloaded / (response.contentLength ?? 0), UpdateState.downloading); updateCallback!(
downloaded / (response.contentLength ?? 0), UpdateState.downloading);
chunks.add(chunk); chunks.add(chunk);
downloaded += chunk.length; downloaded += chunk.length;

View File

@@ -1,7 +1,10 @@
import 'dart:io';
import 'package:background_fetch/background_fetch.dart'; import 'package:background_fetch/background_fetch.dart';
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/database/init.dart'; import 'package:filcnaplo/database/init.dart';
import 'package:filcnaplo/helpers/notification_helper.dart';
import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/models/settings.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -9,6 +12,7 @@ import 'package:filcnaplo/app.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:filcnaplo_mobile_ui/screens/error_screen.dart'; import 'package:filcnaplo_mobile_ui/screens/error_screen.dart';
import 'package:filcnaplo_mobile_ui/screens/error_report_screen.dart'; import 'package:filcnaplo_mobile_ui/screens/error_report_screen.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
void main() async { void main() async {
// Initalize // Initalize
@@ -26,9 +30,10 @@ void main() async {
// Run App // Run App
runApp(App( runApp(App(
database: startup.database, database: startup.database,
settings: startup.settings, settings: startup.settings,
user: startup.user)); user: startup.user,
));
} }
class Startup { class Startup {
@@ -43,6 +48,69 @@ class Startup {
await database.init(); await database.init();
settings = await database.query.getSettings(database); settings = await database.query.getSettings(database);
user = await database.query.getUsers(settings); user = await database.query.getUsers(settings);
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
// Notifications setup
if (!kIsWeb) {
initPlatformState();
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
}
// Get permission to show notifications
if (kIsWeb) {
// do nothing
} else if (Platform.isAndroid) {
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()!
.requestPermission();
} else if (Platform.isIOS) {
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: false,
badge: true,
sound: true,
);
} else if (Platform.isMacOS) {
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
MacOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
alert: false,
badge: true,
sound: true,
);
} else if (Platform.isLinux) {
// no permissions are needed on linux
}
// Platform specific settings
if (!kIsWeb) {
const DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings(
requestSoundPermission: true,
requestBadgePermission: true,
requestAlertPermission: false,
);
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('ic_notification');
const LinuxInitializationSettings initializationSettingsLinux =
LinuxInitializationSettings(defaultActionName: 'Open notification');
const InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
macOS: initializationSettingsDarwin,
linux: initializationSettingsLinux,
);
// Initialize notifications
await flutterLocalNotificationsPlugin.initialize(
initializationSettings,
);
}
} }
} }
@@ -72,8 +140,58 @@ Widget errorBuilder(FlutterErrorDetails details) {
}); });
} }
Future<void> initPlatformState() async {
// Configure BackgroundFetch.
int status = await BackgroundFetch.configure(
BackgroundFetchConfig(
minimumFetchInterval: 15,
stopOnTerminate: false,
enableHeadless: true,
requiresBatteryNotLow: false,
requiresCharging: false,
requiresStorageNotLow: false,
requiresDeviceIdle: false,
requiredNetworkType: NetworkType.ANY,
startOnBoot: true), (String taskId) async {
// <-- Event handler
if (kDebugMode) {
print("[BackgroundFetch] Event received $taskId");
}
NotificationsHelper().backgroundJob();
BackgroundFetch.finish(taskId);
}, (String taskId) async {
// <-- Task timeout handler.
if (kDebugMode) {
print("[BackgroundFetch] TASK TIMEOUT taskId: $taskId");
}
BackgroundFetch.finish(taskId);
});
if (kDebugMode) {
print('[BackgroundFetch] configure success: $status');
}
BackgroundFetch.scheduleTask(TaskConfig(
taskId: "com.transistorsoft.refilcnotification",
delay: 900000, // 15 minutes
periodic: true,
forceAlarmManager: true,
stopOnTerminate: false,
enableHeadless: true));
}
@pragma('vm:entry-point') @pragma('vm:entry-point')
void backgroundHeadlessTask(HeadlessTask task) { void backgroundHeadlessTask(HeadlessTask task) {
print('[BackgroundFetch] Headless event received.'); String taskId = task.taskId;
bool isTimeout = task.timeout;
if (isTimeout) {
if (kDebugMode) {
print("[BackgroundFetch] Headless task timed-out: $taskId");
}
BackgroundFetch.finish(taskId);
return;
}
if (kDebugMode) {
print('[BackgroundFetch] Headless event received.');
}
NotificationsHelper().backgroundJob();
BackgroundFetch.finish(task.taskId); BackgroundFetch.finish(task.taskId);
} }

View File

@@ -0,0 +1,38 @@
class Ad {
String title;
String description;
String author;
Uri? logoUrl;
bool overridePremium;
DateTime date;
DateTime expireDate;
Uri launchUrl;
Ad({
required this.title,
required this.description,
required this.author,
this.logoUrl,
this.overridePremium = false,
required this.date,
required this.expireDate,
required this.launchUrl,
});
factory Ad.fromJson(Map json) {
print(json);
return Ad(
title: json['title'] ?? 'Ad',
description: json['description'] ?? '',
author: json['author'] ?? 'reFilc',
logoUrl: json['logo_url'] != null ? Uri.parse(json['logo_url']) : null,
overridePremium: json['override_premium'] ?? false,
date:
json['date'] != null ? DateTime.parse(json['date']) : DateTime.now(),
expireDate: json['expire_date'] != null
? DateTime.parse(json['expire_date'])
: DateTime.now(),
launchUrl: Uri.parse(json['launch_url'] ?? 'https://refilc.hu'),
);
}
}

View File

@@ -1,30 +1,36 @@
class News { class News {
String id;
String title; String title;
String content; String content;
String link; String link;
String openLabel; String openLabel;
String platform; String platform;
bool emergency; bool emergency;
DateTime expireDate;
Map? json; Map? json;
News({ News({
required this.id,
required this.title, required this.title,
required this.content, required this.content,
required this.link, required this.link,
required this.openLabel, required this.openLabel,
required this.platform, required this.platform,
required this.emergency, required this.emergency,
required this.expireDate,
this.json, this.json,
}); });
factory News.fromJson(Map json) { factory News.fromJson(Map json) {
return News( return News(
id: json["id"] ?? "",
title: json["title"] ?? "", title: json["title"] ?? "",
content: json["content"] ?? "", content: json["content"] ?? "",
link: json["link"] ?? "", link: json["link"] ?? "",
openLabel: json["open_label"] ?? "", openLabel: json["open_label"] ?? "",
platform: json["platform"] ?? "", platform: json["platform"] ?? "",
emergency: json["emergency"] ?? false, emergency: json["emergency"] ?? false,
expireDate: DateTime.parse(json["expire_date"] ?? ''),
json: json, json: json,
); );
} }

View File

@@ -0,0 +1,21 @@
class Personality {
PersonalityType type;
Personality({
this.type = PersonalityType.npc,
});
}
enum PersonalityType {
geek,
sick,
late,
quitter,
healthy,
acceptable,
fallible,
average,
diligent,
cheater,
npc
}

View File

@@ -29,8 +29,12 @@ class SettingsProvider extends ChangeNotifier {
// zero is one, ... // zero is one, ...
List<Color> _gradeColors; List<Color> _gradeColors;
bool _newsEnabled; bool _newsEnabled;
int _newsState; String _seenNews;
bool _notificationsEnabled; bool _notificationsEnabled;
bool _notificationsGradesEnabled;
bool _notificationsAbsencesEnabled;
bool _notificationsMessagesEnabled;
bool _notificationsLessonsEnabled;
/* /*
notificationsBitfield values: notificationsBitfield values:
@@ -68,6 +72,10 @@ class SettingsProvider extends ChangeNotifier {
String _premiumLogin; String _premiumLogin;
String _lastAccountId; String _lastAccountId;
bool _renamedSubjectsEnabled; bool _renamedSubjectsEnabled;
bool _renamedSubjectsItalics;
bool _renamedTeachersEnabled;
bool _renamedTeachersItalics;
Color _liveActivityColor;
SettingsProvider({ SettingsProvider({
DatabaseProvider? database, DatabaseProvider? database,
@@ -78,8 +86,12 @@ class SettingsProvider extends ChangeNotifier {
required AccentColor accentColor, required AccentColor accentColor,
required List<Color> gradeColors, required List<Color> gradeColors,
required bool newsEnabled, required bool newsEnabled,
required int newsState, required String seenNews,
required bool notificationsEnabled, required bool notificationsEnabled,
required bool notificationsGradesEnabled,
required bool notificationsAbsencesEnabled,
required bool notificationsMessagesEnabled,
required bool notificationsLessonsEnabled,
required int notificationsBitfield, required int notificationsBitfield,
required bool developerMode, required bool developerMode,
required int notificationPollInterval, required int notificationPollInterval,
@@ -104,6 +116,10 @@ class SettingsProvider extends ChangeNotifier {
required String premiumLogin, required String premiumLogin,
required String lastAccountId, required String lastAccountId,
required bool renameSubjectsEnabled, required bool renameSubjectsEnabled,
required bool renameSubjectsItalics,
required bool renameTeachersEnabled,
required bool renameTeachersItalics,
required Color liveActivityColor,
}) : _database = database, }) : _database = database,
_language = language, _language = language,
_startPage = startPage, _startPage = startPage,
@@ -112,8 +128,12 @@ class SettingsProvider extends ChangeNotifier {
_accentColor = accentColor, _accentColor = accentColor,
_gradeColors = gradeColors, _gradeColors = gradeColors,
_newsEnabled = newsEnabled, _newsEnabled = newsEnabled,
_newsState = newsState, _seenNews = seenNews,
_notificationsEnabled = notificationsEnabled, _notificationsEnabled = notificationsEnabled,
_notificationsGradesEnabled = notificationsGradesEnabled,
_notificationsAbsencesEnabled = notificationsAbsencesEnabled,
_notificationsMessagesEnabled = notificationsMessagesEnabled,
_notificationsLessonsEnabled = notificationsLessonsEnabled,
_notificationsBitfield = notificationsBitfield, _notificationsBitfield = notificationsBitfield,
_developerMode = developerMode, _developerMode = developerMode,
_notificationPollInterval = notificationPollInterval, _notificationPollInterval = notificationPollInterval,
@@ -137,7 +157,11 @@ class SettingsProvider extends ChangeNotifier {
_premiumAccessToken = premiumAccessToken, _premiumAccessToken = premiumAccessToken,
_premiumLogin = premiumLogin, _premiumLogin = premiumLogin,
_lastAccountId = lastAccountId, _lastAccountId = lastAccountId,
_renamedSubjectsEnabled = renameSubjectsEnabled; _renamedSubjectsEnabled = renameSubjectsEnabled,
_renamedSubjectsItalics = renameSubjectsItalics,
_renamedTeachersEnabled = renameTeachersEnabled,
_renamedTeachersItalics = renameTeachersItalics,
_liveActivityColor = liveActivityColor;
factory SettingsProvider.fromMap(Map map, factory SettingsProvider.fromMap(Map map,
{required DatabaseProvider database}) { {required DatabaseProvider database}) {
@@ -164,8 +188,12 @@ class SettingsProvider extends ChangeNotifier {
Color(map["grade_color5"]), Color(map["grade_color5"]),
], ],
newsEnabled: map["news"] == 1, newsEnabled: map["news"] == 1,
newsState: map["news_state"], seenNews: map["seen_news"],
notificationsEnabled: map["notifications"] == 1, notificationsEnabled: map["notifications"] == 1,
notificationsGradesEnabled: map["notifications_grades"] == 1,
notificationsAbsencesEnabled: map["notifications_absences"] == 1,
notificationsMessagesEnabled: map["notifications_messages"] == 1,
notificationsLessonsEnabled: map["notifications_lessons"] == 1,
notificationsBitfield: map["notifications_bitfield"], notificationsBitfield: map["notifications_bitfield"],
notificationPollInterval: map["notification_poll_interval"], notificationPollInterval: map["notification_poll_interval"],
developerMode: map["developer_mode"] == 1, developerMode: map["developer_mode"] == 1,
@@ -191,6 +219,10 @@ class SettingsProvider extends ChangeNotifier {
premiumLogin: map["premium_login"], premiumLogin: map["premium_login"],
lastAccountId: map["last_account_id"], lastAccountId: map["last_account_id"],
renameSubjectsEnabled: map["renamed_subjects_enabled"] == 1, renameSubjectsEnabled: map["renamed_subjects_enabled"] == 1,
renameSubjectsItalics: map["renamed_subjects_italics"] == 1,
renameTeachersEnabled: map["renamed_teachers_enabled"] == 1,
renameTeachersItalics: map["renamed_teachers_italics"] == 1,
liveActivityColor: Color(map["live_activity_color"]),
); );
} }
@@ -202,8 +234,12 @@ class SettingsProvider extends ChangeNotifier {
"theme": _theme.index, "theme": _theme.index,
"accent_color": _accentColor.index, "accent_color": _accentColor.index,
"news": _newsEnabled ? 1 : 0, "news": _newsEnabled ? 1 : 0,
"news_state": _newsState, "seen_news": _seenNews,
"notifications": _notificationsEnabled ? 1 : 0, "notifications": _notificationsEnabled ? 1 : 0,
"notifications_grades": _notificationsGradesEnabled ? 1 : 0,
"notifications_absences": _notificationsAbsencesEnabled ? 1 : 0,
"notifications_messages": _notificationsMessagesEnabled ? 1 : 0,
"notifications_lessons": _notificationsLessonsEnabled ? 1 : 0,
"notifications_bitfield": _notificationsBitfield, "notifications_bitfield": _notificationsBitfield,
"developer_mode": _developerMode ? 1 : 0, "developer_mode": _developerMode ? 1 : 0,
"grade_color1": _gradeColors[0].value, "grade_color1": _gradeColors[0].value,
@@ -231,7 +267,11 @@ class SettingsProvider extends ChangeNotifier {
"premium_token": _premiumAccessToken, "premium_token": _premiumAccessToken,
"premium_login": _premiumLogin, "premium_login": _premiumLogin,
"last_account_id": _lastAccountId, "last_account_id": _lastAccountId,
"renamed_subjects_enabled": _renamedSubjectsEnabled ? 1 : 0 "renamed_subjects_enabled": _renamedSubjectsEnabled ? 1 : 0,
"renamed_subjects_italics": _renamedSubjectsItalics ? 1 : 0,
"renamed_teachers_enabled": _renamedTeachersEnabled ? 1 : 0,
"renamed_teachers_italics": _renamedTeachersItalics ? 1 : 0,
"live_activity_color": _liveActivityColor.value,
}; };
} }
@@ -251,8 +291,12 @@ class SettingsProvider extends ChangeNotifier {
DarkMobileAppColors().gradeFive, DarkMobileAppColors().gradeFive,
], ],
newsEnabled: true, newsEnabled: true,
newsState: -1, seenNews: '',
notificationsEnabled: true, notificationsEnabled: true,
notificationsGradesEnabled: true,
notificationsAbsencesEnabled: true,
notificationsMessagesEnabled: true,
notificationsLessonsEnabled: true,
notificationsBitfield: 255, notificationsBitfield: 255,
developerMode: false, developerMode: false,
notificationPollInterval: 1, notificationPollInterval: 1,
@@ -277,6 +321,10 @@ class SettingsProvider extends ChangeNotifier {
premiumLogin: "igen", premiumLogin: "igen",
lastAccountId: "", lastAccountId: "",
renameSubjectsEnabled: false, renameSubjectsEnabled: false,
renameSubjectsItalics: false,
renameTeachersEnabled: false,
renameTeachersItalics: false,
liveActivityColor: const Color(0xFF676767),
); );
} }
@@ -288,8 +336,12 @@ class SettingsProvider extends ChangeNotifier {
AccentColor get accentColor => _accentColor; AccentColor get accentColor => _accentColor;
List<Color> get gradeColors => _gradeColors; List<Color> get gradeColors => _gradeColors;
bool get newsEnabled => _newsEnabled; bool get newsEnabled => _newsEnabled;
int get newsState => _newsState; List<String> get seenNews => _seenNews.split(',');
bool get notificationsEnabled => _notificationsEnabled; bool get notificationsEnabled => _notificationsEnabled;
bool get notificationsGradesEnabled => _notificationsGradesEnabled;
bool get notificationsAbsencesEnabled => _notificationsAbsencesEnabled;
bool get notificationsMessagesEnabled => _notificationsMessagesEnabled;
bool get notificationsLessonsEnabled => _notificationsLessonsEnabled;
int get notificationsBitfield => _notificationsBitfield; int get notificationsBitfield => _notificationsBitfield;
bool get developerMode => _developerMode; bool get developerMode => _developerMode;
int get notificationPollInterval => _notificationPollInterval; int get notificationPollInterval => _notificationPollInterval;
@@ -317,6 +369,10 @@ class SettingsProvider extends ChangeNotifier {
String get premiumLogin => _premiumLogin; String get premiumLogin => _premiumLogin;
String get lastAccountId => _lastAccountId; String get lastAccountId => _lastAccountId;
bool get renamedSubjectsEnabled => _renamedSubjectsEnabled; bool get renamedSubjectsEnabled => _renamedSubjectsEnabled;
bool get renamedSubjectsItalics => _renamedSubjectsItalics;
bool get renamedTeachersEnabled => _renamedTeachersEnabled;
bool get renamedTeachersItalics => _renamedTeachersItalics;
Color get liveActivityColor => _liveActivityColor;
Future<void> update({ Future<void> update({
bool store = true, bool store = true,
@@ -327,8 +383,12 @@ class SettingsProvider extends ChangeNotifier {
AccentColor? accentColor, AccentColor? accentColor,
List<Color>? gradeColors, List<Color>? gradeColors,
bool? newsEnabled, bool? newsEnabled,
int? newsState, String? seenNewsId,
bool? notificationsEnabled, bool? notificationsEnabled,
bool? notificationsGradesEnabled,
bool? notificationsAbsencesEnabled,
bool? notificationsMessagesEnabled,
bool? notificationsLessonsEnabled,
int? notificationsBitfield, int? notificationsBitfield,
bool? developerMode, bool? developerMode,
int? notificationPollInterval, int? notificationPollInterval,
@@ -353,69 +413,128 @@ class SettingsProvider extends ChangeNotifier {
String? premiumLogin, String? premiumLogin,
String? lastAccountId, String? lastAccountId,
bool? renamedSubjectsEnabled, bool? renamedSubjectsEnabled,
bool? renamedSubjectsItalics,
bool? renamedTeachersEnabled,
bool? renamedTeachersItalics,
Color? liveActivityColor,
}) 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;
if (rounding != null && rounding != _rounding) _rounding = rounding; if (rounding != null && rounding != _rounding) _rounding = rounding;
if (theme != null && theme != _theme) _theme = theme; if (theme != null && theme != _theme) _theme = theme;
if (accentColor != null && accentColor != _accentColor) if (accentColor != null && accentColor != _accentColor) {
_accentColor = accentColor; _accentColor = accentColor;
if (gradeColors != null && gradeColors != _gradeColors) }
if (gradeColors != null && gradeColors != _gradeColors) {
_gradeColors = gradeColors; _gradeColors = gradeColors;
if (newsEnabled != null && newsEnabled != _newsEnabled) }
if (newsEnabled != null && newsEnabled != _newsEnabled) {
_newsEnabled = newsEnabled; _newsEnabled = newsEnabled;
if (newsState != null && newsState != _newsState) _newsState = newsState; }
if (seenNewsId != null && !_seenNews.split(',').contains(seenNewsId)) {
var tempList = _seenNews.split(',');
tempList.add(seenNewsId);
_seenNews = tempList.join(',');
}
if (notificationsEnabled != null && if (notificationsEnabled != null &&
notificationsEnabled != _notificationsEnabled) notificationsEnabled != _notificationsEnabled) {
_notificationsEnabled = notificationsEnabled; _notificationsEnabled = notificationsEnabled;
}
if (notificationsGradesEnabled != null &&
notificationsGradesEnabled != _notificationsGradesEnabled) {
_notificationsGradesEnabled = notificationsGradesEnabled;
}
if (notificationsAbsencesEnabled != null &&
notificationsAbsencesEnabled != _notificationsAbsencesEnabled) {
_notificationsAbsencesEnabled = notificationsAbsencesEnabled;
}
if (notificationsMessagesEnabled != null &&
notificationsMessagesEnabled != _notificationsMessagesEnabled) {
_notificationsMessagesEnabled = notificationsMessagesEnabled;
}
if (notificationsLessonsEnabled != null &&
notificationsLessonsEnabled != _notificationsLessonsEnabled) {
_notificationsLessonsEnabled = notificationsLessonsEnabled;
}
if (notificationsBitfield != null && if (notificationsBitfield != null &&
notificationsBitfield != _notificationsBitfield) notificationsBitfield != _notificationsBitfield) {
_notificationsBitfield = notificationsBitfield; _notificationsBitfield = notificationsBitfield;
if (developerMode != null && developerMode != _developerMode) }
if (developerMode != null && developerMode != _developerMode) {
_developerMode = developerMode; _developerMode = developerMode;
}
if (notificationPollInterval != null && if (notificationPollInterval != null &&
notificationPollInterval != _notificationPollInterval) { notificationPollInterval != _notificationPollInterval) {
_notificationPollInterval = notificationPollInterval; _notificationPollInterval = notificationPollInterval;
} }
if (vibrate != null && vibrate != _vibrate) _vibrate = vibrate; if (vibrate != null && vibrate != _vibrate) _vibrate = vibrate;
if (abWeeks != null && abWeeks != _abWeeks) _abWeeks = abWeeks; if (abWeeks != null && abWeeks != _abWeeks) _abWeeks = abWeeks;
if (swapABweeks != null && swapABweeks != _swapABweeks) if (swapABweeks != null && swapABweeks != _swapABweeks) {
_swapABweeks = swapABweeks; _swapABweeks = swapABweeks;
if (updateChannel != null && updateChannel != _updateChannel) }
if (updateChannel != null && updateChannel != _updateChannel) {
_updateChannel = updateChannel; _updateChannel = updateChannel;
}
if (config != null && config != _config) _config = config; if (config != null && config != _config) _config = config;
if (xFilcId != null && xFilcId != _xFilcId) _xFilcId = xFilcId; if (xFilcId != null && xFilcId != _xFilcId) _xFilcId = xFilcId;
if (graphClassAvg != null && graphClassAvg != _graphClassAvg) if (graphClassAvg != null && graphClassAvg != _graphClassAvg) {
_graphClassAvg = graphClassAvg; _graphClassAvg = graphClassAvg;
}
if (goodStudent != null) _goodStudent = goodStudent; if (goodStudent != null) _goodStudent = goodStudent;
if (presentationMode != null && presentationMode != _presentationMode) if (presentationMode != null && presentationMode != _presentationMode) {
_presentationMode = presentationMode; _presentationMode = presentationMode;
}
if (bellDelay != null && bellDelay != _bellDelay) _bellDelay = bellDelay; if (bellDelay != null && bellDelay != _bellDelay) _bellDelay = bellDelay;
if (bellDelayEnabled != null && bellDelayEnabled != _bellDelayEnabled) if (bellDelayEnabled != null && bellDelayEnabled != _bellDelayEnabled) {
_bellDelayEnabled = bellDelayEnabled; _bellDelayEnabled = bellDelayEnabled;
if (gradeOpeningFun != null && gradeOpeningFun != _gradeOpeningFun) }
if (gradeOpeningFun != null && gradeOpeningFun != _gradeOpeningFun) {
_gradeOpeningFun = gradeOpeningFun; _gradeOpeningFun = gradeOpeningFun;
}
if (iconPack != null && iconPack != _iconPack) _iconPack = iconPack; if (iconPack != null && iconPack != _iconPack) _iconPack = iconPack;
if (customAccentColor != null && customAccentColor != _customAccentColor) if (customAccentColor != null && customAccentColor != _customAccentColor) {
_customAccentColor = customAccentColor; _customAccentColor = customAccentColor;
}
if (customBackgroundColor != null && if (customBackgroundColor != null &&
customBackgroundColor != _customBackgroundColor) customBackgroundColor != _customBackgroundColor) {
_customBackgroundColor = customBackgroundColor; _customBackgroundColor = customBackgroundColor;
}
if (customHighlightColor != null && if (customHighlightColor != null &&
customHighlightColor != _customHighlightColor) customHighlightColor != _customHighlightColor) {
_customHighlightColor = customHighlightColor; _customHighlightColor = customHighlightColor;
if (premiumScopes != null && premiumScopes != _premiumScopes) }
if (premiumScopes != null && premiumScopes != _premiumScopes) {
_premiumScopes = premiumScopes; _premiumScopes = premiumScopes;
if (premiumAccessToken != null && premiumAccessToken != _premiumAccessToken) }
if (premiumAccessToken != null &&
premiumAccessToken != _premiumAccessToken) {
_premiumAccessToken = premiumAccessToken; _premiumAccessToken = premiumAccessToken;
if (premiumLogin != null && premiumLogin != _premiumLogin) }
if (premiumLogin != null && premiumLogin != _premiumLogin) {
_premiumLogin = premiumLogin; _premiumLogin = premiumLogin;
if (lastAccountId != null && lastAccountId != _lastAccountId) }
if (lastAccountId != null && lastAccountId != _lastAccountId) {
_lastAccountId = lastAccountId; _lastAccountId = lastAccountId;
}
if (renamedSubjectsEnabled != null && if (renamedSubjectsEnabled != null &&
renamedSubjectsEnabled != _renamedSubjectsEnabled) renamedSubjectsEnabled != _renamedSubjectsEnabled) {
_renamedSubjectsEnabled = renamedSubjectsEnabled; _renamedSubjectsEnabled = renamedSubjectsEnabled;
}
if (renamedSubjectsItalics != null &&
renamedSubjectsItalics != _renamedSubjectsItalics) {
_renamedSubjectsItalics = renamedSubjectsItalics;
}
if (renamedTeachersEnabled != null &&
renamedTeachersEnabled != _renamedTeachersEnabled) {
_renamedTeachersEnabled = renamedTeachersEnabled;
}
if (renamedTeachersItalics != null &&
renamedTeachersItalics != _renamedTeachersItalics) {
_renamedTeachersItalics = renamedTeachersItalics;
}
if (liveActivityColor != null && liveActivityColor != _liveActivityColor) {
_liveActivityColor = liveActivityColor;
}
if (store) await _database?.store.storeSettings(this); if (store) await _database?.store.storeSettings(this);
notifyListeners(); notifyListeners();
} }

View File

@@ -10,6 +10,8 @@ enum AccentColor {
red, red,
pink, pink,
purple, purple,
none,
ogfilc,
adaptive, adaptive,
custom custom
} }
@@ -24,6 +26,8 @@ Map<AccentColor, Color> accentColorMap = {
AccentColor.red: Colors.red.shade300, AccentColor.red: Colors.red.shade300,
AccentColor.pink: Colors.pink.shade300, AccentColor.pink: Colors.pink.shade300,
AccentColor.purple: Colors.purple.shade300, AccentColor.purple: Colors.purple.shade300,
//AccentColor.none: Colors.black,
AccentColor.ogfilc: const Color(0xff20AC9B),
AccentColor.adaptive: const Color(0xFF3D7BF4), AccentColor.adaptive: const Color(0xFF3D7BF4),
AccentColor.custom: const Color(0xFF3D7BF4), AccentColor.custom: const Color(0xFF3D7BF4),
}; };

View File

@@ -38,6 +38,7 @@ class DarkMobileAppColors implements ThemeAppColors {
final gradeTwo = const Color(0xFFAE3DF4); final gradeTwo = const Color(0xFFAE3DF4);
@override @override
final gradeOne = const Color(0xFFF43DAB); final gradeOne = const Color(0xFFF43DAB);
@override
final purple = const Color(0xffBF5AF2); final purple = const Color(0xffBF5AF2);
@override @override
final pink = const Color(0xffFF375F); final pink = const Color(0xffFF375F);

View File

@@ -12,7 +12,8 @@ import 'package:filcnaplo_mobile_ui/common/widgets/lesson/changed_lesson_tile.da
import 'package:filcnaplo/utils/format.dart'; import 'package:filcnaplo/utils/format.dart';
// difference.inDays is not reliable // difference.inDays is not reliable
bool _sameDate(DateTime a, DateTime b) => (a.year == b.year && a.month == b.month && a.day == b.day); bool _sameDate(DateTime a, DateTime b) =>
(a.year == b.year && a.month == b.month && a.day == b.day);
List<Widget> sortDateWidgets( List<Widget> sortDateWidgets(
BuildContext context, { BuildContext context, {
@@ -35,13 +36,16 @@ List<Widget> sortDateWidgets(
if (message.conversationId != null) { if (message.conversationId != null) {
convMessages.add(w); convMessages.add(w);
Conversation conv = conversations.firstWhere((e) => e.id == message.conversationId, orElse: () => Conversation(id: message.conversationId!)); Conversation conv = conversations.firstWhere(
(e) => e.id == message.conversationId,
orElse: () => Conversation(id: message.conversationId!));
conv.add(message); conv.add(message);
if (conv.messages.length == 1) conversations.add(conv); if (conv.messages.length == 1) conversations.add(conv);
} }
if (conversations.any((c) => c.id == message.messageId)) { if (conversations.any((c) => c.id == message.messageId)) {
Conversation conv = conversations.firstWhere((e) => e.id == message.messageId); Conversation conv =
conversations.firstWhere((e) => e.id == message.messageId);
convMessages.add(w); convMessages.add(w);
conv.add(message); conv.add(message);
} }
@@ -87,26 +91,41 @@ List<Widget> sortDateWidgets(
// Group Absence Tiles // Group Absence Tiles
List<DateWidget> absenceTileWidgets = elements.where((element) { List<DateWidget> absenceTileWidgets = elements.where((element) {
return element.widget is AbsenceViewable && (element.widget as AbsenceViewable).absence.delay == 0; return element.widget is AbsenceViewable &&
(element.widget as AbsenceViewable).absence.delay == 0;
}).toList(); }).toList();
List<AbsenceViewable> absenceTiles = absenceTileWidgets.map((e) => e.widget as AbsenceViewable).toList(); List<AbsenceViewable> absenceTiles =
absenceTileWidgets.map((e) => e.widget as AbsenceViewable).toList();
if (absenceTiles.length > 1) { if (absenceTiles.length > 1) {
elements.removeWhere((element) => element.widget.runtimeType == AbsenceViewable && (element.widget as AbsenceViewable).absence.delay == 0); elements.removeWhere((element) =>
element.widget.runtimeType == AbsenceViewable &&
(element.widget as AbsenceViewable).absence.delay == 0);
if (elements.isEmpty) { if (elements.isEmpty) {
cst = false; cst = false;
} }
elements.add(DateWidget( elements.add(
widget: AbsenceGroupTile(absenceTiles, showDate: !cst), DateWidget(
date: absenceTileWidgets.first.date, widget: AbsenceGroupTile(
key: "${absenceTileWidgets.first.date.millisecondsSinceEpoch}-absence-group")); absenceTiles,
showDate: !cst,
padding: const EdgeInsets.symmetric(horizontal: 6.0),
),
date: absenceTileWidgets.first.date,
key:
"${absenceTileWidgets.first.date.millisecondsSinceEpoch}-absence-group"),
);
} }
// Bring Lesson Tiles to front & sort by index asc // Bring Lesson Tiles to front & sort by index asc
List<DateWidget> lessonTiles = elements.where((element) { List<DateWidget> lessonTiles = elements.where((element) {
return element.widget.runtimeType == ChangedLessonTile; return element.widget.runtimeType == ChangedLessonTile;
}).toList(); }).toList();
lessonTiles.sort((a, b) => (a.widget as ChangedLessonTile).lesson.lessonIndex.compareTo((b.widget as ChangedLessonTile).lesson.lessonIndex)); lessonTiles.sort((a, b) => (a.widget as ChangedLessonTile)
elements.removeWhere((element) => element.widget.runtimeType == ChangedLessonTile); .lesson
.lessonIndex
.compareTo((b.widget as ChangedLessonTile).lesson.lessonIndex));
elements.removeWhere(
(element) => element.widget.runtimeType == ChangedLessonTile);
elements.insertAll(0, lessonTiles); elements.insertAll(0, lessonTiles);
final date = (elements + absenceTileWidgets).first.date; final date = (elements + absenceTileWidgets).first.date;
@@ -122,7 +141,8 @@ List<Widget> sortDateWidgets(
spawnIsolate: false, spawnIsolate: false,
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, animation, item, index) => filterItemBuilder(context, animation, item.widget, index), itemBuilder: (context, animation, item, index) =>
filterItemBuilder(context, animation, item.widget, index),
items: elements, items: elements,
), ),
), ),
@@ -131,9 +151,12 @@ List<Widget> sortDateWidgets(
} }
final nh = DateTime.now(); final nh = DateTime.now();
final now = DateTime(nh.year, nh.month, nh.day).subtract(const Duration(seconds: 1)); final now =
DateTime(nh.year, nh.month, nh.day).subtract(const Duration(seconds: 1));
if (showDivider && items.any((i) => i.date.isBefore(now)) && items.any((i) => i.date.isAfter(now))) { if (showDivider &&
items.any((i) => i.date.isBefore(now)) &&
items.any((i) => i.date.isAfter(now))) {
items.add( items.add(
DateWidget( DateWidget(
date: now, date: now,
@@ -153,7 +176,9 @@ List<Widget> sortDateWidgets(
} }
// Sort future dates asc, past dates desc // Sort future dates asc, past dates desc
items.sort((a, b) => (a.date.isAfter(now) && b.date.isAfter(now) ? 1 : -1) * a.date.compareTo(b.date)); items.sort((a, b) =>
(a.date.isAfter(now) && b.date.isAfter(now) ? 1 : -1) *
a.date.compareTo(b.date));
return items.map((e) => e.widget).toList(); return items.map((e) => e.widget).toList();
} }

View File

@@ -1,3 +1,4 @@
import 'package:filcnaplo/api/providers/ad_provider.dart';
import 'package:filcnaplo/api/providers/update_provider.dart'; import 'package:filcnaplo/api/providers/update_provider.dart';
import 'package:filcnaplo/models/settings.dart'; import 'package:filcnaplo/models/settings.dart';
import 'package:filcnaplo/ui/date_widget.dart'; import 'package:filcnaplo/ui/date_widget.dart';
@@ -14,6 +15,7 @@ import 'package:filcnaplo/ui/filter/widgets/lessons.dart' as lesson_filter;
import 'package:filcnaplo/ui/filter/widgets/update.dart' as update_filter; import 'package:filcnaplo/ui/filter/widgets/update.dart' as update_filter;
import 'package:filcnaplo/ui/filter/widgets/missed_exams.dart' import 'package:filcnaplo/ui/filter/widgets/missed_exams.dart'
as missed_exam_filter; as missed_exam_filter;
import 'package:filcnaplo/ui/filter/widgets/ads.dart' as ad_filter;
import 'package:filcnaplo_kreta_api/models/week.dart'; import 'package:filcnaplo_kreta_api/models/week.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';
@@ -50,7 +52,8 @@ enum FilterType {
lessons, lessons,
updates, updates,
certifications, certifications,
missedExams missedExams,
ads,
} }
Future<List<DateWidget>> getFilterWidgets(FilterType activeData, Future<List<DateWidget>> getFilterWidgets(FilterType activeData,
@@ -65,6 +68,7 @@ Future<List<DateWidget>> getFilterWidgets(FilterType activeData,
final eventProvider = Provider.of<EventProvider>(context); final eventProvider = Provider.of<EventProvider>(context);
final updateProvider = Provider.of<UpdateProvider>(context); final updateProvider = Provider.of<UpdateProvider>(context);
final settingsProvider = Provider.of<SettingsProvider>(context); final settingsProvider = Provider.of<SettingsProvider>(context);
final adProvider = Provider.of<AdProvider>(context);
List<DateWidget> items = []; List<DateWidget> items = [];
@@ -82,6 +86,7 @@ Future<List<DateWidget>> getFilterWidgets(FilterType activeData,
getFilterWidgets(FilterType.updates, context: context), getFilterWidgets(FilterType.updates, context: context),
getFilterWidgets(FilterType.certifications, context: context), getFilterWidgets(FilterType.certifications, context: context),
getFilterWidgets(FilterType.missedExams, context: context), getFilterWidgets(FilterType.missedExams, context: context),
getFilterWidgets(FilterType.ads, context: context),
]); ]);
items = all.expand((x) => x).toList(); items = all.expand((x) => x).toList();
@@ -89,6 +94,9 @@ Future<List<DateWidget>> getFilterWidgets(FilterType activeData,
// Grades // Grades
case FilterType.grades: case FilterType.grades:
if (!settingsProvider.gradeOpeningFun) {
gradeProvider.seenAll();
}
items = grade_filter.getWidgets( items = grade_filter.getWidgets(
gradeProvider.grades, gradeProvider.lastSeenDate); gradeProvider.grades, gradeProvider.lastSeenDate);
if (settingsProvider.gradeOpeningFun) { if (settingsProvider.gradeOpeningFun) {
@@ -161,6 +169,13 @@ Future<List<DateWidget>> getFilterWidgets(FilterType activeData,
items = missed_exam_filter items = missed_exam_filter
.getWidgets(timetableProvider.getWeek(Week.current()) ?? []); .getWidgets(timetableProvider.getWeek(Week.current()) ?? []);
break; break;
// Ads
case FilterType.ads:
if (adProvider.available) {
items = ad_filter.getWidgets(adProvider.ads);
}
break;
} }
return items; return items;
} }

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