1
0

Compare commits

...

348 Commits
1.7.3 ... 2.2.1

Author SHA1 Message Date
bcd305bef3 Merge branch 'release/2.2.1' 2023-10-03 01:14:17 +02:00
fc5ad16cb7 Version 2.2.1 2023-10-03 01:14:10 +02:00
c8332a0642 Bump org.sonarsource.scanner.gradle:sonarqube-gradle-plugin (#2321) 2023-10-02 22:49:26 +00:00
3212efe21e Bump com.android.tools.build:gradle from 8.1.1 to 8.1.2 (#2320) 2023-10-02 22:49:05 +00:00
693ce8217d New Crowdin updates (#2313) 2023-10-03 00:48:37 +02:00
2cdd322ed4 Add missing class_id colum in JOIN clause of students with semesters (#2317) 2023-10-02 12:22:02 +02:00
c04b3e40d2 Add negative e-mail validation in school input on support dialog (#2315) 2023-10-02 12:21:04 +02:00
d1d665bbdf Fix student auto selection if there is already active some students logged (#2314) 2023-10-02 12:20:34 +02:00
d70568c446 Merge branch 'release/2.2.0' into develop 2023-09-26 23:13:46 +02:00
1d8378e136 Merge branch 'release/2.2.0' 2023-09-26 23:13:40 +02:00
4a2bf539f0 Version 2.2.0 2023-09-26 23:13:32 +02:00
4d085f8266 New Crowdin updates (#2311) 2023-09-26 21:04:27 +00:00
fca69e7234 Add form dialog to login e-mail support (#2306) 2023-09-26 22:27:08 +02:00
711de0f77f Fix average calculation when there is no real semesters available (#2310) 2023-09-26 22:26:19 +02:00
58d5196ac9 Improve symbol input field (#2312) 2023-09-26 22:25:23 +02:00
26a95ecb99 Auto select students for login (#2307)
* Auto select students for login

* Add sign in icon to sign in button on student select screen
2023-09-26 21:02:36 +02:00
1835446468 Fix password reset related issues (#2308)
* Fix login hint in password reset field

* Don't hide first password reset button

* Change recover button label
2023-09-26 21:01:59 +02:00
4d3b16ec80 Fix password toggle icon tint after clearing error (#2309) 2023-09-26 21:01:25 +02:00
95b4d53fac Add schools API integration (#2302) 2023-09-25 19:44:13 +02:00
0fa197d520 New Crowdin updates (#2303) 2023-09-25 19:43:57 +02:00
646b4a149d Bump about_libraries from 10.8.3 to 10.9.0 (#2304) 2023-09-25 17:43:41 +00:00
afd0c8513a Bump mockk from 1.13.7 to 1.13.8 (#2305) 2023-09-25 17:43:16 +00:00
c4a3da93ca Bump com.huawei.hms:hianalytics from 6.10.0.303 to 6.12.0.300 (#2294) 2023-09-20 21:00:06 +00:00
ff2aa6f195 Bump com.huawei.agconnect:agcp from 1.9.1.300 to 1.9.1.301 (#2297) 2023-09-20 20:59:38 +00:00
1d8d71709f Bump com.huawei.agconnect:agconnect-crash from 1.9.1.300 to 1.9.1.301 (#2298) 2023-09-20 20:49:46 +00:00
aabd7345c1 Bump com.google.firebase:firebase-bom from 32.2.3 to 32.3.1 (#2299) 2023-09-20 20:49:25 +00:00
09d16cf6d8 Bump androidx.annotation:annotation from 1.6.0 to 1.7.0 (#2293) 2023-09-20 20:33:50 +00:00
81d8f7ea48 Bump androidx.lifecycle:lifecycle-livedata-ktx from 2.6.1 to 2.6.2 (#2295) 2023-09-20 20:33:30 +00:00
05a804832b Bump com.google.gms:google-services from 4.3.15 to 4.4.0 (#2300) 2023-09-20 20:33:10 +00:00
db02f0c1e1 Bump com.google.android.gms:play-services-ads from 22.3.0 to 22.4.0 (#2301) 2023-09-20 20:32:56 +00:00
0a40237809 Bump com.github.bastienpaulfr:Treessence from 1.0.5 to 1.1.2 (#2289) 2023-09-04 18:30:02 +00:00
017d46e5db Bump hilt_version from 2.47 to 2.48 (#2290) 2023-09-04 18:13:39 +00:00
8478b8b7ed Bump org.sonarsource.scanner.gradle:sonarqube-gradle-plugin (#2291) 2023-09-04 18:13:24 +00:00
8cc69728aa Bump kotlin_version from 1.9.0 to 1.9.10 (#2281) 2023-09-01 17:29:02 +00:00
c82e6ae95b New Crowdin updates (#2287) 2023-09-01 19:06:48 +02:00
50a177d18c Bump org.jetbrains.kotlinx:kotlinx-serialization-json (#2282) 2023-09-01 17:05:47 +00:00
a77b3d4cd7 Bump com.google.firebase:firebase-crashlytics-gradle from 2.9.8 to 2.9.9 (#2283) 2023-09-01 17:05:29 +00:00
aff56a8311 Bump com.google.firebase:firebase-bom from 32.2.2 to 32.2.3 (#2284) 2023-09-01 17:05:12 +00:00
5238e4d187 Bump com.google.android.gms:play-services-ads from 22.2.0 to 22.3.0 (#2285) 2023-09-01 17:04:57 +00:00
10f9812495 Bump com.android.tools.build:gradle from 8.1.0 to 8.1.1 (#2286) 2023-09-01 17:04:34 +00:00
ab1de323d4 Merge branch 'release/2.1.0' into develop 2023-08-25 00:01:47 +02:00
af346842a3 Merge branch 'release/2.1.0' 2023-08-25 00:01:42 +02:00
8f78324940 Version 2.1.0 2023-08-25 00:01:36 +02:00
3dfc55c4d1 Add admin messages to login screen (#2280) 2023-08-24 11:33:40 +02:00
fbce9e58d0 New Crowdin updates (#2277) 2023-08-23 19:46:53 +02:00
2e2b13384a Try to switch to next school year before it starts (#2278) 2023-08-23 12:24:17 +02:00
533157709b Add option to show empty tiles in the timetable (#2236)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2023-08-22 23:47:12 +02:00
024ca89708 Bump mockk from 1.13.5 to 1.13.7 (#2275) 2023-08-22 21:39:04 +00:00
7d5a29d405 Bump org.gradle.toolchains.foojay-resolver-convention (#2276) 2023-08-22 21:20:45 +00:00
8fbe341607 Bump com.huawei.hms:hianalytics from 6.10.0.302 to 6.10.0.303 (#2272) 2023-08-22 21:20:19 +00:00
e21c17ea99 Bump com.google.firebase:firebase-crashlytics-gradle from 2.9.7 to 2.9.8 (#2270) 2023-08-22 21:20:05 +00:00
c4396036ce Bump com.google.firebase:firebase-bom from 32.2.0 to 32.2.2 (#2271) 2023-08-22 21:19:49 +00:00
722b4e5812 Bump androidx.preference:preference-ktx from 1.2.0 to 1.2.1 (#2274) 2023-08-22 21:19:33 +00:00
74820f9571 New Crowdin updates (#2265) 2023-07-31 21:32:07 +02:00
50326c7a48 Bump androidx.recyclerview:recyclerview from 1.3.0 to 1.3.1 (#2268) 2023-07-31 19:00:37 +00:00
0f129109ba Bump com.android.tools.build:gradle from 8.0.2 to 8.1.0 (#2266) 2023-07-31 19:00:17 +00:00
fc2adff997 Bump androidx.fragment:fragment-ktx from 1.6.0 to 1.6.1 (#2269) 2023-07-31 17:35:38 +00:00
7f6a13a9ee Bump coroutines from 1.7.2 to 1.7.3 (#2267) 2023-07-31 17:35:29 +00:00
64cc24ae60 Add incognito mode in messages (#1970)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2023-07-26 22:17:58 +02:00
91d7ee442e New Crowdin updates (#2257) 2023-07-26 19:37:06 +02:00
b296926423 Timetable widget improvements (#2219) 2023-07-25 21:05:14 +00:00
398bc513fb Bump about_libraries from 10.8.0 to 10.8.3 (#2263) 2023-07-25 10:00:31 +00:00
5b2e2ffb34 Remove tests deprecations (#2260) 2023-07-25 11:37:43 +02:00
e79c5d4d2b Bump hilt_version from 2.46.1 to 2.47 (#2261) 2023-07-24 21:36:06 +00:00
c0161f38c6 Bump org.sonarsource.scanner.gradle:sonarqube-gradle-plugin (#2262) 2023-07-24 21:33:17 +00:00
ef72218906 Bump org.gradle.toolchains.foojay-resolver-convention (#2264) 2023-07-24 21:30:37 +00:00
05741761a2 Bump kotlin_version from 1.8.22 to 1.9.0 (#2255) 2023-07-17 20:08:56 +00:00
86c7de6595 Bump room from 2.5.1 to 2.5.2 (#2250) 2023-07-17 19:15:48 +00:00
88ea753fc6 Bump coroutines from 1.7.1 to 1.7.2 (#2251) 2023-07-17 19:15:34 +00:00
d0819928f3 Bump com.huawei.agconnect:agconnect-crash from 1.9.0.300 to 1.9.1.300 (#2252) 2023-07-17 19:15:21 +00:00
8564e12b01 Bump com.huawei.agconnect:agcp from 1.9.0.300 to 1.9.1.300 (#2254) 2023-07-17 19:15:06 +00:00
29a36aaf6e Bump com.huawei.hms:hianalytics from 6.10.0.301 to 6.10.0.302 (#2253) 2023-07-17 18:11:57 +00:00
dbe608f2dd Bump about_libraries from 10.7.0 to 10.8.0 (#2249) 2023-07-17 17:54:26 +00:00
bb79b33b6d Bump com.google.android.gms:play-services-ads from 22.1.0 to 22.2.0 (#2256) 2023-07-17 17:53:58 +00:00
6e7c12a118 Bump com.google.firebase:firebase-crashlytics-gradle from 2.9.5 to 2.9.7 (#2258) 2023-07-17 17:53:38 +00:00
03cd3aeab7 Bump com.google.firebase:firebase-bom from 32.1.0 to 32.2.0 (#2259) 2023-07-17 17:53:21 +00:00
df8849639b Bump org.sonarsource.scanner.gradle:sonarqube-gradle-plugin (#2242) 2023-06-14 10:56:32 +00:00
8913b22a20 Bump org.sonarsource.scanner.gradle:sonarqube-gradle-plugin (#2237) 2023-06-08 23:25:46 +00:00
f20ffe44d5 Bump kotlin_version from 1.8.21 to 1.8.22 (#2238) 2023-06-08 23:24:27 +00:00
2f749a690b Bump androidx.fragment:fragment-ktx from 1.5.7 to 1.6.0 (#2239) 2023-06-08 23:18:23 +00:00
ae1951bf58 Merge branch 'release/2.0.8' into develop 2023-06-01 23:43:12 +02:00
391f38485d Merge branch 'release/2.0.8' 2023-06-01 23:43:06 +02:00
fecd5c707d Version 2.0.8 2023-06-01 23:43:01 +02:00
fa44295d59 New Crowdin updates (#2231) 2023-06-01 23:37:01 +02:00
5306044173 Add custom register host field on login screen (#2221) 2023-06-01 23:22:10 +02:00
c1b86674c2 Merge branch 'release/2.0.7' into develop 2023-06-01 11:00:01 +02:00
fd482777e8 Merge branch 'release/2.0.7' 2023-06-01 10:59:55 +02:00
d4ae0d56d6 Version 2.0.7 2023-06-01 10:59:50 +02:00
63487249b8 New Crowdin updates (#2211) 2023-06-01 10:31:42 +02:00
1bc0f2d214 Add character limit to attendance excuse content (#2222) 2023-06-01 10:30:50 +02:00
41bde45731 Bump androidx.viewpager2:viewpager2 from 1.1.0-beta01 to 1.1.0-beta02 (#2227) 2023-05-31 15:19:25 +00:00
556f42195b Bump com.android.tools.build:gradle from 8.0.1 to 8.0.2 (#2228) 2023-05-31 15:18:55 +00:00
06fd7b0c36 Bump com.google.firebase:firebase-bom from 32.0.0 to 32.1.0 (#2225) 2023-05-31 15:18:30 +00:00
db4e4d8cef Bump com.huawei.hms:hianalytics from 6.10.0.300 to 6.10.0.301 (#2224) 2023-05-31 15:18:07 +00:00
48e4a9fec5 Bump org.sonarsource.scanner.gradle:sonarqube-gradle-plugin (#2223) 2023-05-31 15:17:48 +00:00
70333737cf Bump androidx.activity:activity-ktx from 1.7.1 to 1.7.2 (#2226) 2023-05-31 15:16:42 +00:00
3096fa1538 Bump about_libraries from 10.6.3 to 10.7.0 (#2214) 2023-05-24 21:50:17 +00:00
19ed121466 Bump io.coil-kt:coil from 2.3.0 to 2.4.0 (#2215) 2023-05-24 21:32:28 +00:00
e7733bfa2a Bump com.google.android.gms:play-services-ads from 22.0.0 to 22.1.0 (#2216) 2023-05-24 21:31:38 +00:00
b9b464ea9b Merge branch 'release/2.0.6' into develop 2023-05-23 16:26:43 +02:00
cc46b3b124 Merge branch 'release/2.0.6' 2023-05-23 16:26:36 +02:00
092e86b621 Version 2.0.6 2023-05-23 16:26:31 +02:00
c170614461 Add R8 rule for Wulkanowy SDK (#2220) 2023-05-23 14:09:48 +02:00
6ce8e00ebf Merge branch 'release/2.0.5' into develop 2023-05-23 02:37:55 +02:00
c40cdf88ad Merge branch 'release/2.0.5' 2023-05-23 02:37:43 +02:00
4c1fe233c7 Version 2.0.5 2023-05-23 02:37:38 +02:00
aca88b57e0 Add r8 rules for HMS SDK (#2217) 2023-05-23 02:16:42 +02:00
a603c12625 Merge branch 'release/2.0.4' into develop 2023-05-22 17:10:09 +02:00
5c440010e2 Merge branch 'release/2.0.4' 2023-05-22 17:10:02 +02:00
4920317573 Version 2.0.4 2023-05-22 17:09:57 +02:00
9466482893 Add foojay-resolver and update dependencies (#2212) 2023-05-18 14:14:14 +00:00
48bcf581cf Bump org.jetbrains.kotlinx:kotlinx-serialization-json (#2209) 2023-05-15 18:36:50 +00:00
8a7b7103eb Bump coroutines from 1.7.0 to 1.7.1 (#2207) 2023-05-15 18:36:26 +00:00
ea312c3e12 Bump androidx.core:core-ktx from 1.10.0 to 1.10.1 (#2208) 2023-05-15 17:13:02 +00:00
5b0fe2c006 Bump ru.cian:huawei-publish-gradle-plugin from 1.3.5 to 1.4.0 (#2185) 2023-05-14 19:28:49 +00:00
a06add070e Bump com.android.tools.build:gradle from 7.4.2 to 8.0.1 (#2187) 2023-05-14 18:20:56 +00:00
dce491bffe Bump hilt_version from 2.45 to 2.46.1 (#2205) 2023-05-14 17:28:29 +00:00
adf418cc68 Fix delete user homework button visibility (#2204) 2023-05-13 10:44:09 +02:00
defcfec971 Merge branch 'release/2.0.3' into develop 2023-05-12 22:59:59 +02:00
d08f195968 Merge branch 'release/2.0.3' 2023-05-12 22:59:45 +02:00
1e9a6a5c42 Version 2.0.3 2023-05-12 22:59:40 +02:00
cc752ab0ad New Crowdin updates (#2201) 2023-05-12 22:45:50 +02:00
f2faa7e8b7 Fix button color in high priority admin message (#2202) 2023-05-12 22:45:24 +02:00
030fe8c218 Bump coroutines from 1.6.4 to 1.7.0 (#2186) 2023-05-12 04:45:15 +00:00
c33b309cf0 Bump org.robolectric:robolectric from 4.10 to 4.10.2 (#2188) 2023-05-12 04:34:48 +00:00
a0af55825d Bump about_libraries from 10.6.2 to 10.6.3 (#2189) 2023-05-12 04:34:32 +00:00
cb8303f33d Bump com.google.android.material:material from 1.8.0 to 1.9.0 (#2191) 2023-05-12 04:34:14 +00:00
54fbd56b73 Bump com.google.firebase:firebase-bom from 31.5.0 to 32.0.0 (#2190) 2023-05-12 04:33:56 +00:00
70f50cd51b Merge branch 'release/2.0.2' into develop 2023-05-12 00:46:02 +02:00
88c38c4a8d Merge branch 'release/2.0.2' 2023-05-12 00:45:55 +02:00
b8ac72c247 Version 2.0.2 2023-05-12 00:45:48 +02:00
cbef160ada New Crowdin updates (#2193) 2023-05-12 00:41:53 +02:00
e77894bf3e Merge branch 'release/2.0.1' into develop 2023-05-12 00:21:36 +02:00
9697a39464 Merge branch 'release/2.0.1' 2023-05-12 00:21:28 +02:00
5a2622871f Version 2.0.1 2023-05-12 00:21:24 +02:00
52218e800c Add auth dialog (#2198)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2023-05-11 21:45:20 +00:00
3fdd47c221 Fix ime overlaping message content (#2199) 2023-05-11 16:44:10 +02:00
d8f71f48f3 Merge branch 'release/2.0.0' into develop 2023-05-07 23:40:31 +02:00
18dbbba328 Merge branch 'release/2.0.0' 2023-05-07 23:40:25 +02:00
d99c93ec05 Version 2.0.0 2023-05-07 23:40:18 +02:00
f8431d7ad6 SDK update (#2168) 2023-05-07 23:21:59 +02:00
b195fda026 Bump androidx.activity:activity-ktx from 1.7.0 to 1.7.1 (#2181) 2023-05-01 22:02:43 +00:00
b1a5a77559 Bump androidx.fragment:fragment-ktx from 1.5.6 to 1.5.7 (#2176) 2023-05-01 21:50:48 +00:00
4be6663752 Bump com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter (#2175) 2023-05-01 21:50:34 +00:00
f7fa89638a Bump com.huawei.agconnect:agconnect-crash from 1.8.1.300 to 1.9.0.300 (#2178) 2023-05-01 21:32:49 +00:00
4fedb74005 Bump kotlin_version from 1.8.20 to 1.8.21 (#2182) 2023-05-01 21:32:02 +00:00
56d7e94946 Bump com.huawei.agconnect:agcp from 1.8.1.300 to 1.9.0.300 (#2179) 2023-05-01 21:31:46 +00:00
b2af5ed57d Bump com.squareup.okhttp3:logging-interceptor from 4.10.0 to 4.11.0 (#2177) 2023-05-01 21:30:39 +00:00
b1d22843b5 Bump androidx.core:core-splashscreen from 1.0.0 to 1.0.1 (#2180) 2023-05-01 21:29:42 +00:00
623f0339e6 Bump com.fredporciuncula:flow-preferences from 1.9.0 to 1.9.1 (#2172) 2023-04-21 05:21:17 +00:00
1f30cc1f90 Bump mockk from 1.13.4 to 1.13.5 (#2170) 2023-04-21 05:12:24 +00:00
de8b38dd9c Bump org.robolectric:robolectric from 4.9.2 to 4.10 (#2169) 2023-04-21 05:12:06 +00:00
e7054bb5b9 Bump com.google.firebase:firebase-bom from 31.4.0 to 31.5.0 (#2173) 2023-04-21 05:11:45 +00:00
6978ad11eb Bump com.google.firebase:firebase-crashlytics-gradle from 2.9.4 to 2.9.5 (#2174) 2023-04-21 05:11:17 +00:00
327e61bbdd Bump about_libraries from 10.6.1 to 10.6.2 (#2166) 2023-04-10 16:29:50 +00:00
2c94347668 Bump androidx.core:core-ktx from 1.9.0 to 1.10.0 (#2167) 2023-04-10 16:29:14 +00:00
bce2c39ccc Disable error dialog for admin messages (#2165) 2023-04-06 10:13:34 +02:00
8752607433 Use segmented toggle buttons instead of option group in grades statistics (#2164) 2023-04-06 01:29:46 +02:00
c67d2d767d Set error tint to password toggle icon when error occured (#2163) 2023-04-06 01:28:47 +02:00
253e55f70e New Crowdin updates (#2159) 2023-04-05 22:33:01 +02:00
a7cf54897a Bump kotlin_version from 1.8.10 to 1.8.20 (#2160) 2023-04-05 20:32:06 +00:00
cb914fe32b Bump com.google.android.gms:play-services-ads from 21.5.0 to 22.0.0 (#2161) 2023-04-05 20:30:56 +00:00
7aa65e98ce Bump com.android.tools:desugar_jdk_libs from 2.0.2 to 2.0.3 (#2162) 2023-04-05 20:30:27 +00:00
8d2d7922f9 Fix collapse garde subject when grade is unread (#2158) 2023-03-29 22:23:42 +02:00
bb7e927065 Migrate to material3 (#1660)
Co-authored-by: Rafał Borcz <RafalBO99@outlook.com>
Co-authored-by: doteq <doteeqq@gmail.com>
Co-authored-by: Bartosz Bieniek <itsbk20@gmail.com>
2023-03-29 22:14:29 +02:00
349307b6a3 Remove deprecated code (#2157) 2023-03-29 09:50:36 +02:00
9981f458d0 Bump androidx.fragment:fragment-ktx from 1.5.5 to 1.5.6 (#2154) 2023-03-29 02:39:18 +00:00
a1b9ae2826 Bump work_manager from 2.8.0 to 2.8.1 (#2152) 2023-03-29 02:35:15 +00:00
9afb38d5e2 Bump room from 2.5.0 to 2.5.1 (#2150) 2023-03-29 02:33:48 +00:00
97a7b34b99 Bump com.google.firebase:firebase-bom from 31.2.3 to 31.4.0 (#2151) 2023-03-29 02:27:20 +00:00
6398c9a097 Bump io.coil-kt:coil from 2.2.2 to 2.3.0 (#2153) 2023-03-29 02:26:39 +00:00
597d1d763e Bump androidx.activity:activity-ktx from 1.6.1 to 1.7.0 (#2155) 2023-03-29 02:25:50 +00:00
2203956228 Bump androidx.lifecycle:lifecycle-livedata-ktx from 2.6.0 to 2.6.1 (#2156) 2023-03-29 02:25:26 +00:00
b3c6e2004b Make GradeAverageProvider reactive to configuration changes (#1698)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2023-03-18 15:10:12 +01:00
a2a31df98e Fix crash on deserialize parcelable array (#2149) 2023-03-18 00:41:45 +01:00
060bab46e2 Bump androidx.recyclerview:recyclerview from 1.2.1 to 1.3.0 (#2145) 2023-03-10 18:14:50 +00:00
a350a167f3 Bump androidx.lifecycle:lifecycle-livedata-ktx from 2.5.1 to 2.6.0 (#2146) 2023-03-10 18:14:31 +00:00
cc2079f4c9 New Crowdin updates (#2138) 2023-03-08 21:36:57 +01:00
d778c99bbb Merge branch 'hotfix/1.9.2' into develop 2023-03-08 21:29:39 +01:00
c4672b8de9 Merge branch 'hotfix/1.9.2' 2023-03-08 21:28:57 +01:00
1b40e339b7 Version 1.9.2 2023-03-08 21:28:48 +01:00
ee5ac46493 Show invalid symbol message when nonexistent symbol entered (#2143) 2023-03-08 09:11:25 +01:00
ef398f7409 Add missing override to RemoteConfigHelper.initialize() 2023-03-07 22:29:37 +01:00
5331bf90cd Use user agent template from firebase remote config (#2139)
* Use user agent template from firebase remote config

* Improve base class usage, activation refactor
2023-03-07 18:10:20 +01:00
9ce1ba75b2 Bump com.google.firebase:firebase-bom from 31.2.2 to 31.2.3 (#2141) 2023-03-06 21:46:37 +00:00
fba86930fe Bump com.android.tools.build:gradle from 7.4.1 to 7.4.2 (#2140) 2023-03-06 21:46:18 +00:00
a495fcbc5f Fix saving attachements with same url but from different messages (#2137) 2023-03-02 18:01:48 +01:00
f11354dd35 Fix marking message as read (#2102) 2023-03-01 22:59:44 +01:00
12a54278fc New Crowdin updates (#2109) 2023-03-01 22:53:42 +01:00
6ddaeb99da Bump com.google.firebase:firebase-bom from 31.2.1 to 31.2.2 (#2125) 2023-03-01 21:29:48 +00:00
9ae2ffe7ae Bump androidx.test:runner from 1.5.1 to 1.5.2 (#2133) 2023-03-01 21:17:58 +00:00
5b0e47b1c5 Bump org.sonarsource.scanner.gradle:sonarqube-gradle-plugin (#2127) 2023-03-01 21:14:29 +00:00
3e09a1dcee Bump com.fredporciuncula:flow-preferences from 1.8.0 to 1.9.0 (#2126) 2023-03-01 21:14:08 +00:00
63bd5f95cb Bump about_libraries from 10.5.2 to 10.6.1 (#2130) 2023-03-01 21:02:04 +00:00
531c7592b2 Bump org.jetbrains.kotlinx:kotlinx-serialization-json (#2132) 2023-03-01 21:00:51 +00:00
3d28168749 Bump com.huawei.agconnect:agcp from 1.8.0.300 to 1.8.1.300 (#2131) 2023-03-01 20:59:36 +00:00
0c2fd1d2db Bump androidx.annotation:annotation from 1.5.0 to 1.6.0 (#2134) 2023-03-01 20:58:55 +00:00
811f839949 Bump androidx.test.ext:junit from 1.1.4 to 1.1.5 (#2135) 2023-03-01 20:58:33 +00:00
ea26a6c1c9 Bump com.huawei.agconnect:agconnect-crash from 1.8.0.300 to 1.8.1.300 (#2136) 2023-03-01 20:57:36 +00:00
ac446e4f91 Bump hilt_version from 2.44.2 to 2.45 (#2120) 2023-02-24 09:09:18 +00:00
78ae23df68 Bump kotlin_version from 1.8.0 to 1.8.10 (#2117) 2023-02-17 22:57:25 +00:00
d21e4afad2 Bump com.android.tools:desugar_jdk_libs from 1.1.8 to 2.0.2 (#2118) 2023-02-17 22:46:31 +00:00
6f819bcb80 Bump com.google.android.gms:play-services-ads from 21.4.0 to 21.5.0 (#2116) 2023-02-17 22:44:57 +00:00
4d237d3672 Bump com.android.tools.build:gradle from 7.4.0 to 7.4.1 (#2115) 2023-02-17 22:44:37 +00:00
af6d5c3063 Bump work_manager from 2.7.1 to 2.8.0 (#2119) 2023-02-17 22:44:16 +00:00
87b8989dc8 Bump com.google.firebase:firebase-crashlytics-gradle from 2.9.2 to 2.9.4 (#2121) 2023-02-17 22:40:26 +00:00
2760318f3d Bump androidx.appcompat:appcompat from 1.6.0 to 1.6.1 (#2122) 2023-02-17 22:40:06 +00:00
6596f3226b Bump com.google.firebase:firebase-bom from 31.2.0 to 31.2.1 (#2123) 2023-02-17 22:39:48 +00:00
22dd16d278 Bump mockk from 1.13.3 to 1.13.4 (#2112) 2023-01-30 15:53:30 +00:00
d1b198222d Bump material from 1.7.0 to 1.8.0 (#2113) 2023-01-30 15:52:36 +00:00
277c3c7f0b Bump google-services from 4.3.14 to 4.3.15 (#2110) 2023-01-29 17:55:16 +00:00
f7d12670e7 Bump firebase-bom from 31.1.1 to 31.2.0 (#2111) 2023-01-29 17:54:58 +00:00
32d6b4a7a6 Add menu order settings (#1924) 2023-01-14 17:06:47 +01:00
6df3f22c7d Bump room from 2.4.3 to 2.5.0 (#2105) 2023-01-14 15:30:53 +00:00
95cf521f63 Bump gradle from 7.3.1 to 7.4.0 (#2106) 2023-01-14 15:21:22 +00:00
ef9e4b7ad9 Bump appcompat from 1.5.1 to 1.6.0 (#2107) 2023-01-14 15:14:15 +00:00
ac4a822930 Bump agconnect-crash from 1.7.3.302 to 1.8.0.300 (#2104) 2023-01-14 15:13:34 +00:00
89678c2276 Bump agcp from 1.7.3.302 to 1.8.0.300 (#2108) 2023-01-14 15:13:06 +00:00
e1bffabf10 Fix marking message as read (#2102) 2023-01-14 15:48:58 +01:00
af8bb53c17 Bump junit from 1.1.4 to 1.1.5 (#2098) 2023-01-10 07:28:02 +00:00
0306e38130 Bump runner from 1.5.1 to 1.5.2 (#2099) 2023-01-10 07:17:58 +00:00
84812fb048 Bump hianalytics from 6.9.0.301 to 6.9.1.200 (#2100) 2023-01-10 07:17:38 +00:00
2293e8c1e6 Bump huawei-publish-gradle-plugin from 1.3.4 to 1.3.5 (#2101) 2023-01-10 07:17:17 +00:00
368028c6f4 Bump kotlin_version from 1.7.21 to 1.8.0 (#2092) 2023-01-06 14:11:53 +00:00
13650b3e0d Merge branch 'release/1.9.1' into develop 2023-01-05 23:01:51 +01:00
4bb1198735 Merge branch 'release/1.9.1' 2023-01-05 23:01:43 +01:00
3eb74da945 Version 1.9.1 2023-01-05 23:01:38 +01:00
5161fdd543 Add missing info to student selection email reports (#2096) 2023-01-05 21:47:53 +00:00
377e0c3a0d Fix school name text wrap in dashboard and student details (#2095) 2023-01-05 22:42:35 +01:00
1c9860091a Bump robolectric from 4.9.1 to 4.9.2 (#2093) 2023-01-03 07:45:25 +00:00
a383f7409d Merge branch 'release/1.9.0' into develop 2023-01-01 21:57:53 +01:00
9a8fb593c0 Merge branch 'release/1.9.0' 2023-01-01 21:57:47 +01:00
f4c6e0ad1b Version 1.9.0 2023-01-01 21:57:39 +01:00
b30b7c3318 New Crowdin updates (#2068) 2023-01-01 21:52:46 +01:00
897eac050a Refactor student selection screen (#2087) 2023-01-01 20:26:32 +01:00
83974b6550 Fix NPE when trying to remove a message from mailbox that doesn't match any student (#2090) 2023-01-01 20:21:28 +01:00
7efd106658 Update date in LICENSE file (#2089) 2023-01-01 12:16:09 +01:00
9cedab979c Bump robolectric from 4.9 to 4.9.1 (#2088) 2022-12-26 20:07:25 +00:00
510e2d5b88 Fix html entities parsing in school announcements (#2086) 2022-12-25 04:40:58 +01:00
63d6a0b325 Merge branch 'hotfix/1.8.3' into develop 2022-12-21 13:30:26 +01:00
da0943b319 Merge branch 'hotfix/1.8.3' 2022-12-21 13:29:38 +01:00
67875b1a9a Version 1.8.3 2022-12-21 13:29:32 +01:00
aa3d7e37fc Automatically show current student mailbox only when there is only one mailbox available (#2085)
* Automatically show current student mailbox only when there is only one mailbox for this student available

* Fallback to 'unknown' mailbox key if there is no matching mailbox to message
2022-12-21 13:15:28 +01:00
ede5914d70 Automatically show current student mailbox only when there is only one mailbox available (#2085)
* Automatically show current student mailbox only when there is only one mailbox for this student available

* Fallback to 'unknown' mailbox key if there is no matching mailbox to message
2022-12-21 00:31:29 +01:00
09c968f273 Merge branch 'hotfix/1.8.2' into develop 2022-12-21 00:15:02 +01:00
345b580601 Merge branch 'hotfix/1.8.2' 2022-12-21 00:07:57 +01:00
61240777cf Version 1.8.2 2022-12-21 00:00:03 +01:00
7588345b6d Bump sdk 2022-12-20 23:35:47 +01:00
2fa26c37a9 Revert "Fix app name in french (#2072)"
This reverts commit 277ffd22be.
2022-12-20 21:55:46 +01:00
c34c63c128 Add support for new ADFS light instances (#2084)
* Update known symbols

* Update resman host details

* Add adfslight from tomaszowmazowiecki

* Bump sdk to 1.8.2-SNAPSHOT

* Add migration 54 with tests

* Close db in migration tests

* Run tests workflow on every pull request
2022-12-20 16:06:55 +01:00
a26dadb224 Fix a typo in excuse message subject (#2071) 2022-12-20 15:59:36 +01:00
277ffd22be Fix app name in french (#2072) 2022-12-20 15:59:36 +01:00
f1479d489b Bump play-services-ads from 21.3.0 to 21.4.0 (#2083) 2022-12-20 12:28:26 +00:00
fba4e85311 Bump firebase-bom from 31.1.0 to 31.1.1 (#2079) 2022-12-14 21:52:41 +00:00
4a5991ade4 Bump hianalytics from 6.9.0.300 to 6.9.0.301 (#2080) 2022-12-14 21:43:04 +00:00
a735c378f1 Bump fragment-ktx from 1.5.4 to 1.5.5 (#2077) 2022-12-14 21:42:21 +00:00
217ebfc549 Fix app name in french (#2072) 2022-12-14 22:41:57 +01:00
df5155f1c7 Fix a typo in excuse message subject (#2071) 2022-12-05 15:45:07 +01:00
b93c0222a2 Fix conference details strings (#2070) 2022-12-05 15:44:30 +01:00
083ca34f1b Bump hianalytics from 6.8.0.300 to 6.9.0.300 (#2069) 2022-12-05 13:32:46 +00:00
5d5dfd4eb4 Bump mockk from 1.13.2 to 1.13.3 (#2067) 2022-12-01 18:38:59 +00:00
429fdfa4a0 Update project to Android SDK 33 (#2011) 2022-12-01 19:02:25 +01:00
302d723cfb Suppress menu deprecations (#2031) 2022-12-01 18:14:28 +01:00
8f50ee82b3 Change fakelog to https (#2063) 2022-11-28 19:50:14 +01:00
9dc1220496 Bump about_libraries from 10.5.1 to 10.5.2 (#2066) 2022-11-28 18:36:14 +00:00
ae39bd94e5 Bump hilt_version from 2.44.1 to 2.44.2 (#2058) 2022-11-22 20:42:38 +00:00
85ce23845f Bump firebase-bom from 31.0.3 to 31.1.0 (#2057) 2022-11-21 20:51:23 +00:00
890d60811b Bump agcp from 1.7.3.301 to 1.7.3.302 (#2059) 2022-11-21 20:51:07 +00:00
49e68f5c8b Bump agconnect-crash from 1.7.3.300 to 1.7.3.302 (#2060) 2022-11-21 20:50:47 +00:00
1df4679db8 Merge branch 'release/1.8.1' into develop 2022-11-20 00:05:47 +01:00
e03aae2d56 Merge branch 'release/1.8.1' 2022-11-20 00:05:38 +01:00
9c60ce688b Version 1.8.1 2022-11-20 00:05:34 +01:00
fdce2cf477 Improve error handling in horizontal tile on dashboard (#2053) 2022-11-19 22:50:51 +01:00
650cbd5a10 Add info about optional ads in README (#2054) 2022-11-19 14:11:26 +01:00
b160367744 Add support for reversed student name mailbox matching (#2051)
* Add support for reversed student name mailbox matching

* Add additional log stmt to mailbox matching in all mailbox load

* Revert changes in mapper
2022-11-19 08:52:35 +01:00
6c115fb915 Fallback to subject name from timetable when attendance item doesn't have it (#2052)
* Fallback to subject name from timetable when attendance item doesn't have it

* Fix tests

* Add some unit tests
2022-11-18 16:32:04 +01:00
7a408899df Merge branch 'release/1.8.0' into develop 2022-11-16 20:31:18 +01:00
4bce35f810 Merge branch 'release/1.8.0' 2022-11-16 20:31:09 +01:00
2d83218f61 Version 1.8.0 2022-11-16 20:31:02 +01:00
d3e276d6fc New Crowdin updates (#2049)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2022-11-16 20:13:48 +01:00
51a1097bb4 Add mailbox chooser to messages (#2002) 2022-11-16 13:46:47 +01:00
db4f172fb8 Fix unread status in sent messages (#2048) 2022-11-16 12:54:55 +01:00
4d49e956b8 Bump junit from 1.1.3 to 1.1.4 (#2043) 2022-11-14 20:48:12 +00:00
b8296ac02f Bump kotlin_version from 1.7.20 to 1.7.21 (#2042) 2022-11-14 20:31:26 +00:00
d6385e8cdd Bump core from 1.4.0 to 1.5.0 (#2045) 2022-11-14 20:31:02 +00:00
885319a885 Bump hilt_version from 2.44 to 2.44.1 (#2044) 2022-11-14 18:36:20 +00:00
fded5007c1 Bump firebase-bom from 31.0.2 to 31.0.3 (#2041) 2022-11-14 18:22:25 +00:00
66ff14f719 Bump agcp from 1.7.3.300 to 1.7.3.301 (#2046) 2022-11-14 18:21:35 +00:00
1257dc63d3 Bump runner from 1.4.0 to 1.5.1 (#2047) 2022-11-14 18:21:17 +00:00
50b6d380b6 Fix unexpected error in support ad when no internet (#2030) 2022-11-02 16:44:05 +01:00
62b7d42a73 New Crowdin updates (#1966) 2022-11-01 20:57:05 +01:00
21fe209246 Bump firebase-bom from 31.0.1 to 31.0.2 (#2032) 2022-11-01 19:51:28 +00:00
02cd4e4e06 Bump sonarqube-gradle-plugin from 3.4.0.2513 to 3.5.0.2730 (#2033) 2022-11-01 19:50:59 +00:00
86fe2b61cb Bump agcp from 1.7.2.300 to 1.7.3.300 (#2034) 2022-11-01 19:50:37 +00:00
4113bd9b53 Bump agconnect-crash from 1.7.2.300 to 1.7.3.300 (#2035) 2022-11-01 19:50:17 +00:00
d924902dac Bump CircularImageView from 4.2.0 to 4.3.0 (#2036) 2022-11-01 19:49:56 +00:00
b269360ecb Langs placement in README adjustments (#2029) 2022-10-30 03:00:39 +01:00
ffd5addadb Add Crowdin badges to README (#2025) 2022-10-28 11:10:35 +02:00
c5e2b18695 Fix SSL certificate out-of-date detection (#2028) 2022-10-28 11:10:05 +02:00
515a3973b7 Use text color, font face and red dot to differentiate unread messages (#2027) 2022-10-28 11:09:38 +02:00
7bee10d5ce Hide room view in timetable item if there is no room in API (#2026) 2022-10-28 11:08:40 +02:00
22a4f509dc Add installation id to crashlytics and bug report emails (#2024) 2022-10-27 12:41:33 +02:00
3925a6261b Add missing CS and SK links in German README (#2018) 2022-10-26 22:27:37 +02:00
49b383fbe5 Bump firebase-bom from 31.0.0 to 31.0.1 (#2019) 2022-10-26 18:22:53 +00:00
4a484dc2ce Bump fragment-ktx from 1.5.3 to 1.5.4 (#2020) 2022-10-26 18:22:34 +00:00
a14c4b489b Bump material from 1.6.1 to 1.7.0 (#2022) 2022-10-26 18:22:16 +00:00
e91cd18804 Bump firebase-bom from 30.5.0 to 31.0.0 (#2013) 2022-10-18 19:41:15 +00:00
4c24363599 Bump about_libraries from 10.5.0 to 10.5.1 (#2012) 2022-10-18 19:40:28 +00:00
e20c232f8f Bump kotlinx-serialization-json from 1.4.0 to 1.4.1 (#2014) 2022-10-18 19:39:54 +00:00
1f11eea9b5 Bump gradle from 7.3.0 to 7.3.1 (#2015) 2022-10-18 19:39:36 +00:00
42f9a00e8c Bump play-services-ads from 21.2.0 to 21.3.0 (#2016) 2022-10-18 19:39:16 +00:00
ad487e680c Fix grade weight text truncation in grade dialog with large font set (#2009) 2022-10-05 22:25:09 +02:00
3f431022a5 Bump about_libraries from 10.4.0 to 10.5.0 (#2005) 2022-10-04 08:08:21 +00:00
cd037f0ce0 Bump kotlin_version from 1.7.10 to 1.7.20 (#2003) 2022-10-04 07:58:58 +00:00
37f7f21a03 Reorder action buttons on the message preview screen to hide the forward button in overflow menu (#2000) 2022-10-04 09:51:30 +02:00
c653039590 Bump coil from 2.2.1 to 2.2.2 (#2004) 2022-10-04 07:50:05 +00:00
95a90a7a79 Bump mockk from 1.13.1 to 1.13.2 (#2006) 2022-10-04 07:49:41 +00:00
4dc80595ac Bump robolectric from 4.8.2 to 4.9 (#2007) 2022-10-04 07:49:22 +00:00
8114a2376e Bump gradle from 7.2.2 to 7.3.0 (#1985) 2022-09-28 21:43:45 +00:00
a523850216 Bump annotation from 1.4.0 to 1.5.0 (#1998) 2022-09-28 23:34:06 +02:00
354f51dd70 Fix student average calculation error in grade statistics (#1981)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2022-09-28 23:33:05 +02:00
b271c12ebc Bump hilt_version from 2.43.2 to 2.44 (#1994) 2022-09-28 20:28:31 +00:00
8ca41b5ba3 Bump hianalytics from 6.7.0.300 to 6.8.0.300 (#1995) 2022-09-28 20:28:01 +00:00
edbe45332a Bump mockk from 1.12.8 to 1.13.1 (#1996) 2022-09-28 20:27:43 +00:00
1bbd249275 Bump fragment-ktx from 1.5.2 to 1.5.3 (#1997) 2022-09-28 20:25:58 +00:00
5148ff291b Bump google-services from 4.3.13 to 4.3.14 (#1992) 2022-09-21 20:59:41 +00:00
a1dc00af42 Bump agcp from 1.7.1.300 to 1.7.2.300 (#1989) 2022-09-21 20:49:36 +00:00
f1db993fee Bump agconnect-crash from 1.7.1.300 to 1.7.2.300 (#1990) 2022-09-21 20:40:36 +00:00
4f0519552e Bump firebase-crashlytics-gradle from 2.9.1 to 2.9.2 (#1988) 2022-09-21 20:39:29 +00:00
3625c5c518 Bump firebase-bom from 30.4.1 to 30.5.0 (#1991) 2022-09-21 20:39:08 +00:00
afbfb9761f Bump mockk from 1.12.7 to 1.12.8 (#1986) 2022-09-21 20:38:55 +00:00
a5c636853a Bump coil from 2.2.0 to 2.2.1 (#1973) 2022-09-14 11:19:05 +00:00
d5d45ed1ba Bump play-services-ads from 21.1.0 to 21.2.0 (#1972) 2022-09-14 11:18:29 +00:00
d3f869c6c2 Bump firebase-bom from 30.4.0 to 30.4.1 (#1971) 2022-09-14 11:18:09 +00:00
46c29c438e Bump appcompat from 1.5.0 to 1.5.1 (#1975) 2022-09-14 11:17:19 +00:00
73a7255d3a Bump firebase-bom from 30.3.2 to 30.4.0 (#1968) 2022-09-05 19:49:30 +00:00
c7af85e0e1 Merge branch 'release/1.7.5' into develop 2022-09-02 21:31:39 +02:00
afc16e3d17 Merge branch 'release/1.7.5' 2022-09-02 21:31:31 +02:00
59f6f5c212 Version 1.7.5 2022-09-02 21:31:27 +02:00
86f8763e69 Display lesson number in attendance notification if subject is blank (#1965) 2022-09-02 21:30:30 +02:00
157becb017 Fix matching mailboxes when there is more than one space between words (#1964) 2022-09-02 20:19:19 +02:00
83ca9a7060 Merge branch 'release/1.7.4' into develop 2022-09-01 17:57:30 +02:00
1033be4503 Merge branch 'release/1.7.4' 2022-09-01 17:57:24 +02:00
e67066f3ae Version 1.7.4 2022-09-01 17:57:20 +02:00
bc22808b0e Add support for matching last kingergarten semester if there is no any current (#1962) 2022-09-01 17:48:46 +02:00
e05abb3539 Fix showing empty view in grade details when there is no grades (#1963) 2022-09-01 17:48:03 +02:00
6153c7b97d Add support for match mailboxes with more different names (#1961) 2022-09-01 14:55:00 +02:00
e574e5e2ec Merge branch 'release/1.7.3' into develop 2022-08-31 19:31:39 +02:00
471 changed files with 27871 additions and 4947 deletions

View File

@ -13,10 +13,10 @@ jobs:
environment: google-play
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v2
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 11
java-version: 17
- uses: actions/cache@v3
with:
path: |
@ -49,10 +49,10 @@ jobs:
environment: app-gallery
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v2
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 11
java-version: 17
- uses: actions/cache@v3
with:
path: |

View File

@ -19,10 +19,10 @@ jobs:
environment: app-center
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v2
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 11
java-version: 17
- uses: actions/cache@v3
with:
path: |
@ -89,10 +89,10 @@ jobs:
if: github.event_name != 'pull_request_target'
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v2
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 11
java-version: 17
- uses: actions/cache@v3
with:
path: |

View File

@ -2,10 +2,12 @@ name: Tests
on:
push:
branches: [ master, develop ]
branches:
- master
- develop
- 'hotfix/**'
tags: [ '*' ]
pull_request:
branches: [ master, develop ]
jobs:
@ -17,10 +19,10 @@ jobs:
- uses: fkirc/skip-duplicate-actions@master
- uses: actions/checkout@v3
- uses: gradle/wrapper-validation-action@v1
- uses: actions/setup-java@v2
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 11
java-version: 17
- uses: actions/cache@v3
with:
path: |
@ -43,10 +45,10 @@ jobs:
- uses: fkirc/skip-duplicate-actions@master
- uses: actions/checkout@v3
- uses: gradle/wrapper-validation-action@v1
- uses: actions/setup-java@v2
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 11
java-version: 17
- uses: actions/cache@v3
with:
path: |
@ -69,10 +71,10 @@ jobs:
- uses: fkirc/skip-duplicate-actions@master
- uses: actions/checkout@v3
- uses: gradle/wrapper-validation-action@v1
- uses: actions/setup-java@v2
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 11
java-version: 17
- uses: actions/cache@v3
with:
path: |

1
.gitignore vendored
View File

@ -119,3 +119,4 @@ Thumbs.db
app/src/release/agconnect-services.json
app/src/release/agconnect-credentials.json
.idea/deploymentTargetDropDown.xml
.idea/kotlinc.xml

View File

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2022 Wulkanowy
Copyright 2023 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

@ -1,18 +1,13 @@
[English version of README](README.en.md)
[Deutsche Version von README](README.de.md)
[Polska wersja README](README.md)
[Slovenská verzia README](README.sk.md)
Česká verze / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
# Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=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/)
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl)
Neoficiální klient deníku VULCAN UONET+ pro žáka a rodiče
@ -39,7 +34,7 @@ Neoficiální klient deníku VULCAN UONET+ pro žáka a rodiče
* podpora více účtů s možností přejmenování žáků
* tmavý a černý (AMOLED) motiv
* offline režim
* žádné reklamy
* volitelné reklamy na podporu projektu
## Stáhnout
@ -57,7 +52,7 @@ Aktuální verzi si můžete stáhnout z Google Play, F-Droid nebo Huawei AppGal
Můžete si také stáhnout [vývojovou verzi](https://wulkanowy.github.io/#download), která zahrnuje nové funkce připravované pro příští vydání
## Postaveno s
## Postaveno s pomocí
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)

View File

@ -1,14 +1,13 @@
[Polska wersja README](README.md)
[English version of README](README.en.md)
[Česká verze](README.cs.md) / Deutsche Version / [English version](README.en.md) / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
# Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=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/)
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl)
Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre Eltern
@ -22,7 +21,7 @@ Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre
* Prozentsatz der Anwesenheit
* Prüfungen
* Stundenplan
* Unterricht abgeschlossen
* abgeschlossene Unterrichtsstunden
* Nachrichten
* Hausaufgaben
* Anmerkungen
@ -35,7 +34,7 @@ Inoffizieller Android VULCAN UONET+ Registrierungsclient für Schüler und ihre
* Unterstützung für mehrere Konten mit der Möglichkeit, den Namen des Schülers zu ändern
* dunkles und schwarzes (AMOLED) Thema
* Offline-Modus
* keine Werbung
* optionale Werbungen, die es uns ermöglichen das Projekt zu unterstützen
## Herunterladen

View File

@ -1,18 +1,13 @@
[Polska wersja README](README.md)
[Deutsche Version von README](README.de.md)
[Česká verze README](README.cs.md)
[Slovenská verzia README](README.sk.md)
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / English version / [Polska wersja](README.md) / [Slovenská verzia](README.sk.md)
# Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=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/)
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl)
Unofficial android VULCAN UONET+ register client for both students and their parents
@ -39,7 +34,7 @@ Unofficial android VULCAN UONET+ register client for both students and their par
* support for multiple accounts with the ability to rename students
* dark and black (AMOLED) theme
* offline mode
* no ads
* optional ads which allow to support the project
## Download

View File

@ -1,18 +1,13 @@
[English version of README](README.en.md)
[Deutsche Version von README](README.de.md)
[Česká verze README](README.cs.md)
[Slovenská verzia README](README.sk.md)
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / Polska wersja / [Slovenská verzia](README.sk.md)
# Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=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/)
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl)
Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
@ -39,7 +34,7 @@ Nieoficjalny klient dziennika VULCAN UONET+ dla ucznia i rodzica
* obsługa wielu kont wraz z możliwością zmiany nazwy ucznia
* ciemny i czarny (AMOLED) motyw
* tryb offline
* brak reklam
* opcjonalne reklamy umożliwiające wsparcie projektu
## Pobierz

View File

@ -1,18 +1,13 @@
[English version of README](README.en.md)
[Deutsche Version von README](README.de.md)
[Polska wersja README](README.md)
[Česká verze README](README.cs.md)
[Česká verze](README.cs.md) / [Deutsche Version](README.de.md) / [English version](README.en.md) / [Polska wersja](README.md) / Slovenská verzia
# Wulkanowy
[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/wulkanowy/wulkanowy/Tests/develop?style=flat-square)](https://github.com/wulkanowy/wulkanowy/actions)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/wulkanowy/wulkanowy/test.yml?branch=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/)
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github&style=flat-square)](https://github.com/wulkanowy/wulkanowy/releases)
[![Crowdin](https://badges.crowdin.net/wulkanowy2/localized.svg)](https://translate.wulkanowy.net.pl)
Neoficiálny klient denníka VULCAN UONET+ pre žiaka a rodičov
@ -39,7 +34,7 @@ Neoficiálny klient denníka VULCAN UONET+ pre žiaka a rodičov
* podpora viacerých účtov s možnosťou premenovania žiakov
* tmavý a čierny (AMOLED) motív
* offline režim
* žiadne reklamy
* voliteľné reklamy na podporu projektu
## Stiahnuť
@ -57,7 +52,7 @@ Aktuálnu verziu si môžete stiahnuť z Google Play, F-Droid alebo Huawei AppGa
Môžete si tiež stiahnuť [vývojovú verziu](https://wulkanowy.github.io/#download), ktorá zahrňuje nové funkcie pripravované pre budúce vydanie
## Postavené s
## Postavené s pomocou
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)

View File

@ -1,8 +1,11 @@
import com.github.triplet.gradle.androidpublisher.ReleaseStatus
import ru.cian.huawei.publish.ReleaseNote
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.devtools.ksp'
apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
@ -10,37 +13,29 @@ apply plugin: 'com.github.triplet.play'
apply plugin: 'ru.cian.huawei-publish'
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
apply plugin: 'com.huawei.agconnect'
apply plugin: 'kotlin-kapt'
apply from: 'jacoco.gradle'
apply from: 'sonarqube.gradle'
apply from: 'hooks.gradle'
android {
namespace 'io.github.wulkanowy'
compileSdkVersion 32
compileSdk 33
defaultConfig {
applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 32
versionCode 112
versionName "1.7.3"
targetSdkVersion 33
versionCode 133
versionName "2.2.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
manifestPlaceholders = [
firebase_enabled: project.hasProperty("enableFirebase"),
admob_project_id: ""
]
javaCompileOptions {
annotationProcessorOptions {
arguments += [
"room.schemaLocation": "$projectDir/schemas".toString(),
"room.incremental" : "true"
]
}
}
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
buildConfigField "String", "DASHBOARD_TILE_AD_ID", "null"
@ -73,6 +68,7 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
buildConfigField "String", "SCHOOLS_BASE_URL", '"https://schools.wulkanowy.net.pl"'
}
debug {
minifyEnabled false
@ -82,10 +78,11 @@ android {
versionNameSuffix "-dev"
ext.enableCrashlytics = project.hasProperty("enableFirebase")
buildConfigField "String", "MESSAGES_BASE_URL", "\"https://messages.wulkanowy.net.pl\""
buildConfigField "String", "SCHOOLS_BASE_URL", '"https://schools.wulkanowy.net.pl"'
}
}
flavorDimensions "platform"
flavorDimensions += "platform"
productFlavors {
hms {
@ -124,20 +121,20 @@ android {
}
}
testOptions.unitTests {
includeAndroidResources = true
testOptions {
unitTests.includeAndroidResources = true
// workaround HMS test errors https://github.com/robolectric/robolectric/issues/2750
all { jvmArgs '-noverify' }
unitTests.all { jvmArgs '-noverify' }
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "11"
jvmTarget = "17"
freeCompilerArgs += ["-opt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
}
@ -156,13 +153,16 @@ android {
kapt {
correctErrorTypes true
}
ksp {
arg("room.schemaLocation", "$projectDir/schemas".toString())
}
play {
defaultToAppBundles = false
track = 'production'
// releaseStatus = com.github.triplet.gradle.androidpublisher.ReleaseStatus.IN_PROGRESS
// userFraction = 0.05d
updatePriority = 5
releaseStatus = ReleaseStatus.IN_PROGRESS
userFraction = 0.01d
updatePriority = 3
enabled.set(false)
}
@ -171,54 +171,60 @@ huaweiPublish {
hmsRelease {
credentialsPath = "$rootDir/app/src/release/agconnect-credentials.json"
buildFormat = "aab"
deployType = "draft"
deployType = "publish"
releaseNotes = [
new ReleaseNote(
"pl-PL",
"$projectDir/src/main/play/release-notes/pl-PL/default.txt"
)
]
}
}
}
ext {
work_manager = "2.7.1"
work_manager = "2.8.1"
android_hilt = "1.0.0"
room = "2.4.3"
room = "2.5.2"
chucker = "3.5.2"
mockk = "1.12.7"
coroutines = "1.6.4"
mockk = "1.13.8"
coroutines = "1.7.3"
}
dependencies {
implementation "io.github.wulkanowy:sdk:1.7.3"
implementation 'io.github.wulkanowy:sdk:2.2.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.8'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.0"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
implementation "androidx.core:core-ktx:1.8.0"
implementation 'androidx.core:core-splashscreen:1.0.0'
implementation "androidx.activity:activity-ktx:1.5.1"
implementation "androidx.appcompat:appcompat:1.5.0"
implementation "androidx.fragment:fragment-ktx:1.5.2"
implementation "androidx.annotation:annotation:1.4.0"
implementation "androidx.core:core-ktx:1.10.1"
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation "androidx.activity:activity-ktx:1.7.2"
implementation "androidx.appcompat:appcompat:1.6.1"
implementation "androidx.fragment:fragment-ktx:1.6.1"
implementation "androidx.annotation:annotation:1.7.0"
implementation "androidx.preference:preference-ktx:1.2.0"
implementation "androidx.recyclerview:recyclerview:1.2.1"
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
implementation "androidx.preference:preference-ktx:1.2.1"
implementation "androidx.recyclerview:recyclerview:1.3.1"
implementation "androidx.viewpager2:viewpager2:1.1.0-beta02"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.2.0"
implementation "com.google.android.material:material:1.6.1"
implementation "com.google.android.material:material:1.9.0"
implementation "com.github.wulkanowy:material-chips-input:2.3.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation 'com.github.lopspower:CircularImageView:4.2.0'
implementation 'com.github.lopspower:CircularImageView:4.3.0'
implementation "androidx.work:work-runtime-ktx:$work_manager"
playImplementation "androidx.work:work-gcm:$work_manager"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"
implementation "androidx.room:room-runtime:$room"
implementation "androidx.room:room-ktx:$room"
kapt "androidx.room:room-compiler:$room"
ksp "androidx.room:room-compiler:$room"
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
@ -229,28 +235,31 @@ dependencies {
implementation "com.github.YarikSOffice:lingver:1.3.0"
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.10.0"
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.11.0"
implementation "com.jakewharton.timber:timber:5.0.1"
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation 'com.github.bastienpaulfr:Treessence:1.0.5'
implementation 'com.github.bastienpaulfr:Treessence:1.1.2'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation "io.coil-kt:coil:2.2.0"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation "io.coil-kt:coil:2.4.0"
implementation "io.github.wulkanowy:AppKillerManager:3.0.1"
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.8.0'
implementation 'com.fredporciuncula:flow-preferences:1.9.1'
implementation 'org.apache.commons:commons-text:1.10.0'
playImplementation platform('com.google.firebase:firebase-bom:30.3.2')
playImplementation platform('com.google.firebase:firebase-bom:32.3.1')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation 'com.google.firebase:firebase-crashlytics:'
playImplementation 'com.google.firebase:firebase-config-ktx'
playImplementation 'com.google.android.play:core:1.10.3'
playImplementation 'com.google.android.play:core-ktx:1.8.1'
playImplementation 'com.google.android.gms:play-services-ads:21.1.0'
playImplementation 'com.google.android.gms:play-services-ads:22.4.0'
playImplementation "com.google.android.play:integrity:1.2.0"
hmsImplementation 'com.huawei.hms:hianalytics:6.7.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.7.1.300'
hmsImplementation 'com.huawei.hms:hianalytics:6.12.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.301'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
@ -263,17 +272,17 @@ dependencies {
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testImplementation 'org.robolectric:robolectric:4.8.2'
testImplementation "androidx.test:runner:1.4.0"
testImplementation "androidx.test.ext:junit:1.1.3"
testImplementation "androidx.test:core:1.4.0"
testImplementation 'org.robolectric:robolectric:4.10.3'
testImplementation "androidx.test:runner:1.5.2"
testImplementation "androidx.test.ext:junit:1.1.5"
testImplementation "androidx.test:core:1.5.0"
testImplementation "androidx.room:room-testing:$room"
testImplementation "com.google.dagger:hilt-android-testing:$hilt_version"
kaptTest "com.google.dagger:hilt-android-compiler:$hilt_version"
androidTestImplementation "androidx.test:core:1.4.0"
androidTestImplementation "androidx.test:runner:1.4.0"
androidTestImplementation "androidx.test.ext:junit:1.1.3"
androidTestImplementation "androidx.test:core:1.5.0"
androidTestImplementation "androidx.test:runner:1.5.2"
androidTestImplementation "androidx.test.ext:junit:1.1.5"
androidTestImplementation "io.mockk:mockk-android:$mockk"
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
}

View File

@ -1,5 +1,6 @@
# General
-dontobfuscate
-ignorewarnings
#Config for wulkanowy
@ -24,3 +25,18 @@
#Config for Material Components
-keep class com.google.android.material.tabs.** { *; }
#Config for HMS SDK
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keep class com.huawei.agconnect.**{*;}
-keep class com.huawei.hianalytics.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}
#Config for Wulkanowy SDK
-keep,allowobfuscation,allowshrinking class retrofit2.Response

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

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/colorPrimary" />
<background android:drawable="@color/colorIcon" />
<foreground android:drawable="@drawable/ic_launcher_foreground_dev" />
</adaptive-icon>
<monochrome android:drawable="@drawable/ic_launcher_foreground_dev_mono" />
</adaptive-icon>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/colorPrimary" />
<foreground android:drawable="@drawable/ic_launcher_foreground_dev" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -8,15 +8,7 @@ import javax.inject.Singleton
@Suppress("UNUSED_PARAMETER")
class AnalyticsHelper @Inject constructor() {
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
// do nothing
}
fun setCurrentScreen(activity: Activity, name: String?) {
// do nothing
}
fun popCurrentScreen(name: String?) {
// do nothing
}
fun logEvent(name: String, vararg params: Pair<String, Any?>) = Unit
fun setCurrentScreen(activity: Activity, name: String?) = Unit
fun popCurrentScreen(name: String?) = Unit
}

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.utils
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class IntegrityHelper @Inject constructor() {
@Suppress("UNUSED_PARAMETER")
fun getIntegrityToken(requestId: String): String? = null
}

View File

@ -0,0 +1,7 @@
package io.github.wulkanowy.utils
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class RemoteConfigHelper @Inject constructor() : BaseRemoteConfigHelper()

View File

@ -3,26 +3,38 @@ package io.github.wulkanowy.utils
import android.app.Activity
import android.content.Context
import android.os.Bundle
import com.huawei.agconnect.crash.AGConnectCrash
import com.huawei.hms.analytics.HiAnalytics
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.data.repositories.PreferencesRepository
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AnalyticsHelper @Inject constructor(
@ApplicationContext private val context: Context
@ApplicationContext private val context: Context,
preferencesRepository: PreferencesRepository,
appInfo: AppInfo,
) {
private val analytics by lazy { HiAnalytics.getInstance(context) }
private val connectCrash by lazy { AGConnectCrash.getInstance() }
init {
if (!appInfo.isDebug) {
connectCrash.setUserId(preferencesRepository.installationId)
}
}
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
Bundle().apply {
params.forEach {
if (it.second == null) return@forEach
when (it.second) {
is String, is String? -> putString(it.first, it.second as String)
is Int, is Int? -> putInt(it.first, it.second as Int)
is Boolean, is Boolean? -> putBoolean(it.first, it.second as Boolean)
params.forEach { (key, value) ->
if (value == null) return@forEach
when (value) {
is String -> putString(key, value)
is Int -> putInt(key, value)
is Boolean -> putBoolean(key, value)
}
}
analytics.onEvent(name, this)

View File

@ -2,7 +2,8 @@ package io.github.wulkanowy.utils
import android.util.Log
import com.huawei.agconnect.crash.AGConnectCrash
import fr.bipi.tressence.base.FormatterPriorityTree
import fr.bipi.treessence.base.FormatterPriorityTree
import fr.bipi.treessence.common.StackTraceRecorder
class CrashLogTree : FormatterPriorityTree(Log.VERBOSE) {
@ -22,16 +23,10 @@ class CrashLogExceptionTree : FormatterPriorityTree(Log.ERROR, ExceptionFilter)
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
if (skipLog(priority, tag, message, t)) return
// Disabled due to a bug in the Huawei library
/*connectCrash.setCustomKey("priority", priority)
connectCrash.setCustomKey("tag", tag.orEmpty())
connectCrash.setCustomKey("message", message)
if (t != null) {
connectCrash.recordException(t)
} else {
connectCrash.recordException(StackTraceRecorder(format(priority, tag, message)))
}*/
}
}
}

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.utils
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class IntegrityHelper @Inject constructor() {
@Suppress("UNUSED_PARAMETER")
fun getIntegrityToken(requestId: String): String? = null
}

View File

@ -0,0 +1,7 @@
package io.github.wulkanowy.utils
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class RemoteConfigHelper @Inject constructor() : BaseRemoteConfigHelper()

View File

@ -8,7 +8,8 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<queries>
<intent>
@ -36,13 +37,14 @@
<application
android:name=".WulkanowyApp"
android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules"
android:enableOnBackInvokedCallback="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="false"
android:theme="@style/WulkanowyTheme"
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
tools:ignore="DataExtractionRules,UnusedAttribute">
<activity
android:name=".ui.modules.splash.SplashActivity"
android:exported="true"
@ -70,7 +72,7 @@
android:name=".ui.modules.message.send.SendMessageActivity"
android:configChanges="orientation|screenSize"
android:label="@string/send_message_title"
android:theme="@style/WulkanowyTheme.MessageSend"
android:theme="@style/WulkanowyTheme.NoActionBar"
android:windowSoftInputMode="adjustResize" />
<activity
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"

View File

@ -50,5 +50,9 @@
{
"displayName": "Tomasz F.",
"githubUsername": "Pengwius"
},
{
"displayName": "Antoni Paduch",
"githubUsername": "janAte1"
}
]

View File

@ -6,7 +6,7 @@ import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import com.yariksoffice.lingver.Lingver
import dagger.hilt.android.HiltAndroidApp
import fr.bipi.tressence.file.FileLoggerTree
import fr.bipi.treessence.file.FileLoggerTree
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.ui.base.ThemeManager
import io.github.wulkanowy.utils.*
@ -34,11 +34,15 @@ class WulkanowyApp : Application(), Configuration.Provider {
@Inject
lateinit var adsHelper: AdsHelper
@Inject
lateinit var remoteConfigHelper: RemoteConfigHelper
override fun onCreate() {
super.onCreate()
initializeAppLanguage()
themeManager.applyDefaultTheme()
adsHelper.initialize()
remoteConfigHelper.initialize()
initLogging()
}

View File

@ -14,12 +14,13 @@ import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import io.github.wulkanowy.data.api.AdminMessageService
import io.github.wulkanowy.data.api.SchoolsService
import io.github.wulkanowy.data.db.AppDatabase
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.serialization.ExperimentalSerializationApi
import io.github.wulkanowy.utils.RemoteConfigHelper
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
@ -36,10 +37,11 @@ internal class DataModule {
@Singleton
@Provides
fun provideSdk(chuckerInterceptor: ChuckerInterceptor) =
fun provideSdk(chuckerInterceptor: ChuckerInterceptor, remoteConfig: RemoteConfigHelper) =
Sdk().apply {
androidVersion = android.os.Build.VERSION.RELEASE
buildTag = android.os.Build.MODEL
userAgentTemplate = remoteConfig.userAgentTemplate
setSimpleHttpLogger { Timber.d(it) }
// for debug only
@ -79,22 +81,31 @@ internal class DataModule {
.readTimeout(30, TimeUnit.SECONDS)
.build()
@OptIn(ExperimentalSerializationApi::class)
@Singleton
@Provides
fun provideRetrofit(
fun provideAdminMessageService(
okHttpClient: OkHttpClient,
json: Json,
appInfo: AppInfo
): Retrofit = Retrofit.Builder()
): AdminMessageService = Retrofit.Builder()
.baseUrl(appInfo.messagesBaseUrl)
.client(okHttpClient)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.build()
.create()
@Singleton
@Provides
fun provideAdminMessageService(retrofit: Retrofit): AdminMessageService = retrofit.create()
fun provideSchoolsService(
okHttpClient: OkHttpClient,
json: Json,
appInfo: AppInfo,
): SchoolsService = Retrofit.Builder()
.baseUrl(appInfo.schoolsBaseUrl)
.client(okHttpClient)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.build()
.create()
@Singleton
@Provides

View File

@ -49,8 +49,8 @@ fun <T, U> Resource<T>.mapData(block: (T) -> U) = when (this) {
fun <T> Flow<Resource<T>>.logResourceStatus(name: String, showData: Boolean = false) = onEach {
val description = when (it) {
is Resource.Loading -> "started"
is Resource.Intermediate -> "intermediate data received" + if (showData) " (data: `${it.data}`)" else ""
is Resource.Loading -> "started"
is Resource.Success -> "success" + if (showData) " (data: `${it.data}`)" else ""
is Resource.Error -> "exception occurred: ${it.error}"
}
@ -148,7 +148,7 @@ inline fun <ResultType, RequestType, T> networkBoundResource(
crossinline saveFetchResult: suspend (old: ResultType, new: RequestType) -> Unit,
crossinline onFetchFailed: (Throwable) -> Unit = { },
crossinline shouldFetch: (ResultType) -> Boolean = { true },
crossinline mapResult: (ResultType) -> T
crossinline mapResult: (ResultType) -> T,
) = flow {
emit(Resource.Loading())

View File

@ -0,0 +1,14 @@
package io.github.wulkanowy.data.api
import io.github.wulkanowy.data.pojos.IntegrityRequest
import io.github.wulkanowy.data.pojos.LoginEvent
import retrofit2.http.Body
import retrofit2.http.POST
import javax.inject.Singleton
@Singleton
interface SchoolsService {
@POST("/log/loginEvent")
suspend fun logLoginEvent(@Body request: IntegrityRequest<LoginEvent>)
}

View File

@ -47,6 +47,10 @@ import javax.inject.Singleton
AutoMigration(from = 44, to = 45),
AutoMigration(from = 46, to = 47),
AutoMigration(from = 47, to = 48),
AutoMigration(from = 51, to = 52),
AutoMigration(from = 54, to = 55, spec = Migration55::class),
AutoMigration(from = 55, to = 56),
AutoMigration(from = 56, to = 57, spec = Migration57::class),
],
version = AppDatabase.VERSION_SCHEMA,
exportSchema = true
@ -55,7 +59,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
const val VERSION_SCHEMA = 51
const val VERSION_SCHEMA = 57
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(),
@ -105,6 +109,8 @@ abstract class AppDatabase : RoomDatabase() {
Migration49(),
Migration50(),
Migration51(),
Migration53(),
Migration54(),
)
fun newInstance(

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.data.db
import androidx.room.TypeConverter
import io.github.wulkanowy.data.enums.MessageType
import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.utils.toTimestamp
import kotlinx.serialization.SerializationException
@ -68,4 +69,9 @@ class Converters {
@TypeConverter
fun stringToDestination(destination: String): Destination = json.decodeFromString(destination)
@TypeConverter
fun messageTypesToString(types: List<MessageType>): String = json.encodeToString(types)
@TypeConverter
fun stringToMessageTypes(text: String): List<MessageType> = json.decodeFromString(text)
}

View File

@ -22,4 +22,4 @@ abstract class AdminMessageDao : BaseDao<AdminMessage> {
deleteAll(oldMessages)
insertAll(newMessages)
}
}
}

View File

@ -3,12 +3,16 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Mailbox
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@Dao
interface MailboxDao : BaseDao<Mailbox> {
@Query("SELECT * FROM Mailboxes WHERE userLoginId = :userLoginId ")
suspend fun loadAll(userLoginId: Int): List<Mailbox>
@Query("SELECT * FROM Mailboxes WHERE email = :email")
suspend fun loadAll(email: String): List<Mailbox>
@Query("SELECT * FROM Mailboxes WHERE email = :email AND symbol = :symbol AND schoolId = :schoolId")
fun loadAll(email: String, symbol: String, schoolId: String): Flow<List<Mailbox>>
}

View File

@ -16,4 +16,7 @@ interface MessagesDao : BaseDao<Message> {
@Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
fun loadAll(mailboxKey: String, folder: Int): Flow<List<Message>>
@Query("SELECT * FROM Messages WHERE email = :email AND folder_id = :folder ORDER BY date DESC")
fun loadAll(folder: Int, email: String): Flow<List<Message>>
}

View File

@ -1,8 +1,9 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.*
import androidx.room.OnConflictStrategy.ABORT
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentName
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import javax.inject.Singleton
@ -11,7 +12,7 @@ import javax.inject.Singleton
@Dao
abstract class StudentDao {
@Insert(onConflict = ABORT)
@Insert(onConflict = OnConflictStrategy.ABORT)
abstract suspend fun insertAll(student: List<Student>): List<Long>
@Delete
@ -20,6 +21,9 @@ abstract class StudentDao {
@Update(entity = Student::class)
abstract suspend fun update(studentNickAndAvatar: StudentNickAndAvatar)
@Update(entity = Student::class)
abstract suspend fun update(studentName: StudentName)
@Query("SELECT * FROM Students WHERE is_current = 1")
abstract suspend fun loadCurrent(): Student?
@ -30,12 +34,12 @@ abstract class StudentDao {
abstract suspend fun loadAll(): List<Student>
@Transaction
@Query("SELECT * FROM Students")
abstract suspend fun loadStudentsWithSemesters(): List<StudentWithSemesters>
@Query("SELECT * FROM Students JOIN Semesters ON Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id")
abstract suspend fun loadStudentsWithSemesters(): Map<Student, List<Semester>>
@Transaction
@Query("SELECT * FROM Students WHERE id = :id")
abstract suspend fun loadStudentWithSemestersById(id: Long): StudentWithSemesters?
@Query("SELECT * FROM Students JOIN Semesters ON Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id WHERE Students.id = :id")
abstract suspend fun loadStudentWithSemestersById(id: Long): Map<Student, List<Semester>>
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
abstract suspend fun updateCurrent(id: Long)

View File

@ -13,4 +13,7 @@ interface TimetableDao : BaseDao<Timetable> {
@Query("SELECT * FROM Timetable 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<Timetable>>
@Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun load(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): List<Timetable>
}

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import io.github.wulkanowy.data.enums.MessageType
import kotlinx.serialization.Serializable
@Serializable
@ -33,7 +34,8 @@ data class AdminMessage(
val priority: String,
val type: String,
@ColumnInfo(name = "types", defaultValue = "[]")
val types: List<MessageType> = emptyList(),
@ColumnInfo(name = "is_dismissible")
val isDismissible: Boolean = false

View File

@ -22,6 +22,7 @@ data class Exam(
val subject: String,
@Deprecated("not available anymore")
val group: String,
val type: String,

View File

@ -1,20 +1,27 @@
package io.github.wulkanowy.data.db.entities
import android.os.Parcelable
import androidx.room.Entity
import androidx.room.PrimaryKey
import kotlinx.parcelize.Parcelize
@Parcelize
@Entity(tableName = "Mailboxes")
data class Mailbox(
@PrimaryKey
val globalKey: String,
val email: String,
val symbol: String,
val schoolId: String,
val fullName: String,
val userName: String,
val userLoginId: Int,
val studentName: String,
val schoolNameShort: String,
val type: MailboxType,
)
) : java.io.Serializable, Parcelable
enum class MailboxType {
STUDENT,

View File

@ -9,6 +9,9 @@ import java.time.Instant
@Entity(tableName = "Messages")
data class Message(
@ColumnInfo(name = "email")
val email: String,
@ColumnInfo(name = "message_global_key")
val messageGlobalKey: String,
@ -29,6 +32,12 @@ data class Message(
var unread: Boolean,
@ColumnInfo(name = "read_by")
val readBy: Int?,
@ColumnInfo(name = "unread_by")
val unreadBy: Int?,
@ColumnInfo(name = "has_attachments")
val hasAttachments: Boolean
) : Serializable {

View File

@ -2,16 +2,14 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
@Entity(tableName = "MessageAttachments")
@Entity(
tableName = "MessageAttachments",
primaryKeys = ["message_global_key", "url", "filename"],
)
data class MessageAttachment(
@PrimaryKey
@ColumnInfo(name = "real_id")
val realId: Int,
@ColumnInfo(name = "message_global_key")
val messageGlobalKey: String,

View File

@ -19,6 +19,9 @@ data class Student(
@ColumnInfo(name = "scrapper_base_url")
val scrapperBaseUrl: String,
@ColumnInfo(name = "scrapper_domain_suffix", defaultValue = "")
val scrapperDomainSuffix: String,
@ColumnInfo(name = "mobile_base_url")
val mobileBaseUrl: String,

View File

@ -0,0 +1,18 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
@Entity
data class StudentName(
@ColumnInfo(name = "student_name")
val studentName: String
) : Serializable {
@PrimaryKey
var id: Long = 0
}

View File

@ -1,13 +1,8 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.Embedded
import androidx.room.Relation
import java.io.Serializable
data class StudentWithSemesters(
@Embedded
val student: Student,
@Relation(parentColumn = "student_id", entityColumn = "student_id")
val semesters: List<Semester>
) : Serializable

View File

@ -0,0 +1,57 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration53 : Migration(52, 53) {
override fun migrate(database: SupportSQLiteDatabase) {
createMailboxTable(database)
recreateMessagesTable(database)
}
private fun createMailboxTable(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Mailboxes")
database.execSQL(
"""
CREATE TABLE IF NOT EXISTS `Mailboxes` (
`globalKey` TEXT NOT NULL,
`email` TEXT NOT NULL,
`symbol` TEXT NOT NULL,
`schoolId` TEXT NOT NULL,
`fullName` TEXT NOT NULL,
`userName` TEXT NOT NULL,
`studentName` TEXT NOT NULL,
`schoolNameShort` TEXT NOT NULL,
`type` TEXT NOT NULL,
PRIMARY KEY(`globalKey`)
)""".trimIndent()
)
}
private fun recreateMessagesTable(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Messages")
database.execSQL(
"""
CREATE TABLE IF NOT EXISTS `Messages` (
`email` TEXT NOT NULL,
`message_global_key` TEXT NOT NULL,
`mailbox_key` TEXT NOT NULL,
`message_id` INTEGER NOT NULL,
`correspondents` TEXT NOT NULL,
`subject` TEXT NOT NULL,
`date` INTEGER NOT NULL,
`folder_id` INTEGER NOT NULL,
`unread` INTEGER NOT NULL,
`read_by` INTEGER,
`unread_by` INTEGER,
`has_attachments` INTEGER NOT NULL,
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`is_notified` INTEGER NOT NULL,
`content` TEXT NOT NULL,
`sender` TEXT,
`recipients` TEXT
)""".trimIndent()
)
}
}

View File

@ -0,0 +1,26 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration54 : Migration(53, 54) {
override fun migrate(database: SupportSQLiteDatabase) {
migrateResman(database)
removeTomaszowMazowieckiStudents(database)
}
private fun migrateResman(database: SupportSQLiteDatabase) {
database.execSQL("""
UPDATE Students SET
scrapper_base_url = 'https://vulcan.net.pl',
login_type = 'ADFSLightScoped',
symbol = 'rzeszowprojekt'
WHERE scrapper_base_url = 'https://resman.pl'
""".trimIndent())
}
private fun removeTomaszowMazowieckiStudents(database: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Students WHERE symbol = 'tomaszowmazowiecki'")
}
}

View File

@ -0,0 +1,17 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.DeleteColumn
import androidx.room.migration.AutoMigrationSpec
import androidx.sqlite.db.SupportSQLiteDatabase
@DeleteColumn(
tableName = "MessageAttachments",
columnName = "real_id",
)
class Migration55 : AutoMigrationSpec {
override fun onPostMigrate(db: SupportSQLiteDatabase) {
db.execSQL("DELETE FROM Messages")
db.execSQL("DELETE FROM MessageAttachments")
}
}

View File

@ -0,0 +1,10 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.DeleteColumn
import androidx.room.migration.AutoMigrationSpec
@DeleteColumn(
tableName = "AdminMessages",
columnName = "type",
)
class Migration57 : AutoMigrationSpec

View File

@ -0,0 +1,9 @@
package io.github.wulkanowy.data.enums
enum class MessageType {
GENERAL_MESSAGE,
DASHBOARD_MESSAGE,
LOGIN_MESSAGE,
PASS_RESET_MESSAGE,
ERROR_OVERRIDE,
}

View File

@ -0,0 +1,11 @@
package io.github.wulkanowy.data.enums
enum class TimetableGapsMode(val value: String) {
NO_GAPS("no_gaps"),
BETWEEN_LESSONS("between"),
BETWEEN_AND_BEFORE_LESSONS("before_and_between");
companion object {
fun getByValue(value: String) = entries.find { it.value == value } ?: BETWEEN_LESSONS
}
}

View File

@ -3,17 +3,22 @@ package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.sdk.pojo.Attendance as SdkAttendance
import io.github.wulkanowy.sdk.pojo.AttendanceSummary as SdkAttendanceSummary
fun List<SdkAttendance>.mapToEntities(semester: Semester) = map {
fun List<SdkAttendance>.mapToEntities(semester: Semester, lessons: List<Timetable>) = map {
Attendance(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
timeId = it.timeId,
number = it.number,
subject = it.subject,
subject = it.subject.ifBlank {
lessons.find { lesson ->
lesson.date == it.date && lesson.number == it.number
}?.subject.orEmpty()
},
name = it.name,
presence = it.presence,
absence = it.absence,

View File

@ -10,9 +10,9 @@ fun List<SdkConference>.mapToEntities(semester: Semester) = map {
diaryId = semester.diaryId,
agenda = it.agenda,
conferenceId = it.id,
date = it.dateZoned.toInstant(),
date = it.date.toInstant(),
presentOnConference = it.presentOnConference,
subject = it.subject,
title = it.title
subject = it.topic,
title = it.place,
)
}

View File

@ -11,7 +11,7 @@ fun List<SdkExam>.mapToEntities(semester: Semester) = map {
date = it.date,
entryDate = it.entryDate,
subject = it.subject,
group = it.group,
group = "",
type = it.type,
description = it.description,
teacher = it.teacher,

View File

@ -10,9 +10,11 @@ fun List<SdkMailbox>.mapToEntities(student: Student) = map {
globalKey = it.globalKey,
fullName = it.fullName,
userName = it.userName,
userLoginId = student.userLoginId,
studentName = it.studentName,
schoolNameShort = it.schoolNameShort,
type = MailboxType.valueOf(it.type.name),
email = student.email,
symbol = student.symbol,
schoolId = student.schoolSymbol,
)
}

View File

@ -2,21 +2,36 @@ package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.*
import io.github.wulkanowy.sdk.pojo.MailboxType
import timber.log.Timber
import io.github.wulkanowy.sdk.pojo.Message as SdkMessage
import io.github.wulkanowy.sdk.pojo.MessageAttachment as SdkMessageAttachment
import io.github.wulkanowy.sdk.pojo.Recipient as SdkRecipient
fun List<SdkMessage>.mapToEntities(mailbox: Mailbox) = map {
fun List<SdkMessage>.mapToEntities(
student: Student,
mailbox: Mailbox?,
allMailboxes: List<Mailbox>
): List<Message> = map {
Message(
messageGlobalKey = it.globalKey,
mailboxKey = mailbox.globalKey,
mailboxKey = mailbox?.globalKey ?: allMailboxes.find { box ->
box.fullName == it.mailbox
}?.globalKey.let { mailboxKey ->
if (mailboxKey == null) {
Timber.e("Can't find ${it.mailbox} in $allMailboxes")
"unknown"
} else mailboxKey
},
email = student.email,
messageId = it.id,
correspondents = it.correspondents,
subject = it.subject.trim(),
date = it.dateZoned.toInstant(),
date = it.date.toInstant(),
folderId = it.folderId,
unread = it.unread,
hasAttachments = it.hasAttachments
unreadBy = it.unreadBy,
readBy = it.readBy,
hasAttachments = it.hasAttachments,
).apply {
content = it.content.orEmpty()
}
@ -25,7 +40,6 @@ fun List<SdkMessage>.mapToEntities(mailbox: Mailbox) = map {
fun List<SdkMessageAttachment>.mapToEntities(messageGlobalKey: String) = map {
MessageAttachment(
messageGlobalKey = messageGlobalKey,
realId = it.url.hashCode(),
url = it.url,
filename = it.filename
)

View File

@ -9,7 +9,7 @@ import io.github.wulkanowy.sdk.pojo.Token as SdkToken
fun List<SdkDevice>.mapToEntities(student: Student) = map {
MobileDevice(
userLoginId = student.userLoginId,
date = it.createDateZoned.toInstant(),
date = it.createDate.toInstant(),
deviceId = it.id,
name = it.name
)

View File

@ -0,0 +1,90 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.pojos.*
import java.time.Instant
import io.github.wulkanowy.sdk.pojo.RegisterStudent as SdkRegisterStudent
import io.github.wulkanowy.sdk.pojo.RegisterUser as SdkRegisterUser
fun SdkRegisterUser.mapToPojo(password: String?) = RegisterUser(
email = email,
login = login,
password = password,
scrapperBaseUrl = scrapperBaseUrl,
loginMode = loginMode,
loginType = loginType,
symbols = symbols.map { registerSymbol ->
RegisterSymbol(
symbol = registerSymbol.symbol,
error = registerSymbol.error,
hebeBaseUrl = registerSymbol.hebeBaseUrl,
keyId = registerSymbol.keyId,
privatePem = registerSymbol.privatePem,
userName = registerSymbol.userName,
schools = registerSymbol.schools.map {
RegisterUnit(
userLoginId = it.userLoginId,
schoolId = it.schoolId,
schoolName = it.schoolName,
schoolShortName = it.schoolShortName,
parentIds = it.parentIds,
studentIds = it.studentIds,
employeeIds = it.employeeIds,
error = it.error,
students = it.subjects
.filterIsInstance<SdkRegisterStudent>()
.map { registerSubject ->
RegisterStudent(
studentId = registerSubject.studentId,
studentName = registerSubject.studentName,
studentSecondName = registerSubject.studentSecondName,
studentSurname = registerSubject.studentSurname,
className = registerSubject.className,
classId = registerSubject.classId,
isParent = registerSubject.isParent,
semesters = registerSubject.semesters
.mapToEntities(registerSubject.studentId),
)
},
)
}
)
},
)
fun RegisterStudent.mapToStudentWithSemesters(
user: RegisterUser,
scrapperDomainSuffix: String,
symbol: RegisterSymbol,
unit: RegisterUnit,
colors: List<Long>,
): StudentWithSemesters = StudentWithSemesters(
semesters = semesters,
student = Student(
email = user.login, // for compatibility
userName = symbol.userName,
userLoginId = unit.userLoginId,
isParent = isParent,
className = className,
classId = classId,
studentId = studentId,
symbol = symbol.symbol,
loginType = user.loginType?.name.orEmpty(),
schoolName = unit.schoolName,
schoolShortName = unit.schoolShortName,
schoolSymbol = unit.schoolId,
studentName = "$studentName $studentSurname",
loginMode = user.loginMode.name,
scrapperBaseUrl = user.scrapperBaseUrl.orEmpty(),
scrapperDomainSuffix = scrapperDomainSuffix,
mobileBaseUrl = symbol.hebeBaseUrl.orEmpty(),
certificateKey = symbol.keyId.orEmpty(),
privateKey = symbol.privatePem.orEmpty(),
password = user.password.orEmpty(),
isCurrent = false,
registrationDate = Instant.now(),
).apply {
avatarColor = colors.random()
},
)

View File

@ -1,37 +0,0 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import java.time.Instant
import io.github.wulkanowy.sdk.pojo.Student as SdkStudent
fun List<SdkStudent>.mapToEntities(password: String = "", colors: List<Long>) = map {
StudentWithSemesters(
student = Student(
email = it.email,
password = password,
isParent = it.isParent,
symbol = it.symbol,
studentId = it.studentId,
userLoginId = it.userLoginId,
userName = it.userName,
studentName = it.studentName + " " + it.studentSurname,
schoolSymbol = it.schoolSymbol,
schoolShortName = it.schoolShortName,
schoolName = it.schoolName,
className = it.className,
classId = it.classId,
scrapperBaseUrl = it.scrapperBaseUrl,
loginType = it.loginType.name,
isCurrent = false,
registrationDate = Instant.now(),
mobileBaseUrl = it.mobileBaseUrl,
privateKey = it.privateKey,
certificateKey = it.certificateKey,
loginMode = it.loginMode.name,
).apply {
avatarColor = colors.random()
},
semesters = it.semesters.mapToEntities(it.studentId)
)
}

View File

@ -5,10 +5,10 @@ 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.Timetable 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
import io.github.wulkanowy.sdk.pojo.Lesson as SdkLesson
import io.github.wulkanowy.sdk.pojo.LessonAdditional as SdkTimetableAdditional
fun SdkTimetableFull.mapToEntities(semester: Semester) = TimetableFull(
lessons = lessons.mapToEntities(semester),
@ -16,13 +16,13 @@ fun SdkTimetableFull.mapToEntities(semester: Semester) = TimetableFull(
headers = headers.mapToEntities(semester)
)
fun List<SdkTimetable>.mapToEntities(semester: Semester) = map {
fun List<SdkLesson>.mapToEntities(semester: Semester) = map {
Timetable(
studentId = semester.studentId,
diaryId = semester.diaryId,
number = it.number,
start = it.startZoned.toInstant(),
end = it.endZoned.toInstant(),
start = it.start.toInstant(),
end = it.end.toInstant(),
date = it.date,
subject = it.subject,
subjectOld = it.subjectOld,
@ -45,8 +45,8 @@ fun List<SdkTimetableAdditional>.mapToEntities(semester: Semester) = map {
diaryId = semester.diaryId,
subject = it.subject,
date = it.date,
start = it.startZoned.toInstant(),
end = it.endZoned.toInstant(),
start = it.start.toInstant(),
end = it.end.toInstant(),
)
}

View File

@ -0,0 +1,21 @@
package io.github.wulkanowy.data.pojos
import kotlinx.serialization.Serializable
@Serializable
data class LoginEvent(
val uuid: String,
val schoolName: String,
val schoolShort: String,
val schoolAddress: String,
val scraperBaseUrl: String,
val symbol: String,
val schoolId: String,
val loginType: String,
)
@Serializable
data class IntegrityRequest<T>(
val tokenString: String,
val data: T,
)

View File

@ -0,0 +1,48 @@
package io.github.wulkanowy.data.pojos
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.scrapper.Scrapper
data class RegisterUser(
val email: String,
val password: String?,
val login: String, // may be the same as email
val scrapperBaseUrl: String?,
val loginType: Scrapper.LoginType?,
val loginMode: Sdk.Mode,
val symbols: List<RegisterSymbol>,
) : java.io.Serializable
data class RegisterSymbol(
val symbol: String,
val error: Throwable?,
val hebeBaseUrl: String?,
val keyId: String?,
val privatePem: String?,
val userName: String,
val schools: List<RegisterUnit>,
) : java.io.Serializable
data class RegisterUnit(
val userLoginId: Int,
val schoolId: String,
val schoolName: String,
val schoolShortName: String,
val parentIds: List<Int>,
val studentIds: List<Int>,
val employeeIds: List<Int>,
val error: Throwable?,
val students: List<RegisterStudent>,
) : java.io.Serializable
data class RegisterStudent(
val studentId: Int,
val studentName: String,
val studentSecondName: String,
val studentSurname: String,
val className: String,
val classId: Int,
val isParent: Boolean,
val semesters: List<Semester>,
) : java.io.Serializable

View File

@ -1,10 +1,11 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.Resource
import io.github.wulkanowy.data.api.AdminMessageService
import io.github.wulkanowy.data.db.dao.AdminMessageDao
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.utils.AppInfo
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import javax.inject.Inject
import javax.inject.Singleton
@ -13,34 +14,20 @@ import javax.inject.Singleton
class AdminMessageRepository @Inject constructor(
private val adminMessageService: AdminMessageService,
private val adminMessageDao: AdminMessageDao,
private val appInfo: AppInfo
) {
private val saveFetchResultMutex = Mutex()
suspend fun getAdminMessages(student: Student) = networkBoundResource(
mutex = saveFetchResultMutex,
isResultEmpty = { it == null },
query = { adminMessageDao.loadAll() },
fetch = { adminMessageService.getAdminMessages() },
shouldFetch = { true },
saveFetchResult = { oldItems, newItems ->
adminMessageDao.removeOldAndSaveNew(oldItems, newItems)
},
showSavedOnLoading = false,
mapResult = { adminMessages ->
adminMessages.filter { adminMessage ->
val isCorrectRegister = adminMessage.targetRegisterHost?.let {
student.scrapperBaseUrl.contains(it, true)
} ?: true
val isCorrectFlavor =
adminMessage.targetFlavor?.equals(appInfo.buildFlavor, true) ?: true
val isCorrectMaxVersion =
adminMessage.versionMax?.let { it >= appInfo.versionCode } ?: true
val isCorrectMinVersion =
adminMessage.versionMin?.let { it <= appInfo.versionCode } ?: true
isCorrectRegister && isCorrectFlavor && isCorrectMaxVersion && isCorrectMinVersion
}.maxByOrNull { it.id }
}
)
fun getAdminMessages(): Flow<Resource<List<AdminMessage>>> =
networkBoundResource(
mutex = saveFetchResultMutex,
isResultEmpty = { false },
query = { adminMessageDao.loadAll() },
fetch = { adminMessageService.getAdminMessages() },
shouldFetch = { true },
saveFetchResult = { oldItems, newItems ->
adminMessageDao.removeOldAndSaveNew(oldItems, newItems)
},
showSavedOnLoading = false,
)
}

View File

@ -19,7 +19,6 @@ class AppCreatorRepository @Inject constructor(
) {
@OptIn(ExperimentalSerializationApi::class)
@Suppress("BlockingMethodInNonBlockingContext")
suspend fun getAppCreators() = withContext(dispatchers.io) {
val inputStream = context.assets.open("contributors.json").buffered()
json.decodeFromStream<List<Contributor>>(inputStream)

View File

@ -1,6 +1,7 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
@ -9,8 +10,10 @@ import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Absent
import io.github.wulkanowy.utils.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.withContext
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
@ -20,6 +23,7 @@ import javax.inject.Singleton
@Singleton
class AttendanceRepository @Inject constructor(
private val attendanceDb: AttendanceDao,
private val timetableDb: TimetableDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
@ -48,10 +52,15 @@ class AttendanceRepository @Inject constructor(
attendanceDb.loadAll(semester.diaryId, semester.studentId, start.monday, end.sunday)
},
fetch = {
val lessons = withContext(Dispatchers.IO) {
timetableDb.load(
semester.diaryId, semester.studentId, start.monday, end.sunday
)
}
sdk.init(student)
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getAttendance(start.monday, end.sunday, semester.semesterId)
.mapToEntities(semester)
.getAttendance(start.monday, end.sunday)
.mapToEntities(semester, lessons)
},
saveFetchResult = { old, new ->
attendanceDb.deleteAll(old uniqueSubtract new)

View File

@ -52,7 +52,7 @@ class ExamRepository @Inject constructor(
fetch = {
sdk.init(student)
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getExams(start.startExamsDay, start.endExamsDay, semester.semesterId)
.getExams(start.startExamsDay, start.endExamsDay)
.mapToEntities(semester)
},
saveFetchResult = { old, new ->

View File

@ -1,53 +0,0 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.dao.MailboxDao
import io.github.wulkanowy.data.db.entities.Mailbox
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
import javax.inject.Singleton
@Singleton
class MailboxRepository @Inject constructor(
private val mailboxDao: MailboxDao,
private val sdk: Sdk,
private val refreshHelper: AutoRefreshHelper,
) {
private val cacheKey = "mailboxes"
suspend fun refreshMailboxes(student: Student) {
val new = sdk.init(student).getMailboxes().mapToEntities(student)
val old = mailboxDao.loadAll(student.userLoginId)
mailboxDao.deleteAll(old uniqueSubtract new)
mailboxDao.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student))
}
suspend fun getMailbox(student: Student): Mailbox {
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
val mailboxes = mailboxDao.loadAll(student.userLoginId)
val mailbox = mailboxes.filterByStudent(student)
return if (isExpired || mailbox == null) {
refreshMailboxes(student)
val newMailbox = mailboxDao.loadAll(student.userLoginId).filterByStudent(student)
requireNotNull(newMailbox) {
"Mailbox for ${student.userName} - ${student.studentName} not found! Saved mailboxes: $mailboxes"
}
newMailbox
} else mailbox
}
private fun List<Mailbox>.filterByStudent(student: Student): Mailbox? = find {
it.studentName.trim() == student.studentName.trim()
}
}

View File

@ -5,16 +5,25 @@ 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.MailboxDao
import io.github.wulkanowy.data.db.dao.MessageAttachmentDao
import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.entities.*
import io.github.wulkanowy.data.db.entities.Mailbox
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.Student
import io.github.wulkanowy.data.enums.MessageFolder
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
import io.github.wulkanowy.data.enums.MessageFolder.TRASHED
import io.github.wulkanowy.data.mappers.mapFromEntities
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.networkBoundResource
import io.github.wulkanowy.data.onResourceError
import io.github.wulkanowy.data.onResourceSuccess
import io.github.wulkanowy.data.pojos.MessageDraft
import io.github.wulkanowy.data.waitForResult
import io.github.wulkanowy.domain.messages.GetMailboxByStudentUseCase
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Folder
import io.github.wulkanowy.utils.AutoRefreshHelper
@ -24,7 +33,6 @@ import io.github.wulkanowy.utils.uniqueSubtract
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.sync.Mutex
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import timber.log.Timber
@ -40,16 +48,18 @@ class MessageRepository @Inject constructor(
private val refreshHelper: AutoRefreshHelper,
private val sharedPrefProvider: SharedPrefProvider,
private val json: Json,
private val mailboxDao: MailboxDao,
private val getMailboxByStudentUseCase: GetMailboxByStudentUseCase,
) {
private val saveFetchResultMutex = Mutex()
private val cacheKey = "message"
private val messagesCacheKey = "message"
private val mailboxCacheKey = "mailboxes"
@Suppress("UNUSED_PARAMETER")
fun getMessages(
student: Student,
mailbox: Mailbox,
mailbox: Mailbox?,
folder: MessageFolder,
forceRefresh: Boolean,
notify: Boolean = false,
@ -58,16 +68,20 @@ class MessageRepository @Inject constructor(
isResultEmpty = { it.isEmpty() },
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(
key = getRefreshKey(cacheKey, student, folder)
key = getRefreshKey(messagesCacheKey, mailbox, folder)
)
it.isEmpty() || forceRefresh || isExpired
},
query = { messagesDb.loadAll(mailbox.globalKey, folder.id) },
query = {
if (mailbox == null) {
messagesDb.loadAll(folder.id, student.email)
} else messagesDb.loadAll(mailbox.globalKey, folder.id)
},
fetch = {
sdk.init(student).getMessages(
folder = Folder.valueOf(folder.name),
mailboxKey = mailbox.globalKey,
).mapToEntities(mailbox)
mailboxKey = mailbox?.globalKey,
).mapToEntities(student, mailbox, mailboxDao.loadAll(student.email))
},
saveFetchResult = { old, new ->
messagesDb.deleteAll(old uniqueSubtract new)
@ -75,7 +89,9 @@ class MessageRepository @Inject constructor(
it.isNotified = !notify
})
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(cacheKey, student, folder))
refreshHelper.updateLastRefreshTimestamp(
getRefreshKey(messagesCacheKey, mailbox, folder)
)
}
)
@ -88,18 +104,26 @@ class MessageRepository @Inject constructor(
shouldFetch = {
checkNotNull(it) { "This message no longer exist!" }
Timber.d("Message content in db empty: ${it.message.content.isBlank()}")
it.message.unread || it.message.content.isBlank()
(it.message.unread && markAsRead) || it.message.content.isBlank()
},
query = {
messagesDb.loadMessageWithAttachment(message.messageGlobalKey)
},
query = { messagesDb.loadMessageWithAttachment(message.messageGlobalKey) },
fetch = {
sdk.init(student).getMessageDetails(it!!.message.messageGlobalKey, markAsRead)
sdk.init(student).getMessageDetails(
messageKey = it!!.message.messageGlobalKey,
markAsRead = message.unread && markAsRead,
)
},
saveFetchResult = { old, new ->
checkNotNull(old) { "Fetched message no longer exist!" }
messagesDb.updateAll(
listOf(old.message.apply {
id = message.id
unread = !markAsRead
unread = when {
markAsRead -> false
else -> unread
}
sender = new.sender
recipients = new.recipients.singleOrNull() ?: "Wielu adresatów"
content = content.ifBlank { new.content }
@ -109,12 +133,14 @@ class MessageRepository @Inject constructor(
items = new.attachments.mapToEntities(message.messageGlobalKey),
)
Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read")
Timber.d("Message ${message.messageId} with blank content: ${old.message.content.isBlank()}, marked as read: $markAsRead")
}
)
fun getMessagesFromDatabase(mailbox: Mailbox): Flow<List<Message>> {
return messagesDb.loadAll(mailbox.globalKey, RECEIVED.id)
fun getMessagesFromDatabase(student: Student, mailbox: Mailbox?): Flow<List<Message>> {
return if (mailbox == null) {
messagesDb.loadAll(RECEIVED.id, student.email)
} else messagesDb.loadAll(mailbox.globalKey, RECEIVED.id)
}
suspend fun updateMessages(messages: List<Message>) {
@ -136,7 +162,7 @@ class MessageRepository @Inject constructor(
)
}
suspend fun deleteMessages(student: Student, mailbox: Mailbox, messages: List<Message>) {
suspend fun deleteMessages(student: Student, mailbox: Mailbox?, messages: List<Message>) {
val firstMessage = messages.first()
sdk.init(student).deleteMessages(
messages = messages.map { it.messageGlobalKey },
@ -165,10 +191,44 @@ class MessageRepository @Inject constructor(
).first()
}
suspend fun deleteMessage(student: Student, mailbox: Mailbox, message: Message) {
suspend fun deleteMessage(student: Student, mailbox: Mailbox?, message: Message) {
deleteMessages(student, mailbox, listOf(message))
}
suspend fun getMailboxes(student: Student, forceRefresh: Boolean) = networkBoundResource(
mutex = saveFetchResultMutex,
isResultEmpty = { it.isEmpty() },
shouldFetch = {
val isExpired = refreshHelper.shouldBeRefreshed(
key = getRefreshKey(mailboxCacheKey, student),
)
it.isEmpty() || isExpired || forceRefresh
},
query = { mailboxDao.loadAll(student.email, student.symbol, student.schoolSymbol) },
fetch = {
sdk.init(student).getMailboxes().mapToEntities(student)
},
saveFetchResult = { old, new ->
mailboxDao.deleteAll(old uniqueSubtract new)
mailboxDao.insertAll(new uniqueSubtract old)
refreshHelper.updateLastRefreshTimestamp(getRefreshKey(mailboxCacheKey, student))
}
)
suspend fun getMailboxByStudent(student: Student): Mailbox? {
val mailbox = getMailboxByStudentUseCase(student)
return if (mailbox == null) {
getMailboxes(student, forceRefresh = true)
.onResourceError { throw it }
.onResourceSuccess { Timber.i("Found ${it.size} new mailboxes") }
.waitForResult()
getMailboxByStudentUseCase(student)
} else mailbox
}
var draftMessage: MessageDraft?
get() = sharedPrefProvider.getString(context.getString(R.string.pref_key_message_draft))
?.let { json.decodeFromString(it) }

View File

@ -42,7 +42,7 @@ class NoteRepository @Inject constructor(
fetch = {
sdk.init(student)
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getNotes(semester.semesterId)
.getNotes()
.mapToEntities(semester)
},
saveFetchResult = { old, new ->

View File

@ -2,25 +2,26 @@ package io.github.wulkanowy.data.repositories
import android.content.Context
import android.content.SharedPreferences
import androidx.annotation.StringRes
import androidx.core.content.edit
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
import com.fredporciuncula.flow.preferences.Preference
import com.fredporciuncula.flow.preferences.Serializer
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.R
import io.github.wulkanowy.data.enums.*
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.ui.modules.grade.GradeAverageMode
import kotlinx.coroutines.ExperimentalCoroutinesApi
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.time.Instant
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
@OptIn(ExperimentalCoroutinesApi::class)
@Singleton
class PreferencesRepository @Inject constructor(
@ApplicationContext val context: Context,
@ -29,29 +30,35 @@ class PreferencesRepository @Inject constructor(
private val json: Json,
) {
val startMenuIndex: Int
get() = getString(R.string.pref_key_start_menu, R.string.pref_default_startup).toInt()
val isShowPresent: Boolean
get() = getBoolean(
R.string.pref_key_attendance_present,
R.bool.pref_default_attendance_present
)
val gradeAverageMode: GradeAverageMode
get() = GradeAverageMode.getByValue(
getString(
R.string.pref_key_grade_average_mode,
R.string.pref_default_grade_average_mode
)
private val gradeAverageModePref: Preference<GradeAverageMode>
get() = getObjectFlow(
R.string.pref_key_grade_average_mode,
R.string.pref_default_grade_average_mode,
object : Serializer<GradeAverageMode> {
override fun serialize(value: GradeAverageMode) = value.value
override fun deserialize(serialized: String) =
GradeAverageMode.getByValue(serialized)
},
)
val gradeAverageForceCalc: Boolean
get() = getBoolean(
R.string.pref_key_grade_average_force_calc,
R.bool.pref_default_grade_average_force_calc
val gradeAverageModeFlow: Flow<GradeAverageMode>
get() = gradeAverageModePref.asFlow()
private val gradeAverageForceCalcPref: Preference<Boolean>
get() = flowSharedPref.getBoolean(
context.getString(R.string.pref_key_grade_average_force_calc),
context.resources.getBoolean(R.bool.pref_default_grade_average_force_calc)
)
val gradeAverageForceCalcFlow: Flow<Boolean>
get() = gradeAverageForceCalcPref.asFlow()
val gradeExpandMode: GradeExpandMode
get() = GradeExpandMode.getByValue(
getString(
@ -141,12 +148,24 @@ class PreferencesRepository @Inject constructor(
R.string.pref_default_grade_modifier_plus
).toDouble()
val gradePlusModifierFlow: Flow<Double>
get() = getStringFlow(
R.string.pref_key_grade_modifier_plus,
R.string.pref_default_grade_modifier_plus
).asFlow().map { it.toDouble() }
val gradeMinusModifier: Double
get() = getString(
R.string.pref_key_grade_modifier_minus,
R.string.pref_default_grade_modifier_minus
).toDouble()
val gradeMinusModifierFlow: Flow<Double>
get() = getStringFlow(
R.string.pref_key_grade_modifier_minus,
R.string.pref_default_grade_modifier_minus
).asFlow().map { it.toDouble() }
val fillMessageContent: Boolean
get() = getBoolean(
R.string.pref_key_fill_message_content,
@ -181,12 +200,13 @@ class PreferencesRepository @Inject constructor(
R.bool.pref_default_timetable_show_timers
)
var isHomeworkFullscreen: Boolean
get() = getBoolean(
R.string.pref_key_homework_fullscreen,
R.bool.pref_default_homework_fullscreen
val showTimetableGaps: TimetableGapsMode
get() = TimetableGapsMode.getByValue(
getString(
R.string.pref_key_timetable_show_gaps,
R.string.pref_default_timetable_show_gaps
)
)
set(value) = sharedPref.edit().putBoolean("homework_fullscreen", value).apply()
val showSubjectsWithoutGrades: Boolean
get() = getBoolean(
@ -194,11 +214,11 @@ 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
)
val isOptionalArithmeticAverageFlow: Flow<Boolean>
get() = flowSharedPref.getBoolean(
context.getString(R.string.pref_key_optional_arithmetic_average),
context.resources.getBoolean(R.bool.pref_default_optional_arithmetic_average)
).asFlow()
var lasSyncDate: Instant?
get() = getLong(R.string.pref_key_last_sync_date, R.string.pref_default_last_sync_date)
@ -316,11 +336,56 @@ class PreferencesRepository @Inject constructor(
putBoolean(context.getString(R.string.pref_key_ads_enabled), value)
}
var appMenuItemOrder: List<AppMenuItem>
get() {
val value = sharedPref.getString(PREF_KEY_APP_MENU_ITEM_ORDER, null)
?: return AppMenuItem.defaultAppMenuItemList
return json.decodeFromString(value)
}
set(value) = sharedPref.edit {
putString(
PREF_KEY_APP_MENU_ITEM_ORDER,
json.encodeToString(value)
)
}
var isIncognitoMode: Boolean
get() = getBoolean(R.string.pref_key_incognito_moge, R.bool.pref_default_incognito_mode)
set(value) = sharedPref.edit {
putBoolean(context.getString(R.string.pref_key_incognito_moge), value)
}
var installationId: String
get() = sharedPref.getString(PREF_KEY_INSTALLATION_ID, null).orEmpty()
private set(value) = sharedPref.edit { putString(PREF_KEY_INSTALLATION_ID, value) }
init {
if (installationId.isEmpty()) {
installationId = UUID.randomUUID().toString()
}
}
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 getStringFlow(id: Int, default: Int) =
flowSharedPref.getString(context.getString(id), context.getString(default))
private fun <T : Any> getObjectFlow(
@StringRes id: Int,
@StringRes default: Int,
serializer: Serializer<T>
): Preference<T> = flowSharedPref.getObject(
key = context.getString(id),
serializer = serializer,
defaultValue = serializer.deserialize(
flowSharedPref.getString(context.getString(default)).get()
)
)
private fun getString(id: Int, default: Int) = getString(context.getString(id), default)
private fun getString(id: String, default: Int) =
@ -331,23 +396,15 @@ class PreferencesRepository @Inject constructor(
private fun getBoolean(id: String, default: Int) =
sharedPref.getBoolean(id, context.resources.getBoolean(default))
private fun getBoolean(id: Int, default: Boolean) =
sharedPref.getBoolean(context.getString(id), default)
private companion object {
private const val PREF_KEY_APP_MENU_ITEM_ORDER = "app_menu_item_order"
private const val PREF_KEY_INSTALLATION_ID = "installation_id"
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"
private const val PREF_KEY_APP_SUPPORT_SHOWN = "app_support_shown"
private const val PREF_KEY_PERSONALIZED_ADS_ENABLED = "personalized_ads_enabled"
private const val PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS = "admin_message_dismissed_ids"
}
}

View File

@ -33,9 +33,11 @@ class RecipientRepository @Inject constructor(
suspend fun getRecipients(
student: Student,
mailbox: Mailbox,
type: MailboxType
mailbox: Mailbox?,
type: MailboxType,
): List<Recipient> {
mailbox ?: return emptyList()
val cached = recipientDb.loadAll(type, mailbox.globalKey)
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
@ -47,11 +49,15 @@ class RecipientRepository @Inject constructor(
suspend fun getMessageSender(
student: Student,
mailbox: Mailbox,
message: Message
): List<Recipient> = sdk.init(student)
.getMessageReplayDetails(message.messageGlobalKey)
.sender
.let(::listOf)
.mapToEntities(mailbox.globalKey)
mailbox: Mailbox?,
message: Message,
): List<Recipient> {
mailbox ?: return emptyList()
return sdk.init(student)
.getMessageReplayDetails(message.messageGlobalKey)
.sender
.let(::listOf)
.mapToEntities(mailbox.globalKey)
}
}

View File

@ -0,0 +1,68 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.api.SchoolsService
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.pojos.IntegrityRequest
import io.github.wulkanowy.data.pojos.LoginEvent
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.ui.modules.login.LoginData
import io.github.wulkanowy.utils.IntegrityHelper
import io.github.wulkanowy.utils.getCurrentOrLast
import io.github.wulkanowy.utils.init
import kotlinx.coroutines.withTimeout
import timber.log.Timber
import java.util.UUID
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.time.Duration.Companion.seconds
@Singleton
class SchoolsRepository @Inject constructor(
private val integrityHelper: IntegrityHelper,
private val schoolsService: SchoolsService,
private val sdk: Sdk,
) {
suspend fun logSchoolLogin(loginData: LoginData, students: List<StudentWithSemesters>) {
students.forEach {
runCatching {
withTimeout(10.seconds) {
logLogin(loginData, it.student, it.semesters.getCurrentOrLast())
}
}
.onFailure { Timber.e(it) }
}
}
private suspend fun logLogin(loginData: LoginData, student: Student, semester: Semester) {
val requestId = UUID.randomUUID().toString()
val token = integrityHelper.getIntegrityToken(requestId) ?: return
val schoolInfo = sdk
.init(student.copy(password = loginData.password))
.switchDiary(
diaryId = semester.diaryId,
kindergartenDiaryId = semester.kindergartenDiaryId,
schoolYear = semester.schoolYear
)
.getSchool()
schoolsService.logLoginEvent(
IntegrityRequest(
tokenString = token,
data = LoginEvent(
uuid = requestId,
schoolAddress = schoolInfo.address,
schoolName = schoolInfo.name,
schoolShort = student.schoolShortName,
scraperBaseUrl = student.scrapperBaseUrl,
loginType = student.loginType,
symbol = student.symbol,
schoolId = student.schoolSymbol,
)
)
)
}
}

View File

@ -40,8 +40,8 @@ class SemesterRepository @Inject constructor(
val isNoSemesters = semesters.isEmpty()
val isRefreshOnModeChangeRequired = when {
Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API -> {
semesters.firstOrNull { it.isCurrent }?.let {
Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE -> {
semesters.firstOrNull { it.isCurrent() }?.let {
0 == it.diaryId && 0 == it.kindergartenDiaryId
} == true
}
@ -49,7 +49,7 @@ class SemesterRepository @Inject constructor(
}
val isRefreshOnNoCurrentAppropriate =
refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent }
refreshOnNoCurrent && !semesters.any { semester -> semester.isCurrent() }
return forceRefresh || isNoSemesters || isRefreshOnModeChangeRequired || isRefreshOnNoCurrentAppropriate
}

View File

@ -6,14 +6,17 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentName
import io.github.wulkanowy.data.db.entities.StudentNickAndAvatar
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
import io.github.wulkanowy.data.mappers.mapToEntities
import io.github.wulkanowy.data.mappers.mapToPojo
import io.github.wulkanowy.data.pojos.RegisterUser
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.DispatchersProvider
import io.github.wulkanowy.utils.init
import io.github.wulkanowy.utils.security.decrypt
import io.github.wulkanowy.utils.security.encrypt
import kotlinx.coroutines.withContext
@ -27,55 +30,61 @@ class StudentRepository @Inject constructor(
private val studentDb: StudentDao,
private val semesterDb: SemesterDao,
private val sdk: Sdk,
private val appInfo: AppInfo,
private val appDatabase: AppDatabase
) {
suspend fun isStudentSaved() = getSavedStudents(false).isNotEmpty()
suspend fun isCurrentStudentSet() = studentDb.loadCurrent()?.isCurrent ?: false
suspend fun getStudentsApi(
pin: String,
symbol: String,
token: String
): List<StudentWithSemesters> =
sdk.getStudentsFromMobileApi(token, pin, symbol, "")
.mapToEntities(colors = appInfo.defaultColorsForAvatar)
): RegisterUser = sdk
.getStudentsFromHebe(token, pin, symbol, "")
.mapToPojo(null)
suspend fun getStudentsScrapper(
suspend fun getUserSubjectsFromScrapper(
email: String,
password: String,
scrapperBaseUrl: String,
domainSuffix: String,
symbol: String
): List<StudentWithSemesters> =
sdk.getStudentsFromScrapper(email, password, scrapperBaseUrl, symbol)
.mapToEntities(password, appInfo.defaultColorsForAvatar)
): RegisterUser = sdk
.getUserSubjectsFromScrapper(email, password, scrapperBaseUrl, domainSuffix, symbol)
.mapToPojo(password)
suspend fun getStudentsHybrid(
email: String,
password: String,
scrapperBaseUrl: String,
symbol: String
): List<StudentWithSemesters> =
sdk.getStudentsHybrid(email, password, scrapperBaseUrl, "", symbol)
.mapToEntities(password, appInfo.defaultColorsForAvatar)
): RegisterUser = sdk
.getStudentsHybrid(email, password, scrapperBaseUrl, "", symbol)
.mapToPojo(password)
suspend fun getSavedStudents(decryptPass: Boolean = true) =
studentDb.loadStudentsWithSemesters()
.map {
it.apply {
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
suspend fun getSavedStudents(decryptPass: Boolean = true): List<StudentWithSemesters> {
return studentDb.loadStudentsWithSemesters().map { (student, semesters) ->
StudentWithSemesters(
student = student.apply {
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
student.password = withContext(dispatchers.io) {
decrypt(student.password)
}
}
}
}
},
semesters = semesters,
)
}
}
suspend fun getSavedStudentById(id: Long, decryptPass: Boolean = true) =
studentDb.loadStudentWithSemestersById(id)?.apply {
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
suspend fun getSavedStudentById(id: Long, decryptPass: Boolean = true): StudentWithSemesters? =
studentDb.loadStudentWithSemestersById(id).let { res ->
StudentWithSemesters(
student = res.keys.firstOrNull() ?: return null,
semesters = res.values.first(),
)
}.apply {
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
student.password = withContext(dispatchers.io) {
decrypt(student.password)
}
@ -85,7 +94,7 @@ class StudentRepository @Inject constructor(
suspend fun getStudentById(id: Long, decryptPass: Boolean = true): Student {
val student = studentDb.loadById(id) ?: throw NoCurrentStudentException()
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
student.password = withContext(dispatchers.io) {
decrypt(student.password)
}
@ -96,7 +105,7 @@ class StudentRepository @Inject constructor(
suspend fun getCurrentStudent(decryptPass: Boolean = true): Student {
val student = studentDb.loadCurrent() ?: throw NoCurrentStudentException()
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
if (decryptPass && Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.HEBE) {
student.password = withContext(dispatchers.io) {
decrypt(student.password)
}
@ -109,7 +118,7 @@ class StudentRepository @Inject constructor(
val students = studentsWithSemesters.map { it.student }
.map {
it.apply {
if (Sdk.Mode.valueOf(it.loginMode) != Sdk.Mode.API) {
if (Sdk.Mode.valueOf(it.loginMode) != Sdk.Mode.HEBE) {
password = withContext(dispatchers.io) {
encrypt(password, context)
}
@ -140,4 +149,21 @@ class StudentRepository @Inject constructor(
suspend fun isOneUniqueStudent() = getSavedStudents(false)
.distinctBy { it.student.studentName }.size == 1
suspend fun authorizePermission(student: Student, semester: Semester, pesel: String) =
sdk.init(student)
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.authorizePermission(pesel)
suspend fun refreshStudentName(student: Student, semester: Semester) {
val newCurrentApiStudent = sdk.init(student)
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getCurrentStudent() ?: return
val studentName = StudentName(
studentName = "${newCurrentApiStudent.studentName} ${newCurrentApiStudent.studentSurname}"
).apply { id = student.id }
studentDb.update(studentName)
}
}

View File

@ -40,7 +40,7 @@ class TeacherRepository @Inject constructor(
fetch = {
sdk.init(student)
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getTeachers(semester.semesterId)
.getTeachers()
.mapToEntities(semester)
},
saveFetchResult = { old, new ->

View File

@ -13,6 +13,7 @@ import io.github.wulkanowy.utils.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.sync.Mutex
import java.time.Instant
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@ -65,7 +66,7 @@ class TimetableRepository @Inject constructor(
fetch = {
val timetableFull = sdk.init(student)
.switchDiary(semester.diaryId, semester.kindergartenDiaryId, semester.schoolYear)
.getTimetableFull(start.monday, end.sunday)
.getTimetable(start.monday, end.sunday)
timetableFull.mapToEntities(semester)
},
@ -164,6 +165,11 @@ class TimetableRepository @Inject constructor(
timetableHeaderDb.insertAll(new uniqueSubtract old)
}
fun getLastRefreshTimestamp(semester: Semester, start: LocalDate, end: LocalDate): Instant {
val refreshKey = getRefreshKey(cacheKey, semester, start, end)
return refreshHelper.getLastRefreshTimestamp(refreshKey)
}
suspend fun saveAdditionalList(additionalList: List<TimetableAdditional>) =
timetableAdditionalDb.insertAll(additionalList)

View File

@ -0,0 +1,64 @@
package io.github.wulkanowy.domain.adminmessage
import io.github.wulkanowy.data.Resource
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageType
import io.github.wulkanowy.data.mapResourceData
import io.github.wulkanowy.data.repositories.AdminMessageRepository
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.utils.AppInfo
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class GetAppropriateAdminMessageUseCase @Inject constructor(
private val adminMessageRepository: AdminMessageRepository,
private val preferencesRepository: PreferencesRepository,
private val appInfo: AppInfo
) {
operator fun invoke(student: Student, type: MessageType): Flow<Resource<AdminMessage?>> {
return invoke(student.scrapperBaseUrl, type)
}
operator fun invoke(scrapperBaseUrl: String, type: MessageType): Flow<Resource<AdminMessage?>> {
return adminMessageRepository.getAdminMessages().mapResourceData { adminMessages ->
adminMessages
.asSequence()
.filter { it.isNotDismissed() }
.filter { it.isVersionMatch() }
.filter { it.isRegisterHostMatch(scrapperBaseUrl) }
.filter { it.isFlavorMatch() }
.filter { it.isTypeMatch(type) }
.maxByOrNull { it.id }
}
}
private fun AdminMessage.isNotDismissed(): Boolean {
return id !in preferencesRepository.dismissedAdminMessageIds
}
private fun AdminMessage.isRegisterHostMatch(scrapperBaseUrl: String): Boolean {
return targetRegisterHost?.let {
scrapperBaseUrl.contains(it, true)
} ?: true
}
private fun AdminMessage.isFlavorMatch(): Boolean {
return targetFlavor?.equals(appInfo.buildFlavor, true) ?: true
}
private fun AdminMessage.isVersionMatch(): Boolean {
val isCorrectMaxVersion = versionMax?.let { it >= appInfo.versionCode } ?: true
val isCorrectMinVersion = versionMin?.let { it <= appInfo.versionCode } ?: true
return isCorrectMaxVersion && isCorrectMinVersion
}
private fun AdminMessage.isTypeMatch(messageType: MessageType): Boolean {
if (messageType in types) return true
if (MessageType.GENERAL_MESSAGE in types) return true
return false
}
}

View File

@ -0,0 +1,65 @@
package io.github.wulkanowy.domain.messages
import io.github.wulkanowy.data.db.dao.MailboxDao
import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.Student
import javax.inject.Inject
class GetMailboxByStudentUseCase @Inject constructor(
private val mailboxDao: MailboxDao,
) {
suspend operator fun invoke(student: Student): Mailbox? {
return mailboxDao.loadAll(student.email)
.filterByStudent(student)
}
private fun List<Mailbox>.filterByStudent(student: Student): Mailbox? {
val normalizedStudentName = student.studentName.normalizeStudentName()
return singleOrNull {
it.studentName.normalizeStudentName() == normalizedStudentName
} ?: singleOrNull {
it.studentName.normalizeStudentName() == normalizedStudentName
&& it.schoolNameShort == student.schoolShortName
} ?: singleOrNull {
it.studentName.getFirstAndLastPart() == normalizedStudentName.getFirstAndLastPart()
} ?: singleOrNull {
it.studentName.getReversedName() == normalizedStudentName
} ?: singleOrNull {
it.studentName.getUnauthorizedVersion() == normalizedStudentName
}
}
private fun String.normalizeStudentName(): String {
return trim().split(" ")
.filter { it.isNotBlank() }
.joinToString(" ") { part ->
part.lowercase().replaceFirstChar { it.uppercase() }
}
}
private fun String.getFirstAndLastPart(): String {
val parts = normalizeStudentName().split(" ")
val endParts = parts.filterIndexed { i, _ ->
i == 0 || parts.size - 1 == i
}
return endParts.joinToString(" ")
}
private fun String.getReversedName(): String {
val parts = normalizeStudentName().split(" ")
return parts
.asReversed()
.joinToString(" ")
}
private fun String.getUnauthorizedVersion(): String {
return normalizeStudentName().split(" ")
.joinToString(" ") {
it.first() + "*".repeat(it.length - 1)
}
}
}

View File

@ -4,18 +4,12 @@ import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.O
import androidx.core.app.NotificationManagerCompat
import androidx.lifecycle.asFlow
import androidx.work.*
import androidx.work.BackoffPolicy.EXPONENTIAL
import androidx.work.Constraints
import androidx.work.Data
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
import androidx.work.ExistingPeriodicWorkPolicy.REPLACE
import androidx.work.ExistingWorkPolicy
import androidx.work.ExistingPeriodicWorkPolicy.UPDATE
import androidx.work.NetworkType.CONNECTED
import androidx.work.NetworkType.UNMETERED
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkInfo
import androidx.work.WorkManager
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.SharedPrefProvider.Companion.APP_VERSION_CODE_KEY
import io.github.wulkanowy.data.repositories.PreferencesRepository
@ -60,7 +54,7 @@ class SyncManager @Inject constructor(
val serviceInterval = preferencesRepository.servicesInterval
workManager.enqueueUniquePeriodicWork(
SyncWorker::class.java.simpleName, if (restart) REPLACE else KEEP,
SyncWorker::class.java.simpleName, if (restart) UPDATE else KEEP,
PeriodicWorkRequestBuilder<SyncWorker>(serviceInterval, MINUTES)
.setInitialDelay(10, MINUTES)
.setBackoffCriteria(EXPONENTIAL, 30, MINUTES)

View File

@ -8,7 +8,6 @@ import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.pojos.GroupNotificationData
import io.github.wulkanowy.data.pojos.NotificationData
import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.descriptionRes
import io.github.wulkanowy.utils.getPlural
import io.github.wulkanowy.utils.toFormattedString
@ -22,8 +21,9 @@ class NewAttendanceNotification @Inject constructor(
suspend fun notify(items: List<Attendance>, student: Student) {
val lines = items.filterNot { it.presence || it.name == "UNKNOWN" }
.map {
val lesson = it.subject.ifBlank { "Lekcja ${it.number}" }
val description = context.getString(it.descriptionRes)
"${it.date.toFormattedString("dd.MM")} - ${it.subject}: $description"
"${it.date.toFormattedString("dd.MM")} - $lesson: $description"
}
.ifEmpty { return }

View File

@ -8,7 +8,6 @@ import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.pojos.GroupNotificationData
import io.github.wulkanowy.data.pojos.NotificationData
import io.github.wulkanowy.ui.modules.Destination
import io.github.wulkanowy.ui.modules.splash.SplashActivity
import io.github.wulkanowy.utils.getPlural
import javax.inject.Inject

View File

@ -3,7 +3,6 @@ package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.enums.MessageFolder.RECEIVED
import io.github.wulkanowy.data.repositories.MailboxRepository
import io.github.wulkanowy.data.repositories.MessageRepository
import io.github.wulkanowy.data.waitForResult
import io.github.wulkanowy.services.sync.notifications.NewMessageNotification
@ -12,12 +11,11 @@ import javax.inject.Inject
class MessageWork @Inject constructor(
private val messageRepository: MessageRepository,
private val mailboxRepository: MailboxRepository,
private val newMessageNotification: NewMessageNotification,
) : Work {
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
val mailbox = mailboxRepository.getMailbox(student)
val mailbox = messageRepository.getMailboxByStudent(student)
messageRepository.getMessages(
student = student,
mailbox = mailbox,
@ -26,7 +24,7 @@ class MessageWork @Inject constructor(
notify = notify
).waitForResult()
messageRepository.getMessagesFromDatabase(mailbox).first()
messageRepository.getMessagesFromDatabase(student, mailbox).first()
.filter { !it.isNotified && it.unread }.let {
if (it.isNotEmpty()) newMessageNotification.notify(it, student)
messageRepository.updateMessages(it.onEach { message -> message.isNotified = true })

View File

@ -1,22 +1,23 @@
package io.github.wulkanowy.services.sync.works
import io.github.wulkanowy.data.dataOrNull
import io.github.wulkanowy.data.db.entities.MailboxType
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.MailboxRepository
import io.github.wulkanowy.data.repositories.MessageRepository
import io.github.wulkanowy.data.repositories.RecipientRepository
import io.github.wulkanowy.data.toFirstResult
import javax.inject.Inject
class RecipientWork @Inject constructor(
private val mailboxRepository: MailboxRepository,
private val messageRepository: MessageRepository,
private val recipientRepository: RecipientRepository
) : Work {
override suspend fun doWork(student: Student, semester: Semester, notify: Boolean) {
mailboxRepository.refreshMailboxes(student)
val mailbox = mailboxRepository.getMailbox(student)
recipientRepository.refreshRecipients(student, mailbox, MailboxType.EMPLOYEE)
val mailboxes = messageRepository.getMailboxes(student, forceRefresh = true).toFirstResult()
mailboxes.dataOrNull?.forEach {
recipientRepository.refreshRecipients(student, it, MailboxType.EMPLOYEE)
}
}
}

View File

@ -25,13 +25,21 @@ class TimetableWidgetService : RemoteViewsService() {
lateinit var semesterRepo: SemesterRepository
@Inject
lateinit var prefRepository: PreferencesRepository
lateinit var sharedPref: SharedPrefProvider
@Inject
lateinit var sharedPref: SharedPrefProvider
lateinit var prefRepository: PreferencesRepository
override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory {
Timber.d("TimetableWidgetFactory created")
return TimetableWidgetFactory(timetableRepo, studentRepo, semesterRepo, prefRepository, sharedPref, applicationContext, intent)
return TimetableWidgetFactory(
timetableRepository = timetableRepo,
studentRepository = studentRepo,
semesterRepository = semesterRepo,
sharedPref = sharedPref,
prefRepository = prefRepository,
context = applicationContext,
intent = intent,
)
}
}

View File

@ -4,12 +4,13 @@ import android.app.ActivityManager
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.viewbinding.ViewBinding
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.modules.auth.AuthDialog
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.utils.FragmentLifecycleLogger
import io.github.wulkanowy.utils.getThemeAttrColor
@ -30,6 +31,8 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
protected var messageContainer: View? = null
protected var messageAnchor: View? = null
abstract var presenter: T
override fun onCreate(savedInstanceState: Bundle?) {
@ -48,6 +51,7 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
if (messageContainer != null) {
Snackbar.make(messageContainer!!, text, LENGTH_LONG)
.setAction(R.string.all_details) { showErrorDetailsDialog(error) }
.apply { messageAnchor?.let { anchorView = it } }
.show()
} else showMessage(text)
}
@ -57,12 +61,15 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
}
override fun showMessage(text: String) {
if (messageContainer != null) Snackbar.make(messageContainer!!, text, LENGTH_LONG).show()
else Toast.makeText(this, text, Toast.LENGTH_LONG).show()
if (messageContainer != null) {
Snackbar.make(messageContainer!!, text, LENGTH_LONG)
.apply { messageAnchor?.let { anchorView = it } }
.show()
} else Toast.makeText(this, text, Toast.LENGTH_LONG).show()
}
override fun showExpiredDialog() {
AlertDialog.Builder(this)
MaterialAlertDialogBuilder(this)
.setTitle(R.string.main_session_expired)
.setMessage(R.string.main_session_relogin)
.setPositiveButton(R.string.main_log_in) { _, _ -> presenter.onExpiredLoginSelected() }
@ -70,10 +77,15 @@ abstract class BaseActivity<T : BasePresenter<out BaseView>, VB : ViewBinding> :
.show()
}
override fun showAuthDialog() {
AuthDialog.newInstance().show(supportFragmentManager, "auth_dialog")
}
override fun showChangePasswordSnackbar(redirectUrl: String) {
messageContainer?.let {
Snackbar.make(it, R.string.error_password_change_required, LENGTH_LONG)
.setAction(R.string.all_change) { openInternetBrowser(redirectUrl) }
.apply { messageAnchor?.let { anchorView = it } }
.show()
}
}

View File

@ -1,8 +1,14 @@
package io.github.wulkanowy.ui.base
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.DialogFragment
import androidx.viewbinding.ViewBinding
import com.google.android.material.elevation.SurfaceColors
import io.github.wulkanowy.ui.modules.auth.AuthDialog
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.lifecycleAwareVariable
import javax.inject.Inject
@ -34,10 +40,25 @@ abstract class BaseDialogFragment<VB : ViewBinding> : DialogFragment(), BaseView
(activity as? BaseActivity<*, *>)?.showChangePasswordSnackbar(redirectUrl)
}
override fun showAuthDialog() {
AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
}
override fun showErrorDetailsDialog(error: Throwable) {
ErrorDialog.newInstance(error).show(childFragmentManager, error.toString())
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.setBackgroundColor(SurfaceColors.SURFACE_3.getColor(requireContext()))
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
) = binding.root
override fun onResume() {
super.onResume()
analyticsHelper.setCurrentScreen(requireActivity(), this::class.simpleName)

View File

@ -7,6 +7,7 @@ import androidx.viewbinding.ViewBinding
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.modules.auth.AuthDialog
import io.github.wulkanowy.utils.lifecycleAwareVariable
abstract class BaseFragment<VB : ViewBinding>(@LayoutRes layoutId: Int) : Fragment(layoutId),
@ -42,6 +43,10 @@ abstract class BaseFragment<VB : ViewBinding>(@LayoutRes layoutId: Int) : Fragme
(activity as? BaseActivity<*, *>)?.showExpiredDialog()
}
override fun showAuthDialog() {
AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
}
override fun openClearLoginView() {
(activity as? BaseActivity<*, *>)?.openClearLoginView()
}

View File

@ -1,10 +1,15 @@
package io.github.wulkanowy.ui.base
import io.github.wulkanowy.data.repositories.StudentRepository
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancelChildren
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.launch
import timber.log.Timber
open class BasePresenter<T : BaseView>(
@ -26,6 +31,7 @@ open class BasePresenter<T : BaseView>(
onSessionExpired = view::showExpiredDialog
onNoCurrentStudent = view::openClearLoginView
onPasswordChangeRequired = view::showChangePasswordSnackbar
onAuthorizationRequired = view::showAuthDialog
}
}

View File

@ -8,6 +8,8 @@ interface BaseView {
fun showExpiredDialog()
fun showAuthDialog()
fun openClearLoginView()
fun showErrorDetailsDialog(error: Throwable)

View File

@ -4,27 +4,32 @@ import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import androidx.appcompat.app.AlertDialog
import androidx.core.content.getSystemService
import androidx.core.os.bundleOf
import androidx.core.view.isGone
import androidx.fragment.app.DialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.DialogErrorBinding
import io.github.wulkanowy.utils.*
import javax.inject.Inject
@AndroidEntryPoint
class ErrorDialog : DialogFragment() {
class ErrorDialog : BaseDialogFragment<DialogErrorBinding>() {
@Inject
lateinit var appInfo: AppInfo
@Inject
lateinit var preferencesRepository: PreferencesRepository
private lateinit var error: Throwable
companion object {
private const val ARGUMENT_KEY = "error"
@ -33,32 +38,31 @@ class ErrorDialog : DialogFragment() {
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val error = requireArguments().getSerializable(ARGUMENT_KEY) as Throwable
val binding = DialogErrorBinding.inflate(LayoutInflater.from(context))
binding.bindErrorDetails(error)
return getAlertDialog(binding, error).apply {
enableReportButtonIfErrorIsReportable(error)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
error = requireArguments().serializable(ARGUMENT_KEY)
}
private fun getAlertDialog(binding: DialogErrorBinding, error: Throwable): AlertDialog {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return MaterialAlertDialogBuilder(requireContext()).apply {
val errorStacktrace = error.stackTraceToString()
setTitle(R.string.all_details)
setView(binding.root)
setView(DialogErrorBinding.inflate(layoutInflater).apply { binding = this }.root)
setNeutralButton(R.string.about_feedback) { _, _ ->
openConfirmDialog { openEmailClient(errorStacktrace) }
}
setNegativeButton(android.R.string.cancel) { _, _ -> }
setPositiveButton(android.R.string.copy) { _, _ -> copyErrorToClipboard(errorStacktrace) }
}.create()
}.create().apply {
setOnShowListener {
getButton(AlertDialog.BUTTON_NEUTRAL).isEnabled = error.isShouldBeReported()
}
}
}
private fun DialogErrorBinding.bindErrorDetails(error: Throwable) {
return with(this) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(binding) {
errorDialogHumanizedMessage.text = resources.getErrorString(error)
errorDialogErrorMessage.text = error.localizedMessage
errorDialogErrorMessage.isGone = error.localizedMessage.isNullOrBlank()
@ -67,12 +71,6 @@ class ErrorDialog : DialogFragment() {
}
}
private fun AlertDialog.enableReportButtonIfErrorIsReportable(error: Throwable) {
setOnShowListener {
getButton(AlertDialog.BUTTON_NEUTRAL).isEnabled = error.isShouldBeReported()
}
}
private fun copyErrorToClipboard(errorStacktrace: String) {
val clip = ClipData.newPlainText("Error details", errorStacktrace)
requireActivity().getSystemService<ClipboardManager>()?.setPrimaryClip(clip)
@ -80,7 +78,7 @@ class ErrorDialog : DialogFragment() {
}
private fun openConfirmDialog(callback: () -> Unit) {
AlertDialog.Builder(requireContext())
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.dialog_error_check_update)
.setMessage(R.string.dialog_error_check_update_message)
.setNeutralButton(R.string.about_feedback) { _, _ -> callback() }
@ -99,7 +97,8 @@ class ErrorDialog : DialogFragment() {
R.string.about_feedback_template,
"${appInfo.systemManufacturer} ${appInfo.systemModel}",
appInfo.systemVersion.toString(),
"${appInfo.versionName}-${appInfo.buildFlavor}"
"${appInfo.versionName}-${appInfo.buildFlavor}",
preferencesRepository.installationId,
) + "\n" + content,
onActivityNotFound = {
requireContext().openInternetBrowser(
@ -109,8 +108,4 @@ class ErrorDialog : DialogFragment() {
}
)
}
private fun showMessage(text: String) {
Toast.makeText(requireContext(), text, LENGTH_LONG).show()
}
}

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.base
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.data.exceptions.NoCurrentStudentException
import io.github.wulkanowy.sdk.scrapper.exception.AuthorizationRequiredException
import io.github.wulkanowy.sdk.scrapper.login.BadCredentialsException
import io.github.wulkanowy.sdk.scrapper.login.PasswordChangeRequiredException
import io.github.wulkanowy.utils.getErrorString
@ -20,6 +21,8 @@ open class ErrorHandler @Inject constructor(@ApplicationContext protected val co
var onPasswordChangeRequired: (String) -> Unit = {}
var onAuthorizationRequired: () -> Unit = {}
fun dispatch(error: Throwable) {
Timber.e(error, "An exception occurred while the Wulkanowy was running")
proceed(error)
@ -31,6 +34,7 @@ open class ErrorHandler @Inject constructor(@ApplicationContext protected val co
is PasswordChangeRequiredException -> onPasswordChangeRequired(error.redirectUrl)
is ScramblerException, is BadCredentialsException -> onSessionExpired()
is NoCurrentStudentException -> onNoCurrentStudent()
is AuthorizationRequiredException -> onAuthorizationRequired()
}
}
@ -39,5 +43,6 @@ open class ErrorHandler @Inject constructor(@ApplicationContext protected val co
onSessionExpired = {}
onNoCurrentStudent = {}
onPasswordChangeRequired = {}
onAuthorizationRequired = {}
}
}

View File

@ -1,17 +1,19 @@
package io.github.wulkanowy.ui.base
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.GET_ACTIVITIES
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO
import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES
import com.google.android.material.color.DynamicColors
import io.github.wulkanowy.R
import io.github.wulkanowy.data.enums.AppTheme
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
import io.github.wulkanowy.ui.modules.timetablewidget.TimetableWidgetConfigureActivity
import javax.inject.Inject
import javax.inject.Singleton
@ -25,31 +27,40 @@ class ThemeManager @Inject constructor(private val preferencesRepository: Prefer
when (activity) {
is MainActivity -> activity.setTheme(R.style.WulkanowyTheme_Black)
is LoginActivity -> activity.setTheme(R.style.WulkanowyTheme_Login_Black)
is SendMessageActivity -> activity.setTheme(R.style.WulkanowyTheme_MessageSend_Black)
}
}
} else if (activity is TimetableWidgetConfigureActivity || activity is LuckyNumberWidgetConfigureActivity) {
DynamicColors.applyToActivityIfAvailable(activity)
}
}
fun applyDefaultTheme() {
AppCompatDelegate.setDefaultNightMode(
when (preferencesRepository.appTheme) {
AppTheme.LIGHT -> MODE_NIGHT_NO
AppTheme.DARK, AppTheme.BLACK -> MODE_NIGHT_YES
AppTheme.SYSTEM -> MODE_NIGHT_FOLLOW_SYSTEM
AppTheme.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
AppTheme.DARK, AppTheme.BLACK -> AppCompatDelegate.MODE_NIGHT_YES
AppTheme.SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
}
)
}
private fun isThemeApplicable(activity: AppCompatActivity) =
activity.packageManager
.getPackageInfo(activity.packageName, GET_ACTIVITIES)
private fun isThemeApplicable(activity: AppCompatActivity): Boolean =
getPackageInfo(activity)
.activities
.singleOrNull { it.name == activity::class.java.canonicalName }
?.theme
.let {
it == R.style.WulkanowyTheme_Black || it == R.style.WulkanowyTheme_NoActionBar
|| it == R.style.WulkanowyTheme_Login || it == R.style.WulkanowyTheme_Login_Black
|| it == R.style.WulkanowyTheme_MessageSend || it == R.style.WulkanowyTheme_MessageSend_Black
}
@Suppress("DEPRECATION")
private fun getPackageInfo(activity: AppCompatActivity): PackageInfo {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
activity.packageManager.getPackageInfo(
activity.packageName,
PackageManager.PackageInfoFlags.of(GET_ACTIVITIES.toLong())
)
} else activity.packageManager.getPackageInfo(activity.packageName, GET_ACTIVITIES)
}
}

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