Compare commits

...

280 Commits
1.0.1 ... 1.2.1

Author SHA1 Message Date
3d0dcead50 Merge branch 'release/1.2.1' 2021-09-05 23:29:23 +02:00
b64b41c11c Version 1.2.1 2021-09-05 23:29:15 +02:00
77c5330f91 Dashboard fixes (#1463) 2021-09-05 23:24:03 +02:00
2b55ec02ff New translations strings.xml (Polish) (#1474) 2021-09-05 23:06:44 +02:00
49ebae6e63 Fix overlaping empty and error view in grade statistics (#1475)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2021-09-05 19:59:03 +00:00
44a9db48a6 Bump hianalytics from 6.2.0.300 to 6.2.0.301 (#1476) 2021-09-05 18:17:18 +00:00
0008a72be1 Bump kotlinx-coroutines-test from 1.5.1 to 1.5.2 (#1477) 2021-09-05 18:10:22 +00:00
a43acaaa07 Bump kotlinx-coroutines-android from 1.5.1 to 1.5.2 (#1479) 2021-09-05 18:10:05 +00:00
e6c9abb4e5 Bump core from 1.10.0 to 1.10.1 (#1480) 2021-09-05 18:09:42 +00:00
3b9451184c Fix preview of second student guardian when first guardian is null (#1473) 2021-09-05 03:15:40 +02:00
45d1727dbe Add missing school announcement dialog (#1470) 2021-09-04 15:54:37 +02:00
8d7b611c44 Fix showing error view in timetable (#1472) 2021-09-04 15:54:05 +02:00
c3adb9b6d6 Bump agp to 7.0.2 (#1469) 2021-09-03 22:54:29 +02:00
d87283eb31 Fix opening twitter link from about on android 11 (#1460) 2021-08-30 00:20:13 +02:00
d139c22782 Bump hianalytics from 6.1.1.300 to 6.2.0.300 (#1457) 2021-08-29 19:37:18 +00:00
e557021ad9 Bump huawei-publish-gradle-plugin from 1.2.4 to 1.3.0 (#1458) 2021-08-29 19:37:01 +00:00
37af5de25c Merge branch 'release/1.2.0' into develop 2021-08-29 21:08:23 +02:00
db6c84775b Merge branch 'release/1.2.0' 2021-08-29 21:08:18 +02:00
72d8b4aa84 Version 1.2.0 2021-08-29 21:08:08 +02:00
170b7c4379 New Crowdin updates (#1459) 2021-08-29 21:06:33 +02:00
79e9e1a780 New Crowdin updates (#1321) 2021-08-29 20:01:36 +02:00
98dcc62bb7 Add excuse function to "not excusable" account (#1429) 2021-08-29 19:47:14 +02:00
ea0fb00bde Fix crash on opening date pickers during holidays (#1456) 2021-08-29 19:31:28 +02:00
4aa6b0b995 Hide keyboard on opening login host dropdown (#1455) 2021-08-29 19:00:30 +02:00
57d11e825b Update readBy and unreadBy fields during message list fetch (#1452) 2021-08-29 15:40:28 +02:00
2f43b6e552 Change display name for MRmlik12 (#1451) 2021-08-29 14:08:48 +02:00
765f8a2d1f Add in app review (#1435) 2021-08-29 00:43:58 +02:00
04c727a0c8 Exams and homework notification fixes (#1292) 2021-08-29 00:41:58 +02:00
55518cb044 Add missing dashboard item in default view settings (#1450) 2021-08-28 21:43:10 +02:00
cebd1aa75d Remove lithuanian lang (#1449) 2021-08-28 12:14:01 +02:00
4a38a0be70 Add change password snackbar (#1336) 2021-08-26 17:35:41 +00:00
b4b9d91ea6 Update dependencies (#1448) 2021-08-25 20:49:44 +02:00
a6a2bcff3b Remove Zachowanie from all count of subjects (#1447) 2021-08-24 19:51:08 +02:00
2979d8b62a Show information when the recipient has read the message (#1430) 2021-08-23 16:16:41 +00:00
aba2068a84 New timetable widget design (#1384) 2021-08-23 16:02:21 +00:00
076948a680 Bump gradle from 7.0.0 to 7.0.1 (#1445) 2021-08-23 13:53:04 +00:00
1cfabe43a5 Add captions for averages from how many items have been counted (#1437) 2021-08-23 15:48:48 +02:00
02b87c8c6a Bump firebase-bom from 28.3.1 to 28.4.0 (#1446) 2021-08-23 13:42:20 +00:00
eb94e06d54 Fix buggy timers in timetable (#1428)
Co-authored-by: Rafał Borcz <RafalBO99@outlook.com>
2021-08-22 16:33:12 +02:00
d3b3939d26 Bump timber from 4.7.1 to 5.0.1 (#1440) 2021-08-17 13:44:06 +00:00
9c5d2fbf84 Bump google-services from 4.3.9 to 4.3.10 (#1439) 2021-08-17 13:32:48 +00:00
428e40d7fe Bump hianalytics from 6.1.0.300 to 6.1.1.300 (#1441) 2021-08-17 13:32:34 +00:00
9c819835ca Add last sync date in sync settings (#1436) 2021-08-15 13:59:32 +00:00
626169de11 Add drag and drop to dashboard tiles (#1415) 2021-08-10 11:55:51 +02:00
72ef5f428e Bump firebase-bom from 28.3.0 to 28.3.1 (#1431) 2021-08-09 13:55:03 +00:00
4ae3f7b016 Bump google-services from 4.3.8 to 4.3.9 (#1432) 2021-08-09 13:54:48 +00:00
7c94837af0 Bump coil from 1.3.1 to 1.3.2 (#1433) 2021-08-09 13:54:31 +00:00
2a91346155 Bump activity-ktx from 1.3.0 to 1.3.1 (#1434) 2021-08-09 13:53:54 +00:00
ec6d18968f Fix filter search bug (#1427)
* Fix filter search bug

* refractor
2021-08-07 10:27:51 +02:00
b61e63249c Add messages sorting (#1262) 2021-08-04 15:16:54 +02:00
d73aa605f9 Change dashboard no data strings (#1426) 2021-08-03 18:55:20 +02:00
14f4808434 Add student nick-or-name to notification summary (#1425) 2021-08-03 15:48:11 +02:00
2bc6d7ad0d Bump gradle from 4.2.2 to 7.0.0 (#1419) 2021-08-02 16:28:12 +00:00
888052cd9c Bump agcp from 1.5.3.200 to 1.6.0.300 (#1424) 2021-08-02 15:18:29 +00:00
bdc2281fdc Bump agconnect-crash from 1.5.3.200 to 1.6.0.300 (#1423) 2021-08-02 15:18:18 +00:00
d01edc2312 Bump activity-ktx from 1.2.4 to 1.3.0 (#1422) 2021-08-02 15:17:05 +00:00
484a3aa731 Bump chucker from 3.5.1 to 3.5.2 (#1417) 2021-08-02 13:26:33 +00:00
51be23470f Bump hilt_version from 2.38 to 2.38.1 (#1418) 2021-08-02 13:25:19 +00:00
19495ffce9 Bump constraintlayout from 2.1.0-beta02 to 2.1.0 (#1420) 2021-08-02 13:24:31 +00:00
bd766d33db Bump coil from 1.3.0 to 1.3.1 (#1421) 2021-08-02 13:23:25 +00:00
ff8b3f8837 Send mutltiple notifications instead of summary notification (#1365) 2021-08-01 13:19:46 +02:00
e678e6d7f9 Fix margin and attedance destination (#1414) 2021-07-31 20:19:05 +02:00
f6f3447f1d Fix sorting notes in loading state (#1413) 2021-07-31 18:08:35 +02:00
e1c1f305c4 Add draft message (#1306) 2021-07-31 18:00:22 +02:00
c8c9001277 Add twitter page link to about fragment (#1411) 2021-07-30 19:13:06 +02:00
3422951e47 Add dashboard (#1267) 2021-07-30 18:49:19 +02:00
3278c11cce Bump hilt_version from 2.37 to 2.38 (#1405) 2021-07-27 08:39:37 +00:00
e00dea51f1 Bump appcompat from 1.3.0 to 1.3.1 (#1409) 2021-07-26 19:55:08 +00:00
5bf411039d Bump fragment-ktx from 1.3.5 to 1.3.6 (#1404) 2021-07-26 19:54:50 +00:00
62ca394c9a Bump appcompat-resources from 1.3.0 to 1.3.1 (#1403) 2021-07-26 19:48:14 +00:00
255b89bbb3 Bump about_libraries from 8.9.0 to 8.9.1 (#1406) 2021-07-26 19:42:25 +00:00
f7987f4b29 Bump chucker from 3.5.0 to 3.5.1 (#1407) 2021-07-26 19:42:11 +00:00
0b583439dd Bump firebase-bom from 28.2.1 to 28.3.0 (#1408) 2021-07-26 19:41:55 +00:00
ca481dc6f5 Bump activity-ktx from 1.2.3 to 1.2.4 (#1410) 2021-07-26 19:41:28 +00:00
f6a92a4cc3 Bump hianalytics from 6.0.0.301 to 6.1.0.300 (#1402) 2021-07-21 07:21:49 +00:00
55a6219a42 Bump kotlin_version from 1.5.20 to 1.5.21 (#1401) 2021-07-21 07:21:25 +00:00
ad653f10df Bump firebase-bom from 28.2.0 to 28.2.1 (#1400) 2021-07-12 22:44:06 +02:00
7a780486f6 Bump kotlinx-coroutines-android from 1.5.0 to 1.5.1-native-mt (#1395) 2021-07-12 19:54:35 +00:00
c01b0eff9d Bump agconnect-crash from 1.5.2.300 to 1.5.3.200 (#1399) 2021-07-12 19:53:03 +00:00
3a4614e2b7 Bump robolectric from 4.5.1 to 4.6.1 (#1392) 2021-07-12 19:52:39 +00:00
44ee8859b1 Bump junit from 1.1.2 to 1.1.3 (#1389) 2021-07-12 19:52:25 +00:00
3dd7878ae5 Bump mockk from 1.11.0 to 1.12.0 (#1387) 2021-07-12 19:47:16 +00:00
0305a005ab Bump agcp from 1.5.2.300 to 1.5.3.200 (#1398) 2021-07-12 19:47:04 +00:00
2229f0e3e9 Bump coil from 1.2.2 to 1.3.0 (#1397) 2021-07-12 19:46:13 +00:00
d9aab7afa2 Bump runner from 1.3.0 to 1.4.0 (#1386) 2021-07-12 19:45:36 +00:00
0558f30646 Bump material from 1.3.0 to 1.4.0 (#1390) 2021-07-12 19:44:04 +00:00
238f257c6c Bump hianalytics from 5.3.1.300 to 6.0.0.301 (#1394) 2021-07-12 19:43:46 +00:00
40372e7cea Bump core-ktx from 1.5.0 to 1.6.0 (#1388) 2021-07-12 19:40:32 +00:00
b65a060fca Bump chucker from 3.4.0 to 3.5.0 (#1385) 2021-07-12 19:40:15 +00:00
c1ed748188 Bump gradle from 4.2.1 to 4.2.2 (#1393) 2021-07-12 19:39:19 +00:00
b911521ccc Bump core from 1.3.0 to 1.4.0 (#1391) 2021-07-12 19:39:02 +00:00
b046679542 Bump kotlin_version from 1.5.10 to 1.5.20 (#1381) 2021-06-27 20:09:46 +00:00
3decc95a20 Bump firebase-crashlytics-gradle from 2.7.0 to 2.7.1 (#1382) 2021-06-27 19:37:24 +00:00
c301198006 Bump firebase-bom from 28.1.0 to 28.2.0 (#1383) 2021-06-27 19:33:51 +00:00
190a5f2067 Bump fragment-ktx from 1.3.4 to 1.3.5 (#1380) 2021-06-22 20:37:21 +00:00
27e1a07eec Add notifications debug screen (#1370) 2021-06-21 10:29:04 +02:00
64feae9f1c Bump hilt_version from 2.36 to 2.37 (#1376) 2021-06-12 12:31:59 +00:00
085158721e Bump sonarqube-gradle-plugin from 3.2.0 to 3.3 (#1378) 2021-06-11 11:45:25 +00:00
44888b048d Add "I forgot my password" button in upper bar (#1375) 2021-06-11 09:53:11 +02:00
b9a12e46bf Upgrade gradle to 6.9 (#1371) 2021-06-09 09:46:16 +02:00
2fe5e62e72 Bump recyclerview from 1.2.0 to 1.2.1 (#1366) 2021-06-08 10:02:09 +00:00
6305e1a908 Bump firebase-bom from 28.0.1 to 28.1.0 (#1367) 2021-06-08 10:01:12 +00:00
6bf7a2e26c Bump firebase-crashlytics-gradle from 2.6.1 to 2.7.0 (#1368) 2021-06-08 10:00:27 +00:00
34487175d8 Bump coil from 1.2.1 to 1.2.2 (#1369) 2021-06-08 10:00:10 +00:00
f02db914bf Fix treessence upgrade (#1361) 2021-06-02 12:45:16 +02:00
18e0a59e2b Bump hilt_version from 2.35.1 to 2.36 (#1362) 2021-06-02 09:12:01 +00:00
e4371af284 Bump about_libraries from 8.8.5 to 8.9.0 (#1363) 2021-06-02 08:21:34 +00:00
44d5f69de1 Remove jcenter repository and unused code from gradle config (#1360) 2021-05-28 10:57:25 +02:00
d13e0adb00 Bump appcompat from 1.2.0 to 1.3.0 (#1357) 2021-05-28 07:09:47 +00:00
e60e573ac0 Bump appcompat-resources from 1.2.0 to 1.3.0 (#1359) 2021-05-28 07:01:57 +00:00
91dbc9e3d7 Bump core-ktx from 1.3.2 to 1.5.0 (#1356) 2021-05-28 06:15:18 +00:00
8ccbea2c21 Bump fragment-ktx from 1.3.3 to 1.3.4 (#1358) 2021-05-25 11:10:52 +00:00
211cb5e4f2 Merge branch 'hotfix/messages-send' into develop 2021-05-21 14:09:45 +02:00
b60c59216d Merge branch 'hotfix/messages-send' 2021-05-21 14:08:00 +02:00
d20f3180cf Version 1.1.6 2021-05-21 14:03:13 +02:00
17761af9d6 Bump sdk 2021-05-21 12:35:57 +02:00
067817bace Bump huawei-publish-gradle-plugin from 1.2.2 to 1.2.4 (#1314)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
(cherry picked from commit 022a4d1ea2)
2021-05-21 12:30:36 +02:00
51800d91b2 Bump gradle from 4.1.3 to 4.2.1 (#1339) 2021-05-19 22:40:21 +00:00
3640c4f249 Update dependabot config (#1353) 2021-05-18 09:40:08 +00:00
05aa38b591 Add arrows to student family list items (#1338) 2021-05-17 15:35:36 +02:00
983dcd8656 Add conferences and announcements notifications (#1330) 2021-05-17 15:19:39 +02:00
59cf4fb222 Bump kotlinx-coroutines-android from 1.5.0-RC to 1.5.0 (#1348) 2021-05-17 11:33:27 +00:00
d6ebcc97e3 Bump firebase-crashlytics-gradle from 2.5.2 to 2.6.1 (#1342) 2021-05-17 11:32:03 +00:00
047579c394 Bump agcp from 1.5.2.201 to 1.5.2.300 (#1349) 2021-05-17 11:24:31 +00:00
a90fd4b776 Bump agconnect-crash from 1.5.2.201 to 1.5.2.300 (#1350) 2021-05-17 11:21:48 +00:00
03d3a5db11 Bump firebase-bom from 27.1.0 to 28.0.1 (#1341) 2021-05-17 11:21:31 +00:00
bf5e61490d Bump google-services from 4.3.5 to 4.3.8 (#1344) 2021-05-17 11:18:08 +00:00
d87fa589a8 Bump hianalytics from 5.3.0.300 to 5.3.1.300 (#1332) 2021-05-10 11:50:20 +00:00
1fff1c2b14 Bump kotlin_version from 1.4.32 to 1.5.0 (#1310) 2021-05-06 11:02:08 +00:00
58d66b6e70 Bump work_hilt from 1.0.0-beta01 to 1.0.0 (#1329) 2021-05-05 22:23:31 +00:00
202d13d509 Bump activity-ktx from 1.2.2 to 1.2.3 (#1328) 2021-05-05 22:21:48 +00:00
db808de06c Fix no info text position in school announcements (#1327) 2021-05-05 20:18:16 +02:00
d8dae09f39 Add notification icons (#1276)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2021-05-03 18:24:54 +02:00
32640e0796 Change mobile devices item order (#1324)
* Change more items order

* Resolve conflicts
2021-05-03 18:23:09 +02:00
4e80441167 Add school announcements (#1323) 2021-05-03 17:24:01 +02:00
075cfb20b1 Fix missing snackbar in sync settings fragment (#1325) 2021-05-03 16:42:59 +02:00
56e4e9be5e Fix homework dialog attachments margin (#1322) 2021-05-02 21:56:41 +02:00
53c798ebdb Change titles in Student Info (#1121) 2021-05-02 14:09:42 +00:00
022a4d1ea2 Bump huawei-publish-gradle-plugin from 1.2.2 to 1.2.4 (#1314)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2021-05-02 13:49:28 +02:00
dfa25d8445 New Crowdin updates (#1268) 2021-05-02 12:53:53 +02:00
b2efe0d981 Probably fix list divider color (#1270)
Co-authored-by: Rafał Borcz <RafalBO99@outlook.com>
2021-05-02 12:33:27 +02:00
2a7f846d3f Bump hilt_version from 2.35 to 2.35.1 (#1313) 2021-04-30 14:05:08 +00:00
da5817d08a Bump sonarqube-gradle-plugin from 3.1.1 to 3.2.0 (#1315) 2021-04-30 13:59:46 +00:00
cacf2f651a Bump agcp from 1.5.1.300 to 1.5.2.201 (#1311) 2021-04-30 13:57:51 +00:00
605c816a32 Bump coil from 1.2.0 to 1.2.1 (#1312) 2021-04-30 13:57:35 +00:00
1587be2fa8 Bump hianalytics from 5.2.0.301 to 5.3.0.300 (#1319) 2021-04-30 13:53:54 +00:00
00b23ca20c Bump agconnect-crash from 1.5.1.300 to 1.5.2.201 (#1316) 2021-04-30 13:46:30 +00:00
34db20ab0c Upgrade to GitHub-native Dependabot (#1309) 2021-04-30 13:23:57 +00:00
0d271d925a Bump room from 2.3.0-rc01 to 2.3.0 (#1302) 2021-04-25 01:31:48 +02:00
b7da43a52a Bump hilt_version from 2.34.1-beta to 2.35 (#1303) 2021-04-24 12:57:55 +00:00
44af5d59fb Bump fragment-ktx from 1.3.2 to 1.3.3 (#1304) 2021-04-24 12:57:41 +00:00
bc776993a9 Bump firebase-bom from 27.0.0 to 27.1.0 (#1305) 2021-04-24 12:57:21 +00:00
9a19ce9ca4 Fix Homework dialog buttons layout (#1297) 2021-04-19 16:09:14 +00:00
6855296de4 Merge branch 'hotfix/all-year-average' into develop 2021-04-18 20:43:29 +02:00
800a31f160 Merge branch 'hotfix/all-year-average' 2021-04-18 20:40:02 +02:00
8b83b37b09 Version 1.1.5 2021-04-18 20:38:18 +02:00
43e95cfdc6 Fix all year average 2021-04-18 19:36:02 +02:00
ae2a697e01 Merge pull request #1295 from wulkanowy/rbo/update-workflow
Update github action workflow
2021-04-18 19:34:32 +02:00
b695c7f600 Bump hilt_version from 2.34-beta to 2.34.1-beta (#1293) 2021-04-17 20:45:38 +00:00
3a1a383383 Bump recyclerview from 1.1.0 to 1.2.0 (#1287) 2021-04-14 18:59:12 +00:00
97810d02ab Bump moshi from 1.11.0 to 1.12.0 (#1284) 2021-04-14 18:58:54 +00:00
30b337a364 Bump about_libraries from 8.8.4 to 8.8.5 (#1281) 2021-04-13 11:55:39 +00:00
8f6c847562 Bump agconnect-crash from 1.5.1.200 to 1.5.1.300 (#1283) 2021-04-13 11:44:01 +00:00
e5d54c95f3 Bump firebase-bom from 26.8.0 to 27.0.0 (#1285) 2021-04-13 11:43:09 +00:00
eb5ad81ec1 Bump agcp from 1.5.1.200 to 1.5.1.300 (#1286) 2021-04-13 11:42:48 +00:00
3aa9f0ca2f Bump coil from 1.1.1 to 1.2.0 (#1282) 2021-04-13 11:42:21 +00:00
8e587358aa Bump hilt_version from 2.33-beta to 2.34-beta (#1280) 2021-04-13 11:39:14 +00:00
4492f4a864 Dialogs adjustments to meet MD rules (#1227) 2021-04-12 20:06:28 +00:00
b453225941 Student info and Teachers screens unification (#1279) 2021-04-12 19:58:58 +00:00
13ccfda009 Migrate material date picker (#1277) 2021-04-12 21:43:52 +02:00
95ffb0a687 Ignore all throwable from WebView (#1275) 2021-04-08 10:41:49 +02:00
f131edf857 Add system settings shortcut (#1271) 2021-04-07 11:56:33 +00:00
bd2d26418a Cleanup github workflows (#1272) 2021-04-07 13:25:48 +02:00
aeb3b2a030 Display day header from website in timetable (#1269) 2021-04-05 15:07:29 +02:00
7bc5219d81 Add new notifications (#1243) 2021-04-04 14:15:07 +00:00
6cb4ea4b0f Drop support for android 4.x (#1232) 2021-04-03 09:56:07 +00:00
0bdd33ef4a Migrate to material components bottom navigation (#1244) 2021-04-03 11:46:36 +02:00
792de4cd3d Merge branch 'hotfix/fix-recovery-visibility' into develop 2021-04-01 22:40:33 +02:00
3f5fbbc71b Merge branch 'hotfix/fix-recovery-visibility' 2021-04-01 22:40:20 +02:00
206b40ce1b Change version in changelog 2021-04-01 22:38:35 +02:00
43c56b5534 Version 1.1.4 2021-04-01 22:36:51 +02:00
a1076539dc Fix content visibility in login recovery 2021-04-01 22:30:09 +02:00
3071e19584 Implement a toggleable setting to count an arithmetic average of grades when all weights are equal to zero (#1186) 2021-03-30 13:59:36 +02:00
f2130998ec Bump firebase-crashlytics-gradle from 2.5.1 to 2.5.2 (#1264) 2021-03-30 10:49:40 +00:00
8a5ca8c91f Bump firebase-bom from 26.7.0 to 26.8.0 (#1263) 2021-03-30 10:48:12 +00:00
fada13e2d3 Update issue templates (#1257) 2021-03-29 18:39:08 +02:00
6e19eb943d Add deploy to AppGallery github actions config (#1259) 2021-03-29 17:37:26 +02:00
c70fe3430c Merge branch 'release/1.1.3' into develop 2021-03-28 20:13:43 +02:00
3c48264539 Merge branch 'release/1.1.3' 2021-03-28 20:13:37 +02:00
539cf2207b Version 1.1.3 2021-03-28 20:13:32 +02:00
f0e897713c New Crowdin updates (#1233) 2021-03-28 19:52:38 +02:00
a448092008 Allow special login format in login form (#1258) 2021-03-28 19:46:56 +02:00
f5b46707ff Fixing README.md (#1255) 2021-03-28 15:56:44 +02:00
e6247d4428 Fix clearing no existing dialog fragment (#1242) 2021-03-28 08:18:07 +02:00
d0869b235a Use db student id to distinguish reporting units and recipients (#1254) 2021-03-27 13:43:25 +01:00
464900d95b Bump annotation from 1.1.0 to 1.2.0 (#1245) 2021-03-25 10:12:05 +00:00
368274239e Bump agconnect-crash from 1.5.0.300 to 1.5.1.200 (#1247) 2021-03-25 10:11:19 +00:00
ee33197494 Bump room from 2.3.0-beta03 to 2.3.0-rc01 (#1246) 2021-03-25 10:09:21 +00:00
d3ea743707 Bump kotlin_version from 1.4.31 to 1.4.32 (#1253) 2021-03-25 10:07:43 +00:00
976d4b8ce2 Bump fragment-ktx from 1.3.1 to 1.3.2 (#1248) 2021-03-25 11:05:14 +01:00
b77fc0d32a Bump activity-ktx from 1.2.1 to 1.2.2 (#1249) 2021-03-25 11:04:37 +01:00
bd3716609e Bump hianalytics from 5.2.0.300 to 5.2.0.301 (#1250) 2021-03-25 11:04:04 +01:00
5b87cc9009 Bump agcp from 1.5.0.300 to 1.5.1.200 (#1251) 2021-03-25 11:03:37 +01:00
4f7be8d2cb Bump lifecycle-livedata-ktx from 2.3.0 to 2.3.1 (#1252) 2021-03-25 11:02:39 +01:00
8733e7782f Fix colorPrimary and class name in widget account manager (#1241) 2021-03-21 22:37:34 +01:00
e03b0dfa01 Fix missing avatars in widgets (#1238) 2021-03-21 12:04:55 +01:00
efafd2094a Add dialog with info about dropping support for android 4 (#1221) 2021-03-20 14:01:17 +01:00
1560335749 Fix very rare crash in login recovery (#1231) 2021-03-20 13:27:47 +01:00
5bee155f1e Remove listenablefuture from dependencies (#1237) 2021-03-20 12:10:53 +00:00
c9dc9a323f Bump gradle from 4.1.2 to 4.1.3 (#1234) 2021-03-19 15:02:28 +00:00
87e7e00705 Remove firebase inappmessage dependency (#1235) 2021-03-19 15:57:12 +01:00
57681b35ea Bump mockk from 1.10.6 to 1.11.0 (#1229) 2021-03-17 22:58:17 +00:00
8fb09d7b7d Merge branch 'release/1.1.2' into develop 2021-03-16 12:59:00 +01:00
168f750863 Merge branch 'release/1.1.2' 2021-03-16 12:58:56 +01:00
3e1acbd3bf Version 1.1.2 2021-03-16 12:58:52 +01:00
21ef2adcf6 Disable optimization in r8 config and fix crash in grade fragment (#1226) 2021-03-16 11:49:17 +00:00
3f6159e976 Fix show error details button in additional lessons (#1225) 2021-03-16 12:47:51 +01:00
555b5ec112 Merge branch 'release/1.1.1' into develop 2021-03-16 00:43:39 +01:00
60a9bcae46 Merge branch 'release/1.1.1' 2021-03-16 00:43:33 +01:00
eeb1341c1f Version 1.1.1 2021-03-16 00:43:28 +01:00
c77b50d51b New Crowdin updates (#1204) 2021-03-16 00:30:28 +01:00
8644ce32d5 Fix semester switch when student have only one semester (#1215) 2021-03-15 23:58:50 +01:00
94506aca52 Add github actions config to deploy apk to App Center (#1220) 2021-03-15 18:18:08 +01:00
eee4e1f4b5 Fix empty view in attendance (#1217) 2021-03-15 00:33:40 +01:00
c1942d012f Maybe fix fragment commits after activity state is saved (#1216) 2021-03-13 20:15:12 +01:00
fe846b463a Update material chips input (#1214) 2021-03-13 20:14:36 +01:00
0ea2e68249 Fix and clean proguard/r8 file (#1213) 2021-03-13 20:14:10 +01:00
be0445b227 Change the absence request confirmation message string (#1212) 2021-03-13 20:13:57 +01:00
48249f3093 Update kotlin coroutines (#1211) 2021-03-13 20:13:48 +01:00
8d7110735d Ignore no current student during avatar loading (#1210) 2021-03-13 20:13:37 +01:00
94957850c3 Bump fragment-ktx from 1.3.0 to 1.3.1 (#1205) 2021-03-12 21:50:59 +00:00
fa2cfc8427 Bump room from 2.3.0-beta02 to 2.3.0-beta03 (#1207) 2021-03-12 21:33:30 +00:00
3d467c43ba Use new kotlin compiler backend (#1202) 2021-03-12 22:07:27 +01:00
b76032044d Bump activity-ktx from 1.2.0 to 1.2.1 (#1206) 2021-03-12 21:06:33 +00:00
495b84204c Bump work_hilt from 1.0.0-alpha03 to 1.0.0-beta01 (#1208) 2021-03-12 21:06:27 +00:00
ea4b299de6 Bump firebase-bom from 26.6.0 to 26.7.0 (#1209) 2021-03-12 12:39:01 +00:00
acb5e2afd4 Replace dash mark with no data string in SchoolFragment (#1203) 2021-03-09 17:49:24 +01:00
50863d6ac2 Merge branch 'release/1.1.0' into develop 2021-03-07 21:58:30 +01:00
e15eb03299 Merge branch 'release/1.1.0' 2021-03-07 21:58:23 +01:00
be48791d51 Version 1.1.0 2021-03-07 21:58:14 +01:00
c0e1a5b401 New Crowdin updates (#1167) 2021-03-07 20:48:29 +00:00
cb1b467a21 Add studzinskik to contributors (#1198) 2021-03-07 20:31:14 +00:00
f14346ff32 Fix duplicate items after running automatic and manual sync at the same time (#1197) 2021-03-07 20:47:18 +01:00
af8108a649 Add lucky number history (#1184) 2021-03-07 20:17:03 +01:00
5743928126 Fix notification and status bars colors (#1196) 2021-03-07 14:04:37 +00:00
388d37bf9c Fix date picker theme (#1194) 2021-03-07 13:41:54 +01:00
d572fc737f Fix typo (#1193) 2021-03-07 00:07:57 +01:00
47b0f1b527 Settings revamp (#1160) 2021-03-06 17:18:42 +00:00
1afa7ecf3c Fix OOM in grade statistics (#1192) 2021-03-06 16:50:06 +01:00
9139febbdf Migrate database migrations from androidTest to roboelectric (#1191) 2021-03-06 14:34:07 +00:00
2dd0b56333 Bump agconnect-crash from 1.5.0.200 to 1.5.0.300 (#1190) 2021-03-06 12:08:43 +00:00
3b970209a5 Fix grade fragment subtitle (#1185) 2021-03-06 13:01:41 +01:00
6f590eb194 Fix empty license dialogs (#1182) 2021-03-06 13:01:17 +01:00
b20b8fb243 Bump firebase-bom from 26.5.0 to 26.6.0 (#1189) 2021-03-06 11:23:16 +00:00
7e4a212951 Bump agcp from 1.5.0.200 to 1.5.0.300 (#1187) 2021-03-06 10:55:37 +00:00
6dfeed3a26 Fix API host key capitalisation for powiat krasnostawski (#1181) 2021-03-04 20:32:17 +00:00
06a27199ee Add early validation for special mail domains (#1000) (#1176) 2021-03-03 22:37:58 +01:00
76039e5eb9 Remove hardcoded strings (#1177) 2021-03-03 20:18:03 +01:00
6a4aaff8d6 Fix no system theme option in Czech and Slovak (#1178) 2021-03-03 19:16:46 +00:00
9e2985864a Add avatars (#1146) 2021-03-02 23:34:25 +00:00
412057b512 Remove deprecations (#1170) 2021-03-02 17:28:47 +01:00
963caadced Bump firebase-crashlytics-gradle from 2.5.0 to 2.5.1 (#1171) 2021-03-01 22:19:31 +00:00
8388a8a5fc Fix calling of binding outside lifecycle (#1169) 2021-03-01 21:57:47 +00:00
a801c8f8be Add exception ignoring to UpdateHelper when PendingIntent is duplicated (#1168) 2021-03-01 21:35:49 +00:00
9d8ad73e63 Bump hilt_version from 2.32-alpha to 2.33-beta (#1163)
* Bump hilt_version from 2.32-alpha to 2.33-beta

Bumps `hilt_version` from 2.32-alpha to 2.33-beta.

Updates `hilt-android-gradle-plugin` from 2.32-alpha to 2.33-beta
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/commits)

Updates `hilt-android` from 2.32-alpha to 2.33-beta
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/commits)

Updates `hilt-android-compiler` from 2.32-alpha to 2.33-beta
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

* Add inject before super.onCreate() in activity

* Fix format

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
Co-authored-by: Rafał Borcz <RafalBO99@outlook.com>
2021-02-27 22:49:50 +01:00
182f6c8a81 Bump kotlin_version from 1.4.30 to 1.4.31 (#1166) 2021-02-26 19:21:02 +00:00
1e4a3536cf Bump desugar_jdk_libs from 1.1.1 to 1.1.5 (#1164) 2021-02-26 18:50:58 +00:00
169a314664 Bump about_libraries from 8.8.2 to 8.8.3 (#1165) 2021-02-26 18:49:43 +00:00
904eed648b Bump hianalytics from 5.1.0.301 to 5.2.0.300 (#1161) 2021-02-24 23:00:00 +00:00
3bb94adece Bump room from 2.3.0-beta01 to 2.3.0-beta02 (#1158) 2021-02-22 23:07:37 +00:00
105b70fcad Add Daxxxis to contributors (#1156) 2021-02-18 21:25:46 +01:00
b4bf7c7589 Add Slovak to dialog (#1154) 2021-02-18 00:05:40 +01:00
ff425d6d2b Change background color of navigation and notification bars (#1120) 2021-02-18 00:05:27 +01:00
4fceb854b3 Bump activity-ktx from 1.1.0 to 1.2.0 (#1134) 2021-02-17 12:08:10 +00:00
3adac154b4 Bump firebase-crashlytics-gradle from 2.4.1 to 2.5.0 (#1147) 2021-02-17 11:55:27 +00:00
a320cf8f7c Bump fragment-ktx from 1.2.5 to 1.3.0 (#1148) 2021-02-17 11:39:26 +00:00
1ed0884dfd Bump hilt_version from 2.31.2-alpha to 2.32-alpha (#1133) 2021-02-17 11:38:51 +00:00
021e9726c6 Bump lifecycle-livedata-ktx from 2.2.0 to 2.3.0 (#1136) 2021-02-17 11:38:33 +00:00
3c438757e3 Bump firebase-bom from 26.4.0 to 26.5.0 (#1151) 2021-02-17 11:31:05 +00:00
99c4a65df5 Merge tag '1.0.1' into develop
Version 1.0.1
2021-02-16 12:46:54 +01:00
499 changed files with 26441 additions and 3419 deletions

View File

@ -1,3 +1,12 @@
---
name: Bug report
about: Utwórz raport błędu, aby pomóc nam ulepszyć Wulkanowego
title: ''
labels: ''
assignees: ''
---
## Co powinno się dziać ## Co powinno się dziać

View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Zaproponuj nowy pomysł dla Wulkanowego
title: ''
labels: ''
assignees: ''
---
** Czy Twoja prośba o funkcję jest związana z problemem? Proszę opisz.**
Jasny i zwięzły opis problemu. Np. Zawsze jestem sfrustrowany, gdy [...]
** Opisz żądane rozwiązanie **
Jasny i zwięzły opis tego, co chcesz, aby się wydarzyło.
** Opisz alternatywy, które rozważałeś **
Jasny i zwięzły opis wszelkich rozważanych alternatywnych rozwiązań lub funkcji.
** Dodatkowy kontekst **
Dodaj inny kontekst lub zrzuty ekranu dotyczące żądania funkcji tutaj.

12
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: gradle
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
target-branch: develop
ignore:
- dependency-name: io.github.wulkanowy:sdk
reviewers:
- Faierbel

74
.github/workflows/deploy-store.yml vendored Normal file
View File

@ -0,0 +1,74 @@
name: Deploy to app stores
on:
release:
types: [ created ]
jobs:
deploy-google-play:
name: Deploy to google play
runs-on: ubuntu-latest
timeout-minutes: 10
environment: google-play
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- name: Decrypt keys
env:
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
SERVICES_ENCRYPT_KEY: ${{ secrets.SERVICES_ENCRYPT_KEY }}
run: |
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg
- name: Upload apk to google play
env:
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
PLAY_SERVICE_ACCOUNT_EMAIL: ${{ secrets.PLAY_SERVICE_ACCOUNT_EMAIL }}
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
run: ./gradlew publishPlayRelease -PenableFirebase --stacktrace;
deploy-app-gallery:
name: Deploy to AppGallery
runs-on: ubuntu-latest
timeout-minutes: 10
environment: app-gallery
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- name: Decrypt keys
env:
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
SERVICES_ENCRYPT_KEY: ${{ secrets.SERVICES_ENCRYPT_KEY }}
run: |
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/agconnect-services.json.gpg
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg
- name: Prepare credentials
env:
AGC_CREDENTIALS: ${{ secrets.AGC_CREDENTIALS }}
run: echo $AGC_CREDENTIALS > ./app/src/release/agconnect-credentials.json
- name: Build and publish HMS version
env:
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
run: ./gradlew assembleHmsRelease --stacktrace && ./gradlew publishHuaweiAppGalleryHmsRelease --stacktrace

144
.github/workflows/deploy-test.yml vendored Normal file
View File

@ -0,0 +1,144 @@
name: Deploy to app tests
on:
push:
# branches: [ develop ]
branches: [ '!*' ]
pull_request_target:
# branches: [ develop ]
branches: [ '!*' ]
workflow_dispatch:
jobs:
deploy-appcenter:
name: App Center
runs-on: ubuntu-latest
timeout-minutes: 10
environment: app-center
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- name: Set run number with offset
env:
BUILD_NUMBER_OFFSET: ${{ secrets.BUILD_NUMBER_OFFSET }}
run: echo "RUN_NUMBER=$((GITHUB_RUN_NUMBER+BUILD_NUMBER_OFFSET))" >> $GITHUB_ENV
- name: Prepare build configuration
run: |
sed -i -e "s#applicationIdSuffix \".dev\"#applicationIdSuffix \".${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/build.gradle
sed -i -e "s#.dev\"#.${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/src/debug/google-services.json
sed -i -e "s#.dev\"#.${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/src/debug/agconnect-services.json
sed -i -e '/versionNameSuffix/d' app/build.gradle
- name: Add signing config
run: |
cat >> app/build.gradle <<EOF
android.signingConfigs.debug {
storeFile file("bitrise.jks")
storePassword System.getenv("BITRISE_KEYSTORE_PASSWORD")
keyAlias System.getenv("BITRISE_KEY_ALIAS")
keyPassword System.getenv("BITRISE_KEY_PASSWORD")
}
EOF
- name: Decrypt keys
env:
BITRISE_ENCRYPT_KEY: ${{ secrets.BITRISE_ENCRYPT_KEY }}
run: |
gpg --yes --batch --passphrase=$BITRISE_ENCRYPT_KEY ./app/bitrise.jks.gpg
- name: Bump version
uses: chkfung/android-version-actions@v1.1
with:
gradlePath: app/build.gradle
versionCode: ${{ env.RUN_NUMBER }}
versionName: ${{ env.RUN_NUMBER }}-${{ github.head_ref }}
- name: Build apk
env:
BITRISE_KEYSTORE_PASSWORD: ${{ secrets.BITRISE_KEYSTORE_PASSWORD }}
BITRISE_KEY_ALIAS: ${{ secrets.BITRISE_KEY_ALIAS }}
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
run: ./gradlew assembleFdroidDebug --stacktrace
- name: Upload apk to github artifacts
uses: actions/upload-artifact@v2
with:
name: wulkanowyDEV-${{ env.RUN_NUMBER }}.apk
path: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
- name: Deploy to app center
uses: wzieba/AppCenter-Github-Action@v1
with:
appName: wulkanowy/wulkanowy
token: ${{ secrets.APP_CENTER_TOKEN }}
group: Testers
file: app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk
notifyTesters: true
debug: true
deploy-app-distribution:
name: App Distribution
runs-on: ubuntu-latest
timeout-minutes: 10
environment: app-distribution
if: github.event_name != 'pull_request_target'
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- name: Set run number with offset
env:
BUILD_NUMBER_OFFSET: ${{ secrets.BUILD_NUMBER_OFFSET }}
run: echo "RUN_NUMBER=$((GITHUB_RUN_NUMBER+BUILD_NUMBER_OFFSET))" >> $GITHUB_ENV
- name: Add signing config
run: |
cat >> app/build.gradle <<EOF
android.signingConfigs.debug {
storeFile file("bitrise.jks")
storePassword System.getenv("BITRISE_KEYSTORE_PASSWORD")
keyAlias System.getenv("BITRISE_KEY_ALIAS")
keyPassword System.getenv("BITRISE_KEY_PASSWORD")
}
EOF
- name: Decrypt keys
env:
BITRISE_ENCRYPT_KEY: ${{ secrets.BITRISE_ENCRYPT_KEY }}
BITRISE_SERVICES_ENCRYPT_KEY: ${{ secrets.BITRISE_SERVICES_ENCRYPT_KEY }}
run: |
gpg --yes --batch --passphrase=$BITRISE_SERVICES_ENCRYPT_KEY ./app/src/debug/google-services.json.gpg
gpg --yes --batch --passphrase=$BITRISE_ENCRYPT_KEY ./app/bitrise.jks.gpg
- name: Bump version
uses: chkfung/android-version-actions@v1.1
with:
gradlePath: app/build.gradle
versionCode: ${{ env.RUN_NUMBER }}
versionName: ${{ env.RUN_NUMBER }}
- name: Build apk
env:
BITRISE_KEYSTORE_PASSWORD: ${{ secrets.BITRISE_KEYSTORE_PASSWORD }}
BITRISE_KEY_ALIAS: ${{ secrets.BITRISE_KEY_ALIAS }}
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
run: ./gradlew assemblePlayDebug -PenableFirebase --stacktrace
- name: Upload apk to github artifacts
uses: actions/upload-artifact@v2
with:
name: wulkanowyDEV-${{ env.RUN_NUMBER }}-dev.apk
path: app/build/outputs/apk/play/debug/app-play-debug.apk
- name: Deploy to app distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{ secrets.FIREBASE_APP_ID }}
token: ${{ secrets.FIREBASE_TOKEN }}
groups: discord
file: app/build/outputs/apk/play/debug/app-play-debug.apk

View File

@ -1,17 +1,15 @@
name: Test and deploy name: Tests
on: on:
push: push:
branches: [ develop ] branches: [ master, develop ]
tags: [ '*' ] tags: [ '*' ]
pull_request: pull_request:
branches: [ develop ] branches: [ master, develop ]
workflow_dispatch:
jobs: jobs:
build: unit-tests:
name: Pre-build name: Unit tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
@ -27,116 +25,10 @@ jobs:
~/.gradle/caches ~/.gradle/caches
~/.gradle/wrapper ~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }} key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- name: Build
run: ./gradlew --build-cache compileFdroidDebugUnitTestKotlin preFdroidDebugAndroidTestBuild dexBuilderFdroidDebugAndroidTest packageFdroidDebug packageFdroidDebugAndroidTest
- name: Prepare build cache
run: tar -cf prebuild.tar .build-cache .gradle app/build
- uses: actions/upload-artifact@v2
with:
name: prebuild.tar
path: prebuild.tar
unit-tests:
name: Unit tests
runs-on: ubuntu-latest
timeout-minutes: 10
needs: [ build ]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- uses: actions/download-artifact@v2
with:
name: prebuild.tar
- name: Extract build cache
run: tar -xf prebuild.tar
- name: Unit tests - name: Unit tests
run: | run: |
./gradlew --build-cache -Pcoverage testFdroidDebugUnitTest --stacktrace ./gradlew testFdroidDebugUnitTest --stacktrace
./gradlew --build-cache -Pcoverage jacocoTestReport --stacktrace ./gradlew jacocoTestReport --stacktrace
- uses: codecov/codecov-action@v1 - uses: codecov/codecov-action@v1
with: with:
flags: unit flags: unit
instrumentation-tests:
name: Instrumentation tests
runs-on: macOS-latest
timeout-minutes: 15
needs: [ build ]
strategy:
fail-fast: true
matrix:
api-level: [21, 29]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- uses: actions/download-artifact@v2
with:
name: prebuild.tar
- name: Extract build cache
run: tar -xf prebuild.tar
- name: Instrumentation tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
arch: x86
script: |
./gradlew --build-cache -Pcoverage connectedFdroidDebugAndroidTest --stacktrace
./gradlew --build-cache -Pcoverage jacocoTestReport --stacktrace
- uses: codecov/codecov-action@v1
with:
flags: instrumented,api-${{ matrix.api-level }}
deploy-google-play:
name: Deploy to google play
runs-on: ubuntu-latest
timeout-minutes: 10
environment: google-play
needs: [ build, unit-tests, instrumentation-tests ]
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
with:
java-version: 11
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- uses: actions/download-artifact@v2
with:
name: prebuild.tar
- name: Extract build cache
run: tar -xf prebuild.tar
- name: Decrypt keys
env:
ENCRYPT_KEY: ${{ secrets.ENCRYPT_KEY }}
SERVICES_ENCRYPT_KEY: ${{ secrets.SERVICES_ENCRYPT_KEY }}
run: |
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg
- name: Upload apk to google play
env:
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
PLAY_SERVICE_ACCOUNT_EMAIL: ${{ secrets.PLAY_SERVICE_ACCOUNT_EMAIL }}
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
run: ./gradlew publishPlayRelease -PenableFirebase --stacktrace;

2
.gitignore vendored
View File

@ -117,3 +117,5 @@ Thumbs.db
app/src/release/agconnect-services.json app/src/release/agconnect-services.json
app/src/release/agconnect-credentials.json
.idea/deploymentTargetDropDown.xml

View File

@ -7,15 +7,6 @@
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" /> <package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
</value> </value>
</option> </option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />
<option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" /> <option name="NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS" value="2147483647" />
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" /> <option name="WRAP_ELVIS_EXPRESSIONS" value="0" />

View File

@ -2,7 +2,7 @@
# Wulkanowy # Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Test%20and%20deploy/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr) [![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/) [![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)

View File

@ -2,7 +2,7 @@
# Wulkanowy # Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Test%20and%20deploy/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr) [![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/) [![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg?style=flat-square)](https://f-droid.org/packages/io.github.wulkanowy/)
@ -32,7 +32,7 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
* powiadomienia np. o nowej ocenie * powiadomienia np. o nowej ocenie
* obsługa wielu kont wraz z możliwością zmiany nazwy ucznia * obsługa wielu kont wraz z możliwością zmiany nazwy ucznia
* ciemny i czarny (AMOLED) motyw * ciemny i czarny (AMOLED) motyw
* tryb offilne * tryb offline
* brak reklam * brak reklam
## Pobierz ## Pobierz

BIN
app/bitrise.jks.gpg Normal file

Binary file not shown.

View File

@ -1,26 +1,28 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin' apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.github.triplet.play' apply plugin: 'com.github.triplet.play'
apply plugin: 'ru.cian.huawei-publish'
apply plugin: 'com.mikepenz.aboutlibraries.plugin' apply plugin: 'com.mikepenz.aboutlibraries.plugin'
apply plugin: 'com.huawei.agconnect'
apply from: 'jacoco.gradle' apply from: 'jacoco.gradle'
apply from: 'sonarqube.gradle' apply from: 'sonarqube.gradle'
apply from: 'hooks.gradle' apply from: 'hooks.gradle'
android { android {
compileSdkVersion 30 compileSdkVersion 30
buildToolsVersion '30.0.3'
defaultConfig { defaultConfig {
applicationId "io.github.wulkanowy" applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy" testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 17 minSdkVersion 21
targetSdkVersion 30 targetSdkVersion 30
versionCode 85 versionCode 94
versionName "1.0.1" versionName "1.2.1"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
@ -41,7 +43,8 @@ android {
} }
sourceSets { sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString()) // https://github.com/robolectric/robolectric/issues/3928#issuecomment-395309991
debug.assets.srcDirs += files("$projectDir/schemas".toString())
} }
signingConfigs { signingConfigs {
@ -64,7 +67,6 @@ android {
resValue "string", "app_name", "Wulkanowy DEV " + defaultConfig.versionCode resValue "string", "app_name", "Wulkanowy DEV " + defaultConfig.versionCode
applicationIdSuffix ".dev" applicationIdSuffix ".dev"
versionNameSuffix "-dev" versionNameSuffix "-dev"
testCoverageEnabled = project.hasProperty('coverage')
ext.enableCrashlytics = project.hasProperty("enableFirebase") ext.enableCrashlytics = project.hasProperty("enableFirebase")
} }
} }
@ -74,7 +76,6 @@ android {
productFlavors { productFlavors {
hms { hms {
dimension "platform" dimension "platform"
minSdkVersion 19
manifestPlaceholders = [ manifestPlaceholders = [
install_channel: "AppGallery" install_channel: "AppGallery"
] ]
@ -96,21 +97,21 @@ android {
} }
buildFeatures { buildFeatures {
viewBinding = true viewBinding true
} }
lintOptions { testOptions.unitTests {
disable 'HardwareIds' includeAndroidResources = true
} }
compileOptions { compileOptions {
coreLibraryDesugaringEnabled true coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_11
} }
kotlinOptions { kotlinOptions {
jvmTarget = "1.8" jvmTarget = "11"
freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"] freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
} }
@ -124,53 +125,66 @@ android {
} }
} }
kapt {
correctErrorTypes true
}
play { play {
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf" serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
serviceAccountCredentials = file('key.p12') serviceAccountCredentials = file('key.p12')
defaultToAppBundles = false defaultToAppBundles = false
track = 'alpha' track = 'production'
updatePriority = 3 updatePriority = 3
} }
huaweiPublish {
instances {
hmsRelease {
credentialsPath = "$rootDir/app/src/release/agconnect-credentials.json"
buildFormat = "apk"
deployType = "draft"
}
}
}
ext { ext {
work_manager = "2.5.0" work_manager = "2.5.0"
work_hilt = "1.0.0-alpha03" android_hilt = "1.0.0"
room = "2.3.0-beta01" room = "2.3.0"
chucker = "3.4.0" chucker = "3.5.2"
mockk = "1.10.6" mockk = "1.12.0"
moshi = "1.11.0" moshi = "1.12.0"
} }
dependencies { dependencies {
implementation "io.github.wulkanowy:sdk:1.0.1" implementation "io.github.wulkanowy:sdk:1.2.1"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2'
implementation "androidx.core:core-ktx:1.3.2" implementation "androidx.core:core-ktx:1.6.0"
implementation "androidx.activity:activity-ktx:1.1.0" implementation "androidx.activity:activity-ktx:1.3.1"
implementation "androidx.appcompat:appcompat:1.2.0" implementation "androidx.appcompat:appcompat:1.3.1"
implementation "androidx.appcompat:appcompat-resources:1.2.0" implementation "androidx.appcompat:appcompat-resources:1.3.1"
implementation "androidx.fragment:fragment-ktx:1.2.5" implementation "androidx.fragment:fragment-ktx:1.3.6"
implementation "androidx.annotation:annotation:1.1.0" implementation "androidx.annotation:annotation:1.2.0"
implementation "androidx.multidex:multidex:2.0.1"
implementation "androidx.preference:preference-ktx:1.1.1" implementation "androidx.preference:preference-ktx:1.1.1"
implementation "androidx.recyclerview:recyclerview:1.1.0" implementation "androidx.recyclerview:recyclerview:1.2.1"
implementation "androidx.viewpager:viewpager:1.0.0" implementation "androidx.viewpager:viewpager:1.0.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:2.0.4" implementation "androidx.constraintlayout:constraintlayout:2.1.0"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0" implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "com.google.android.material:material:1.3.0" implementation "com.google.android.material:material:1.4.0"
implementation "com.github.wulkanowy:material-chips-input:2.1.1" implementation "com.github.wulkanowy:material-chips-input:2.2.0"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0" implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation 'com.github.lopspower:CircularImageView:4.2.0'
implementation "androidx.work:work-runtime-ktx:$work_manager" implementation "androidx.work:work-runtime-ktx:$work_manager"
playImplementation "androidx.work:work-gcm:$work_manager" playImplementation "androidx.work:work-gcm:$work_manager"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
implementation "androidx.room:room-runtime:$room" implementation "androidx.room:room-runtime:$room"
implementation "androidx.room:room-ktx:$room" implementation "androidx.room:room-ktx:$room"
@ -178,54 +192,56 @@ dependencies {
implementation "com.google.dagger:hilt-android:$hilt_version" implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version" kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
implementation "androidx.hilt:hilt-work:$work_hilt" kapt "androidx.hilt:hilt-compiler:$android_hilt"
kapt "androidx.hilt:hilt-compiler:$work_hilt" implementation "androidx.hilt:hilt-work:$android_hilt"
implementation "com.aurelhubert:ahbottomnavigation:2.3.4" implementation 'com.github.ncapdevi:FragNav:3.3.0'
implementation "com.ncapdevi:frag-nav:3.3.0"
implementation "com.github.YarikSOffice:lingver:1.3.0" implementation "com.github.YarikSOffice:lingver:1.3.0"
implementation "com.squareup.moshi:moshi:$moshi" implementation "com.squareup.moshi:moshi:$moshi"
implementation "com.squareup.moshi:moshi-adapters:$moshi" implementation "com.squareup.moshi:moshi-adapters:$moshi"
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi" kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi"
implementation "com.jakewharton.timber:timber:4.7.1"
implementation "com.jakewharton.timber:timber:5.0.1"
implementation "at.favre.lib:slf4j-timber:1.0.1" implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation "fr.bipi.treessence:treessence:0.3.2" implementation 'com.github.bastienpaulfr:Treessence:1.0.4'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries" implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation 'com.wdullaer:materialdatetimepicker:4.2.3' implementation "io.coil-kt:coil:1.3.2"
implementation "io.coil-kt:coil:1.1.1"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0" implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.3.1' implementation 'me.xdrop:fuzzywuzzy:1.3.1'
implementation 'com.fredporciuncula:flow-preferences:1.5.0'
playImplementation platform('com.google.firebase:firebase-bom:26.4.0') playImplementation platform('com.google.firebase:firebase-bom:28.4.0')
playImplementation 'com.google.firebase:firebase-analytics-ktx' playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx'
playImplementation "com.google.firebase:firebase-inappmessaging-ktx"
playImplementation 'com.google.firebase:firebase-messaging:' playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:' playImplementation 'com.google.firebase:firebase-crashlytics:'
playImplementation 'com.google.android.play:core:1.10.1'
playImplementation 'com.google.android.play:core-ktx:1.8.1' playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
hmsImplementation 'com.huawei.hms:hianalytics:5.1.0.301' hmsImplementation 'com.huawei.hms:hianalytics:6.2.0.301'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.5.0.200' hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.0.300'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker" releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker" debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
debugImplementation "com.amitshekhar.android:debug-db:1.0.6" debugImplementation 'com.github.amitshekhariitbhu.Android-Debug-Database:debug-db:v1.0.6'
testImplementation "junit:junit:4.13.2" testImplementation "junit:junit:4.13.2"
testImplementation "io.mockk:mockk:$mockk" testImplementation "io.mockk:mockk:$mockk"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.4.2' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.2'
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
androidTestImplementation "androidx.test:core:1.3.0" testImplementation 'org.robolectric:robolectric:4.6.1'
androidTestImplementation "androidx.test:runner:1.3.0" testImplementation "androidx.test:runner:1.4.0"
androidTestImplementation "androidx.test.ext:junit:1.1.2" testImplementation "androidx.test.ext:junit:1.1.3"
testImplementation "androidx.test:core:1.4.0"
testImplementation "androidx.room:room-testing:$room"
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
androidTestImplementation "androidx.test:core:1.4.0"
androidTestImplementation "androidx.test:runner:1.4.0"
androidTestImplementation "androidx.test.ext:junit:1.1.3"
androidTestImplementation "io.mockk:mockk-android:$mockk" androidTestImplementation "io.mockk:mockk-android:$mockk"
androidTestImplementation "androidx.room:room-testing:$room"
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
} }
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.huawei.agconnect'

View File

@ -1,8 +1,8 @@
apply plugin: "jacoco" apply plugin: "jacoco"
jacoco { jacoco {
toolVersion "0.8.5" toolVersion "0.8.7"
reportsDir = file("$buildDir/reports") reportsDirectory.set(file("$buildDir/reports"))
} }
tasks.withType(Test) { tasks.withType(Test) {
@ -16,8 +16,8 @@ task jacocoTestReport(type: JacocoReport) {
description = "Generate Jacoco coverage reports" description = "Generate Jacoco coverage reports"
reports { reports {
xml.enabled = true xml.required.set(true)
html.enabled = true html.required.set(true)
} }
def excludes = ['**/R.class', def excludes = ['**/R.class',

View File

@ -1,33 +1,21 @@
# Optimizations # General
-optimizationpasses 5
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-dontobfuscate -dontobfuscate
-allowaccessmodification
-repackageclasses ''
-verbose
#Keep all wulkanowy files #Config for wulkanowy
-keep class io.github.wulkanowy.** {*;} -keep class io.github.wulkanowy.** {*;}
#Config for anallitycs #Config for firebase crashlitycs
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable -keepattributes SourceFile,LineNumberTable
-keep class com.crashlytics.** {*;}
-keep public class * extends java.lang.Exception -keep public class * extends java.lang.Exception
-dontwarn com.crashlytics.**
#Config for OkHttp #Config for Okio and OkHttp
-dontwarn javax.annotation.**
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase -keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
-dontwarn org.codehaus.mojo.animal_sniffer.* -dontwarn org.codehaus.mojo.animal_sniffer.*
-dontwarn okhttp3.internal.platform.ConscryptPlatform -dontwarn okhttp3.internal.platform.ConscryptPlatform
-dontwarn javax.annotation.**
#Config for MPAndroidChart #Config for MPAndroidChart
@ -36,10 +24,3 @@
#Config for Material Components #Config for Material Components
-keep class com.google.android.material.tabs.** { *; } -keep class com.google.android.material.tabs.** { *; }
#Config for About Libraries
-keep class .R
-keep class **.R$* {
<fields>;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 335 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 781 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 700 B

View File

@ -0,0 +1,17 @@
package io.github.wulkanowy.utils
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.ui.modules.main.MainActivity
import javax.inject.Singleton
import javax.inject.Inject
@Singleton
class InAppReviewHelper @Inject constructor(
@ApplicationContext private val context: Context
) {
fun showInAppReview(activity: MainActivity) {
// do nothing
}
}

View File

@ -3,11 +3,6 @@ package io.github.wulkanowy.utils
import android.util.Log import android.util.Log
import com.huawei.agconnect.crash.AGConnectCrash import com.huawei.agconnect.crash.AGConnectCrash
import fr.bipi.tressence.base.FormatterPriorityTree import fr.bipi.tressence.base.FormatterPriorityTree
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
import java.io.InterruptedIOException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) { class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
@ -20,21 +15,10 @@ class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
} }
} }
class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR) { class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR, ExceptionFilter) {
private val connectCrash by lazy { AGConnectCrash.getInstance() } private val connectCrash by lazy { AGConnectCrash.getInstance() }
override fun skipLog(priority: Int, tag: String?, message: String, t: Throwable?): Boolean {
return when (t) {
is FeatureDisabledException,
is FeatureNotAvailableException,
is UnknownHostException,
is SocketTimeoutException,
is InterruptedIOException -> true
else -> super.skipLog(priority, tag, message, t)
}
}
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) { override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
if (skipLog(priority, tag, message, t)) return if (skipLog(priority, tag, message, t)) return

View File

@ -0,0 +1,17 @@
package io.github.wulkanowy.utils
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.ui.modules.main.MainActivity
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class InAppReviewHelper @Inject constructor(
@ApplicationContext private val context: Context
) {
fun showInAppReview(activity: MainActivity) {
// do nothing
}
}

View File

@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
@ -56,7 +57,7 @@
android:name=".ui.modules.login.LoginActivity" android:name=".ui.modules.login.LoginActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:label="@string/login_title" android:label="@string/login_title"
android:theme="@style/WulkanowyTheme.NoActionBar" android:theme="@style/WulkanowyTheme.Login"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".ui.modules.main.MainActivity" android:name=".ui.modules.main.MainActivity"
@ -68,7 +69,7 @@
android:name=".ui.modules.message.send.SendMessageActivity" android:name=".ui.modules.message.send.SendMessageActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:label="@string/send_message_title" android:label="@string/send_message_title"
android:theme="@style/WulkanowyTheme.NoActionBar" android:theme="@style/WulkanowyTheme.MessageSend"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity" android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
@ -167,7 +168,7 @@
<meta-data <meta-data
android:name="com.google.firebase.messaging.default_notification_icon" android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_push" /> android:resource="@drawable/ic_stat_all" />
<meta-data <meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id" android:name="com.google.firebase.messaging.default_notification_channel_id"

View File

@ -36,7 +36,19 @@
"githubUsername": "Luncenok" "githubUsername": "Luncenok"
}, },
{ {
"displayName": "MRmlik12", "displayName": "Daniel Olczyk",
"githubUsername": "MRmlik12" "githubUsername": "MRmlik12"
},
{
"displayName": "Damian Czupryn",
"githubUsername": "Daxxxis"
},
{
"displayName": "Kamil Studziński",
"githubUsername": "studzinskik"
},
{
"displayName": "Tomasz F.",
"githubUsername": "Pengwius"
} }
] ]

View File

@ -1,13 +1,13 @@
package io.github.wulkanowy package io.github.wulkanowy
import android.annotation.SuppressLint
import android.app.Application import android.app.Application
import android.content.Context
import android.util.Log.DEBUG import android.util.Log.DEBUG
import android.util.Log.INFO import android.util.Log.INFO
import android.util.Log.VERBOSE import android.util.Log.VERBOSE
import android.webkit.WebView import android.webkit.WebView
import androidx.fragment.app.FragmentManager
import androidx.hilt.work.HiltWorkerFactory import androidx.hilt.work.HiltWorkerFactory
import androidx.multidex.MultiDex
import androidx.work.Configuration import androidx.work.Configuration
import com.yariksoffice.lingver.Lingver import com.yariksoffice.lingver.Lingver
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
@ -41,14 +41,10 @@ class WulkanowyApp : Application(), Configuration.Provider {
@Inject @Inject
lateinit var analyticsHelper: AnalyticsHelper lateinit var analyticsHelper: AnalyticsHelper
override fun attachBaseContext(base: Context?) { @SuppressLint("UnsafeOptInUsageWarning")
super.attachBaseContext(base)
MultiDex.install(this)
}
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
FragmentManager.enableNewStateManager(false)
initializeAppLanguage() initializeAppLanguage()
themeManager.applyDefaultTheme() themeManager.applyDefaultTheme()
initLogging() initLogging()
@ -88,7 +84,7 @@ class WulkanowyApp : Application(), Configuration.Provider {
//https://stackoverflow.com/questions/40398528/android-webview-language-changes-abruptly-on-android-7-0-and-above //https://stackoverflow.com/questions/40398528/android-webview-language-changes-abruptly-on-android-7-0-and-above
try { try {
WebView(this).destroy() WebView(this).destroy()
} catch (e: Exception) { } catch (e: Throwable) {
//Ignore exceptions //Ignore exceptions
} }
} }

View File

@ -8,6 +8,8 @@ import androidx.preference.PreferenceManager
import com.chuckerteam.chucker.api.ChuckerCollector import com.chuckerteam.chucker.api.ChuckerCollector
import com.chuckerteam.chucker.api.ChuckerInterceptor import com.chuckerteam.chucker.api.ChuckerInterceptor
import com.chuckerteam.chucker.api.RetentionManager import com.chuckerteam.chucker.api.RetentionManager
import com.squareup.moshi.Moshi
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
@ -17,6 +19,8 @@ import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.SharedPrefProvider import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AppInfo
import kotlinx.coroutines.ExperimentalCoroutinesApi
import timber.log.Timber import timber.log.Timber
import javax.inject.Singleton import javax.inject.Singleton
@ -60,7 +64,8 @@ internal class RepositoryModule {
fun provideDatabase( fun provideDatabase(
@ApplicationContext context: Context, @ApplicationContext context: Context,
sharedPrefProvider: SharedPrefProvider, sharedPrefProvider: SharedPrefProvider,
) = AppDatabase.newInstance(context, sharedPrefProvider) appInfo: AppInfo
) = AppDatabase.newInstance(context, sharedPrefProvider, appInfo)
@Singleton @Singleton
@Provides @Provides
@ -75,6 +80,16 @@ internal class RepositoryModule {
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences = fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context) PreferenceManager.getDefaultSharedPreferences(context)
@OptIn(ExperimentalCoroutinesApi::class)
@Singleton
@Provides
fun provideFlowSharedPref(sharedPreferences: SharedPreferences) =
FlowSharedPreferences(sharedPreferences)
@Singleton
@Provides
fun provideMoshi() = Moshi.Builder().build()
@Singleton @Singleton
@Provides @Provides
fun provideStudentDao(database: AppDatabase) = database.studentDao fun provideStudentDao(database: AppDatabase) = database.studentDao
@ -179,4 +194,12 @@ internal class RepositoryModule {
@Singleton @Singleton
@Provides @Provides
fun provideStudentInfoDao(database: AppDatabase) = database.studentInfoDao fun provideStudentInfoDao(database: AppDatabase) = database.studentInfoDao
@Singleton
@Provides
fun provideTimetableHeaderDao(database: AppDatabase) = database.timetableHeaderDao
@Singleton
@Provides
fun provideSchoolAnnouncementDao(database: AppDatabase) = database.schoolAnnouncementDao
} }

View File

@ -6,11 +6,11 @@ import androidx.room.Room
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.RoomDatabase.JournalMode.TRUNCATE import androidx.room.RoomDatabase.JournalMode.TRUNCATE
import androidx.room.TypeConverters import androidx.room.TypeConverters
import androidx.room.migration.Migration
import io.github.wulkanowy.data.db.dao.AttendanceDao import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.db.dao.ConferenceDao import io.github.wulkanowy.data.db.dao.ConferenceDao
import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao
import io.github.wulkanowy.data.db.dao.ExamDao import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.dao.GradeDao import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao
@ -33,10 +33,12 @@ import io.github.wulkanowy.data.db.dao.SubjectDao
import io.github.wulkanowy.data.db.dao.TeacherDao import io.github.wulkanowy.data.db.dao.TeacherDao
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
import io.github.wulkanowy.data.db.dao.TimetableDao import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.CompletedLesson import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Conference import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradePartialStatistics import io.github.wulkanowy.data.db.entities.GradePartialStatistics
@ -59,6 +61,7 @@ import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.data.db.entities.Teacher import io.github.wulkanowy.data.db.entities.Teacher
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.entities.TimetableAdditional import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.data.db.entities.TimetableHeader
import io.github.wulkanowy.data.db.migrations.Migration10 import io.github.wulkanowy.data.db.migrations.Migration10
import io.github.wulkanowy.data.db.migrations.Migration11 import io.github.wulkanowy.data.db.migrations.Migration11
import io.github.wulkanowy.data.db.migrations.Migration12 import io.github.wulkanowy.data.db.migrations.Migration12
@ -86,12 +89,18 @@ import io.github.wulkanowy.data.db.migrations.Migration31
import io.github.wulkanowy.data.db.migrations.Migration32 import io.github.wulkanowy.data.db.migrations.Migration32
import io.github.wulkanowy.data.db.migrations.Migration33 import io.github.wulkanowy.data.db.migrations.Migration33
import io.github.wulkanowy.data.db.migrations.Migration34 import io.github.wulkanowy.data.db.migrations.Migration34
import io.github.wulkanowy.data.db.migrations.Migration35
import io.github.wulkanowy.data.db.migrations.Migration36
import io.github.wulkanowy.data.db.migrations.Migration37
import io.github.wulkanowy.data.db.migrations.Migration38
import io.github.wulkanowy.data.db.migrations.Migration39
import io.github.wulkanowy.data.db.migrations.Migration4 import io.github.wulkanowy.data.db.migrations.Migration4
import io.github.wulkanowy.data.db.migrations.Migration5 import io.github.wulkanowy.data.db.migrations.Migration5
import io.github.wulkanowy.data.db.migrations.Migration6 import io.github.wulkanowy.data.db.migrations.Migration6
import io.github.wulkanowy.data.db.migrations.Migration7 import io.github.wulkanowy.data.db.migrations.Migration7
import io.github.wulkanowy.data.db.migrations.Migration8 import io.github.wulkanowy.data.db.migrations.Migration8
import io.github.wulkanowy.data.db.migrations.Migration9 import io.github.wulkanowy.data.db.migrations.Migration9
import io.github.wulkanowy.utils.AppInfo
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
@ -123,6 +132,8 @@ import javax.inject.Singleton
Conference::class, Conference::class,
TimetableAdditional::class, TimetableAdditional::class,
StudentInfo::class, StudentInfo::class,
TimetableHeader::class,
SchoolAnnouncement::class,
], ],
version = AppDatabase.VERSION_SCHEMA, version = AppDatabase.VERSION_SCHEMA,
exportSchema = true exportSchema = true
@ -131,10 +142,9 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
companion object { companion object {
const val VERSION_SCHEMA = 34 const val VERSION_SCHEMA = 39
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> { fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
return arrayOf(
Migration2(), Migration2(),
Migration3(), Migration3(),
Migration4(), Migration4(),
@ -167,19 +177,25 @@ abstract class AppDatabase : RoomDatabase() {
Migration31(), Migration31(),
Migration32(), Migration32(),
Migration33(), Migration33(),
Migration34() Migration34(),
Migration35(appInfo),
Migration36(),
Migration37(),
Migration38(),
Migration39(),
) )
}
fun newInstance(context: Context, sharedPrefProvider: SharedPrefProvider): AppDatabase { fun newInstance(
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database") context: Context,
sharedPrefProvider: SharedPrefProvider,
appInfo: AppInfo
) = Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
.setJournalMode(TRUNCATE) .setJournalMode(TRUNCATE)
.fallbackToDestructiveMigrationFrom(VERSION_SCHEMA + 1) .fallbackToDestructiveMigrationFrom(VERSION_SCHEMA + 1)
.fallbackToDestructiveMigrationOnDowngrade() .fallbackToDestructiveMigrationOnDowngrade()
.addMigrations(*getMigrations(sharedPrefProvider)) .addMigrations(*getMigrations(sharedPrefProvider, appInfo))
.build() .build()
} }
}
abstract val studentDao: StudentDao abstract val studentDao: StudentDao
@ -232,4 +248,8 @@ abstract class AppDatabase : RoomDatabase() {
abstract val timetableAdditionalDao: TimetableAdditionalDao abstract val timetableAdditionalDao: TimetableAdditionalDao
abstract val studentInfoDao: StudentInfoDao abstract val studentInfoDao: StudentInfoDao
abstract val timetableHeaderDao: TimetableHeaderDao
abstract val schoolAnnouncementDao: SchoolAnnouncementDao
} }

View File

@ -20,9 +20,15 @@ class SharedPrefProvider @Inject constructor(
fun getLong(key: String, defaultValue: Long) = sharedPref.getLong(key, defaultValue) fun getLong(key: String, defaultValue: Long) = sharedPref.getLong(key, defaultValue)
fun getString(key: String) = sharedPref.getString(key, null)
fun getString(key: String, defaultValue: String): String = sharedPref.getString(key, defaultValue) ?: defaultValue fun getString(key: String, defaultValue: String): String = sharedPref.getString(key, defaultValue) ?: defaultValue
fun putString(key: String, value: String, sync: Boolean = false) { fun getBoolean(key: String, defaultValue: Boolean): Boolean = sharedPref.getBoolean(key, defaultValue)
fun putBoolean(key: String, value: Boolean, sync: Boolean = false) = sharedPref.edit(sync) { putBoolean(key, value) }
fun putString(key: String, value: String?, sync: Boolean = false) {
sharedPref.edit(sync) { putString(key, value) } sharedPref.edit(sync) { putString(key, value) }
} }

View File

@ -4,12 +4,13 @@ import androidx.room.Dao
import androidx.room.Query import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Conference import io.github.wulkanowy.data.db.entities.Conference
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import java.time.LocalDateTime
import javax.inject.Singleton import javax.inject.Singleton
@Dao @Dao
@Singleton @Singleton
interface ConferenceDao : BaseDao<Conference> { interface ConferenceDao : BaseDao<Conference> {
@Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId") @Query("SELECT * FROM Conferences WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :startDate")
fun loadAll(diaryId: Int, studentId: Int): Flow<List<Conference>> fun loadAll(diaryId: Int, studentId: Int, startDate: LocalDateTime): Flow<List<Conference>>
} }

View File

@ -13,4 +13,7 @@ interface LuckyNumberDao : BaseDao<LuckyNumber> {
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date") @Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date")
fun load(studentId: Int, date: LocalDate): Flow<LuckyNumber?> fun load(studentId: Int, date: LocalDate): Flow<LuckyNumber?>
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date >= :start AND date <= :end")
fun getAll(studentId: Int, start: LocalDate, end: LocalDate): Flow<List<LuckyNumber>>
} }

View File

@ -9,6 +9,6 @@ import javax.inject.Singleton
@Dao @Dao
interface RecipientDao : BaseDao<Recipient> { interface RecipientDao : BaseDao<Recipient> {
@Query("SELECT * FROM Recipients WHERE student_id = :userLoginId AND unit_id = :unitId AND role = :role") @Query("SELECT * FROM Recipients WHERE student_id = :studentId AND unit_id = :unitId AND role = :role")
suspend fun loadAll(userLoginId: Int, unitId: Int, role: Int): List<Recipient> suspend fun loadAll(studentId: Int, unitId: Int, role: Int): List<Recipient>
} }

View File

@ -0,0 +1,15 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Dao
@Singleton
interface SchoolAnnouncementDao : BaseDao<SchoolAnnouncement> {
@Query("SELECT * FROM SchoolAnnouncements WHERE student_id = :studentId")
fun loadAll(studentId: Int): Flow<List<SchoolAnnouncement>>
}

View File

@ -8,7 +8,7 @@ import androidx.room.Query
import androidx.room.Transaction import androidx.room.Transaction
import androidx.room.Update import androidx.room.Update
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentNick import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
import io.github.wulkanowy.data.db.entities.StudentWithSemesters import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import javax.inject.Singleton import javax.inject.Singleton
@ -23,13 +23,13 @@ interface StudentDao {
suspend fun delete(student: Student) suspend fun delete(student: Student)
@Update(entity = Student::class) @Update(entity = Student::class)
suspend fun update(studentNick: StudentNick) suspend fun update(studentNickAndAvatar: StudentNickAndAvatar)
@Query("SELECT * FROM Students WHERE is_current = 1") @Query("SELECT * FROM Students WHERE is_current = 1")
suspend fun loadCurrent(): Student? suspend fun loadCurrent(): Student?
@Query("SELECT * FROM Students WHERE id = :id") @Query("SELECT * FROM Students WHERE id = :id")
suspend fun loadById(id: Int): Student? suspend fun loadById(id: Long): Student?
@Query("SELECT * FROM Students") @Query("SELECT * FROM Students")
suspend fun loadAll(): List<Student> suspend fun loadAll(): List<Student>

View File

@ -0,0 +1,16 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.TimetableHeader
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Dao
@Singleton
interface TimetableHeaderDao : BaseDao<TimetableHeader> {
@Query("SELECT * FROM TimetableHeaders WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<TimetableHeader>>
}

View File

@ -32,4 +32,7 @@ data class Conference(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var id: Long = 0 var id: Long = 0
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
} }

View File

@ -36,4 +36,7 @@ data class Exam(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var id: Long = 0 var id: Long = 0
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
} }

View File

@ -37,4 +37,7 @@ data class Homework(
@ColumnInfo(name = "is_done") @ColumnInfo(name = "is_done")
var isDone: Boolean = false var isDone: Boolean = false
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
} }

View File

@ -10,7 +10,7 @@ import java.time.LocalDateTime
data class Message( data class Message(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
val studentId: Int, val studentId: Long,
@ColumnInfo(name = "real_id") @ColumnInfo(name = "real_id")
val realId: Int, val realId: Int,

View File

@ -3,13 +3,15 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.squareup.moshi.JsonClass
import java.io.Serializable import java.io.Serializable
@JsonClass(generateAdapter = true)
@Entity(tableName = "Recipients") @Entity(tableName = "Recipients")
data class Recipient( data class Recipient(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
val userLoginId: Int, val studentId: Int,
@ColumnInfo(name = "real_id") @ColumnInfo(name = "real_id")
val realId: String, val realId: String,

View File

@ -0,0 +1,27 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "SchoolAnnouncements")
data class SchoolAnnouncement(
@ColumnInfo(name = "student_id")
val studentId: Int,
val date: LocalDate,
val subject: String,
val content: String
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
}

View File

@ -81,4 +81,7 @@ data class Student(
var id: Long = 0 var id: Long = 0
var nick = "" var nick = ""
@ColumnInfo(name = "avatar_color")
var avatarColor = 0L
} }

View File

@ -1,13 +1,17 @@
package io.github.wulkanowy.data.db.entities package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import java.io.Serializable import java.io.Serializable
@Entity @Entity
data class StudentNick( data class StudentNickAndAvatar(
val nick: String val nick: String,
@ColumnInfo(name = "avatar_color")
var avatarColor: Long
) : Serializable { ) : Serializable {

View File

@ -0,0 +1,25 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "TimetableHeaders")
data class TimetableHeader(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "diary_id")
val diaryId: Int,
val date: LocalDate,
val content: String,
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View File

@ -0,0 +1,24 @@
package io.github.wulkanowy.data.db.migrations
import androidx.core.database.getLongOrNull
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import io.github.wulkanowy.utils.AppInfo
class Migration35(private val appInfo: AppInfo) : Migration(34, 35) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN `avatar_color` INTEGER NOT NULL DEFAULT 0")
val studentsCursor = database.query("SELECT * FROM Students")
while (studentsCursor.moveToNext()) {
val studentId = studentsCursor.getLongOrNull(0)
database.execSQL(
"""UPDATE Students
SET avatar_color = ${appInfo.defaultColorsForAvatar.random()}
WHERE id = $studentId"""
)
}
}
}

View File

@ -0,0 +1,12 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration36 : Migration(35, 36) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Exams ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE Homework ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
}
}

View File

@ -0,0 +1,21 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration37 : Migration(36, 37) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"""
CREATE TABLE IF NOT EXISTS TimetableHeaders (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
diary_id INTEGER NOT NULL,
date INTEGER NOT NULL,
content TEXT NOT NULL
)
"""
)
}
}

View File

@ -0,0 +1,19 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration38 : Migration(37, 38) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS `SchoolAnnouncements` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`student_id` INTEGER NOT NULL,
`date` INTEGER NOT NULL,
`subject` TEXT NOT NULL,
`content` TEXT NOT NULL
)
""")
}
}

View File

@ -0,0 +1,12 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration39 : Migration(38, 39) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Conferences ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE SchoolAnnouncements ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
}
}

View File

@ -0,0 +1,14 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.pojo.DirectorInformation as SdkDirectorInformation
fun List<SdkDirectorInformation>.mapToEntities(student: Student) = map {
SchoolAnnouncement(
studentId = student.studentId,
date = it.date,
subject = it.subject,
content = it.content,
)
}

View File

@ -5,10 +5,9 @@ import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.pojos.GradeStatisticsItem import io.github.wulkanowy.data.pojos.GradeStatisticsItem
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject as SdkGradeStatisticsSubject
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSemester as SdkGradeStatisticsSemester
import io.github.wulkanowy.sdk.pojo.GradePointsStatistics as SdkGradePointsStatistics import io.github.wulkanowy.sdk.pojo.GradePointsStatistics as SdkGradePointsStatistics
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSemester as SdkGradeStatisticsSemester
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject as SdkGradeStatisticsSubject
@JvmName("mapToEntitiesSubject") @JvmName("mapToEntitiesSubject")
fun List<SdkGradeStatisticsSubject>.mapToEntities(semester: Semester) = map { fun List<SdkGradeStatisticsSubject>.mapToEntities(semester: Semester) = map {
@ -51,7 +50,7 @@ fun List<SdkGradePointsStatistics>.mapToEntities(semester: Semester) = map {
fun List<GradePartialStatistics>.mapPartialToStatisticItems() = filterNot { it.classAmounts.isEmpty() }.map { fun List<GradePartialStatistics>.mapPartialToStatisticItems() = filterNot { it.classAmounts.isEmpty() }.map {
GradeStatisticsItem( GradeStatisticsItem(
type = ViewType.PARTIAL, type = GradeStatisticsItem.DataType.PARTIAL,
average = it.classAverage, average = it.classAverage,
partial = it, partial = it,
points = null, points = null,
@ -61,7 +60,7 @@ fun List<GradePartialStatistics>.mapPartialToStatisticItems() = filterNot { it.c
fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it.amounts.isEmpty() }.map { fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it.amounts.isEmpty() }.map {
GradeStatisticsItem( GradeStatisticsItem(
type = ViewType.SEMESTER, type = GradeStatisticsItem.DataType.SEMESTER,
partial = null, partial = null,
points = null, points = null,
average = "", average = "",
@ -71,7 +70,7 @@ fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it
fun List<GradePointsStatistics>.mapPointsToStatisticsItems() = map { fun List<GradePointsStatistics>.mapPointsToStatisticsItems() = map {
GradeStatisticsItem( GradeStatisticsItem(
type = ViewType.POINTS, type = GradeStatisticsItem.DataType.POINTS,
partial = null, partial = null,
semester = null, semester = null,
average = "", average = "",

View File

@ -4,14 +4,14 @@ import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageAttachment import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
import java.time.LocalDateTime import java.time.LocalDateTime
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
fun List<SdkMessage>.mapToEntities(student: Student) = map { fun List<SdkMessage>.mapToEntities(student: Student) = map {
Message( Message(
studentId = student.id.toInt(), studentId = student.id,
realId = it.id ?: 0, realId = it.id ?: 0,
messageId = it.messageId ?: 0, messageId = it.messageId ?: 0,
sender = it.sender?.name.orEmpty(), sender = it.sender?.name.orEmpty(),

View File

@ -5,7 +5,7 @@ import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
fun List<SdkRecipient>.mapToEntities(userLoginId: Int) = map { fun List<SdkRecipient>.mapToEntities(userLoginId: Int) = map {
Recipient( Recipient(
userLoginId = userLoginId, studentId = userLoginId,
realId = it.id, realId = it.id,
realName = it.name, realName = it.name,
name = it.shortName, name = it.shortName,

View File

@ -6,7 +6,7 @@ import io.github.wulkanowy.sdk.pojo.ReportingUnit as SdkReportingUnit
fun List<SdkReportingUnit>.mapToEntities(student: Student) = map { fun List<SdkReportingUnit>.mapToEntities(student: Student) = map {
ReportingUnit( ReportingUnit(
studentId = student.studentId, studentId = student.id.toInt(),
unitId = it.id, unitId = it.id,
roles = it.roles, roles = it.roles,
senderId = it.senderId, senderId = it.senderId,

View File

@ -5,7 +5,7 @@ import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import java.time.LocalDateTime import java.time.LocalDateTime
import io.github.wulkanowy.sdk.pojo.Student as SdkStudent import io.github.wulkanowy.sdk.pojo.Student as SdkStudent
fun List<SdkStudent>.mapToEntities(password: String = "") = map { fun List<SdkStudent>.mapToEntities(password: String = "", colors: List<Long>) = map {
StudentWithSemesters( StudentWithSemesters(
student = Student( student = Student(
email = it.email, email = it.email,
@ -28,8 +28,10 @@ fun List<SdkStudent>.mapToEntities(password: String = "") = map {
mobileBaseUrl = it.mobileBaseUrl, mobileBaseUrl = it.mobileBaseUrl,
privateKey = it.privateKey, privateKey = it.privateKey,
certificateKey = it.certificateKey, certificateKey = it.certificateKey,
loginMode = it.loginMode.name loginMode = it.loginMode.name,
), ).apply {
avatarColor = colors.random()
},
semesters = it.semesters.mapToEntities(it.studentId) semesters = it.semesters.mapToEntities(it.studentId)
) )
} }

View File

@ -3,9 +3,19 @@ package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.entities.TimetableAdditional import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.data.db.entities.TimetableHeader
import io.github.wulkanowy.data.pojos.TimetableFull
import io.github.wulkanowy.sdk.pojo.TimetableFull as SdkTimetableFull
import io.github.wulkanowy.sdk.pojo.TimetableDayHeader as SdkTimetableHeader
import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetable import io.github.wulkanowy.sdk.pojo.Timetable as SdkTimetable
import io.github.wulkanowy.sdk.pojo.TimetableAdditional as SdkTimetableAdditional import io.github.wulkanowy.sdk.pojo.TimetableAdditional as SdkTimetableAdditional
fun SdkTimetableFull.mapToEntities(semester: Semester) = TimetableFull(
lessons = lessons.mapToEntities(semester),
additional = additional.mapToEntities(semester),
headers = headers.mapToEntities(semester)
)
fun List<SdkTimetable>.mapToEntities(semester: Semester) = map { fun List<SdkTimetable>.mapToEntities(semester: Semester) = map {
Timetable( Timetable(
studentId = semester.studentId, studentId = semester.studentId,
@ -39,3 +49,13 @@ fun List<SdkTimetableAdditional>.mapToEntities(semester: Semester) = map {
end = it.end end = it.end
) )
} }
@JvmName("mapToEntitiesTimetableHeaders")
fun List<SdkTimetableHeader>.mapToEntities(semester: Semester) = map {
TimetableHeader(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
content = it.content
)
}

View File

@ -3,11 +3,10 @@ package io.github.wulkanowy.data.pojos
import io.github.wulkanowy.data.db.entities.GradePartialStatistics import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
data class GradeStatisticsItem( data class GradeStatisticsItem(
val type: ViewType, val type: DataType,
val average: String, val average: String,
@ -16,4 +15,11 @@ data class GradeStatisticsItem(
val semester: GradeSemesterStatistics?, val semester: GradeSemesterStatistics?,
val points: GradePointsStatistics? val points: GradePointsStatistics?
)
) {
enum class DataType {
SEMESTER,
PARTIAL,
POINTS,
}
}

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.data.pojos
import com.squareup.moshi.JsonClass
import io.github.wulkanowy.ui.modules.message.send.RecipientChipItem
@JsonClass(generateAdapter = true)
data class MessageDraft(
val recipients: List<RecipientChipItem>,
val subject: String,
val content: String,
)

View File

@ -0,0 +1,36 @@
package io.github.wulkanowy.data.pojos
import androidx.annotation.DrawableRes
import androidx.annotation.PluralsRes
import androidx.annotation.StringRes
import io.github.wulkanowy.services.sync.notifications.NotificationType
import io.github.wulkanowy.ui.modules.main.MainView
sealed interface Notification {
val type: NotificationType
val startMenu: MainView.Section
val icon: Int
val titleStringRes: Int
val contentStringRes: Int
}
data class MultipleNotifications(
override val type: NotificationType,
override val startMenu: MainView.Section,
@DrawableRes override val icon: Int,
@PluralsRes override val titleStringRes: Int,
@PluralsRes override val contentStringRes: Int,
@PluralsRes val summaryStringRes: Int,
val lines: List<String>,
) : Notification
data class OneNotification(
override val type: NotificationType,
override val startMenu: MainView.Section,
@DrawableRes override val icon: Int,
@StringRes override val titleStringRes: Int,
@StringRes override val contentStringRes: Int,
val contentValues: List<String>,
) : Notification

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.data.pojos
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.data.db.entities.TimetableHeader
data class TimetableFull(
val lessons: List<Timetable>,
val additional: List<TimetableAdditional>,
val headers: List<TimetableHeader>,
)

View File

@ -15,6 +15,7 @@ class AppCreatorRepository @Inject constructor(
private val dispatchers: DispatchersProvider private val dispatchers: DispatchersProvider
) { ) {
@Suppress("BlockingMethodInNonBlockingContext")
suspend fun getAppCreators() = withContext(dispatchers.backgroundThread) { suspend fun getAppCreators() = withContext(dispatchers.backgroundThread) {
val moshi = Moshi.Builder().build() val moshi = Moshi.Builder().build()
val type = Types.newParameterizedType(List::class.java, Contributor::class.java) val type = Types.newParameterizedType(List::class.java, Contributor::class.java)

View File

@ -14,6 +14,7 @@ import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.LocalTime import java.time.LocalTime
@ -27,9 +28,12 @@ class AttendanceRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "attendance" private val cacheKey = "attendance"
fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource( fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday) }, query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday) },
fetch = { fetch = {

View File

@ -10,6 +10,7 @@ import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -20,10 +21,21 @@ class AttendanceSummaryRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "attendance_summary" private val cacheKey = "attendance_summary"
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource( fun getAttendanceSummary(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) }, student: Student,
semester: Semester,
subjectId: Int,
forceRefresh: Boolean
) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = {
it.isEmpty() || forceRefresh
|| refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
},
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) }, query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)

View File

@ -12,6 +12,7 @@ import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate import java.time.LocalDate
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -23,9 +24,12 @@ class CompletedLessonsRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "completed" private val cacheKey = "completed"
fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource( fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { completedLessonsDb.loadAll(semester.studentId, semester.diaryId, start.monday, end.sunday) }, query = { completedLessonsDb.loadAll(semester.studentId, semester.diaryId, start.monday, end.sunday) },
fetch = { fetch = {

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.ConferenceDao import io.github.wulkanowy.data.db.dao.ConferenceDao
import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
@ -10,6 +11,11 @@ import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneOffset
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -20,20 +26,48 @@ class ConferenceRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "conference" private val cacheKey = "conference"
fun getConferences(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource( fun getConferences(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) }, student: Student,
query = { conferenceDb.loadAll(semester.diaryId, student.studentId) }, semester: Semester,
forceRefresh: Boolean,
notify: Boolean = false,
startDate: LocalDateTime = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC)
) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = {
it.isEmpty() || forceRefresh
|| refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
},
query = {
conferenceDb.loadAll(semester.diaryId, student.studentId, startDate)
},
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getConferences() .getConferences()
.mapToEntities(semester) .mapToEntities(semester)
.filter { it.date >= startDate }
}, },
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
val conferencesToSave = (new uniqueSubtract old).onEach {
if (notify) it.isNotified = false
}
conferenceDb.deleteAll(old uniqueSubtract new) conferenceDb.deleteAll(old uniqueSubtract new)
conferenceDb.insertAll(new uniqueSubtract old) conferenceDb.insertAll(conferencesToSave)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester)) refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester))
} }
) )
fun getConferenceFromDatabase(semester: Semester): Flow<List<Conference>> =
conferenceDb.loadAll(
diaryId = semester.diaryId,
studentId = semester.studentId,
startDate = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC)
)
suspend fun updateConference(conference: List<Conference>) = conferenceDb.updateAll(conference)
} }

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.ExamDao import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
@ -12,6 +13,8 @@ import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.startExamsDay import io.github.wulkanowy.utils.startExamsDay
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate import java.time.LocalDate
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -23,21 +26,58 @@ class ExamRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "exam" private val cacheKey = "exam"
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource( fun getExams(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) }, student: Student,
query = { examDb.loadAll(semester.diaryId, semester.studentId, start.startExamsDay, start.endExamsDay) }, semester: Semester,
start: LocalDate,
end: LocalDate,
forceRefresh: Boolean,
notify: Boolean = false
) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = {
val isShouldBeRefreshed = refreshHelper.isShouldBeRefreshed(
key = getRefreshKey(cacheKey, semester, start, end)
)
it.isEmpty() || forceRefresh || isShouldBeRefreshed
},
query = {
examDb.loadAll(
diaryId = semester.diaryId,
studentId = semester.studentId,
from = start.startExamsDay,
end = start.endExamsDay
)
},
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getExams(start.startExamsDay, start.endExamsDay, semester.semesterId) .getExams(start.startExamsDay, start.endExamsDay, semester.semesterId)
.mapToEntities(semester) .mapToEntities(semester)
}, },
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
val examsToSave = (new uniqueSubtract old).onEach {
if (notify) it.isNotified = false
}
examDb.deleteAll(old uniqueSubtract new) examDb.deleteAll(old uniqueSubtract new)
examDb.insertAll(new uniqueSubtract old) examDb.insertAll(examsToSave)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end)) refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
}, },
filterResult = { it.filter { item -> item.date in start..end } } filterResult = { it.filter { item -> item.date in start..end } }
) )
fun getExamsFromDatabase(semester: Semester, start: LocalDate): Flow<List<Exam>> {
return examDb.loadAll(
diaryId = semester.diaryId,
studentId = semester.studentId,
from = start.startExamsDay,
end = start.endExamsDay
)
}
suspend fun updateExam(exam: List<Exam>) = examDb.updateAll(exam)
} }

View File

@ -16,6 +16,7 @@ import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDateTime import java.time.LocalDateTime
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -28,14 +29,26 @@ class GradeRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "grade" private val cacheKey = "grade"
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource( fun getGrades(
shouldFetch = { (details, summaries) -> details.isEmpty() || summaries.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) }, student: Student,
semester: Semester,
forceRefresh: Boolean,
notify: Boolean = false
) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { (details, summaries) ->
val isShouldBeRefreshed =
refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester))
details.isEmpty() || summaries.isEmpty() || forceRefresh || isShouldBeRefreshed
},
query = { query = {
gradeDb.loadAll(semester.semesterId, semester.studentId).combine(gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)) { details, summaries -> val detailsFlow = gradeDb.loadAll(semester.semesterId, semester.studentId)
details to summaries val summaryFlow = gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
} detailsFlow.combine(summaryFlow) { details, summaries -> details to summaries }
}, },
fetch = { fetch = {
val (details, summary) = sdk.init(student) val (details, summary) = sdk.init(student)
@ -52,8 +65,14 @@ class GradeRepository @Inject constructor(
} }
) )
private suspend fun refreshGradeDetails(student: Student, oldGrades: List<Grade>, newDetails: List<Grade>, notify: Boolean) { private suspend fun refreshGradeDetails(
val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date ?: student.registrationDate.toLocalDate() student: Student,
oldGrades: List<Grade>,
newDetails: List<Grade>,
notify: Boolean
) {
val notifyBreakDate =
oldGrades.maxByOrNull { it.date }?.date ?: student.registrationDate.toLocalDate()
gradeDb.deleteAll(oldGrades uniqueSubtract newDetails) gradeDb.deleteAll(oldGrades uniqueSubtract newDetails)
gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach { gradeDb.insertAll((newDetails uniqueSubtract oldGrades).onEach {
if (it.date >= notifyBreakDate) it.apply { if (it.date >= notifyBreakDate) it.apply {
@ -63,10 +82,15 @@ class GradeRepository @Inject constructor(
}) })
} }
private suspend fun refreshGradeSummaries(oldSummaries: List<GradeSummary>, newSummary: List<GradeSummary>, notify: Boolean) { private suspend fun refreshGradeSummaries(
oldSummaries: List<GradeSummary>,
newSummary: List<GradeSummary>,
notify: Boolean
) {
gradeSummaryDb.deleteAll(oldSummaries uniqueSubtract newSummary) gradeSummaryDb.deleteAll(oldSummaries uniqueSubtract newSummary)
gradeSummaryDb.insertAll((newSummary uniqueSubtract oldSummaries).onEach { summary -> gradeSummaryDb.insertAll((newSummary uniqueSubtract oldSummaries).onEach { summary ->
val oldSummary = oldSummaries.find { oldSummary -> oldSummary.subject == summary.subject } val oldSummary =
oldSummaries.find { oldSummary -> oldSummary.subject == summary.subject }
summary.isPredictedGradeNotified = when { summary.isPredictedGradeNotified = when {
summary.predictedGrade.isEmpty() -> true summary.predictedGrade.isEmpty() -> true
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
@ -92,19 +116,21 @@ class GradeRepository @Inject constructor(
} }
fun getUnreadGrades(semester: Semester): Flow<List<Grade>> { fun getUnreadGrades(semester: Semester): Flow<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId).map { it.filter { grade -> !grade.isRead } } return gradeDb.loadAll(semester.semesterId, semester.studentId).map {
it.filter { grade -> !grade.isRead }
}
} }
fun getNotNotifiedGrades(semester: Semester): Flow<List<Grade>> { fun getGradesFromDatabase(semester: Semester): Flow<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId).map { it.filter { grade -> !grade.isNotified } } return gradeDb.loadAll(semester.semesterId, semester.studentId)
} }
fun getNotNotifiedPredictedGrades(semester: Semester): Flow<List<GradeSummary>> { fun getGradesPredictedFromDatabase(semester: Semester): Flow<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map { it.filter { gradeSummary -> !gradeSummary.isPredictedGradeNotified } } return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
} }
fun getNotNotifiedFinalGrades(semester: Semester): Flow<List<GradeSummary>> { fun getGradesFinalFromDatabase(semester: Semester): Flow<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map { it.filter { gradeSummary -> !gradeSummary.isFinalGradeNotified } } return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
} }
suspend fun updateGrade(grade: Grade) { suspend fun updateGrade(grade: Grade) {

View File

@ -17,6 +17,7 @@ import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -30,11 +31,16 @@ class GradeStatisticsRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
private val partialMutex = Mutex()
private val semesterMutex = Mutex()
private val pointsMutex = Mutex()
private val partialCacheKey = "grade_stats_partial" private val partialCacheKey = "grade_stats_partial"
private val semesterCacheKey = "grade_stats_semester" private val semesterCacheKey = "grade_stats_semester"
private val pointsCacheKey = "grade_stats_points" private val pointsCacheKey = "grade_stats_points"
fun getGradesPartialStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource( fun getGradesPartialStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
mutex = partialMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(partialCacheKey, semester)) }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(partialCacheKey, semester)) },
query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) }, query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = { fetch = {
@ -71,6 +77,7 @@ class GradeStatisticsRepository @Inject constructor(
) )
fun getGradesSemesterStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource( fun getGradesSemesterStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
mutex = semesterMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(semesterCacheKey, semester)) }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(semesterCacheKey, semester)) },
query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) }, query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = { fetch = {
@ -112,6 +119,7 @@ class GradeStatisticsRepository @Inject constructor(
) )
fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource( fun getGradesPointsStatistics(student: Student, semester: Semester, subjectName: String, forceRefresh: Boolean) = networkBoundResource(
mutex = pointsMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(pointsCacheKey, semester)) }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(pointsCacheKey, semester)) },
query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) }, query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = { fetch = {

View File

@ -13,6 +13,7 @@ import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate import java.time.LocalDate
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -24,19 +25,42 @@ class HomeworkRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "homework" private val cacheKey = "homework"
fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource( fun getHomework(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) }, student: Student, semester: Semester,
query = { homeworkDb.loadAll(semester.semesterId, semester.studentId, start.monday, end.sunday) }, start: LocalDate, end: LocalDate,
forceRefresh: Boolean, notify: Boolean = false
) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = {
val isShouldBeRefreshed = refreshHelper.isShouldBeRefreshed(
key = getRefreshKey(cacheKey, semester, start, end)
)
it.isEmpty() || forceRefresh || isShouldBeRefreshed
},
query = {
homeworkDb.loadAll(
semesterId = semester.semesterId,
studentId = semester.studentId,
from = start.monday,
end = end.sunday
)
},
fetch = { fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear) sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getHomework(start.monday, end.sunday) .getHomework(start.monday, end.sunday)
.mapToEntities(semester) .mapToEntities(semester)
}, },
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
val homeWorkToSave = (new uniqueSubtract old).onEach {
if (notify) it.isNotified = false
}
homeworkDb.deleteAll(old uniqueSubtract new) homeworkDb.deleteAll(old uniqueSubtract new)
homeworkDb.insertAll(new uniqueSubtract old) homeworkDb.insertAll(homeWorkToSave)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end)) refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
} }
@ -47,4 +71,9 @@ class HomeworkRepository @Inject constructor(
isDone = !isDone isDone = !isDone
})) }))
} }
fun getHomeworkFromDatabase(semester: Semester, start: LocalDate, end: LocalDate) =
homeworkDb.loadAll(semester.semesterId, semester.studentId, start.monday, end.sunday)
suspend fun updateHomework(homework: List<Homework>) = homeworkDb.updateAll(homework)
} }

View File

@ -9,6 +9,8 @@ import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate
import java.time.LocalDate.now import java.time.LocalDate.now
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -19,7 +21,10 @@ class LuckyNumberRepository @Inject constructor(
private val sdk: Sdk private val sdk: Sdk
) { ) {
private val saveFetchResultMutex = Mutex()
fun getLuckyNumber(student: Student, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource( fun getLuckyNumber(student: Student, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it == null || forceRefresh }, shouldFetch = { it == null || forceRefresh },
query = { luckyNumberDb.load(student.studentId, now()) }, query = { luckyNumberDb.load(student.studentId, now()) },
fetch = { sdk.init(student).getLuckyNumber(student.schoolShortName)?.mapToEntity(student) }, fetch = { sdk.init(student).getLuckyNumber(student.schoolShortName)?.mapToEntity(student) },
@ -33,6 +38,9 @@ class LuckyNumberRepository @Inject constructor(
} }
) )
fun getLuckyNumberHistory(student: Student, start: LocalDate, end: LocalDate) =
luckyNumberDb.getAll(student.studentId, start, end)
suspend fun getNotNotifiedLuckyNumber(student: Student) = luckyNumberDb.load(student.studentId, now()).map { suspend fun getNotNotifiedLuckyNumber(student: Student) = luckyNumberDb.load(student.studentId, now()).map {
if (it?.isNotified == false) it else null if (it?.isNotified == false) it else null
}.first() }.first()

View File

@ -1,8 +1,15 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories
import android.content.Context
import com.squareup.moshi.Moshi
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R
import io.github.wulkanowy.data.Resource
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
import io.github.wulkanowy.data.db.dao.MessagesDao import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.entities.Message import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
import io.github.wulkanowy.data.db.entities.Recipient import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
@ -10,6 +17,8 @@ import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
import io.github.wulkanowy.data.mappers.mapFromEntities import io.github.wulkanowy.data.mappers.mapFromEntities
import io.github.wulkanowy.data.mappers.mapToEntities import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.pojos.MessageDraft
import io.github.wulkanowy.data.pojos.MessageDraftJsonAdapter
import io.github.wulkanowy.sdk.Sdk import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder import io.github.wulkanowy.sdk.pojo.Folder
import io.github.wulkanowy.sdk.pojo.SentMessage import io.github.wulkanowy.sdk.pojo.SentMessage
@ -19,7 +28,7 @@ import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.sync.Mutex
import timber.log.Timber import timber.log.Timber
import java.time.LocalDateTime.now import java.time.LocalDateTime.now
import javax.inject.Inject import javax.inject.Inject
@ -30,27 +39,65 @@ class MessageRepository @Inject constructor(
private val messagesDb: MessagesDao, private val messagesDb: MessagesDao,
private val messageAttachmentDao: MessageAttachmentDao, private val messageAttachmentDao: MessageAttachmentDao,
private val sdk: Sdk, private val sdk: Sdk,
@ApplicationContext private val context: Context,
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
private val sharedPrefProvider: SharedPrefProvider,
private val moshi: Moshi,
) { ) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "message" private val cacheKey = "message"
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource( fun getMessages(
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student, folder)) }, student: Student, semester: Semester,
folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false
): Flow<Resource<List<Message>>> = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = {
it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(
getRefreshKey(cacheKey, student, folder)
)
},
query = { messagesDb.loadAll(student.id.toInt(), folder.id) }, query = { messagesDb.loadAll(student.id.toInt(), folder.id) },
fetch = { sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now()).mapToEntities(student) }, fetch = {
sdk.init(student).getMessages(Folder.valueOf(folder.name), now().minusMonths(3), now())
.mapToEntities(student)
},
saveFetchResult = { old, new -> saveFetchResult = { old, new ->
messagesDb.deleteAll(old uniqueSubtract new) messagesDb.deleteAll(old uniqueSubtract new)
messagesDb.insertAll((new uniqueSubtract old).onEach { messagesDb.insertAll((new uniqueSubtract old).onEach {
it.isNotified = !notify it.isNotified = !notify
}) })
messagesDb.updateAll(getMessagesWithReadByChange(old, new, !notify))
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder)) refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder))
} }
) )
fun getMessage(student: Student, message: Message, markAsRead: Boolean = false) = networkBoundResource( private fun getMessagesWithReadByChange(
old: List<Message>, new: List<Message>,
setNotified: Boolean
): List<Message> {
val oldMeta = old.map { Triple(it, it.readBy, it.unreadBy) }
val newMeta = new.map { Triple(it, it.readBy, it.unreadBy) }
val updatedItems = newMeta uniqueSubtract oldMeta
return updatedItems.map {
val oldItem = old.find { item -> item.messageId == it.first.messageId }
it.first.apply {
id = oldItem?.id ?: 0
isNotified = oldItem?.isNotified ?: setNotified
content = oldItem?.content.orEmpty()
}
}
}
fun getMessage(
student: Student, message: Message, markAsRead: Boolean = false
): Flow<Resource<MessageWithAttachment?>> = networkBoundResource(
shouldFetch = { shouldFetch = {
checkNotNull(it, { "This message no longer exist!" }) checkNotNull(it, { "This message no longer exist!" })
Timber.d("Message content in db empty: ${it.message.content.isEmpty()}") Timber.d("Message content in db empty: ${it.message.content.isEmpty()}")
@ -58,14 +105,20 @@ class MessageRepository @Inject constructor(
}, },
query = { messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId) }, query = { messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId) },
fetch = { fetch = {
sdk.init(student).getMessageDetails(it!!.message.messageId, message.folderId, markAsRead, message.realId).let { details -> sdk.init(student).getMessageDetails(
messageId = it!!.message.messageId,
folderId = message.folderId,
read = markAsRead,
id = message.realId
).let { details ->
details.content to details.attachments.mapToEntities() details.content to details.attachments.mapToEntities()
} }
}, },
saveFetchResult = { old, (downloadedMessage, attachments) -> saveFetchResult = { old, (downloadedMessage, attachments) ->
checkNotNull(old, { "Fetched message no longer exist!" }) checkNotNull(old, { "Fetched message no longer exist!" })
messagesDb.updateAll(listOf(old.message.copy(unread = !markAsRead).apply { messagesDb.updateAll(listOf(old.message.apply {
id = old.message.id id = old.message.id
unread = !markAsRead
content = content.ifBlank { downloadedMessage } content = content.ifBlank { downloadedMessage }
})) }))
messageAttachmentDao.insertAttachments(attachments) messageAttachmentDao.insertAttachments(attachments)
@ -73,30 +126,42 @@ class MessageRepository @Inject constructor(
} }
) )
fun getNotNotifiedMessages(student: Student): Flow<List<Message>> { fun getMessagesFromDatabase(student: Student): Flow<List<Message>> {
return messagesDb.loadAll(student.id.toInt(), RECEIVED.id).map { it.filter { message -> !message.isNotified && message.unread } } return messagesDb.loadAll(student.id.toInt(), RECEIVED.id)
} }
suspend fun updateMessages(messages: List<Message>) { suspend fun updateMessages(messages: List<Message>) {
return messagesDb.updateAll(messages) return messagesDb.updateAll(messages)
} }
suspend fun sendMessage(student: Student, subject: String, content: String, recipients: List<Recipient>): SentMessage { suspend fun sendMessage(
return sdk.init(student).sendMessage( student: Student, subject: String, content: String,
recipients: List<Recipient>
): SentMessage = sdk.init(student).sendMessage(
subject = subject, subject = subject,
content = content, content = content,
recipients = recipients.mapFromEntities() recipients = recipients.mapFromEntities()
) )
}
suspend fun deleteMessage(student: Student, message: Message) { suspend fun deleteMessage(student: Student, message: Message) {
val isDeleted = sdk.init(student).deleteMessages(listOf(message.messageId), message.folderId) val isDeleted = sdk.init(student).deleteMessages(
messages = listOf(message.messageId), message.folderId
)
if (message.folderId != MessageFolder.TRASHED.id) { if (message.folderId != MessageFolder.TRASHED.id && isDeleted) {
if (isDeleted) messagesDb.updateAll(listOf(message.copy(folderId = MessageFolder.TRASHED.id).apply { val deletedMessage = message.copy(folderId = MessageFolder.TRASHED.id).apply {
id = message.id id = message.id
content = message.content content = message.content
})) }
messagesDb.updateAll(listOf(deletedMessage))
} else messagesDb.deleteAll(listOf(message)) } else messagesDb.deleteAll(listOf(message))
} }
var draftMessage: MessageDraft?
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_send_draft))
?.let { MessageDraftJsonAdapter(moshi).fromJson(it) }
set(value) = sharedPrefProvider.putString(
context.getString(R.string.pref_key_message_send_draft),
value?.let { MessageDraftJsonAdapter(moshi).toJson(it) }
)
} }

View File

@ -13,6 +13,7 @@ import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -23,9 +24,12 @@ class MobileDeviceRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "devices" private val cacheKey = "devices"
fun getDevices(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource( fun getDevices(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student)) }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, student)) },
query = { mobileDb.loadAll(student.userLoginId.takeIf { it != 0 } ?: student.studentId) }, query = { mobileDb.loadAll(student.userLoginId.takeIf { it != 0 } ?: student.studentId) },
fetch = { fetch = {

View File

@ -13,6 +13,7 @@ import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -23,9 +24,12 @@ class NoteRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper, private val refreshHelper: AutoRefreshHelper,
) { ) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "note" private val cacheKey = "note"
fun getNotes(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource( fun getNotes(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) }, shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
query = { noteDb.loadAll(student.studentId) }, query = { noteDb.loadAll(student.studentId) },
fetch = { fetch = {
@ -46,8 +50,8 @@ class NoteRepository @Inject constructor(
} }
) )
fun getNotNotifiedNotes(student: Student): Flow<List<Note>> { fun getNotesFromDatabase(student: Student): Flow<List<Note>> {
return noteDb.loadAll(student.studentId).map { it.filter { note -> !note.isNotified } } return noteDb.loadAll(student.studentId)
} }
suspend fun updateNote(note: Note) { suspend fun updateNote(note: Note) {

View File

@ -2,42 +2,83 @@ package io.github.wulkanowy.data.repositories
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
import com.fredporciuncula.flow.preferences.Preference
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R import io.github.wulkanowy.R
import io.github.wulkanowy.sdk.toLocalDate
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
import io.github.wulkanowy.ui.modules.grade.GradeSortingMode import io.github.wulkanowy.ui.modules.grade.GradeSortingMode
import io.github.wulkanowy.utils.toTimestamp
import io.github.wulkanowy.utils.toLocalDateTime
import io.github.wulkanowy.utils.toTimestamp
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import java.time.LocalDate
import java.time.LocalDateTime
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@OptIn(ExperimentalCoroutinesApi::class)
@Singleton @Singleton
class PreferencesRepository @Inject constructor( class PreferencesRepository @Inject constructor(
private val sharedPref: SharedPreferences, private val sharedPref: SharedPreferences,
@ApplicationContext val context: Context private val flowSharedPref: FlowSharedPreferences,
@ApplicationContext val context: Context,
moshi: Moshi
) { ) {
@OptIn(ExperimentalStdlibApi::class)
private val dashboardItemsPositionAdapter: JsonAdapter<Map<DashboardItem.Type, Int>> =
moshi.adapter()
val startMenuIndex: Int val startMenuIndex: Int
get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt() get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt()
val isShowPresent: Boolean val isShowPresent: Boolean
get() = getBoolean(R.string.pref_key_attendance_present, R.bool.pref_default_attendance_present) get() = getBoolean(
R.string.pref_key_attendance_present,
R.bool.pref_default_attendance_present
)
val gradeAverageMode: GradeAverageMode val gradeAverageMode: GradeAverageMode
get() = GradeAverageMode.getByValue(getString(R.string.pref_key_grade_average_mode, R.string.pref_default_grade_average_mode)) get() = GradeAverageMode.getByValue(
getString(
R.string.pref_key_grade_average_mode,
R.string.pref_default_grade_average_mode
)
)
val gradeAverageForceCalc: Boolean val gradeAverageForceCalc: Boolean
get() = getBoolean(R.string.pref_key_grade_average_force_calc, R.bool.pref_default_grade_average_force_calc) get() = getBoolean(
R.string.pref_key_grade_average_force_calc,
R.bool.pref_default_grade_average_force_calc
)
val isGradeExpandable: Boolean val isGradeExpandable: Boolean
get() = !getBoolean(R.string.pref_key_expand_grade, R.bool.pref_default_expand_grade) get() = !getBoolean(R.string.pref_key_expand_grade, R.bool.pref_default_expand_grade)
val showAllSubjectsOnStatisticsList: Boolean val showAllSubjectsOnStatisticsList: Boolean
get() = getBoolean(R.string.pref_key_grade_statistics_list, R.bool.pref_default_grade_statistics_list) get() = getBoolean(
R.string.pref_key_grade_statistics_list,
R.bool.pref_default_grade_statistics_list
)
val appThemeKey = context.getString(R.string.pref_key_app_theme) val appThemeKey = context.getString(R.string.pref_key_app_theme)
val appTheme: String val appTheme: String
get() = getString(appThemeKey, R.string.pref_default_app_theme) get() = getString(appThemeKey, R.string.pref_default_app_theme)
val gradeColorTheme: String val gradeColorTheme: String
get() = getString(R.string.pref_key_grade_color_scheme, R.string.pref_default_grade_color_scheme) get() = getString(
R.string.pref_key_grade_color_scheme,
R.string.pref_default_grade_color_scheme
)
val appLanguageKey = context.getString(R.string.pref_key_app_language) val appLanguageKey = context.getString(R.string.pref_key_app_language)
val appLanguage val appLanguage
@ -55,50 +96,170 @@ class PreferencesRepository @Inject constructor(
val isServicesOnlyWifi: Boolean val isServicesOnlyWifi: Boolean
get() = getBoolean(servicesOnlyWifiKey, R.bool.pref_default_services_wifi_only) get() = getBoolean(servicesOnlyWifiKey, R.bool.pref_default_services_wifi_only)
val notificationsEnableKey = context.getString(R.string.pref_key_notifications_enable)
val isNotificationsEnable: Boolean val isNotificationsEnable: Boolean
get() = getBoolean(R.string.pref_key_notifications_enable, R.bool.pref_default_notifications_enable) get() = getBoolean(notificationsEnableKey, R.bool.pref_default_notifications_enable)
val isUpcomingLessonsNotificationsEnableKey = context.getString(R.string.pref_key_notifications_upcoming_lessons_enable) val isUpcomingLessonsNotificationsEnableKey =
context.getString(R.string.pref_key_notifications_upcoming_lessons_enable)
val isUpcomingLessonsNotificationsEnable: Boolean val isUpcomingLessonsNotificationsEnable: Boolean
get() = getBoolean(isUpcomingLessonsNotificationsEnableKey, R.bool.pref_default_notification_upcoming_lessons_enable) get() = getBoolean(
isUpcomingLessonsNotificationsEnableKey,
R.bool.pref_default_notification_upcoming_lessons_enable
)
val isDebugNotificationEnableKey = context.getString(R.string.pref_key_notification_debug) val isDebugNotificationEnableKey = context.getString(R.string.pref_key_notification_debug)
val isDebugNotificationEnable: Boolean val isDebugNotificationEnable: Boolean
get() = getBoolean(isDebugNotificationEnableKey, R.bool.pref_default_notification_debug) get() = getBoolean(isDebugNotificationEnableKey, R.bool.pref_default_notification_debug)
val gradePlusModifier: Double val gradePlusModifier: Double
get() = getString(R.string.pref_key_grade_modifier_plus, R.string.pref_default_grade_modifier_plus).toDouble() get() = getString(
R.string.pref_key_grade_modifier_plus,
R.string.pref_default_grade_modifier_plus
).toDouble()
val gradeMinusModifier: Double val gradeMinusModifier: Double
get() = getString(R.string.pref_key_grade_modifier_minus, R.string.pref_default_grade_modifier_minus).toDouble() get() = getString(
R.string.pref_key_grade_modifier_minus,
R.string.pref_default_grade_modifier_minus
).toDouble()
val fillMessageContent: Boolean val fillMessageContent: Boolean
get() = getBoolean(R.string.pref_key_fill_message_content, R.bool.pref_default_fill_message_content) get() = getBoolean(
R.string.pref_key_fill_message_content,
R.bool.pref_default_fill_message_content
)
val showGroupsInPlan: Boolean val showGroupsInPlan: Boolean
get() = getBoolean(R.string.pref_key_timetable_show_groups, R.bool.pref_default_timetable_show_groups) get() = getBoolean(
R.string.pref_key_timetable_show_groups,
R.bool.pref_default_timetable_show_groups
)
val showWholeClassPlan: String val showWholeClassPlan: String
get() = getString(R.string.pref_key_timetable_show_whole_class, R.string.pref_default_timetable_show_whole_class) get() = getString(
R.string.pref_key_timetable_show_whole_class,
R.string.pref_default_timetable_show_whole_class
)
val gradeSortingMode: GradeSortingMode val gradeSortingMode: GradeSortingMode
get() = GradeSortingMode.getByValue(getString(R.string.pref_key_grade_sorting_mode, R.string.pref_default_grade_sorting_mode)) get() = GradeSortingMode.getByValue(
getString(
R.string.pref_key_grade_sorting_mode,
R.string.pref_default_grade_sorting_mode
)
)
val showTimetableTimers: Boolean val showTimetableTimers: Boolean
get() = getBoolean(R.string.pref_key_timetable_show_timers, R.bool.pref_default_timetable_show_timers) get() = getBoolean(
R.string.pref_key_timetable_show_timers,
R.bool.pref_default_timetable_show_timers
)
var isHomeworkFullscreen: Boolean var isHomeworkFullscreen: Boolean
get() = getBoolean(R.string.pref_key_homework_fullscreen, R.bool.pref_default_homework_fullscreen) get() = getBoolean(
R.string.pref_key_homework_fullscreen,
R.bool.pref_default_homework_fullscreen
)
set(value) = sharedPref.edit().putBoolean("homework_fullscreen", value).apply() set(value) = sharedPref.edit().putBoolean("homework_fullscreen", value).apply()
val showSubjectsWithoutGrades: Boolean val showSubjectsWithoutGrades: Boolean
get() = getBoolean(R.string.pref_key_subjects_without_grades, R.bool.pref_default_subjects_without_grades) get() = getBoolean(
R.string.pref_key_subjects_without_grades,
R.bool.pref_default_subjects_without_grades
)
val isOptionalArithmeticAverage: Boolean
get() = getBoolean(
R.string.pref_key_optional_arithmetic_average,
R.bool.pref_default_optional_arithmetic_average
)
var lasSyncDate: LocalDateTime
get() = getLong(
R.string.pref_key_last_sync_date,
R.string.pref_default_last_sync_date
).toLocalDateTime()
set(value) = sharedPref.edit().putLong("last_sync_date", value.toTimestamp()).apply()
var dashboardItemsPosition: Map<DashboardItem.Type, Int>?
get() {
val json = sharedPref.getString(PREF_KEY_DASHBOARD_ITEMS_POSITION, null) ?: return null
return dashboardItemsPositionAdapter.fromJson(json)
}
set(value) = sharedPref.edit {
putString(
PREF_KEY_DASHBOARD_ITEMS_POSITION,
dashboardItemsPositionAdapter.toJson(value)
)
}
val selectedDashboardTilesFlow: Flow<Set<DashboardItem.Tile>>
get() = selectedDashboardTilesPreference.asFlow()
.map { set ->
set.map { DashboardItem.Tile.valueOf(it) }
.plus(DashboardItem.Tile.ACCOUNT)
.toSet()
}
var selectedDashboardTiles: Set<DashboardItem.Tile>
get() = selectedDashboardTilesPreference.get()
.map { DashboardItem.Tile.valueOf(it) }
.plus(DashboardItem.Tile.ACCOUNT)
.toSet()
set(value) {
val filteredValue = value.filterNot { it == DashboardItem.Tile.ACCOUNT }
.map { it.name }
.toSet()
selectedDashboardTilesPreference.set(filteredValue)
}
private val selectedDashboardTilesPreference: Preference<Set<String>>
get() {
val defaultSet =
context.resources.getStringArray(R.array.pref_default_dashboard_tiles).toSet()
val prefKey = context.getString(R.string.pref_key_dashboard_tiles)
return flowSharedPref.getStringSet(prefKey, defaultSet)
}
var inAppReviewCount: Int
get() = sharedPref.getInt(PREF_KEY_IN_APP_REVIEW_COUNT, 0)
set(value) = sharedPref.edit().putInt(PREF_KEY_IN_APP_REVIEW_COUNT, value).apply()
var inAppReviewDate: LocalDate?
get() = sharedPref.getLong(PREF_KEY_IN_APP_REVIEW_DATE, 0).takeIf { it != 0L }?.toLocalDate()
set(value) = sharedPref.edit().putLong(PREF_KEY_IN_APP_REVIEW_DATE, value!!.toTimestamp()).apply()
var isAppReviewDone: Boolean
get() = sharedPref.getBoolean(PREF_KEY_IN_APP_REVIEW_DONE, false)
set(value) = sharedPref.edit().putBoolean(PREF_KEY_IN_APP_REVIEW_DONE, value).apply()
private fun getLong(id: Int, default: Int) = getLong(context.getString(id), default)
private fun getLong(id: String, default: Int) =
sharedPref.getLong(id, context.resources.getString(default).toLong())
private fun getString(id: Int, default: Int) = getString(context.getString(id), default) private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
private fun getString(id: String, default: Int) = sharedPref.getString(id, context.getString(default)) ?: context.getString(default) private fun getString(id: String, default: Int) =
sharedPref.getString(id, context.getString(default)) ?: context.getString(default)
private fun getBoolean(id: Int, default: Int) = getBoolean(context.getString(id), default) private fun getBoolean(id: Int, default: Int) = getBoolean(context.getString(id), default)
private fun getBoolean(id: String, default: Int) = sharedPref.getBoolean(id, context.resources.getBoolean(default)) private fun getBoolean(id: String, default: Int) =
sharedPref.getBoolean(id, context.resources.getBoolean(default))
private companion object {
private const val PREF_KEY_DASHBOARD_ITEMS_POSITION = "dashboard_items_position"
private const val PREF_KEY_IN_APP_REVIEW_COUNT = "in_app_review_count"
private const val PREF_KEY_IN_APP_REVIEW_DATE = "in_app_review_date"
private const val PREF_KEY_IN_APP_REVIEW_DONE = "in_app_review_done"
}
} }

View File

@ -19,22 +19,22 @@ class RecipientRepository @Inject constructor(
) { ) {
suspend fun refreshRecipients(student: Student, unit: ReportingUnit, role: Int) { suspend fun refreshRecipients(student: Student, unit: ReportingUnit, role: Int) {
val new = sdk.init(student).getRecipients(unit.unitId, role).mapToEntities(unit.senderId) val new = sdk.init(student).getRecipients(unit.unitId, role).mapToEntities(unit.studentId)
val old = recipientDb.loadAll(unit.senderId, unit.unitId, role) val old = recipientDb.loadAll(unit.studentId, unit.unitId, role)
recipientDb.deleteAll(old uniqueSubtract new) recipientDb.deleteAll(old uniqueSubtract new)
recipientDb.insertAll(new uniqueSubtract old) recipientDb.insertAll(new uniqueSubtract old)
} }
suspend fun getRecipients(student: Student, unit: ReportingUnit, role: Int): List<Recipient> { suspend fun getRecipients(student: Student, unit: ReportingUnit, role: Int): List<Recipient> {
return recipientDb.loadAll(unit.senderId, unit.unitId, role).ifEmpty { return recipientDb.loadAll(unit.studentId, unit.unitId, role).ifEmpty {
refreshRecipients(student, unit, role) refreshRecipients(student, unit, role)
recipientDb.loadAll(unit.senderId, unit.unitId, role) recipientDb.loadAll(unit.studentId, unit.unitId, role)
} }
} }
suspend fun getMessageRecipients(student: Student, message: Message): List<Recipient> { suspend fun getMessageRecipients(student: Student, message: Message): List<Recipient> {
return sdk.init(student).getMessageRecipients(message.messageId, message.senderId).mapToEntities(student.userLoginId) return sdk.init(student).getMessageRecipients(message.messageId, message.senderId).mapToEntities(student.studentId)
} }
} }

View File

@ -18,25 +18,25 @@ class ReportingUnitRepository @Inject constructor(
suspend fun refreshReportingUnits(student: Student) { suspend fun refreshReportingUnits(student: Student) {
val new = sdk.init(student).getReportingUnits().mapToEntities(student) val new = sdk.init(student).getReportingUnits().mapToEntities(student)
val old = reportingUnitDb.load(student.studentId) val old = reportingUnitDb.load(student.id.toInt())
reportingUnitDb.deleteAll(old.uniqueSubtract(new)) reportingUnitDb.deleteAll(old.uniqueSubtract(new))
reportingUnitDb.insertAll(new.uniqueSubtract(old)) reportingUnitDb.insertAll(new.uniqueSubtract(old))
} }
suspend fun getReportingUnits(student: Student): List<ReportingUnit> { suspend fun getReportingUnits(student: Student): List<ReportingUnit> {
return reportingUnitDb.load(student.studentId).ifEmpty { return reportingUnitDb.load(student.id.toInt()).ifEmpty {
refreshReportingUnits(student) refreshReportingUnits(student)
reportingUnitDb.load(student.studentId) reportingUnitDb.load(student.id.toInt())
} }
} }
suspend fun getReportingUnit(student: Student, unitId: Int): ReportingUnit? { suspend fun getReportingUnit(student: Student, unitId: Int): ReportingUnit? {
return reportingUnitDb.loadOne(student.studentId, unitId) ?: run { return reportingUnitDb.loadOne(student.id.toInt(), unitId) ?: run {
refreshReportingUnits(student) refreshReportingUnits(student)
return reportingUnitDb.loadOne(student.studentId, unitId) return reportingUnitDb.loadOne(student.id.toInt(), unitId)
} }
} }
} }

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