Compare commits

...

262 Commits
1.1.2 ... 1.3.0

Author SHA1 Message Date
689012131f Merge branch 'release/1.3.0' 2021-09-28 23:26:18 +02:00
6cdcf92782 Version 1.3.0 2021-09-28 23:26:10 +02:00
9c8bcbfdd3 New Crowdin updates (#1544) 2021-09-28 21:11:59 +00:00
0b83a66b85 Remove disappearing teachers workaround from timetable repository (#1545) 2021-09-28 23:10:11 +02:00
9711cc868c New Crowdin updates (#1522) 2021-09-28 22:42:06 +02:00
f8cb7599e6 Add missing auto refresh to recipients, subjects and teachers (#1540) 2021-09-28 22:40:43 +02:00
7636618e23 Update License (#1542) 2021-09-28 21:55:40 +02:00
5bc54c12f1 Add option to make upcoming lesson notification not persistent (#1537) 2021-09-28 11:48:25 +02:00
e10e530dee Remove seconds from timetable timer (#1539) 2021-09-27 23:03:59 +02:00
d69118b085 Add notifications center (#1524) 2021-09-27 20:58:25 +02:00
dc90549b9d Fix hiding last element in messages (#1538) 2021-09-27 17:56:43 +02:00
b552dbc904 Bump constraintlayout from 2.1.0 to 2.1.1 (#1535) 2021-09-27 15:56:11 +00:00
a6a1678b47 Bump core from 1.10.1 to 1.10.2 (#1536) 2021-09-27 15:51:06 +00:00
7a46ef5f19 Add calculated average help dialog (#1379)
Co-authored-by: Rafał Borcz <RafalBO99@outlook.com>
2021-09-25 17:19:21 +02:00
f9e0f7b390 Don't stop loading the timetable when error occurs in upcoming lessons notification scheduling (#1532) 2021-09-25 15:18:40 +02:00
9211baf7ec Add notification piggyback (#1503) 2021-09-25 14:02:38 +02:00
de6131f4f5 Add transparency to lucky number widget (#1530) 2021-09-25 13:46:35 +02:00
2cb11e443c Mark teacher with yellow when new and old are the same (#1529) 2021-09-25 13:46:11 +02:00
a43ffcdef4 Display bad credentials error in the message box above login form (#1525) 2021-09-24 21:02:51 +02:00
6615e68430 Bump kotlin_version from 1.5.30 to 1.5.31 (#1528) 2021-09-22 09:25:54 +02:00
36daa7ccc1 Always include all language resources in app bundle (#1527) 2021-09-22 09:25:16 +02:00
6e5481f345 Upgrade Gradle Play Publisher to 3.6.0 (#1526) 2021-09-20 11:38:13 +02:00
ba1c14ca0e Merge branch 'release/1.2.3' into develop 2021-09-16 12:01:58 +02:00
c69bb2ef71 Merge branch 'release/1.2.3' 2021-09-16 12:01:54 +02:00
9cb4754132 Version 1.2.3 2021-09-16 12:01:49 +02:00
5ba8289c87 Display info in timetable as-is when lesson has change flag (#1521) 2021-09-16 11:59:23 +02:00
258782c648 New Crowdin updates (#1482) 2021-09-16 11:30:05 +02:00
c568bc1515 Fix ghost account after logout not current student (#1518) 2021-09-16 11:29:11 +02:00
da668f93cf Fix bugs in dashboard (#1517) 2021-09-16 11:24:52 +02:00
037dbd792f Add conference dialog (#1519) 2021-09-16 10:51:38 +02:00
7ec7afed87 Bump firebase-bom from 28.4.0 to 28.4.1 (#1520) 2021-09-16 08:22:06 +00:00
bea50e6db5 Merge branch 'release/1.2.2' into develop 2021-09-13 14:53:38 +02:00
6a00e75816 Merge branch 'release/1.2.2' 2021-09-13 14:53:32 +02:00
957adaf6ee Version 1.2.2 2021-09-13 14:53:27 +02:00
827fb33eeb Fix login process after was interrupted (#1505) 2021-09-13 14:36:31 +02:00
19c96ee83f Unlock sunday in navigation datepicker (#1506) 2021-09-13 14:19:46 +02:00
5a7f52c773 Update help email pre-filled content (#1507) 2021-09-13 14:19:24 +02:00
dddeff802f Fix date picker crash after saved state (#1502) 2021-09-12 17:29:46 +02:00
91f6310892 Restore lucky number in more view (#1504) 2021-09-11 19:43:05 +02:00
0389642543 Fix empty list on excuse submit (#1501) 2021-09-11 19:40:09 +02:00
8528e0beff Fix crash in school info when dialer is unavailable (#1500) 2021-09-10 09:49:22 +00:00
e665a8f18b Fix error view in attendance summary (#1492) 2021-09-10 00:48:29 +02:00
6d5acbad2c Fix overlapping error view (#1493) 2021-09-10 00:36:44 +02:00
7217d0f753 Fix NPE in timetable dashboard tile (#1498) 2021-09-10 00:27:48 +02:00
16a5d88dfb Fix overlapping shadow in dashboard (#1494) 2021-09-10 00:25:23 +02:00
646a46727f Update material chips input (#1495) 2021-09-08 09:13:52 +02:00
f5e9197f98 Bump work_manager from 2.5.0 to 2.6.0 (#1478) 2021-09-06 23:38:10 +00:00
b47f26684b Change AppGallery deploy format to aab (#1483) 2021-09-06 03:27:54 +02:00
3a03b5f1c6 Merge branch 'release/1.2.1' into develop 2021-09-05 23:29:30 +02:00
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
466 changed files with 25081 additions and 3470 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ć

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

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

@ -0,0 +1,72 @@
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/upload-key.jks.gpg
- name: Upload apk to google play
env:
PLAY_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
ANDROID_PUBLISHER_CREDENTIALS: ${{ secrets.ANDROID_PUBLISHER_CREDENTIALS }}
run: ./gradlew publishPlayReleaseApps -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/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_STORE_PASSWORD: ${{ secrets.PLAY_STORE_PASSWORD }}
PLAY_KEY_ALIAS: ${{ secrets.PLAY_KEY_ALIAS }}
PLAY_KEY_PASSWORD: ${{ secrets.PLAY_KEY_PASSWORD }}
run: ./gradlew bundleHmsRelease --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,13 +1,11 @@
name: Test and deploy
name: Tests
on:
push:
branches: [ develop ]
branches: [ master, develop ]
tags: [ '*' ]
pull_request:
branches: [ develop ]
workflow_dispatch:
branches: [ master, develop ]
jobs:
unit-tests:
@ -29,174 +27,8 @@ jobs:
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle*') }}
- name: Unit tests
run: |
./gradlew --build-cache -Pcoverage testFdroidDebugUnitTest --stacktrace
./gradlew --build-cache -Pcoverage jacocoTestReport --stacktrace
./gradlew testFdroidDebugUnitTest --stacktrace
./gradlew jacocoTestReport --stacktrace
- uses: codecov/codecov-action@v1
with:
flags: unit
deploy-google-play:
name: Deploy to google play
runs-on: ubuntu-latest
timeout-minutes: 10
environment: google-play
needs: [ unit-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*') }}
- 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-appcenter:
name: Deploy to App Center
runs-on: ubuntu-latest
timeout-minutes: 10
environment: app-center
if: github.ref != 'refs/heads/develop'
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: Deploy to AppDistribution
runs-on: ubuntu-latest
timeout-minutes: 10
environment: app-distribution
if: github.ref == 'refs/heads/develop'
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

2
.gitignore vendored
View File

@ -117,3 +117,5 @@ Thumbs.db
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" />
</value>
</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_FOR_MEMBERS" value="2147483647" />
<option name="WRAP_ELVIS_EXPRESSIONS" value="0" />

View File

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2019 Wulkanowy
Copyright 2021 Wulkanowy
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -2,7 +2,7 @@
# 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)
[![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/)

View File

@ -2,7 +2,7 @@
# 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)
[![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/)
@ -32,7 +32,7 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
* powiadomienia np. o nowej ocenie
* obsługa wielu kont wraz z możliwością zmiany nazwy ucznia
* ciemny i czarny (AMOLED) motyw
* tryb offilne
* tryb offline
* brak reklam
## Pobierz

Binary file not shown.

View File

@ -1,11 +1,13 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.github.triplet.play'
apply plugin: 'ru.cian.huawei-publish'
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.huawei.agconnect'
apply from: 'jacoco.gradle'
apply from: 'sonarqube.gradle'
@ -13,16 +15,14 @@ apply from: 'hooks.gradle'
android {
compileSdkVersion 30
buildToolsVersion '30.0.3'
defaultConfig {
applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 17
minSdkVersion 21
targetSdkVersion 30
versionCode 88
versionName "1.1.2"
multiDexEnabled true
versionCode 97
versionName "1.3.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
@ -67,7 +67,6 @@ android {
resValue "string", "app_name", "Wulkanowy DEV " + defaultConfig.versionCode
applicationIdSuffix ".dev"
versionNameSuffix "-dev"
testCoverageEnabled = project.hasProperty('coverage')
ext.enableCrashlytics = project.hasProperty("enableFirebase")
}
}
@ -77,7 +76,6 @@ android {
productFlavors {
hms {
dimension "platform"
minSdkVersion 19
manifestPlaceholders = [
install_channel: "AppGallery"
]
@ -98,12 +96,18 @@ android {
}
}
buildFeatures {
viewBinding = true
playConfigs {
play { enabled.set(true) }
}
lintOptions {
disable 'HardwareIds'
buildFeatures {
viewBinding true
}
bundle {
language {
enableSplit = false
}
}
testOptions.unitTests {
@ -112,13 +116,12 @@ android {
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
useIR = true
jvmTarget = "1.8"
jvmTarget = "11"
freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
}
@ -132,54 +135,65 @@ android {
}
}
kapt {
correctErrorTypes true
}
play {
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
serviceAccountCredentials = file('key.p12')
defaultToAppBundles = false
track = 'production'
updatePriority = 5
updatePriority = 3
enabled.set(false)
}
huaweiPublish {
instances {
hmsRelease {
credentialsPath = "$rootDir/app/src/release/agconnect-credentials.json"
buildFormat = "aab"
deployType = "draft"
}
}
}
ext {
work_manager = "2.5.0"
work_hilt = "1.0.0-beta01"
room = "2.3.0-beta03"
chucker = "3.4.0"
mockk = "1.10.6"
moshi = "1.11.0"
work_manager = "2.6.0"
android_hilt = "1.0.0"
room = "2.3.0"
chucker = "3.5.2"
mockk = "1.12.0"
moshi = "1.12.0"
}
dependencies {
implementation "io.github.wulkanowy:sdk:1.1.2"
implementation "io.github.wulkanowy:sdk:1.3.0"
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.4.3'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
implementation "androidx.core:core-ktx:1.3.2"
implementation "androidx.activity:activity-ktx:1.2.1"
implementation "androidx.appcompat:appcompat:1.2.0"
implementation "androidx.appcompat:appcompat-resources:1.2.0"
implementation "androidx.fragment:fragment-ktx:1.3.1"
implementation "androidx.annotation:annotation:1.1.0"
implementation "androidx.multidex:multidex:2.0.1"
implementation "androidx.core:core-ktx:1.6.0"
implementation "androidx.activity:activity-ktx:1.3.1"
implementation "androidx.appcompat:appcompat:1.3.1"
implementation "androidx.appcompat:appcompat-resources:1.3.1"
implementation "androidx.fragment:fragment-ktx:1.3.6"
implementation "androidx.annotation:annotation:1.2.0"
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.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
implementation "androidx.constraintlayout:constraintlayout:2.1.1"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "com.google.android.material:material:1.3.0"
implementation "com.github.wulkanowy:material-chips-input:2.2.0"
implementation "com.google.android.material:material:1.4.0"
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation 'com.mikhaellopez:circularimageview:4.2.0'
implementation 'com.github.lopspower:CircularImageView:4.2.0'
implementation "androidx.work:work-runtime-ktx:$work_manager"
playImplementation "androidx.work:work-gcm:$work_manager"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
implementation "androidx.room:room-runtime:$room"
implementation "androidx.room:room-ktx:$room"
@ -187,58 +201,56 @@ dependencies {
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
implementation "androidx.hilt:hilt-work:$work_hilt"
kapt "androidx.hilt:hilt-compiler:$work_hilt"
kapt "androidx.hilt:hilt-compiler:$android_hilt"
implementation "androidx.hilt:hilt-work:$android_hilt"
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
implementation "com.ncapdevi:frag-nav:3.3.0"
implementation 'com.github.ncapdevi:FragNav:3.3.0'
implementation "com.github.YarikSOffice:lingver:1.3.0"
implementation "com.squareup.moshi:moshi:$moshi"
implementation "com.squareup.moshi:moshi-adapters:$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 "fr.bipi.treessence:treessence:0.3.2"
implementation 'com.github.bastienpaulfr:Treessence:1.0.4'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
implementation "io.coil-kt:coil:1.1.1"
implementation "io.coil-kt:coil:1.3.2"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
implementation 'com.fredporciuncula:flow-preferences:1.5.0'
playImplementation platform('com.google.firebase:firebase-bom:26.7.0')
playImplementation platform('com.google.firebase:firebase-bom:28.4.1')
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-crashlytics:'
playImplementation 'com.google.android.play:core:1.10.2'
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.2.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.5.0.300'
hmsImplementation 'com.huawei.hms:hianalytics:6.2.0.301'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.6.0.300'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$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 "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.robolectric:robolectric:4.5.1'
testImplementation "androidx.test:runner:1.3.0"
testImplementation "androidx.test.ext:junit:1.1.2"
testImplementation "androidx.test:core:1.3.0"
testImplementation 'org.robolectric:robolectric:4.6.1'
testImplementation "androidx.test:runner:1.4.0"
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.3.0"
androidTestImplementation "androidx.test:runner:1.3.0"
androidTestImplementation "androidx.test.ext:junit:1.1.2"
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 "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
}

View File

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

Binary file not shown.

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 com.huawei.agconnect.crash.AGConnectCrash
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) {
@ -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() }
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?) {
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.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.VIBRATE" />
@ -44,6 +45,7 @@
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
<activity
android:name=".ui.modules.splash.SplashActivity"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@style/WulkanowyTheme.SplashScreen"
tools:ignore="LockedOrientationActivity">
@ -73,6 +75,7 @@
<activity
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
android:excludeFromRecents="true"
android:exported="true"
android:noHistory="true"
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
<intent-filter>
@ -82,6 +85,7 @@
<activity
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity"
android:excludeFromRecents="true"
android:exported="true"
android:noHistory="true"
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
<intent-filter>
@ -92,6 +96,22 @@
<service
android:name=".services.widgets.TimetableWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS" />
<service
android:name=".services.piggyback.VulcanNotificationListenerService"
android:exported="true"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
<service
android:name=".services.messaging.AppMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<receiver
android:name=".ui.modules.timetablewidget.TimetableWidgetProvider"
@ -106,6 +126,7 @@
</receiver>
<receiver
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetProvider"
android:exported="true"
android:label="@string/lucky_number_title">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -118,11 +139,9 @@
<receiver android:name=".services.alarm.TimetableNotificationReceiver" />
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:exported="false"
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
@ -167,7 +186,7 @@
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_push" />
android:resource="@drawable/ic_stat_all" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"

View File

@ -36,7 +36,7 @@
"githubUsername": "Luncenok"
},
{
"displayName": "MRmlik12",
"displayName": "Daniel Olczyk",
"githubUsername": "MRmlik12"
},
{
@ -46,5 +46,9 @@
{
"displayName": "Kamil Studziński",
"githubUsername": "studzinskik"
},
{
"displayName": "Tomasz F.",
"githubUsername": "Pengwius"
}
]

View File

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

View File

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

View File

@ -22,8 +22,10 @@ import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
import io.github.wulkanowy.data.db.dao.NoteDao
import io.github.wulkanowy.data.db.dao.NotificationDao
import io.github.wulkanowy.data.db.dao.RecipientDao
import io.github.wulkanowy.data.db.dao.ReportingUnitDao
import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao
import io.github.wulkanowy.data.db.dao.SchoolDao
import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.dao.StudentDao
@ -32,6 +34,7 @@ import io.github.wulkanowy.data.db.dao.SubjectDao
import io.github.wulkanowy.data.db.dao.TeacherDao
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
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.AttendanceSummary
import io.github.wulkanowy.data.db.entities.CompletedLesson
@ -48,9 +51,11 @@ import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.Note
import io.github.wulkanowy.data.db.entities.Notification
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.School
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentInfo
@ -58,6 +63,7 @@ import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.data.db.entities.Teacher
import io.github.wulkanowy.data.db.entities.Timetable
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.Migration11
import io.github.wulkanowy.data.db.migrations.Migration12
@ -86,7 +92,12 @@ import io.github.wulkanowy.data.db.migrations.Migration32
import io.github.wulkanowy.data.db.migrations.Migration33
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.Migration40
import io.github.wulkanowy.data.db.migrations.Migration5
import io.github.wulkanowy.data.db.migrations.Migration6
import io.github.wulkanowy.data.db.migrations.Migration7
@ -124,6 +135,9 @@ import javax.inject.Singleton
Conference::class,
TimetableAdditional::class,
StudentInfo::class,
TimetableHeader::class,
SchoolAnnouncement::class,
Notification::class
],
version = AppDatabase.VERSION_SCHEMA,
exportSchema = true
@ -132,7 +146,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
const val VERSION_SCHEMA = 35
const val VERSION_SCHEMA = 40
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(),
@ -168,7 +182,12 @@ abstract class AppDatabase : RoomDatabase() {
Migration32(),
Migration33(),
Migration34(),
Migration35(appInfo)
Migration35(appInfo),
Migration36(),
Migration37(),
Migration38(),
Migration39(),
Migration40()
)
fun newInstance(
@ -234,4 +253,10 @@ abstract class AppDatabase : RoomDatabase() {
abstract val timetableAdditionalDao: TimetableAdditionalDao
abstract val studentInfoDao: StudentInfoDao
abstract val timetableHeaderDao: TimetableHeaderDao
abstract val schoolAnnouncementDao: SchoolAnnouncementDao
abstract val notificationDao: NotificationDao
}

View File

@ -20,9 +20,15 @@ class SharedPrefProvider @Inject constructor(
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 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) }
}

View File

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

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.Notification
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@Dao
interface NotificationDao : BaseDao<Notification> {
@Query("SELECT * FROM Notifications WHERE student_id = :studentId OR student_id = -1")
fun loadAll(studentId: Long): Flow<List<Notification>>
}

View File

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

@ -14,33 +14,39 @@ import javax.inject.Singleton
@Singleton
@Dao
interface StudentDao {
abstract class StudentDao {
@Insert(onConflict = ABORT)
suspend fun insertAll(student: List<Student>): List<Long>
abstract suspend fun insertAll(student: List<Student>): List<Long>
@Delete
suspend fun delete(student: Student)
abstract suspend fun delete(student: Student)
@Update(entity = Student::class)
suspend fun update(studentNickAndAvatar: StudentNickAndAvatar)
abstract suspend fun update(studentNickAndAvatar: StudentNickAndAvatar)
@Query("SELECT * FROM Students WHERE is_current = 1")
suspend fun loadCurrent(): Student?
abstract suspend fun loadCurrent(): Student?
@Query("SELECT * FROM Students WHERE id = :id")
suspend fun loadById(id: Long): Student?
abstract suspend fun loadById(id: Long): Student?
@Query("SELECT * FROM Students")
suspend fun loadAll(): List<Student>
abstract suspend fun loadAll(): List<Student>
@Transaction
@Query("SELECT * FROM Students")
suspend fun loadStudentsWithSemesters(): List<StudentWithSemesters>
abstract suspend fun loadStudentsWithSemesters(): List<StudentWithSemesters>
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
suspend fun updateCurrent(id: Long)
abstract suspend fun updateCurrent(id: Long)
@Query("UPDATE Students SET is_current = 0")
suspend fun resetCurrent()
abstract suspend fun resetCurrent()
@Transaction
open suspend fun switchCurrent(id: Long) {
resetCurrent()
updateCurrent(id)
}
}

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)
var id: Long = 0
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
}

View File

@ -36,4 +36,7 @@ data class Exam(
@PrimaryKey(autoGenerate = true)
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")
var isDone: Boolean = false
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
}

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 io.github.wulkanowy.services.sync.notifications.NotificationType
import java.time.LocalDateTime
@Entity(tableName = "Notifications")
data class Notification(
@ColumnInfo(name = "student_id")
val studentId: Long,
val title: String,
val content: String,
val type: NotificationType,
val date: LocalDateTime,
val data: String? = null
) {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View File

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

@ -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,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,23 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration40 : Migration(39, 40) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"""
CREATE TABLE IF NOT EXISTS `Notifications` (
`student_id` INTEGER NOT NULL,
`title` TEXT NOT NULL,
`content` TEXT NOT NULL,
`type` TEXT NOT NULL,
`date` INTEGER NOT NULL,
`data` TEXT,
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
)
"""
)
}
}

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,7 +5,7 @@ import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
fun List<SdkRecipient>.mapToEntities(userLoginId: Int) = map {
Recipient(
userLoginId = userLoginId,
studentId = userLoginId,
realId = it.id,
realName = it.name,
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 {
ReportingUnit(
studentId = student.studentId,
studentId = student.id.toInt(),
unitId = it.id,
roles = it.roles,
senderId = it.senderId,

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.Timetable
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.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 {
Timetable(
studentId = semester.studentId,
@ -39,3 +49,13 @@ fun List<SdkTimetableAdditional>.mapToEntities(semester: Semester) = map {
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

@ -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 NotificationData {
val type: NotificationType
val startMenu: MainView.Section
val icon: Int
val titleStringRes: Int
val contentStringRes: Int
}
data class MultipleNotificationsData(
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>,
) : NotificationData
data class OneNotificationData(
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>,
) : NotificationData

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
) {
@Suppress("BlockingMethodInNonBlockingContext")
suspend fun getAppCreators() = withContext(dispatchers.backgroundThread) {
val moshi = Moshi.Builder().build()
val type = Types.newParameterizedType(List::class.java, Contributor::class.java)

View File

@ -32,10 +32,23 @@ class AttendanceRepository @Inject constructor(
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)) },
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday) },
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(
key = getRefreshKey(cacheKey, semester, start, end)
)
it.isEmpty() || forceRefresh || isExpired
},
query = {
attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
},
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getAttendance(start.monday, end.sunday, semester.semesterId)
@ -50,12 +63,17 @@ class AttendanceRepository @Inject constructor(
filterResult = { it.filter { item -> item.date in start..end } }
)
suspend fun excuseForAbsence(student: Student, semester: Semester, absenceList: List<Attendance>, reason: String? = null) {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance ->
suspend fun excuseForAbsence(
student: Student, semester: Semester,
absenceList: List<Attendance>, reason: String? = null
) {
val items = absenceList.map { attendance ->
Absent(
date = LocalDateTime.of(attendance.date, LocalTime.of(0, 0)),
timeId = attendance.timeId
)
}, reason)
}
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.excuseForAbsence(items, reason)
}
}

View File

@ -25,9 +25,17 @@ class AttendanceSummaryRepository @Inject constructor(
private val cacheKey = "attendance_summary"
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource(
fun getAttendanceSummary(
student: Student,
semester: Semester,
subjectId: Int,
forceRefresh: Boolean,
) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester)) },
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
it.isEmpty() || forceRefresh || isExpired
},
query = { attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)

View File

@ -28,10 +28,28 @@ class CompletedLessonsRepository @Inject constructor(
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)) },
query = { completedLessonsDb.loadAll(semester.studentId, semester.diaryId, start.monday, end.sunday) },
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(
key = getRefreshKey(cacheKey, semester, start, end)
)
it.isEmpty() || forceRefresh || isExpired
},
query = {
completedLessonsDb.loadAll(
studentId = semester.studentId,
diaryId = semester.diaryId,
from = start.monday,
end = end.sunday
)
},
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getCompletedLessons(start.monday, end.sunday)

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.data.repositories
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.Student
import io.github.wulkanowy.data.mappers.mapToEntities
@ -10,7 +11,11 @@ import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
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.Singleton
@ -25,19 +30,44 @@ class ConferenceRepository @Inject constructor(
private val cacheKey = "conference"
fun getConferences(student: Student, semester: Semester, forceRefresh: Boolean) = networkBoundResource(
fun getConferences(
student: Student,
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) },
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
it.isEmpty() || forceRefresh || isExpired
},
query = {
conferenceDb.loadAll(semester.diaryId, student.studentId, startDate)
},
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getConferences()
.mapToEntities(semester)
.filter { it.date >= startDate }
},
saveFetchResult = { old, new ->
val conferencesToSave = (new uniqueSubtract old).onEach {
if (notify) it.isNotified = false
}
conferenceDb.deleteAll(old uniqueSubtract new)
conferenceDb.insertAll(new uniqueSubtract old)
conferenceDb.insertAll(conferencesToSave)
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
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.Student
import io.github.wulkanowy.data.mappers.mapToEntities
@ -12,6 +13,7 @@ import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.startExamsDay
import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import java.time.LocalDate
import javax.inject.Inject
@ -28,20 +30,54 @@ class ExamRepository @Inject constructor(
private val cacheKey = "exam"
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
fun getExams(
student: Student,
semester: Semester,
start: LocalDate,
end: LocalDate,
forceRefresh: Boolean,
notify: Boolean = false,
) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { examDb.loadAll(semester.diaryId, semester.studentId, start.startExamsDay, start.endExamsDay) },
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(
key = getRefreshKey(cacheKey, semester, start, end)
)
it.isEmpty() || forceRefresh || isExpired
},
query = {
examDb.loadAll(
diaryId = semester.diaryId,
studentId = semester.studentId,
from = start.startExamsDay,
end = start.endExamsDay
)
},
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getExams(start.startExamsDay, start.endExamsDay, semester.semesterId)
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
val examsToSave = (new uniqueSubtract old).onEach {
if (notify) it.isNotified = false
}
examDb.deleteAll(old uniqueSubtract new)
examDb.insertAll(new uniqueSubtract old)
examDb.insertAll(examsToSave)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, 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

@ -33,11 +33,16 @@ class GradeRepository @Inject constructor(
private val cacheKey = "grade"
fun getGrades(student: Student, semester: Semester, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
fun getGrades(
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
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, semester))
details.isEmpty() || summaries.isEmpty() || forceRefresh || isExpired
},
query = {
val detailsFlow = gradeDb.loadAll(semester.semesterId, semester.studentId)
@ -59,8 +64,14 @@ class GradeRepository @Inject constructor(
}
)
private suspend fun refreshGradeDetails(student: Student, oldGrades: List<Grade>, newDetails: List<Grade>, notify: Boolean) {
val notifyBreakDate = oldGrades.maxByOrNull { it.date }?.date ?: student.registrationDate.toLocalDate()
private suspend fun refreshGradeDetails(
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.insertAll((newDetails uniqueSubtract oldGrades).onEach {
if (it.date >= notifyBreakDate) it.apply {
@ -70,10 +81,14 @@ 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.insertAll((newSummary uniqueSubtract oldSummaries).onEach { summary ->
val oldSummary = oldSummaries.find { oldSummary -> oldSummary.subject == summary.subject }
val oldSummary = oldSummaries.find { old -> old.subject == summary.subject }
summary.isPredictedGradeNotified = when {
summary.predictedGrade.isEmpty() -> true
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
@ -104,22 +119,16 @@ class GradeRepository @Inject constructor(
}
}
fun getNotNotifiedGrades(semester: Semester): Flow<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId).map {
it.filter { grade -> !grade.isNotified }
}
fun getGradesFromDatabase(semester: Semester): Flow<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId)
}
fun getNotNotifiedPredictedGrades(semester: Semester): Flow<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map {
it.filter { gradeSummary -> !gradeSummary.isPredictedGradeNotified }
}
fun getGradesPredictedFromDatabase(semester: Semester): Flow<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
}
fun getNotNotifiedFinalGrades(semester: Semester): Flow<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId).map {
it.filter { gradeSummary -> !gradeSummary.isFinalGradeNotified }
}
fun getGradesFinalFromDatabase(semester: Semester): Flow<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
}
suspend fun updateGrade(grade: Grade) {

View File

@ -39,9 +39,19 @@ class GradeStatisticsRepository @Inject constructor(
private val semesterCacheKey = "grade_stats_semester"
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 = {
val isExpired = refreshHelper.shouldBeRefreshed(
key = getRefreshKey(partialCacheKey, semester)
)
it.isEmpty() || forceRefresh || isExpired
},
query = { gradePartialStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -76,9 +86,19 @@ 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 = {
val isExpired = refreshHelper.shouldBeRefreshed(
key = getRefreshKey(semesterCacheKey, semester)
)
it.isEmpty() || forceRefresh || isExpired
},
query = { gradeSemesterStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -94,10 +114,12 @@ class GradeStatisticsRepository @Inject constructor(
val itemsWithAverage = items.map { item ->
item.copy().apply {
val denominator = item.amounts.sum()
average = if (denominator == 0) "" else (item.amounts.mapIndexed { gradeValue, amount ->
(gradeValue + 1) * amount
}.sum().toDouble() / denominator).let {
"%.2f".format(Locale.FRANCE, it)
average = if (denominator == 0) "" else {
(item.amounts.mapIndexed { gradeValue, amount ->
(gradeValue + 1) * amount
}.sum().toDouble() / denominator).let {
"%.2f".format(Locale.FRANCE, it)
}
}
}
}
@ -109,7 +131,9 @@ class GradeStatisticsRepository @Inject constructor(
amounts = itemsWithAverage.map { it.amounts }.sumGradeAmounts(),
studentGrade = 0
).apply {
average = itemsWithAverage.mapNotNull { it.average.replace(",", ".").toDoubleOrNull() }.average().let {
average = itemsWithAverage.mapNotNull {
it.average.replace(",", ".").toDoubleOrNull()
}.average().let {
"%.2f".format(Locale.FRANCE, it)
}
}).reversed()
@ -118,9 +142,17 @@ 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 = {
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(pointsCacheKey, semester))
it.isEmpty() || forceRefresh || isExpired
},
query = { gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)

View File

@ -29,18 +29,41 @@ class HomeworkRepository @Inject constructor(
private val cacheKey = "homework"
fun getHomework(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
fun getHomework(
student: Student,
semester: Semester,
start: LocalDate,
end: LocalDate,
forceRefresh: Boolean,
notify: Boolean = false,
) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it.isEmpty() || forceRefresh || refreshHelper.isShouldBeRefreshed(getRefreshKey(cacheKey, semester, start, end)) },
query = { homeworkDb.loadAll(semester.semesterId, semester.studentId, start.monday, end.sunday) },
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(
key = getRefreshKey(cacheKey, semester, start, end)
)
it.isEmpty() || forceRefresh || isExpired
},
query = {
homeworkDb.loadAll(
semesterId = semester.semesterId,
studentId = semester.studentId,
from = start.monday,
end = end.sunday
)
},
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getHomework(start.monday, end.sunday)
.mapToEntities(semester)
},
saveFetchResult = { old, new ->
val homeWorkToSave = (new uniqueSubtract old).onEach {
if (notify) it.isNotified = false
}
homeworkDb.deleteAll(old uniqueSubtract new)
homeworkDb.insertAll(new uniqueSubtract old)
homeworkDb.insertAll(homeWorkToSave)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, semester, start, end))
}
@ -51,4 +74,9 @@ class HomeworkRepository @Inject constructor(
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

@ -23,11 +23,17 @@ class LuckyNumberRepository @Inject constructor(
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 },
query = { luckyNumberDb.load(student.studentId, now()) },
fetch = { sdk.init(student).getLuckyNumber(student.schoolShortName)?.mapToEntity(student) },
fetch = {
sdk.init(student).getLuckyNumber(student.schoolShortName)?.mapToEntity(student)
},
saveFetchResult = { old, new ->
if (new != old) {
old?.let { luckyNumberDb.deleteAll(listOfNotNull(it)) }
@ -41,9 +47,11 @@ 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 {
if (it?.isNotified == false) it else null
}.first()
suspend fun getNotNotifiedLuckyNumber(student: Student) =
luckyNumberDb.load(student.studentId, now()).map {
if (it?.isNotified == false) it else null
}.first()
suspend fun updateLuckyNumber(luckyNumber: LuckyNumber?) = luckyNumberDb.updateAll(listOfNotNull(luckyNumber))
suspend fun updateLuckyNumber(luckyNumber: LuckyNumber?) =
luckyNumberDb.updateAll(listOfNotNull(luckyNumber))
}

View File

@ -1,8 +1,15 @@
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.MessagesDao
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.Semester
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.mappers.mapFromEntities
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.pojo.Folder
import io.github.wulkanowy.sdk.pojo.SentMessage
@ -19,7 +28,6 @@ import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
import timber.log.Timber
import java.time.LocalDateTime.now
@ -31,7 +39,10 @@ class MessageRepository @Inject constructor(
private val messagesDb: MessagesDao,
private val messageAttachmentDao: MessageAttachmentDao,
private val sdk: Sdk,
@ApplicationContext private val context: Context,
private val refreshHelper: AutoRefreshHelper,
private val sharedPrefProvider: SharedPrefProvider,
private val moshi: Moshi,
) {
private val saveFetchResultMutex = Mutex()
@ -39,22 +50,61 @@ class MessageRepository @Inject constructor(
private val cacheKey = "message"
@Suppress("UNUSED_PARAMETER")
fun getMessages(student: Student, semester: Semester, folder: MessageFolder, forceRefresh: Boolean, notify: Boolean = false) = networkBoundResource(
fun getMessages(
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)) },
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(
key = getRefreshKey(cacheKey, student, folder)
)
it.isEmpty() || forceRefresh || isExpired
},
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 ->
messagesDb.deleteAll(old uniqueSubtract new)
messagesDb.insertAll((new uniqueSubtract old).onEach {
it.isNotified = !notify
})
messagesDb.updateAll(getMessagesWithReadByChange(old, new, !notify))
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 = {
checkNotNull(it, { "This message no longer exist!" })
Timber.d("Message content in db empty: ${it.message.content.isEmpty()}")
@ -62,14 +112,20 @@ class MessageRepository @Inject constructor(
},
query = { messagesDb.loadMessageWithAttachment(student.id.toInt(), message.messageId) },
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()
}
},
saveFetchResult = { old, (downloadedMessage, attachments) ->
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
unread = !markAsRead
content = content.ifBlank { downloadedMessage }
}))
messageAttachmentDao.insertAttachments(attachments)
@ -77,30 +133,44 @@ class MessageRepository @Inject constructor(
}
)
fun getNotNotifiedMessages(student: Student): Flow<List<Message>> {
return messagesDb.loadAll(student.id.toInt(), RECEIVED.id).map { it.filter { message -> !message.isNotified && message.unread } }
fun getMessagesFromDatabase(student: Student): Flow<List<Message>> {
return messagesDb.loadAll(student.id.toInt(), RECEIVED.id)
}
suspend fun updateMessages(messages: List<Message>) {
return messagesDb.updateAll(messages)
}
suspend fun sendMessage(student: Student, subject: String, content: String, recipients: List<Recipient>): SentMessage {
return sdk.init(student).sendMessage(
subject = subject,
content = content,
recipients = recipients.mapFromEntities()
)
}
suspend fun sendMessage(
student: Student,
subject: String,
content: String,
recipients: List<Recipient>,
): SentMessage = sdk.init(student).sendMessage(
subject = subject,
content = content,
recipients = recipients.mapFromEntities()
)
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 (isDeleted) messagesDb.updateAll(listOf(message.copy(folderId = MessageFolder.TRASHED.id).apply {
if (message.folderId != MessageFolder.TRASHED.id && isDeleted) {
val deletedMessage = message.copy(folderId = MessageFolder.TRASHED.id).apply {
id = message.id
content = message.content
}))
}
messagesDb.updateAll(listOf(deletedMessage))
} 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

@ -28,9 +28,16 @@ class MobileDeviceRepository @Inject constructor(
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 = {
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
it.isEmpty() || forceRefresh || isExpired
},
query = { mobileDb.loadAll(student.userLoginId.takeIf { it != 0 } ?: student.studentId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)

View File

@ -12,7 +12,6 @@ import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
import javax.inject.Singleton
@ -28,9 +27,19 @@ class NoteRepository @Inject constructor(
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 = {
val isExpired = refreshHelper.shouldBeRefreshed(
getRefreshKey(cacheKey, semester)
)
it.isEmpty() || forceRefresh || isExpired
},
query = { noteDb.loadAll(student.studentId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
@ -50,8 +59,8 @@ class NoteRepository @Inject constructor(
}
)
fun getNotNotifiedNotes(student: Student): Flow<List<Note>> {
return noteDb.loadAll(student.studentId).map { it.filter { note -> !note.isNotified } }
fun getNotesFromDatabase(student: Student): Flow<List<Note>> {
return noteDb.loadAll(student.studentId)
}
suspend fun updateNote(note: Note) {

View File

@ -0,0 +1,17 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.NotificationDao
import io.github.wulkanowy.data.db.entities.Notification
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class NotificationRepository @Inject constructor(
private val notificationDao: NotificationDao,
) {
fun getNotifications(studentId: Long) = notificationDao.loadAll(studentId)
suspend fun saveNotification(notification: Notification) =
notificationDao.insertAll(listOf(notification))
}

View File

@ -2,18 +2,41 @@ package io.github.wulkanowy.data.repositories
import android.content.Context
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 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.GradeSortingMode
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.Singleton
@OptIn(ExperimentalCoroutinesApi::class)
@Singleton
class PreferencesRepository @Inject constructor(
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
get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt()
@ -84,6 +107,22 @@ class PreferencesRepository @Inject constructor(
R.bool.pref_default_notification_upcoming_lessons_enable
)
val isUpcomingLessonsNotificationsPersistentKey =
context.getString(R.string.pref_key_notifications_upcoming_lessons_persistent)
val isUpcomingLessonsNotificationsPersistent: Boolean
get() = getBoolean(
isUpcomingLessonsNotificationsPersistentKey,
R.bool.pref_default_notification_upcoming_lessons_persistent
)
val isNotificationPiggybackEnabledKey =
context.getString(R.string.pref_key_notifications_piggyback)
val isNotificationPiggybackEnabled: Boolean
get() = getBoolean(
R.string.pref_key_notifications_piggyback,
R.bool.pref_default_notification_piggyback
)
val isDebugNotificationEnableKey = context.getString(R.string.pref_key_notification_debug)
val isDebugNotificationEnable: Boolean
get() = getBoolean(isDebugNotificationEnableKey, R.bool.pref_default_notification_debug)
@ -145,6 +184,79 @@ class PreferencesRepository @Inject constructor(
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: String, default: Int) =
@ -154,4 +266,15 @@ class PreferencesRepository @Inject constructor(
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

@ -7,6 +7,8 @@ import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.uniqueSubtract
import javax.inject.Inject
@ -15,26 +17,34 @@ import javax.inject.Singleton
@Singleton
class RecipientRepository @Inject constructor(
private val recipientDb: RecipientDao,
private val sdk: Sdk
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val cacheKey = "recipient"
suspend fun refreshRecipients(student: Student, unit: ReportingUnit, role: Int) {
val new = sdk.init(student).getRecipients(unit.unitId, role).mapToEntities(unit.senderId)
val old = recipientDb.loadAll(unit.senderId, unit.unitId, role)
val new = sdk.init(student).getRecipients(unit.unitId, role).mapToEntities(unit.studentId)
val old = recipientDb.loadAll(unit.studentId, unit.unitId, role)
recipientDb.deleteAll(old uniqueSubtract new)
recipientDb.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
}
suspend fun getRecipients(student: Student, unit: ReportingUnit, role: Int): List<Recipient> {
return recipientDb.loadAll(unit.senderId, unit.unitId, role).ifEmpty {
refreshRecipients(student, unit, role)
val cached = recipientDb.loadAll(unit.studentId, unit.unitId, role)
recipientDb.loadAll(unit.senderId, unit.unitId, role)
}
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
return if (cached.isEmpty() || isExpired) {
refreshRecipients(student, unit, role)
recipientDb.loadAll(unit.studentId, unit.unitId, role)
} else cached
}
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

@ -11,7 +11,7 @@ class RecoverRepository @Inject constructor(private val sdk: Sdk) {
return sdk.getPasswordResetCaptchaCode(host, symbol)
}
suspend fun sendRecoverRequest(url: String, symbol: String, email: String, reCaptchaResponse: String): String {
return sdk.sendPasswordResetRequest(url, symbol, email, reCaptchaResponse)
}
suspend fun sendRecoverRequest(
url: String, symbol: String, email: String, reCaptchaResponse: String
): String = sdk.sendPasswordResetRequest(url, symbol, email, reCaptchaResponse)
}

View File

@ -18,25 +18,25 @@ class ReportingUnitRepository @Inject constructor(
suspend fun refreshReportingUnits(student: 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.insertAll(new.uniqueSubtract(old))
}
suspend fun getReportingUnits(student: Student): List<ReportingUnit> {
return reportingUnitDb.load(student.studentId).ifEmpty {
return reportingUnitDb.load(student.id.toInt()).ifEmpty {
refreshReportingUnits(student)
reportingUnitDb.load(student.studentId)
reportingUnitDb.load(student.id.toInt())
}
}
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)
return reportingUnitDb.loadOne(student.studentId, unitId)
return reportingUnitDb.loadOne(student.id.toInt(), unitId)
}
}
}

View File

@ -0,0 +1,63 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class SchoolAnnouncementRepository @Inject constructor(
private val schoolAnnouncementDb: SchoolAnnouncementDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "school_announcement"
fun getSchoolAnnouncements(
student: Student,
forceRefresh: Boolean, notify: Boolean = false
) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
it.isEmpty() || forceRefresh || isExpired
},
query = {
schoolAnnouncementDb.loadAll(student.studentId)
},
fetch = {
sdk.init(student)
.getDirectorInformation()
.mapToEntities(student)
},
saveFetchResult = { old, new ->
val schoolAnnouncementsToSave = (new uniqueSubtract old).onEach {
if (notify) it.isNotified = false
}
schoolAnnouncementDb.deleteAll(old uniqueSubtract new)
schoolAnnouncementDb.insertAll(schoolAnnouncementsToSave)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
}
)
fun getSchoolAnnouncementFromDatabase(student: Student): Flow<List<SchoolAnnouncement>> {
return schoolAnnouncementDb.loadAll(student.studentId)
}
suspend fun updateSchoolAnnouncement(schoolAnnouncement: List<SchoolAnnouncement>) =
schoolAnnouncementDb.updateAll(schoolAnnouncement)
}

View File

@ -5,6 +5,8 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.mappers.mapToEntity
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AutoRefreshHelper
import io.github.wulkanowy.utils.getRefreshKey
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.networkBoundResource
import kotlinx.coroutines.sync.Mutex
@ -14,29 +16,41 @@ import javax.inject.Singleton
@Singleton
class SchoolRepository @Inject constructor(
private val schoolDb: SchoolDao,
private val sdk: Sdk
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val saveFetchResultMutex = Mutex()
fun getSchoolInfo(student: Student, semester: Semester, forceRefresh: Boolean) =
networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = { it == null || forceRefresh },
query = { schoolDb.load(semester.studentId, semester.classId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).getSchool()
.mapToEntity(semester)
},
saveFetchResult = { old, new ->
if (old != null && new != old) {
with(schoolDb) {
deleteAll(listOf(old))
insertAll(listOf(new))
}
} else if (old == null) {
schoolDb.insertAll(listOf(new))
private val cacheKey = "school_info"
fun getSchoolInfo(
student: Student,
semester: Semester,
forceRefresh: Boolean,
) = networkBoundResource(
mutex = saveFetchResultMutex,
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(
key = getRefreshKey(cacheKey, student)
)
it == null || forceRefresh || isExpired
},
query = { schoolDb.load(semester.studentId, semester.classId) },
fetch = {
sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).getSchool()
.mapToEntity(semester)
},
saveFetchResult = { old, new ->
if (old != null && new != old) {
with(schoolDb) {
deleteAll(listOf(old))
insertAll(listOf(new))
}
} else if (old == null) {
schoolDb.insertAll(listOf(new))
}
)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
}
)
}

View File

@ -22,7 +22,11 @@ class SemesterRepository @Inject constructor(
private val dispatchers: DispatchersProvider
) {
suspend fun getSemesters(student: Student, forceRefresh: Boolean = false, refreshOnNoCurrent: Boolean = false) = withContext(dispatchers.backgroundThread) {
suspend fun getSemesters(
student: Student,
forceRefresh: Boolean = false,
refreshOnNoCurrent: Boolean = false
) = withContext(dispatchers.backgroundThread) {
val semesters = semesterDb.loadAll(student.studentId, student.classId)
if (isShouldFetch(student, semesters, forceRefresh, refreshOnNoCurrent)) {
@ -31,14 +35,21 @@ class SemesterRepository @Inject constructor(
} else semesters
}
private fun isShouldFetch(student: Student, semesters: List<Semester>, forceRefresh: Boolean, refreshOnNoCurrent: Boolean): Boolean {
private fun isShouldFetch(
student: Student,
semesters: List<Semester>,
forceRefresh: Boolean,
refreshOnNoCurrent: Boolean
): Boolean {
val isNoSemesters = semesters.isEmpty()
val isRefreshOnModeChangeRequired = if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
semesters.firstOrNull { it.isCurrent }?.diaryId == 0
} else false
val isRefreshOnModeChangeRequired =
if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
semesters.firstOrNull { it.isCurrent }?.diaryId == 0
} else false
val isRefreshOnNoCurrentAppropriate = refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent }
val isRefreshOnNoCurrentAppropriate =
refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent }
return forceRefresh || isNoSemesters || isRefreshOnModeChangeRequired || isRefreshOnNoCurrentAppropriate
}
@ -52,7 +63,8 @@ class SemesterRepository @Inject constructor(
semesterDb.insertSemesters(new.uniqueSubtract(old))
}
suspend fun getCurrentSemester(student: Student, forceRefresh: Boolean = false) = withContext(dispatchers.backgroundThread) {
getSemesters(student, forceRefresh).getCurrentOrLast()
}
suspend fun getCurrentSemester(student: Student, forceRefresh: Boolean = false) =
withContext(dispatchers.backgroundThread) {
getSemesters(student, forceRefresh).getCurrentOrLast()
}
}

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