1
0

Compare commits

...

290 Commits

Author SHA1 Message Date
a69361708e Merge branch 'release/2.6.4' 2024-05-10 12:34:11 +02:00
567d868f76 Version 2.6.4 2024-05-10 12:30:30 +02:00
12030efee2 Version 2.6.3 2024-05-09 22:59:20 +02:00
3cbe98d7b8 Merge branch 'release/2.6.3' 2024-05-09 22:58:03 +02:00
503a97bc4c Version 2.6.3 2024-05-09 22:57:58 +02:00
04c382643d Fix a typo in settings - apperance & behaviour - menu configuration (#2547) 2024-05-09 18:17:10 +02:00
fc140ad9c1 Merge branch 'release/2.6.2' into develop 2024-05-08 01:55:42 +02:00
ae6a35121b Merge branch 'release/2.6.2' 2024-05-08 01:55:38 +02:00
78a2cc89e9 Version 2.6.2 2024-05-08 01:55:09 +02:00
dbfe5c8918 Bump com.android.tools.build:gradle from 8.3.2 to 8.4.0 (#2539) 2024-05-05 08:27:41 +00:00
c697ca7ad1 Bump androidx.fragment:fragment-ktx from 1.6.2 to 1.7.0 (#2538) 2024-05-05 08:27:28 +00:00
1b00f4e518 Bump about_libraries from 11.1.3 to 11.1.4 (#2540) 2024-05-05 08:27:10 +00:00
fb77bf882f Bump androidx.viewpager2:viewpager2 from 1.1.0-beta02 to 1.1.0-rc01 (#2542) 2024-05-05 08:26:55 +00:00
466ebbef3a Bump com.google.firebase:firebase-bom from 32.8.1 to 33.0.0 (#2544) 2024-05-05 08:26:29 +00:00
458a4c8164 Bump androidx.core:core-ktx from 1.13.0 to 1.13.1 (#2545) 2024-05-05 08:26:14 +00:00
0363c0854f Merge branch 'release/2.6.1' into develop 2024-05-02 15:20:56 +02:00
558addd097 Merge branch 'release/2.6.1' 2024-05-02 15:20:51 +02:00
233ddc955b Version 2.6.1 2024-05-02 15:20:45 +02:00
065c711f91 Add missing release client_info definition to conform gms plugin in hms release (#2537) 2024-05-02 14:10:33 +02:00
49655c11c9 Revert "Bump com.google.android.gms:play-services-ads from 22.6.0 to 23.0.0 (…" (#2536)
This reverts commit a7c2009e49.
2024-05-02 12:43:03 +02:00
38fd4eda22 Merge branch 'release/2.6.0' into develop 2024-05-01 22:30:53 +02:00
e8f9c57c34 Merge branch 'release/2.6.0' 2024-05-01 22:30:48 +02:00
b71630246a Version 2.6.0 2024-05-01 22:30:41 +02:00
fd2eac1f08 New Crowdin updates (#2535) 2024-05-01 19:28:49 +02:00
1545ff65d3 CS and SK listing update (#2534) 2024-05-01 19:07:41 +02:00
ff32c82851 New Crowdin updates (#2532)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2024-05-01 18:59:57 +02:00
d531a94594 Update screenshots (#2533) 2024-05-01 18:50:57 +02:00
71ab9586ac Add admin message to LoginStudentSelect and LoginSymbol (#2531)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2024-05-01 16:57:31 +02:00
e1a19be06c New Crowdin updates (#2530) 2024-05-01 12:29:41 +02:00
6f2168d641 Additional lessons in timetable view (#2491)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2024-04-26 23:33:45 +02:00
cde2121b60 New Crowdin updates (#2527) 2024-04-26 22:05:46 +02:00
a0bc37e826 Merge branch 'bugfix/2.5.8' into develop 2024-04-25 12:45:26 +02:00
4d67de8e5f Merge branch 'bugfix/2.5.8' 2024-04-25 12:45:19 +02:00
f983a23b1a Version 2.5.8 2024-04-25 12:45:09 +02:00
6a1851da13 Bump sdk to 2.5.8-SNAPSHOT 2024-04-25 09:26:47 +02:00
ad5381ce34 Fix race condition of showing empty view in timetable (#2486)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2024-04-24 22:46:55 +02:00
dbc7587741 Add settings button to attendance calculator (#2492) 2024-04-24 22:44:59 +02:00
bc3aa7b8dc New Crowdin updates (#2526) 2024-04-24 22:28:16 +02:00
6bf6a9da11 New Crowdin updates (#2480) 2024-04-24 19:27:11 +02:00
ab175bdd9a Merge branch 'bugfix/2.5.7' into develop 2024-04-22 22:42:22 +02:00
8dbbea2138 Merge branch 'bugfix/2.5.7' 2024-04-22 22:36:13 +02:00
f6226e6b53 Version 2.5.7 2024-04-22 22:36:05 +02:00
43d13db07c Update translations 2024-04-22 22:17:03 +02:00
82210c37e3 Display separate annual average and semester average if available (#2524)
* Add displaying year average on grade details screen

* Add displaying year average on grade summary screen

* Add displaying year average on grade summary header

* Fix tests

* Hide semester average if it is not available in grade summary item

* Add full names of summary averages labels
2024-04-22 22:03:42 +02:00
2816d7217a Version 2.5.6 2024-04-22 00:39:44 +02:00
2fa868173b Show graduated students on top of student select items list 2024-04-22 00:39:44 +02:00
622c75bb42 Don't display brackets in login student select items when schoolShortName is blank 2024-04-22 00:39:44 +02:00
2121125283 Migrate away from userLoginId to studentId due to vulcan last changes 2024-04-22 00:39:44 +02:00
c72a117e34 Bump sdk to 2.5.6-SNAPSHOT 2024-04-22 00:39:44 +02:00
b5cc32d59f Merge branch 'bugfix/2.5.6' 2024-04-22 00:39:19 +02:00
d943d03266 Version 2.5.6 2024-04-22 00:39:04 +02:00
6eca8c42f5 Show graduated students on top of student select items list 2024-04-22 00:11:29 +02:00
af989ba9f6 Don't display brackets in login student select items when schoolShortName is blank 2024-04-21 23:59:29 +02:00
4a65a5b192 Migrate away from userLoginId to studentId due to vulcan last changes 2024-04-21 23:51:34 +02:00
bbbafdfe70 Bump sdk to 2.5.6-SNAPSHOT 2024-04-21 20:37:31 +02:00
860095e862 Bump androidx.activity:activity-ktx from 1.8.2 to 1.9.0 (#2522) 2024-04-21 02:31:28 +00:00
ff9be43291 Bump org.apache.commons:commons-text from 1.11.0 to 1.12.0 (#2523) 2024-04-21 02:25:16 +00:00
a487378daf Bump androidx.core:core-ktx from 1.12.0 to 1.13.0 (#2521) 2024-04-21 02:24:04 +00:00
895f5cbb76 Bump com.android.tools.build:gradle from 8.2.2 to 8.3.2 (#2517) 2024-04-14 14:24:38 +00:00
8b9b1460ab Update AuthDialog text (#2506) 2024-04-13 22:03:23 +02:00
7edd3df074 Bump about_libraries from 11.1.1 to 11.1.3 (#2518) 2024-04-13 19:56:16 +00:00
16c51f7b07 Bump com.google.firebase:firebase-bom from 32.8.0 to 32.8.1 (#2519) 2024-04-13 19:55:50 +00:00
7a3a97447f Add isAdded check in AdditionalLessonAddDialog (#2515) 2024-04-08 20:51:05 +02:00
b500d8e204 Bump org.sonarsource.scanner.gradle:sonarqube-gradle-plugin (#2511) 2024-04-08 18:09:38 +00:00
c34a369286 Bump org.robolectric:robolectric from 4.11.1 to 4.12.1 (#2514) 2024-04-08 18:08:20 +00:00
b9f3ab2e56 Bump com.squareup.retrofit2:retrofit from 2.10.0 to 2.11.0 (#2513) 2024-04-08 18:08:01 +00:00
6b59973624 Bump hilt_version from 2.51 to 2.51.1 (#2510) 2024-04-08 17:41:28 +00:00
d18485293d Merge branch 'bugfix/2.5.5' into develop 2024-03-26 20:38:07 +01:00
a82e11d694 Merge branch 'bugfix/2.5.5' 2024-03-26 20:38:01 +01:00
4dc5fc65ac Version 2.5.5 2024-03-26 20:37:51 +01:00
7463cf6253 Replace function in DAO to 'OR' in SQL query 2024-03-26 20:29:35 +01:00
d799ec7ac9 Add skipping migration when previous attempt failed (#2508) 2024-03-26 19:19:44 +01:00
254719f22f Remove classId from semester query when eduOne (#2509) 2024-03-26 19:02:35 +01:00
596e8df4fc Merge branch 'bugfix/2.5.4' into develop 2024-03-26 13:29:54 +01:00
e1e276e1ea Merge branch 'bugfix/2.5.4' 2024-03-26 13:29:26 +01:00
8cdd4311a9 Version 2.5.4 2024-03-26 13:29:22 +01:00
b7f7b16aef Add logging error from units and symbols during registration (#2507) 2024-03-26 12:54:07 +01:00
f13ce6e2b4 Bump com.squareup.retrofit2:retrofit from 2.9.0 to 2.10.0 (#2502) 2024-03-25 12:32:28 +00:00
8c10606b61 Bump about_libraries from 11.1.0 to 11.1.1 (#2503) 2024-03-25 12:32:07 +00:00
7fda4276d6 Bump com.google.firebase:firebase-bom from 32.7.4 to 32.8.0 (#2504) 2024-03-25 12:31:46 +00:00
7993366bfc Merge branch 'bugfix/2.5.3' into develop 2024-03-25 00:05:11 +01:00
2e71c50894 Merge branch 'bugfix/2.5.3' 2024-03-24 23:43:51 +01:00
b3faac01a5 Version 2.5.3 2024-03-24 23:43:45 +01:00
3881678208 Fix issues related to not authenticated eduOne students (#2501) 2024-03-24 23:22:07 +01:00
76d038eefa Hide grade statistics when is eduOne, add isEduOne flag migration (#2496)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2024-03-24 19:42:36 +01:00
3a55c3c760 Add ignoring FeatureUnavailableException in SyncWorker (#2500) 2024-03-24 18:55:23 +01:00
a0818de7d1 Add isAdded condition to HomeworkAddDialog (#2499) 2024-03-24 14:55:05 +01:00
b280316b07 Bump sdk to 2.5.3-SNAPSHOT 2024-03-21 23:06:18 +01:00
0554aa91fd Add WulkanowySdkFactory (#2479) 2024-03-21 22:11:03 +01:00
5a77d1e940 Hide lesson number when is eduOne (#2498) 2024-03-21 21:19:49 +01:00
c9a42a6cf6 Add try catch to initialize MobileAds SDK (#2497) 2024-03-21 11:03:08 +01:00
27eb0588d7 Merge branch 'bugfix/2.5.2' into develop 2024-03-20 02:24:26 +01:00
e17129efea Merge branch 'bugfix/2.5.2' 2024-03-20 02:18:07 +01:00
6047af9ff0 Version 2.5.2 2024-03-20 02:18:00 +01:00
d789aa718e Change AuthDialog condition to isAuth flag (#2495)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2024-03-20 01:49:55 +01:00
8623b53357 Fix lateness color in attendance (#2481) 2024-03-19 22:13:32 +01:00
78e28ad791 Remove savedInstance in MessagePreviewFragment (#2477) 2024-03-19 22:13:09 +01:00
377c288e9e Add missing onDetachView in AutDialog (#2476) 2024-03-19 22:12:54 +01:00
b31c7e1720 Fix task description color crash (#2475) 2024-03-19 22:12:39 +01:00
d01fe9c370 Bump sdk to 2.5.2-SNAPSHOT 2024-03-19 22:11:02 +01:00
34d34a050a Add widget updating on data sync (#2487)
---------

Co-authored-by: Faierbel <RafalBO99@outlook.com>
2024-03-17 21:06:40 +01:00
961bc24f27 Add docs to Resource, changing networkBoundResource generics naming (#2483) 2024-03-13 19:13:56 +01:00
8a90b61b97 Refactor networkBoundResource (#2482)
---------

Co-authored-by: Faierbel <RafalBO99@outlook.com>
2024-03-13 13:01:00 +01:00
6a8f6f9496 Add WulkanowySdkFactory (#2479) 2024-03-11 23:38:39 +01:00
afb5ae741c Fix lateness color in attendance (#2481) 2024-03-11 23:38:17 +01:00
95e41b5570 Handle subjects with no attendances in attendance calculator better (#2478)
---------

Co-authored-by: Faierbel <RafalBO99@outlook.com>
2024-03-11 19:19:24 +00:00
eb6fdd900e New Crowdin updates (#2470) 2024-03-11 11:47:13 +01:00
88def5eff8 Remove savedInstance in MessagePreviewFragment (#2477) 2024-03-11 11:45:28 +01:00
0e99c81eb8 Add missing onDetachView in AutDialog (#2476) 2024-03-11 11:45:15 +01:00
38c00ddab5 Fix task description color crash (#2475) 2024-03-11 11:44:59 +01:00
c72cc39920 Separate strings from array to avoid duplications (#2473) 2024-03-09 21:01:58 +01:00
4ef9fb1f28 Update preferences strings (#2472) 2024-03-09 10:05:12 +01:00
5dd5697f65 Remove firebase disable flag (#2471) 2024-03-09 10:03:36 +01:00
a7c2009e49 Bump com.google.android.gms:play-services-ads from 22.6.0 to 23.0.0 (#2469) 2024-03-08 20:16:03 +00:00
a71ef4a4b2 Bump com.google.firebase:firebase-bom from 32.7.3 to 32.7.4 (#2467) 2024-03-08 20:14:33 +00:00
30413086fc Bump kotlin_version from 1.9.22 to 1.9.23 (#2466) 2024-03-08 20:13:58 +00:00
98ddf97855 Update gradle wrapper to 8.6 (#2468) 2024-03-08 20:57:26 +01:00
8f5a210ec7 Add attendance calculator (#1597)
---------

Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
Co-authored-by: Faierbel <RafalBO99@outlook.com>
2024-03-08 20:36:43 +01:00
ce09b07cfd Merge branch 'release/2.5.1' into develop 2024-03-03 11:19:48 +01:00
5ed19cb21a Merge branch 'release/2.5.1' 2024-03-03 11:19:42 +01:00
0a1f7270b4 Version 2.5.1 2024-03-03 11:15:11 +01:00
47d8513a77 New Crowdin updates (#2464) 2024-03-03 10:35:17 +01:00
00432ab911 Merge branch 'release/2.5.0' into develop 2024-03-02 21:18:14 +01:00
7b2c839775 Merge branch 'release/2.5.0' 2024-03-02 21:18:10 +01:00
f455064b9d Version 2.5.0 2024-03-02 21:18:02 +01:00
2bbc157d03 Add some new symbols to symbol autocomplete field (#2461) 2024-03-02 20:45:23 +01:00
a0a0b8dea6 New Crowdin updates (#2460) 2024-03-02 20:37:36 +01:00
3bab883a56 Add a message explaining the reason for the captcha to the captcha dialog (#2459) 2024-03-02 19:49:08 +01:00
b319bb03cd New Crowdin updates (#2458) 2024-03-02 17:31:44 +01:00
333306e7ba Wrap delete and save operations in database transactions (#2450) 2024-03-02 16:25:27 +00:00
fb240938ed Bump about_libraries from 10.10.0 to 11.1.0 (#2454) 2024-03-02 16:21:55 +00:00
dc9af29a44 Bump hilt_version from 2.50 to 2.51 (#2456) 2024-03-02 16:11:13 +00:00
e9d64de0cb Improve invalid password message (#2451) 2024-03-02 17:10:38 +01:00
05bda598fc Bump mockk from 1.13.9 to 1.13.10 (#2455) 2024-03-02 16:10:19 +00:00
3564366a8f Bump com.google.firebase:firebase-bom from 32.7.2 to 32.7.3 (#2453) 2024-03-02 16:08:32 +00:00
f2d26453ed Fix calculating average with optional arithmetic average on and no grade with average in second semester (#2448) 2024-03-02 17:01:12 +01:00
ccba31f2e8 Add last announcements to school announcements (#2452) 2024-03-02 16:55:54 +01:00
a7238e3f23 New Crowdin updates (#2447) 2024-03-01 22:16:56 +01:00
ea28fc783c Add message from trash restoring (#2438) 2024-03-01 21:14:43 +01:00
c04752ed39 Fix timetable items layout (#2446) 2024-03-01 10:32:55 +01:00
c198e6a2f7 New Crowdin updates (#2445) 2024-03-01 00:06:54 +01:00
2c1337bb51 New Crowdin updates (#2439) 2024-02-29 21:36:51 +01:00
7a4032dda4 Add mute message senders (#2415)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2024-02-29 21:30:02 +01:00
1ab300d74f Bump android_hilt from 1.1.0 to 1.2.0 (#2443) 2024-02-27 08:53:00 +00:00
1b8c389984 Bump io.coil-kt:coil from 2.5.0 to 2.6.0 (#2441) 2024-02-27 08:52:47 +00:00
74a20b2f65 Add Github Sponsor (#2444) 2024-02-27 09:42:44 +01:00
d5c17285c1 Fix error handling in login (#2437) 2024-02-25 16:37:28 +01:00
e378b4c70a Fix loading timetable and attendance when should be refreshed returns true (#2436) 2024-02-25 16:36:50 +01:00
31854fc4b8 Fix text cut off across the app when text size is set to 200% (#2435) 2024-02-25 16:35:56 +01:00
f52fe8306f Merge branch 'release/2.4.2' into develop 2024-02-22 16:15:36 +01:00
3eae3a7667 Merge branch 'release/2.4.2' 2024-02-22 16:15:30 +01:00
b613b84469 Version 2.4.2 2024-02-22 16:15:24 +01:00
2776d019b9 Revert "Bump com.google.android.ump:user-messaging-platform from 2.1.0 to 2.2…" (#2434)
This reverts commit fc91936884.
2024-02-22 15:52:40 +01:00
729e72cddb Fix text pasting into date field in additional lesson add dialog (#2433) 2024-02-21 21:36:20 +01:00
ec101c1f52 Fix error handling in widgets (#2430) 2024-02-19 11:30:05 +01:00
cfec79405f Bump org.jetbrains.kotlinx:kotlinx-serialization-json (#2429) 2024-02-18 14:21:59 +00:00
7d8be1b9fc Bump coroutines from 1.7.3 to 1.8.0 (#2428) 2024-02-18 14:21:38 +00:00
c781159e75 Merge branch 'release/2.4.1' into develop 2024-02-17 13:10:39 +01:00
90a5b9e20f Merge branch 'release/2.4.1' 2024-02-17 13:10:34 +01:00
3cf6c295b0 Version 2.4.1 2024-02-17 13:07:45 +01:00
e757585bd3 New Crowdin updates (#2426) 2024-02-17 12:43:52 +01:00
736d16a7ab Make WebkitCookieManagerProxy no-op if webview is not available on the device (#2427) 2024-02-17 12:31:14 +01:00
6f4a8d5534 Add missing symbol and custom domain suffix validation (#2425) 2024-02-17 11:41:32 +01:00
b5e17c4ff7 Bump com.google.firebase:firebase-bom from 32.7.1 to 32.7.2 (#2424) 2024-02-16 18:50:07 +00:00
cc01525f16 Bump com.google.gms:google-services from 4.4.0 to 4.4.1 (#2423) 2024-02-16 18:49:46 +00:00
c2ec05662b Merge branch 'release/2.4.0' into develop 2024-02-09 19:45:05 +01:00
b99ba48d2c Merge branch 'release/2.4.0' 2024-02-09 19:45:01 +01:00
2d4a1bff83 Version 2.4.0 2024-02-09 19:44:55 +01:00
cd853e4d57 New Crowdin updates (#2417) 2024-02-09 18:34:04 +00:00
8183d7d5a0 Change default symbol for standard register variant (#2421) 2024-02-09 16:35:18 +01:00
3f199cb610 Replace fakelog.cf to wulkanowy.net.pl (#2419) 2024-02-09 12:40:01 +00:00
22f72981cb Add descriptive grades (#2411) 2024-02-08 09:16:09 +01:00
bce92b7347 Fix displaying lessons for tomorrow if there is no more lessons for today (#2416) 2024-02-08 07:49:17 +01:00
ed5166333a Add the ability to dynamically expand the application window (#2413) 2024-02-06 19:48:31 +01:00
a05f1f70f7 Add colors to attendance and ! to unexcused lateness (#2412) 2024-02-06 18:21:56 +01:00
e58a60410c Fix android tests (#2410) 2024-02-04 10:48:59 +01:00
fc91936884 Bump com.google.android.ump:user-messaging-platform from 2.1.0 to 2.2.0 (#2408) 2024-01-26 10:30:36 +00:00
88043569ac Bump com.huawei.hms:hianalytics from 6.12.0.300 to 6.12.0.301 (#2407) 2024-01-26 10:23:01 +00:00
10add8a70e Bump com.android.tools.build:gradle from 8.2.1 to 8.2.2 (#2406) 2024-01-26 10:21:30 +00:00
098af9884a Bump com.google.firebase:firebase-bom from 32.7.0 to 32.7.1 (#2404) 2024-01-23 19:17:29 +00:00
554c1b1261 Merge branch 'release/2.3.5' into develop 2024-01-21 21:04:35 +01:00
496695162d Merge branch 'release/2.3.5' 2024-01-21 21:04:29 +01:00
dc59f4ffa3 Version 2.3.5 2024-01-21 21:04:23 +01:00
e0f4cad7fb Add missing unitId to sdk switchSemester call (#2402) 2024-01-21 20:01:00 +01:00
a51a54dc7a Normalize synchronization date ranges to fix weird notification issues (#2403) 2024-01-21 18:59:54 +01:00
7cdac6ede1 Add admin message to error view in dashboard (#2400) 2024-01-21 12:39:23 +01:00
9dfb282e88 Add X to close admin message (#2401) 2024-01-21 11:39:55 +01:00
725668f855 Bump androidx.lifecycle:lifecycle-livedata-ktx from 2.6.2 to 2.7.0 (#2398) 2024-01-19 09:22:34 +00:00
e58c155961 New Crowdin updates (#2396) 2024-01-14 18:02:15 +01:00
05a5047a70 Merge branch 'release/2.3.4' into develop 2024-01-14 17:33:30 +01:00
1fe464a289 Merge branch 'release/2.3.4' 2024-01-14 17:33:14 +01:00
497acf9d68 Version 2.3.4 2024-01-14 17:32:41 +01:00
976eb5a772 Fix cancelling dashboard jobs (#2395) 2024-01-14 16:45:30 +01:00
9ececeb4e9 New Crowdin updates (#2394) 2024-01-14 16:41:57 +01:00
096fe359e7 Make some improvements in captcha dialog (#2393)
* Add improvements retrying after captcha solved

* Add showAuthDialog from BaseActivity instead of displaying this dialog manually

* Add getCookieStore() with removeAll impl in WebkitCookieManagerProxy

* Add debounce to captcha dialog showing logic

* Add refresh button to captcha dialog

* Destroy webview along with captcha dialog

* Add clear webkit cookies button to debug menu

* Add captcha error message

* Update captcha verified message
2024-01-14 13:09:04 +00:00
a98e8398fd Add webview to obtain cloudflare captcha cookies for okhttp (#2392) 2024-01-12 18:34:43 +01:00
d8c4926a97 Merge branch 'release/2.3.3' into develop 2024-01-09 21:46:10 +01:00
17c139b559 Merge branch 'release/2.3.3' 2024-01-09 21:46:04 +01:00
ddbcc7a04c Version 2.3.3 2024-01-09 21:45:59 +01:00
9f9eb60280 Merge branch 'release/2.3.2' into develop 2024-01-09 19:31:29 +01:00
f893170dec Merge branch 'release/2.3.2' 2024-01-09 19:31:22 +01:00
cff08d6322 Version 2.3.2 2024-01-09 19:27:03 +01:00
9dee7f01f6 Avoid deleting luckynumber when SDK returns null (#2391) 2024-01-09 19:07:46 +01:00
8324a9cac3 Use emptyCookieJarInterceptor in SDK configuration (#2390) 2024-01-09 19:00:37 +01:00
5316e3e1bf Bump mockk from 1.13.8 to 1.13.9 (#2389) 2024-01-08 15:32:30 +00:00
81e80181f2 New Crowdin updates (#2388) 2024-01-08 16:32:06 +01:00
6ee38e9259 Add clearing all data and key entry when decryption failed (#2386) 2024-01-06 00:01:33 +01:00
40df80371c Use forked slf4j-timber to fix logging problems with slf4j v2 (#2387) 2024-01-05 16:03:50 +01:00
a3596c35b8 Update AGP and Gradle (#2385) 2024-01-04 09:33:51 +01:00
66b7ea4cb4 Merge branch 'release/2.3.1' into develop 2024-01-03 16:02:39 +01:00
770749e158 Merge branch 'release/2.3.1' 2024-01-03 16:02:32 +01:00
0aa83b020e Bump sdk to 2.3.3 2024-01-03 16:01:30 +01:00
4d1218d1d3 Version 2.3.1 2024-01-03 14:53:16 +01:00
0ea6cbc8ed Merge branch 'release/2.3.0' into develop 2024-01-02 01:51:58 +01:00
eb31f9578f Merge branch 'release/2.3.0' 2024-01-02 01:51:52 +01:00
f69d50d2c1 Version 2.3.0 2024-01-02 01:51:09 +01:00
8a424ee6a4 New Crowdin updates (#2381) 2024-01-02 01:30:31 +01:00
7dfa48bbe3 Add User Messaging Platform SDK for ads agreements (#2375) 2024-01-01 21:19:00 +01:00
d811cdb919 Bump com.huawei.agconnect:agcp from 1.9.1.302 to 1.9.1.303 (#2377) 2024-01-01 17:39:08 +00:00
e2f2e21081 Bump com.huawei.agconnect:agconnect-crash from 1.9.1.302 to 1.9.1.303 (#2379) 2024-01-01 17:38:29 +00:00
c812310497 Bump about_libraries from 10.9.2 to 10.10.0 (#2380) 2024-01-01 18:36:02 +01:00
7f6475cf35 Merge branch 'release/2.2.7' into develop 2023-12-27 22:21:18 +01:00
a2a7d2ebb2 Merge branch 'release/2.2.7' 2023-12-27 22:21:13 +01:00
a5bc45c5da Version 2.2.7 2023-12-27 22:21:07 +01:00
5646befbd7 Revert "Bump com.google.android.material:material from 1.10.0 to 1.11.0 (#2368)" (#2376)
This reverts commit 7f4539fd27.
2023-12-27 21:52:04 +01:00
75f496b5d2 Bump kotlin_version from 1.9.21 to 1.9.22 (#2371) 2023-12-27 16:11:58 +00:00
23d989d22a Bump hilt_version from 2.49 to 2.50 (#2372) 2023-12-24 07:01:40 +00:00
9e013f7cd9 Bump ru.cian:huawei-publish-gradle-plugin from 1.4.0 to 1.4.2 (#2370) 2023-12-24 07:00:42 +00:00
c63a7c03f1 Bump com.huawei.agconnect:agcp from 1.9.1.301 to 1.9.1.302 (#2373) 2023-12-24 06:54:28 +00:00
5ceee84f0e Bump com.huawei.agconnect:agconnect-crash from 1.9.1.301 to 1.9.1.302 (#2374) 2023-12-24 06:54:09 +00:00
7f4539fd27 Bump com.google.android.material:material from 1.10.0 to 1.11.0 (#2368) 2023-12-22 13:48:13 +00:00
71ebf1260b Bump com.android.tools.build:gradle from 8.1.4 to 8.2.0 (#2361) 2023-12-15 19:44:32 +00:00
784ee58384 Bump work_manager from 2.8.1 to 2.9.0 (#2363) 2023-12-15 16:21:08 +00:00
eceef3f582 Bump com.google.firebase:firebase-bom from 32.6.0 to 32.7.0 (#2366) 2023-12-15 15:52:54 +00:00
0d950fbd86 Bump com.google.android.gms:play-services-ads from 22.5.0 to 22.6.0 (#2367) 2023-12-15 15:52:35 +00:00
003d63b516 Bump room from 2.6.0 to 2.6.1 (#2360) 2023-12-07 22:44:50 +00:00
b4c0440a8e Bump hilt_version from 2.48.1 to 2.49 (#2362) 2023-12-07 22:44:37 +00:00
137c305295 Bump org.jetbrains.kotlinx:kotlinx-serialization-json (#2365) 2023-12-07 22:44:23 +00:00
2c40c221c3 Bump kotlin_version from 1.9.10 to 1.9.21 (#2357) 2023-11-28 22:32:32 +00:00
e82ac78d4a Bump androidx.fragment:fragment-ktx from 1.6.1 to 1.6.2 (#2348) 2023-11-28 22:32:18 +00:00
59d46ce956 Bump com.google.android.gms:play-services-ads from 22.4.0 to 22.5.0 (#2346) 2023-11-28 22:21:19 +00:00
17caa8ecbd Bump com.android.tools:desugar_jdk_libs from 2.0.3 to 2.0.4 (#2345) 2023-11-28 22:21:00 +00:00
e9540b4012 Bump androidx.activity:activity-ktx from 1.8.0 to 1.8.1 (#2354) 2023-11-28 22:20:41 +00:00
643ad60455 Bump com.google.firebase:firebase-bom from 32.5.0 to 32.6.0 (#2355) 2023-11-28 22:20:18 +00:00
01f892ce5c Bump com.android.tools.build:gradle from 8.1.2 to 8.1.4 (#2356) 2023-11-28 22:19:53 +00:00
f61b6a5e78 Bump com.google.android.play:integrity from 1.2.0 to 1.3.0 (#2351) 2023-11-28 22:10:32 +00:00
650cf7484e Bump android_hilt from 1.0.0 to 1.1.0 (#2343) 2023-11-28 22:10:11 +00:00
037cbb0b19 Bump about_libraries from 10.9.1 to 10.9.2 (#2344)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2023-11-28 23:08:13 +01:00
e49835e89e Merge branch 'release/2.2.6' into develop 2023-11-06 11:22:25 +01:00
c64be2fab0 Merge branch 'release/2.2.6' 2023-11-06 11:22:19 +01:00
ce9cb35172 Version 2.2.6 2023-11-06 11:22:15 +01:00
7fa9219c7b Bump sdk version 2023-11-06 09:40:47 +01:00
1fe1618220 Merge branch 'release/2.2.5' into develop 2023-11-03 23:05:48 +01:00
d9bab2af78 Merge branch 'release/2.2.5' 2023-11-03 23:05:42 +01:00
06b6d88dd1 Version 2.2.5 2023-11-03 23:05:35 +01:00
3bf27baed5 Bump org.robolectric:robolectric from 4.11 to 4.11.1 (#2342) 2023-11-01 17:31:24 +00:00
6802d74002 Bump com.google.firebase:firebase-bom from 32.4.1 to 32.5.0 (#2341) 2023-11-01 17:31:05 +00:00
3fd2683df7 Update dependencies and remove deprecations (#2340) 2023-11-01 16:47:39 +01:00
b708c70ea2 Merge branch 'release/2.2.4' into develop 2023-10-27 14:49:54 +02:00
aba08e6aa9 Merge branch 'release/2.2.4' 2023-10-27 14:49:46 +02:00
124b6dfd79 Version 2.2.4 2023-10-27 14:49:41 +02:00
1dbaa8bfdc Migrate to separate app-update and review artifacts from play:core (#2336) 2023-10-27 14:09:42 +02:00
25ac171298 Merge branch 'release/2.2.3' into develop 2023-10-26 18:32:01 +02:00
387ff1cba7 Merge branch 'release/2.2.3' 2023-10-26 18:31:56 +02:00
eef3464d0b Version 2.2.3 2023-10-26 18:31:51 +02:00
61297a01c7 New Crowdin updates (#2334) 2023-10-26 14:01:45 +02:00
762d4b1393 Timetable timers fixes (#2333) 2023-10-26 10:06:54 +02:00
2e86b67eec Merge branch 'release/2.2.2' into develop 2023-10-23 20:02:32 +02:00
6071b7571b Merge branch 'release/2.2.2' 2023-10-23 20:02:25 +02:00
fcea2218b5 Version 2.2.2 2023-10-23 19:56:46 +02:00
a4a191700e Bump com.google.firebase:firebase-bom from 32.3.1 to 32.4.0 (#2331) 2023-10-23 17:28:38 +00:00
3d76d41b55 Bump com.squareup.okhttp3:logging-interceptor from 4.11.0 to 4.12.0 (#2330) 2023-10-23 16:49:58 +00:00
0e1c20a952 Bump room from 2.5.2 to 2.6.0 (#2329) 2023-10-23 16:48:23 +00:00
5d14ee7f4e Bump androidx.recyclerview:recyclerview from 1.3.1 to 1.3.2 (#2332) 2023-10-23 16:47:03 +00:00
83527d91f3 Allow direct access to weekend from day navigation when there is any lesson during weekend (#2326) 2023-10-23 13:05:46 +02:00
9d62410530 Sort teachers by name in school and teachers tab (#2327) 2023-10-23 13:05:05 +02:00
5dffbdadfa Points statistics improvements (#2328) 2023-10-23 13:04:42 +02:00
516922d5aa Bump org.sonarsource.scanner.gradle:sonarqube-gradle-plugin (#2324) 2023-10-14 19:18:28 +00:00
9098e74065 Bump com.google.android.material:material from 1.9.0 to 1.10.0 (#2325) 2023-10-14 19:17:56 +00:00
2f5577cc54 Update SDK to 34 (#2322) 2023-10-06 10:07:55 +02:00
3272c38356 Merge branch 'release/2.2.1' into develop 2023-10-03 01:14:25 +02:00
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
389 changed files with 25748 additions and 5422 deletions

View File

@ -162,7 +162,7 @@ jobs:
openssl aes-256-cbc -d -in ./app/upload-key-encrypted.jks -k $ENCRYPT_KEY >> ./app/upload-key.jks
- run:
name: Publish release
command: ./gradlew publishPlayRelease --no-daemon --stacktrace --console=plain -PenableCrashlytics -PdisablePreDex
command: ./gradlew publishPlayRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
workflows:
version: 2

4
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
github: wulkanowy
custom: https://www.paypal.com/paypalme/wulkanowy

View File

@ -13,7 +13,7 @@ jobs:
environment: google-play
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v2
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 17
@ -40,7 +40,7 @@ jobs:
SINGLE_SUPPORT_AD_ID: ${{ secrets.SINGLE_SUPPORT_AD_ID }}
DASHBOARD_TILE_AD_ID: ${{ secrets.DASHBOARD_TILE_AD_ID }}
SET_BUILD_TIMESTAMP: ${{ secrets.SET_BUILD_TIMESTAMP }}
run: ./gradlew publishPlayReleaseApps -PenableFirebase --stacktrace;
run: ./gradlew publishPlayReleaseApps --stacktrace;
deploy-app-gallery:
name: AppGallery
@ -49,7 +49,7 @@ jobs:
environment: app-gallery
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v2
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 17

View File

@ -19,7 +19,7 @@ jobs:
environment: app-center
steps:
- uses: actions/checkout@v3
- uses: actions/setup-java@v2
- uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: 17
@ -36,8 +36,7 @@ jobs:
- name: Prepare build configuration
run: |
sed -i -e "s#applicationIdSuffix \".dev\"#applicationIdSuffix \".${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/build.gradle
sed -i -e "s#.dev\"#.${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/src/debug/google-services.json
sed -i -e "s#.dev\"#.${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/src/debug/agconnect-services.json
sed -i -e "s#.dev\"#.${GITHUB_HEAD_REF//[-.\/]/_}\"#" app/google-services.json
sed -i -e '/versionNameSuffix/d' app/build.gradle
- name: Add signing config
run: |
@ -89,7 +88,7 @@ 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: 17
@ -131,7 +130,7 @@ jobs:
BITRISE_KEYSTORE_PASSWORD: ${{ secrets.BITRISE_KEYSTORE_PASSWORD }}
BITRISE_KEY_ALIAS: ${{ secrets.BITRISE_KEY_ALIAS }}
BITRISE_KEY_PASSWORD: ${{ secrets.BITRISE_KEY_PASSWORD }}
run: ./gradlew assemblePlayDebug -PenableFirebase --stacktrace
run: ./gradlew assemblePlayDebug --stacktrace
- name: Upload apk to github artifacts
uses: actions/upload-artifact@v3
with:

View File

@ -19,7 +19,7 @@ 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: 17
@ -45,7 +45,7 @@ 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: 17
@ -71,7 +71,7 @@ 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: 17

17
.gitignore vendored
View File

@ -65,6 +65,12 @@ captures/
.idea/uiDesigner.xml
.idea/runConfigurations.xml
.idea/discord.xml
.idea/migrations.xml
.idea/androidTestResultsUserPreferences.xml
.idea/copilot
.idea/deploymentTargetDropDown.xml
.idea/deploymentTargetSelector.xml
.idea/kotlinc.xml
# Keystore files
*.jks
@ -111,12 +117,13 @@ Thumbs.db
*.ear
### AndroidStudio Patch ###
!/gradle/wrapper/gradle-wrapper.jar
.idea/jarRepositories.xml
### Services config files
agconnect-services.json
agconnect-credentials.json
google-services.json
!app/google-services.json
app/src/release/agconnect-services.json
app/src/release/agconnect-credentials.json
.idea/deploymentTargetDropDown.xml
.idea/kotlinc.xml

View File

@ -61,7 +61,7 @@ script:
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/agconnect-services.json.gpg;
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg;
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg;
./gradlew publishPlayRelease -PenableFirebase --stacktrace;
./gradlew publishPlayRelease --stacktrace;
fi
after_success:

View File

@ -20,22 +20,19 @@ apply from: 'hooks.gradle'
android {
namespace 'io.github.wulkanowy'
compileSdk 33
compileSdk 34
defaultConfig {
applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 21
targetSdkVersion 33
versionCode 132
versionName "2.2.0"
targetSdkVersion 34
versionCode 164
versionName "2.6.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "app_name", "Wulkanowy"
manifestPlaceholders = [
firebase_enabled: project.hasProperty("enableFirebase"),
admob_project_id: ""
]
manifestPlaceholders = [admob_project_id: ""]
buildConfigField "String", "SINGLE_SUPPORT_AD_ID", "null"
buildConfigField "String", "DASHBOARD_TILE_AD_ID", "null"
@ -76,7 +73,6 @@ android {
resValue "string", "app_name", "Wulkanowy DEV"
applicationIdSuffix ".dev"
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"'
}
@ -113,6 +109,7 @@ android {
buildFeatures {
viewBinding true
buildConfig true
}
bundle {
@ -141,7 +138,9 @@ android {
packagingOptions {
resources {
excludes += ['META-INF/library_release.kotlin_module',
'META-INF/library-core_release.kotlin_module']
'META-INF/library-core_release.kotlin_module',
'META-INF/LICENSE.md',
'META-INF/LICENSE-notice.md']
}
}
@ -161,8 +160,8 @@ play {
defaultToAppBundles = false
track = 'production'
releaseStatus = ReleaseStatus.IN_PROGRESS
userFraction = 0.01d
updatePriority = 1
userFraction = 0.99d
updatePriority = 4
enabled.set(false)
}
@ -183,44 +182,44 @@ huaweiPublish {
}
ext {
work_manager = "2.8.1"
android_hilt = "1.0.0"
room = "2.5.2"
chucker = "3.5.2"
mockk = "1.13.8"
coroutines = "1.7.3"
work_manager = "2.9.0"
android_hilt = "1.2.0"
room = "2.6.1"
chucker = "4.0.0"
mockk = "1.13.10"
coroutines = "1.8.0"
}
dependencies {
implementation 'io.github.wulkanowy:sdk:2.2.0'
implementation 'io.github.wulkanowy:sdk:2.6.3'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines"
implementation "androidx.core:core-ktx:1.10.1"
implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation "androidx.activity:activity-ktx:1.7.2"
implementation "androidx.activity:activity-ktx:1.9.0"
implementation "androidx.appcompat:appcompat:1.6.1"
implementation "androidx.fragment:fragment-ktx:1.6.1"
implementation "androidx.annotation:annotation:1.7.0"
implementation "androidx.fragment:fragment-ktx:1.7.0"
implementation "androidx.annotation:annotation:1.7.1"
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.recyclerview:recyclerview:1.3.2"
implementation "androidx.viewpager2:viewpager2:1.1.0-rc01"
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.9.0"
implementation "com.google.android.material:material:1.10.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.3.0'
implementation "androidx.work:work-runtime-ktx:$work_manager"
implementation "androidx.work:work-runtime:$work_manager"
playImplementation "androidx.work:work-gcm:$work_manager"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.2"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.7.0"
implementation "androidx.room:room-runtime:$room"
implementation "androidx.room:room-ktx:$room"
@ -234,36 +233,39 @@ dependencies {
implementation 'com.github.ncapdevi:FragNav:3.3.0'
implementation "com.github.YarikSOffice:lingver:1.3.0"
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:retrofit:2.11.0'
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.11.0"
implementation "com.squareup.okhttp3:logging-interceptor:4.12.0"
implementation "com.squareup.okhttp3:okhttp-urlconnection:4.12.0"
implementation "com.jakewharton.timber:timber:5.0.1"
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation 'com.github.Faierbel:slf4j-timber:2.0'
implementation 'com.github.bastienpaulfr:Treessence:1.1.2'
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation "io.coil-kt:coil:2.4.0"
implementation 'io.coil-kt:coil:2.6.0'
implementation "io.github.wulkanowy:AppKillerManager:3.0.1"
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation 'com.fredporciuncula:flow-preferences:1.9.1'
implementation 'org.apache.commons:commons-text:1.10.0'
implementation 'org.apache.commons:commons-text:1.12.0'
playImplementation platform('com.google.firebase:firebase-bom:32.3.1')
playImplementation 'com.google.firebase:firebase-analytics-ktx'
playImplementation 'com.google.firebase:firebase-messaging:'
playImplementation platform('com.google.firebase:firebase-bom:33.0.0')
playImplementation 'com.google.firebase:firebase-analytics'
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:22.4.0'
playImplementation "com.google.android.play:integrity:1.2.0"
playImplementation 'com.google.firebase:firebase-config'
hmsImplementation 'com.huawei.hms:hianalytics:6.12.0.300'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.301'
playImplementation 'com.google.android.gms:play-services-ads:22.6.0'
playImplementation "com.google.android.play:integrity:1.3.0"
playImplementation 'com.google.android.play:app-update-ktx:2.1.0'
playImplementation 'com.google.android.play:review-ktx:2.0.1'
playImplementation "com.google.android.ump:user-messaging-platform:2.1.0"
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
hmsImplementation 'com.huawei.hms:hianalytics:6.12.0.301'
hmsImplementation 'com.huawei.agconnect:agconnect-crash:1.9.1.303'
debugImplementation "com.github.ChuckerTeam.Chucker:library:$chucker"
releaseImplementation "com.github.chuckerteam.chucker:library-no-op:$chucker"
debugImplementation "com.github.chuckerteam.chucker:library:$chucker"
debugImplementation 'com.github.amitshekhariitbhu.Android-Debug-Database:debug-db:1.0.6'
debugImplementation 'com.github.haroldadmin:WhatTheStack:1.0.0-alpha04'
@ -272,7 +274,7 @@ dependencies {
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines"
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
testImplementation 'org.robolectric:robolectric:4.10.3'
testImplementation 'org.robolectric:robolectric:4.12.1'
testImplementation "androidx.test:runner:1.5.2"
testImplementation "androidx.test.ext:junit:1.1.5"
testImplementation "androidx.test:core:1.5.0"

View File

@ -36,6 +36,37 @@
"status": 2
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:1091101852179:android:b558a25f65d088b1",
"android_client_info": {
"package_name": "io.github.wulkanowy"
}
},
"oauth_client": [
{
"client_id": "",
"client_type": 3
}
],
"api_key": [
{
"current_key": ""
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
}
}
}
],
"configuration_version": "1"

View File

@ -1,16 +1,16 @@
apply plugin: "jacoco"
jacoco {
toolVersion "0.8.7"
toolVersion "0.8.11"
reportsDirectory.set(file("$buildDir/reports"))
}
tasks.withType(Test) {
tasks.withType(Test).configureEach {
jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*']
}
task jacocoTestReport(type: JacocoReport) {
tasks.register('jacocoTestReport', JacocoReport) {
group = "Reporting"
description = "Generate Jacoco coverage reports"
@ -33,19 +33,19 @@ task jacocoTestReport(type: JacocoReport) {
'**/*_Factory.*']
classDirectories.setFrom(fileTree(
dir: "$buildDir/intermediates/classes/debug",
excludes: excludes
dir: "$buildDir/intermediates/classes/debug",
excludes: excludes
) + fileTree(
dir: "$buildDir/tmp/kotlin-classes/fdroidDebug",
excludes: excludes
dir: "$buildDir/tmp/kotlin-classes/fdroidDebug",
excludes: excludes
))
sourceDirectories.setFrom(files([
"src/main/java",
"src/fdroid/java"
"src/main/java",
"src/fdroid/java"
]))
executionData.setFrom(fileTree(
dir: project.projectDir,
includes: ["**/*.exec", "**/*.ec"]
dir: project.projectDir,
includes: ["**/*.exec", "**/*.ec"]
))
}

View File

@ -1,7 +1,8 @@
#!/bin/bash -
content=$(cat < "app/src/main/play/release-notes/pl-PL/default.txt") || exit
if [[ "${#content}" -gt 500 ]]; then
content2=echo "$content" | dos2unix
if [[ "${#content2}" -gt 500 ]]; then
echo >&2 "Release notes content has reached the limit of 500 characters"
exit 1
fi

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

File diff suppressed because it is too large Load Diff

View File

@ -14,34 +14,37 @@ import kotlin.test.assertFailsWith
@RunWith(AndroidJUnit4::class)
class ScramblerTest {
private val scrambler = Scrambler(ApplicationProvider.getApplicationContext())
@Test
fun encryptDecryptTest() {
assertEquals("TEST", decrypt(encrypt("TEST",
ApplicationProvider.getApplicationContext())))
assertEquals(
"TEST", scrambler.decrypt(scrambler.encrypt("TEST"))
)
}
@Test
fun emptyTextEncryptTest() {
assertFailsWith<ScramblerException> {
decrypt("")
scrambler.decrypt("")
}
assertFailsWith<ScramblerException> {
encrypt("", ApplicationProvider.getApplicationContext())
scrambler.encrypt("")
}
}
@Test
@SdkSuppress(minSdkVersion = 18)
fun emptyKeyStoreTest() {
val text = encrypt("test", ApplicationProvider.getApplicationContext())
val text = scrambler.encrypt("test")
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
keyStore.deleteEntry("wulkanowy_password")
assertFailsWith<ScramblerException> {
decrypt(text)
scrambler.decrypt(text)
}
}
}

View File

@ -1,92 +0,0 @@
{
"agcgw": {
"backurl": "connect-dre.hispace.hicloud.com",
"url": "connect-dre.dbankcloud.cn",
"websocketbackurl": "connect-ws-dre.hispace.dbankcloud.com",
"websocketurl": "connect-ws-dre.hispace.dbankcloud.cn"
},
"agcgw_all": {
"CN": "connect-drcn.dbankcloud.cn",
"CN_back": "connect-drcn.hispace.hicloud.com",
"DE": "connect-dre.dbankcloud.cn",
"DE_back": "connect-dre.hispace.hicloud.com",
"RU": "connect-drru.hispace.dbankcloud.ru",
"RU_back": "connect-drru.hispace.dbankcloud.cn",
"SG": "connect-dra.dbankcloud.cn",
"SG_back": "connect-dra.hispace.hicloud.com"
},
"websocketgw_all": {
"CN": "connect-ws-drcn.hispace.dbankcloud.cn",
"CN_back": "connect-ws-drcn.hispace.dbankcloud.com",
"DE": "connect-ws-dre.hispace.dbankcloud.cn",
"DE_back": "connect-ws-dre.hispace.dbankcloud.com",
"RU": "connect-ws-drru.hispace.dbankcloud.ru",
"RU_back": "connect-ws-drru.hispace.dbankcloud.cn",
"SG": "connect-ws-dra.hispace.dbankcloud.cn",
"SG_back": "connect-ws-dra.hispace.dbankcloud.com"
},
"client": {
"cp_id": "890048000024105546",
"product_id": "736430079244736562",
"client_id": "514530959291319360",
"client_secret": "C42522DBF17D3D4BBE9D9C1783A54484B7E6844B388B7A67502D36A633A4186B",
"project_id": "736430079244736562",
"app_id": "106552551",
"api_key": "CgB6e3x9BUNiq+r8ebCHNojjjYsMT4pJSjjNDOkm9owtBb6rVI6LjnASoZBRxbjjhObcrV5gANo99fI/eKZDTbWS",
"package_name": "io.github.wulkanowy.dev"
},
"oauth_client": {
"client_id": "106552551",
"client_type": 1
},
"app_info": {
"app_id": "106552551",
"package_name": "io.github.wulkanowy.dev"
},
"service": {
"analytics": {
"collector_url": "datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
"collector_url_ru": "datacollector-drru.dt.dbankcloud.ru,datacollector-drru.dt.hicloud.com",
"collector_url_sg": "datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn",
"collector_url_de": "datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn",
"collector_url_cn": "datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn",
"resource_id": "p1",
"channel_id": ""
},
"search":{
"url":"https://search-dre.cloud.huawei.com"
},
"cloudstorage": {
"storage_url_sg_back": "https://agc-storage-dra.cloud.huawei.asia",
"storage_url_ru_back": "https://agc-storage-drru.cloud.huawei.ru",
"storage_url_ru": "https://agc-storage-drru.cloud.huawei.ru",
"storage_url_de_back": "https://agc-storage-dre.cloud.huawei.eu",
"storage_url_de": "https://ops-dre.agcstorage.link",
"storage_url": "https://agc-storage-drcn.platform.dbankcloud.cn",
"storage_url_sg": "https://ops-dra.agcstorage.link",
"storage_url_cn_back": "https://agc-storage-drcn.cloud.huawei.com.cn",
"storage_url_cn": "https://agc-storage-drcn.platform.dbankcloud.cn"
},
"ml": {
"mlservice_url": "ml-api-dre.ai.dbankcloud.com,ml-api-dre.ai.dbankcloud.cn"
}
},
"region": "DE",
"configuration_version": "3.0",
"appInfos": [
{
"package_name": "io.github.wulkanowy.dev",
"client": {
"app_id": "106552551"
},
"app_info": {
"package_name": "io.github.wulkanowy.dev",
"app_id": "106552551"
},
"oauth_client": {
"client_type": 1,
"client_id": "106552551"
}
}
]
}

View File

@ -5,6 +5,7 @@ import android.view.View
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject
@Suppress("unused")
@ -13,9 +14,11 @@ class AdsHelper @Inject constructor(
private val preferencesRepository: PreferencesRepository
) {
val isMobileAdsSdkInitialized = MutableStateFlow(false)
val canShowAd = false
fun initialize() {
preferencesRepository.isAdsEnabled = false
preferencesRepository.isAgreeToProcessData = false
preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
}

View File

@ -0,0 +1,13 @@
package io.github.wulkanowy.utils
import android.view.View
import javax.inject.Inject
class InAppUpdateHelper @Inject constructor() {
lateinit var messageContainer: View
fun checkAndInstallUpdates() {}
fun onResume() {}
}

View File

@ -1,17 +0,0 @@
package io.github.wulkanowy.utils
import android.app.Activity
import android.view.View
import javax.inject.Inject
@Suppress("UNUSED_PARAMETER")
class UpdateHelper @Inject constructor() {
lateinit var messageContainer: View
fun checkAndInstallUpdates(activity: Activity) {}
fun onActivityResult(requestCode: Int, resultCode: Int) {}
fun onResume(activity: Activity) {}
}

View File

@ -5,6 +5,7 @@ import android.view.View
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject
@Suppress("unused")
@ -12,10 +13,11 @@ class AdsHelper @Inject constructor(
@ApplicationContext private val context: Context,
private val preferencesRepository: PreferencesRepository
) {
val isMobileAdsSdkInitialized = MutableStateFlow(false)
val canShowAd = false
fun initialize() {
preferencesRepository.isAdsEnabled = false
preferencesRepository.isAgreeToProcessData = false
preferencesRepository.selectedDashboardTiles -= DashboardItem.Tile.ADS
}

View File

@ -0,0 +1,13 @@
package io.github.wulkanowy.utils
import android.view.View
import javax.inject.Inject
class InAppUpdateHelper @Inject constructor() {
lateinit var messageContainer: View
fun checkAndInstallUpdates() {}
fun onResume() {}
}

View File

@ -1,17 +0,0 @@
package io.github.wulkanowy.utils
import android.app.Activity
import android.view.View
import javax.inject.Inject
@Suppress("UNUSED_PARAMETER")
class UpdateHelper @Inject constructor() {
lateinit var messageContainer: View
fun checkAndInstallUpdates(activity: Activity) {}
fun onActivityResult(requestCode: Int, resultCode: Int) {}
fun onResume(activity: Activity) {}
}

View File

@ -44,13 +44,14 @@
android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="false"
android:theme="@style/WulkanowyTheme"
android:resizeableActivity="true"
tools:ignore="DataExtractionRules,UnusedAttribute">
<activity
android:name=".ui.modules.splash.SplashActivity"
android:exported="true"
android:screenOrientation="portrait"
android:theme="@style/WulkanowyTheme.SplashScreen"
tools:ignore="LockedOrientationActivity">
tools:ignore="DiscouragedApi,LockedOrientationActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@ -154,33 +155,9 @@
android:resource="@xml/provider_paths" />
</provider>
<!-- workaround for https://github.com/firebase/firebase-android-sdk/issues/473 enabled:false -->
<!-- https://firebase.googleblog.com/2017/03/take-control-of-your-firebase-init-on.html -->
<provider
android:name="com.google.firebase.provider.FirebaseInitProvider"
android:authorities="${applicationId}.firebaseinitprovider"
android:enabled="${firebase_enabled}"
android:exported="false"
tools:ignore="MissingClass" />
<meta-data
android:name="install_channel"
android:value="${install_channel}" />
<meta-data
android:name="firebase_analytics_collection_enabled"
android:value="${firebase_enabled}" />
<meta-data
android:name="google_analytics_adid_collection_enabled"
android:value="${firebase_enabled}" />
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="${firebase_enabled}" />
<meta-data
android:name="firebase_messaging_auto_init_enabled"
android:value="${firebase_enabled}" />
<meta-data
android:name="firebase_inapp_messaging_auto_data_collection_enabled"
android:value="${firebase_enabled}" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_stat_all" />

View File

@ -54,5 +54,9 @@
{
"displayName": "Antoni Paduch",
"githubUsername": "janAte1"
},
{
"displayName": "Kamil Wąsik",
"githubUsername": "JestemKamil"
}
]

View File

@ -1,7 +1,9 @@
package io.github.wulkanowy
import android.app.Application
import android.util.Log.*
import android.util.Log.DEBUG
import android.util.Log.INFO
import android.util.Log.VERBOSE
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import com.yariksoffice.lingver.Lingver
@ -9,16 +11,19 @@ import dagger.hilt.android.HiltAndroidApp
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.*
import io.github.wulkanowy.utils.ActivityLifecycleLogger
import io.github.wulkanowy.utils.AnalyticsHelper
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.CrashLogExceptionTree
import io.github.wulkanowy.utils.CrashLogTree
import io.github.wulkanowy.utils.DebugLogTree
import io.github.wulkanowy.utils.RemoteConfigHelper
import timber.log.Timber
import javax.inject.Inject
@HiltAndroidApp
class WulkanowyApp : Application(), Configuration.Provider {
@Inject
lateinit var workerFactory: HiltWorkerFactory
@Inject
lateinit var themeManager: ThemeManager
@ -32,16 +37,21 @@ class WulkanowyApp : Application(), Configuration.Provider {
lateinit var analyticsHelper: AnalyticsHelper
@Inject
lateinit var adsHelper: AdsHelper
lateinit var remoteConfigHelper: RemoteConfigHelper
@Inject
lateinit var remoteConfigHelper: RemoteConfigHelper
lateinit var workerFactory: HiltWorkerFactory
override val workManagerConfiguration: Configuration
get() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.setMinimumLoggingLevel(if (appInfo.isDebug) VERBOSE else INFO)
.build()
override fun onCreate() {
super.onCreate()
initializeAppLanguage()
themeManager.applyDefaultTheme()
adsHelper.initialize()
remoteConfigHelper.initialize()
initLogging()
}
@ -74,9 +84,4 @@ class WulkanowyApp : Application(), Configuration.Provider {
analyticsHelper.logEvent("language", "startup" to preferencesRepository.appLanguage)
}
}
override fun getWorkManagerConfiguration() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.setMinimumLoggingLevel(if (appInfo.isDebug) VERBOSE else INFO)
.build()
}

View File

@ -18,16 +18,13 @@ 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 io.github.wulkanowy.utils.RemoteConfigHelper
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.create
import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Singleton
@ -35,19 +32,6 @@ import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
internal class DataModule {
@Singleton
@Provides
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
addInterceptor(chuckerInterceptor, network = true)
}
@Singleton
@Provides
fun provideChuckerCollector(
@ -251,4 +235,12 @@ internal class DataModule {
@Singleton
@Provides
fun provideAdminMessageDao(database: AppDatabase) = database.adminMessagesDao
@Singleton
@Provides
fun provideMutesDao(database: AppDatabase) = database.mutedMessageSendersDao
@Singleton
@Provides
fun provideGradeDescriptiveDao(database: AppDatabase) = database.gradeDescriptiveDao
}

View File

@ -1,27 +1,73 @@
package io.github.wulkanowy.data
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNot
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import timber.log.Timber
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
sealed class Resource<T> {
open class Loading<T> : Resource<T>()
sealed interface Resource<out T> {
/**
* The initial value of a resource flow. Indicates no data that is currently available to be shown,
* however with the expectation that the state will transition to another one soon.
*/
open class Loading<T> : Resource<T>
/**
* A semi-loading state with some data available to be displayed (usually cached data loaded from
* the database). Still not the target state and it's expected to transition into another one soon.
*/
data class Intermediate<T>(val data: T) : Loading<T>()
data class Success<T>(val data: T) : Resource<T>()
/**
* The happy-path target state. Data can either be:
* - loaded from the database - while it may seem like this case is already handled by the
* Intermediate state, the difference here is semantic. Cached data is returned as Intermediate
* when there's a API request in progress (or soon expected to be), however when there is no
* intention of immediately querying the API, the cached data is returned as a Success.
* - fetched from the API.
*/
data class Success<T>(val data: T) : Resource<T>
data class Error<T>(val error: Throwable) : Resource<T>()
/**
* Something bad happened and we were unable to get the requested data. This can be caused by
* a database error, a network error, or really just any other error. Upon receiving this state
* the UI can either: display a full screen error, or, when it has received any data previously,
* display a snack bar informing of the problem.
*/
data class Error<T>(val error: Throwable) : Resource<T>
}
val <T> Resource<T>.dataOrNull: T?
get() = when (this) {
is Resource.Success -> this.data
is Resource.Intermediate -> this.data
is Resource.Loading -> null
is Resource.Error -> null
else -> null
}
val <T> Resource<T>.dataOrThrow: T
get() = when (this) {
is Resource.Success -> this.data
is Resource.Intermediate -> this.data
is Resource.Loading -> throw IllegalStateException("Resource is in loading state")
is Resource.Error -> throw this.error
}
val <T> Resource<T>.errorOrNull: Throwable?
@ -47,6 +93,22 @@ fun <T, U> Resource<T>.mapData(block: (T) -> U) = when (this) {
is Resource.Error -> Resource.Error(this.error)
}
/**
* Injects another flow into this flow's resource data.
*/
inline fun <T1, T2, R> Flow<Resource<T1>>.combineWithResourceData(
flow: Flow<T2>,
crossinline block: suspend (T1, T2) -> R
): Flow<Resource<R>> =
combine(flow) { resource, inject ->
when (resource) {
is Resource.Success -> Resource.Success(block(resource.data, inject))
is Resource.Intermediate -> Resource.Intermediate(block(resource.data, inject))
is Resource.Loading -> Resource.Loading()
is Resource.Error -> Resource.Error(resource.error)
}
}
fun <T> Flow<Resource<T>>.logResourceStatus(name: String, showData: Boolean = false) = onEach {
val description = when (it) {
is Resource.Intermediate -> "intermediate data received" + if (showData) " (data: `${it.data}`)" else ""
@ -57,8 +119,29 @@ fun <T> Flow<Resource<T>>.logResourceStatus(name: String, showData: Boolean = fa
Timber.i("$name: $description")
}
fun <T, U> Flow<Resource<T>>.mapResourceData(block: (T) -> U) = map {
it.mapData(block)
inline fun <T, U> Flow<Resource<T>>.mapResourceData(crossinline block: suspend (T) -> U) = map {
when (it) {
is Resource.Success -> Resource.Success(block(it.data))
is Resource.Intermediate -> Resource.Intermediate(block(it.data))
is Resource.Loading -> Resource.Loading()
is Resource.Error -> Resource.Error(it.error)
}
}
@OptIn(ExperimentalCoroutinesApi::class)
fun <T, U> Flow<Resource<T>>.flatMapResourceData(
inheritIntermediate: Boolean = true, block: suspend (T) -> Flow<Resource<U>>
) = flatMapLatest {
when (it) {
is Resource.Success -> block(it.data)
is Resource.Intermediate -> block(it.data).map { newRes ->
if (inheritIntermediate && newRes is Resource.Success) Resource.Intermediate(newRes.data)
else newRes
}
is Resource.Loading -> flowOf(Resource.Loading())
is Resource.Error -> flowOf(Resource.Error(it.error))
}
}
fun <T> Flow<Resource<T>>.onResourceData(block: suspend (T) -> Unit) = onEach {
@ -88,13 +171,13 @@ fun <T> Flow<Resource<T>>.onResourceSuccess(block: suspend (T) -> Unit) = onEach
}
}
fun <T> Flow<Resource<T>>.onResourceError(block: (Throwable) -> Unit) = onEach {
fun <T> Flow<Resource<T>>.onResourceError(block: suspend (Throwable) -> Unit) = onEach {
if (it is Resource.Error) {
block(it.error)
}
}
fun <T> Flow<Resource<T>>.onResourceNotLoading(block: () -> Unit) = onEach {
fun <T> Flow<Resource<T>>.onResourceNotLoading(block: suspend () -> Unit) = onEach {
if (it !is Resource.Loading) {
block()
}
@ -104,70 +187,99 @@ suspend fun <T> Flow<Resource<T>>.toFirstResult() = filter { it !is Resource.Loa
suspend fun <T> Flow<Resource<T>>.waitForResult() = takeWhile { it is Resource.Loading }.collect()
inline fun <ResultType, RequestType> networkBoundResource(
mutex: Mutex = Mutex(),
showSavedOnLoading: Boolean = true,
crossinline isResultEmpty: (ResultType) -> Boolean,
crossinline query: () -> Flow<ResultType>,
crossinline fetch: suspend (ResultType) -> RequestType,
crossinline saveFetchResult: suspend (old: ResultType, new: RequestType) -> Unit,
crossinline onFetchFailed: (Throwable) -> Unit = { },
crossinline shouldFetch: (ResultType) -> Boolean = { true },
crossinline filterResult: (ResultType) -> ResultType = { it }
) = flow {
emit(Resource.Loading())
// Can cause excessive amounts of `Resource.Intermediate` to be emitted. Unless that is desired,
// use `debounceIntermediates` to alleviate this behavior.
inline fun <reified T> combineResourceFlows(flows: Iterable<Flow<Resource<T>>>): Flow<Resource<List<T>>> =
combine(flows) { items ->
var isIntermediate = false
val data = mutableListOf<T>()
for (item in items) {
when (item) {
is Resource.Success -> data.add(item.data)
is Resource.Intermediate -> {
isIntermediate = true
data.add(item.data)
}
val data = query().first()
emitAll(if (shouldFetch(data)) {
val filteredResult = filterResult(data)
if (showSavedOnLoading && !isResultEmpty(filteredResult)) {
emit(Resource.Intermediate(filteredResult))
is Resource.Loading -> return@combine Resource.Loading()
is Resource.Error -> continue
}
}
try {
val newData = fetch(data)
mutex.withLock { saveFetchResult(query().first(), newData) }
query().map { Resource.Success(filterResult(it)) }
} catch (throwable: Throwable) {
onFetchFailed(throwable)
query().map { Resource.Error(throwable) }
if (data.isEmpty()) {
// All items have to be errors for this to happen, so just return the first one.
// mapData is functionally useless and exists only to satisfy the type checker
items.first().mapData { listOf(it) }
} else if (isIntermediate) {
Resource.Intermediate(data)
} else {
Resource.Success(data)
}
}
@OptIn(FlowPreview::class)
fun <T> Flow<Resource<T>>.debounceIntermediates(timeout: Duration = 5.seconds) = flow {
var wasIntermediate = false
emitAll(this@debounceIntermediates.debounce {
if (it is Resource.Intermediate) {
if (!wasIntermediate) {
wasIntermediate = true
Duration.ZERO
} else {
timeout
}
} else {
wasIntermediate = false
Duration.ZERO
}
} else {
query().map { Resource.Success(filterResult(it)) }
})
}
inline fun <OutputType, ApiType> networkBoundResource(
mutex: Mutex = Mutex(),
crossinline isResultEmpty: (OutputType) -> Boolean,
crossinline query: () -> Flow<OutputType>,
crossinline fetch: suspend () -> ApiType,
crossinline saveFetchResult: suspend (old: OutputType, new: ApiType) -> Unit,
crossinline shouldFetch: (OutputType) -> Boolean = { true },
crossinline filterResult: (OutputType) -> OutputType = { it }
) = networkBoundResource(
mutex = mutex,
isResultEmpty = isResultEmpty,
query = query,
fetch = fetch,
saveFetchResult = saveFetchResult,
shouldFetch = shouldFetch,
mapResult = filterResult
)
@JvmName("networkBoundResourceWithMap")
inline fun <ResultType, RequestType, T> networkBoundResource(
inline fun <DatabaseType, ApiType, OutputType> networkBoundResource(
mutex: Mutex = Mutex(),
showSavedOnLoading: Boolean = true,
crossinline isResultEmpty: (T) -> Boolean,
crossinline query: () -> Flow<ResultType>,
crossinline fetch: suspend (ResultType) -> RequestType,
crossinline saveFetchResult: suspend (old: ResultType, new: RequestType) -> Unit,
crossinline onFetchFailed: (Throwable) -> Unit = { },
crossinline shouldFetch: (ResultType) -> Boolean = { true },
crossinline mapResult: (ResultType) -> T,
crossinline isResultEmpty: (OutputType) -> Boolean,
crossinline query: () -> Flow<DatabaseType>,
crossinline fetch: suspend () -> ApiType,
crossinline saveFetchResult: suspend (old: DatabaseType, new: ApiType) -> Unit,
crossinline shouldFetch: (DatabaseType) -> Boolean = { true },
crossinline mapResult: (DatabaseType) -> OutputType,
) = flow {
emit(Resource.Loading())
val data = query().first()
emitAll(if (shouldFetch(data)) {
val mappedResult = mapResult(data)
if (shouldFetch(data)) {
emit(Resource.Intermediate(data))
if (showSavedOnLoading && !isResultEmpty(mappedResult)) {
emit(Resource.Intermediate(mappedResult))
}
try {
val newData = fetch(data)
val newData = fetch()
mutex.withLock { saveFetchResult(query().first(), newData) }
query().map { Resource.Success(mapResult(it)) }
} catch (throwable: Throwable) {
onFetchFailed(throwable)
query().map { Resource.Error(throwable) }
emit(Resource.Error(throwable))
return@flow
}
} else {
query().map { Resource.Success(mapResult(it)) }
})
}
emitAll(query().map { Resource.Success(it) })
}
.mapResourceData { mapResult(it) }
.filterNot { it is Resource.Intermediate && isResultEmpty(it.data) }

View File

@ -0,0 +1,125 @@
package io.github.wulkanowy.data
import com.chuckerteam.chucker.api.ChuckerInterceptor
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.StudentIsEduOne
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.RemoteConfigHelper
import io.github.wulkanowy.utils.WebkitCookieManagerProxy
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class WulkanowySdkFactory @Inject constructor(
private val chuckerInterceptor: ChuckerInterceptor,
private val remoteConfig: RemoteConfigHelper,
private val webkitCookieManagerProxy: WebkitCookieManagerProxy,
private val studentDb: StudentDao,
) {
private val eduOneMutex = Mutex()
private val migrationFailedStudentIds = mutableSetOf<Long>()
private val sdk = Sdk().apply {
androidVersion = android.os.Build.VERSION.RELEASE
buildTag = android.os.Build.MODEL
userAgentTemplate = remoteConfig.userAgentTemplate
setSimpleHttpLogger { Timber.d(it) }
setAdditionalCookieManager(webkitCookieManagerProxy)
// for debug only
addInterceptor(chuckerInterceptor, network = true)
}
fun create() = sdk
suspend fun create(student: Student, semester: Semester? = null): Sdk {
val overrideIsEduOne = checkEduOneAndMigrateIfNecessary(student)
return buildSdk(student, semester, overrideIsEduOne)
}
private fun buildSdk(student: Student, semester: Semester?, isStudentEduOne: Boolean): Sdk {
return create().apply {
email = student.email
password = student.password
symbol = student.symbol
schoolSymbol = student.schoolSymbol
studentId = student.studentId
classId = student.classId
emptyCookieJarInterceptor = true
isEduOne = isStudentEduOne
if (Sdk.Mode.valueOf(student.loginMode) == Sdk.Mode.HEBE) {
mobileBaseUrl = student.mobileBaseUrl
} else {
scrapperBaseUrl = student.scrapperBaseUrl
domainSuffix = student.scrapperDomainSuffix
loginType = Sdk.ScrapperLoginType.valueOf(student.loginType)
}
mode = Sdk.Mode.valueOf(student.loginMode)
mobileBaseUrl = student.mobileBaseUrl
keyId = student.certificateKey
privatePem = student.privateKey
if (semester != null) {
diaryId = semester.diaryId
kindergartenDiaryId = semester.kindergartenDiaryId
schoolYear = semester.schoolYear
unitId = semester.unitId
}
}
}
private suspend fun checkEduOneAndMigrateIfNecessary(student: Student): Boolean {
if (student.isEduOne != null) return student.isEduOne
if (student.id in migrationFailedStudentIds) {
Timber.i("Migration eduOne: skipping because of previous failure")
return false
}
eduOneMutex.withLock {
if (student.id in migrationFailedStudentIds) {
Timber.i("Migration eduOne: skipping because of previous failure")
return false
}
val studentFromDatabase = studentDb.loadById(student.id)
if (studentFromDatabase?.isEduOne != null) {
Timber.i("Migration eduOne: already done")
return studentFromDatabase.isEduOne
}
Timber.i("Migration eduOne: flag missing. Running migration...")
val initializedSdk = buildSdk(
student = student,
semester = null,
isStudentEduOne = false, // doesn't matter
)
val newCurrentStudent = runCatching { initializedSdk.getCurrentStudent() }
.onFailure { Timber.e(it, "Migration eduOne: can't get current student") }
.getOrNull()
if (newCurrentStudent == null) {
Timber.i("Migration eduOne: failed, so skipping")
migrationFailedStudentIds.add(student.id)
return false
}
Timber.i("Migration eduOne: success. New isEduOne flag: ${newCurrentStudent.isEduOne}")
val studentIsEduOne = StudentIsEduOne(
id = student.id,
isEduOne = newCurrentStudent.isEduOne
)
studentDb.update(studentIsEduOne)
return newCurrentStudent.isEduOne
}
}
}

View File

@ -1,11 +1,129 @@
package io.github.wulkanowy.data.db
import android.content.Context
import androidx.room.*
import androidx.room.AutoMigration
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.RoomDatabase.JournalMode.TRUNCATE
import io.github.wulkanowy.data.db.dao.*
import io.github.wulkanowy.data.db.entities.*
import io.github.wulkanowy.data.db.migrations.*
import androidx.room.TypeConverters
import io.github.wulkanowy.data.db.dao.AdminMessageDao
import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.db.dao.ConferenceDao
import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.dao.GradeDescriptiveDao
import io.github.wulkanowy.data.db.dao.GradePartialStatisticsDao
import io.github.wulkanowy.data.db.dao.GradePointsStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeSemesterStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
import io.github.wulkanowy.data.db.dao.HomeworkDao
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
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.dao.MobileDeviceDao
import io.github.wulkanowy.data.db.dao.MutedMessageSendersDao
import io.github.wulkanowy.data.db.dao.NoteDao
import io.github.wulkanowy.data.db.dao.NotificationDao
import io.github.wulkanowy.data.db.dao.RecipientDao
import io.github.wulkanowy.data.db.dao.SchoolAnnouncementDao
import io.github.wulkanowy.data.db.dao.SchoolDao
import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.dao.StudentInfoDao
import io.github.wulkanowy.data.db.dao.SubjectDao
import io.github.wulkanowy.data.db.dao.TeacherDao
import io.github.wulkanowy.data.db.dao.TimetableAdditionalDao
import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.dao.TimetableHeaderDao
import io.github.wulkanowy.data.db.entities.AdminMessage
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Conference
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradeDescriptive
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Mailbox
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.MutedMessageSender
import io.github.wulkanowy.data.db.entities.Note
import io.github.wulkanowy.data.db.entities.Notification
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.School
import io.github.wulkanowy.data.db.entities.SchoolAnnouncement
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentInfo
import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.data.db.entities.Teacher
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.entities.TimetableAdditional
import io.github.wulkanowy.data.db.entities.TimetableHeader
import io.github.wulkanowy.data.db.migrations.Migration10
import io.github.wulkanowy.data.db.migrations.Migration11
import io.github.wulkanowy.data.db.migrations.Migration12
import io.github.wulkanowy.data.db.migrations.Migration13
import io.github.wulkanowy.data.db.migrations.Migration14
import io.github.wulkanowy.data.db.migrations.Migration15
import io.github.wulkanowy.data.db.migrations.Migration16
import io.github.wulkanowy.data.db.migrations.Migration17
import io.github.wulkanowy.data.db.migrations.Migration18
import io.github.wulkanowy.data.db.migrations.Migration19
import io.github.wulkanowy.data.db.migrations.Migration2
import io.github.wulkanowy.data.db.migrations.Migration20
import io.github.wulkanowy.data.db.migrations.Migration21
import io.github.wulkanowy.data.db.migrations.Migration22
import io.github.wulkanowy.data.db.migrations.Migration23
import io.github.wulkanowy.data.db.migrations.Migration24
import io.github.wulkanowy.data.db.migrations.Migration25
import io.github.wulkanowy.data.db.migrations.Migration26
import io.github.wulkanowy.data.db.migrations.Migration27
import io.github.wulkanowy.data.db.migrations.Migration28
import io.github.wulkanowy.data.db.migrations.Migration29
import io.github.wulkanowy.data.db.migrations.Migration3
import io.github.wulkanowy.data.db.migrations.Migration30
import io.github.wulkanowy.data.db.migrations.Migration31
import io.github.wulkanowy.data.db.migrations.Migration32
import io.github.wulkanowy.data.db.migrations.Migration33
import io.github.wulkanowy.data.db.migrations.Migration34
import io.github.wulkanowy.data.db.migrations.Migration35
import io.github.wulkanowy.data.db.migrations.Migration36
import io.github.wulkanowy.data.db.migrations.Migration37
import io.github.wulkanowy.data.db.migrations.Migration38
import io.github.wulkanowy.data.db.migrations.Migration39
import io.github.wulkanowy.data.db.migrations.Migration4
import io.github.wulkanowy.data.db.migrations.Migration40
import io.github.wulkanowy.data.db.migrations.Migration41
import io.github.wulkanowy.data.db.migrations.Migration42
import io.github.wulkanowy.data.db.migrations.Migration43
import io.github.wulkanowy.data.db.migrations.Migration44
import io.github.wulkanowy.data.db.migrations.Migration46
import io.github.wulkanowy.data.db.migrations.Migration49
import io.github.wulkanowy.data.db.migrations.Migration5
import io.github.wulkanowy.data.db.migrations.Migration50
import io.github.wulkanowy.data.db.migrations.Migration51
import io.github.wulkanowy.data.db.migrations.Migration53
import io.github.wulkanowy.data.db.migrations.Migration54
import io.github.wulkanowy.data.db.migrations.Migration55
import io.github.wulkanowy.data.db.migrations.Migration57
import io.github.wulkanowy.data.db.migrations.Migration58
import io.github.wulkanowy.data.db.migrations.Migration6
import io.github.wulkanowy.data.db.migrations.Migration63
import io.github.wulkanowy.data.db.migrations.Migration7
import io.github.wulkanowy.data.db.migrations.Migration8
import io.github.wulkanowy.data.db.migrations.Migration9
import io.github.wulkanowy.utils.AppInfo
import javax.inject.Singleton
@ -41,7 +159,9 @@ import javax.inject.Singleton
TimetableHeader::class,
SchoolAnnouncement::class,
Notification::class,
AdminMessage::class
AdminMessage::class,
MutedMessageSender::class,
GradeDescriptive::class,
],
autoMigrations = [
AutoMigration(from = 44, to = 45),
@ -51,6 +171,13 @@ import javax.inject.Singleton
AutoMigration(from = 54, to = 55, spec = Migration55::class),
AutoMigration(from = 55, to = 56),
AutoMigration(from = 56, to = 57, spec = Migration57::class),
AutoMigration(from = 57, to = 58, spec = Migration58::class),
AutoMigration(from = 58, to = 59),
AutoMigration(from = 59, to = 60),
AutoMigration(from = 60, to = 61),
AutoMigration(from = 61, to = 62),
AutoMigration(from = 62, to = 63, spec = Migration63::class),
AutoMigration(from = 63, to = 64),
],
version = AppDatabase.VERSION_SCHEMA,
exportSchema = true
@ -59,7 +186,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
const val VERSION_SCHEMA = 57
const val VERSION_SCHEMA = 64
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
Migration2(),
@ -184,4 +311,8 @@ abstract class AppDatabase : RoomDatabase() {
abstract val notificationDao: NotificationDao
abstract val adminMessagesDao: AdminMessageDao
abstract val mutedMessageSendersDao: MutedMessageSendersDao
abstract val gradeDescriptiveDao: GradeDescriptiveDao
}

View File

@ -2,24 +2,14 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import androidx.room.Transaction
import io.github.wulkanowy.data.db.entities.AdminMessage
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@Dao
abstract class AdminMessageDao : BaseDao<AdminMessage> {
interface AdminMessageDao : BaseDao<AdminMessage> {
@Query("SELECT * FROM AdminMessages")
abstract fun loadAll(): Flow<List<AdminMessage>>
@Transaction
open suspend fun removeOldAndSaveNew(
oldMessages: List<AdminMessage>,
newMessages: List<AdminMessage>
) {
deleteAll(oldMessages)
insertAll(newMessages)
}
fun loadAll(): Flow<List<AdminMessage>>
}

View File

@ -3,6 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Transaction
import androidx.room.Update
interface BaseDao<T> {
@ -15,4 +16,10 @@ interface BaseDao<T> {
@Delete
suspend fun deleteAll(items: List<T>)
@Transaction
suspend fun removeOldAndSaveNew(oldItems: List<T>, newItems: List<T>) {
deleteAll(oldItems)
insertAll(newItems)
}
}

View File

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

View File

@ -5,15 +5,23 @@ import androidx.room.Query
import androidx.room.Transaction
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
import io.github.wulkanowy.data.db.entities.MessageWithMutedAuthor
import kotlinx.coroutines.flow.Flow
@Dao
interface MessagesDao : BaseDao<Message> {
@Transaction
@Query("SELECT * FROM Messages WHERE message_global_key = :messageGlobalKey")
fun loadMessageWithAttachment(messageGlobalKey: String): Flow<MessageWithAttachment?>
@Transaction
@Query("SELECT * FROM Messages WHERE mailbox_key = :mailboxKey AND folder_id = :folder ORDER BY date DESC")
fun loadMessagesWithMutedAuthor(mailboxKey: String, folder: Int): Flow<List<MessageWithMutedAuthor>>
@Transaction
@Query("SELECT * FROM Messages WHERE email = :email AND folder_id = :folder ORDER BY date DESC")
fun loadMessagesWithMutedAuthor(folder: Int, email: String): Flow<List<MessageWithMutedAuthor>>
@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>>

View File

@ -8,6 +8,6 @@ import kotlinx.coroutines.flow.Flow
@Dao
interface MobileDeviceDao : BaseDao<MobileDevice> {
@Query("SELECT * FROM MobileDevices WHERE user_login_id = :userLoginId ORDER BY date DESC")
fun loadAll(userLoginId: Int): Flow<List<MobileDevice>>
@Query("SELECT * FROM MobileDevices WHERE user_login_id = :studentId ORDER BY date DESC")
fun loadAll(studentId: Int): Flow<List<MobileDevice>>
}

View File

@ -0,0 +1,20 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.MutedMessageSender
@Dao
interface MutedMessageSendersDao : BaseDao<MutedMessageSender> {
@Query("SELECT COUNT(*) FROM MutedMessageSenders WHERE author = :author")
suspend fun checkMute(author: String): Boolean
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertMute(mute: MutedMessageSender): Long
@Query("DELETE FROM MutedMessageSenders WHERE author = :author")
suspend fun deleteMute(author: String)
}

View File

@ -10,6 +10,6 @@ import javax.inject.Singleton
@Singleton
interface SchoolAnnouncementDao : BaseDao<SchoolAnnouncement> {
@Query("SELECT * FROM SchoolAnnouncements WHERE user_login_id = :userLoginId ORDER BY date DESC")
fun loadAll(userLoginId: Int): Flow<List<SchoolAnnouncement>>
@Query("SELECT * FROM SchoolAnnouncements WHERE user_login_id = :studentId ORDER BY date DESC")
fun loadAll(studentId: Int): Flow<List<SchoolAnnouncement>>
}

View File

@ -14,6 +14,6 @@ interface SemesterDao : BaseDao<Semester> {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertSemesters(items: List<Semester>): List<Long>
@Query("SELECT * FROM Semesters WHERE student_id = :studentId AND class_id = :classId")
@Query("SELECT * FROM Semesters WHERE (student_id = :studentId AND class_id = :classId) OR (student_id = :studentId AND class_id = 0)")
suspend fun loadAll(studentId: Int, classId: Int): List<Semester>
}

View File

@ -1,10 +1,18 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.*
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.StudentIsAuthorized
import io.github.wulkanowy.data.db.entities.StudentIsEduOne
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
@Singleton
@ -17,6 +25,12 @@ abstract class StudentDao {
@Delete
abstract suspend fun delete(student: Student)
@Update(entity = Student::class)
abstract suspend fun update(studentIsAuthorized: StudentIsAuthorized)
@Update(entity = Student::class)
abstract suspend fun update(studentIsEduOne: StudentIsEduOne)
@Update(entity = Student::class)
abstract suspend fun update(studentNickAndAvatar: StudentNickAndAvatar)
@ -33,12 +47,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) OR (Students.student_id = Semesters.student_id AND Semesters.class_id = 0)")
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) OR (Students.student_id = Semesters.student_id AND Semesters.class_id = 0) 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)
@ -46,6 +60,9 @@ abstract class StudentDao {
@Query("UPDATE Students SET is_current = 0")
abstract suspend fun resetCurrent()
@Query("DELETE FROM Students WHERE email = :email AND user_name = :userName")
abstract suspend fun deleteByEmailAndUserName(email: String, userName: String)
@Transaction
open suspend fun switchCurrent(id: Long) {
resetCurrent()

View File

@ -15,5 +15,5 @@ interface TimetableDao : BaseDao<Timetable> {
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>
suspend fun load(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): List<Timetable>
}

View File

@ -4,6 +4,8 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import io.github.wulkanowy.data.enums.MessageType
import io.github.wulkanowy.data.serializers.SafeMessageTypeEnumListSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
@ -34,9 +36,14 @@ data class AdminMessage(
val priority: String,
@SerialName("messageTypes")
@Serializable(with = SafeMessageTypeEnumListSerializer::class)
@ColumnInfo(name = "types", defaultValue = "[]")
val types: List<MessageType> = emptyList(),
@ColumnInfo(name = "is_dismissible")
val isDismissible: Boolean = false
@ColumnInfo(name = "is_ok_visible", defaultValue = "0")
val isOkVisible: Boolean = false,
@ColumnInfo(name = "is_x_visible", defaultValue = "0")
val isXVisible: Boolean = false
)

View File

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

View File

@ -33,7 +33,13 @@ data class GradeSummary(
@ColumnInfo(name = "points_sum")
val pointsSum: String,
val average: Double
@ColumnInfo(name = "points_sum_all_year")
val pointsSumAllYear: String?,
val average: Double,
@ColumnInfo(name = "average_all_year")
val averageAllYear: Double? = null,
) {
@PrimaryKey(autoGenerate = true)
var id: Long = 0

View File

@ -2,11 +2,15 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.Embedded
import androidx.room.Relation
import java.io.Serializable
data class MessageWithAttachment(
@Embedded
val message: Message,
@Relation(parentColumn = "message_global_key", entityColumn = "message_global_key")
val attachments: List<MessageAttachment>
)
val attachments: List<MessageAttachment>,
@Relation(parentColumn = "correspondents", entityColumn = "author")
val mutedMessageSender: MutedMessageSender?,
) : Serializable

View File

@ -0,0 +1,12 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.Embedded
import androidx.room.Relation
data class MessageWithMutedAuthor(
@Embedded
val message: Message,
@Relation(parentColumn = "correspondents", entityColumn = "author")
val mutedMessageSender: MutedMessageSender?,
)

View File

@ -9,8 +9,8 @@ import java.time.Instant
@Entity(tableName = "MobileDevices")
data class MobileDevice(
@ColumnInfo(name = "user_login_id")
val userLoginId: Int,
@ColumnInfo(name = "user_login_id") // todo: change column name
val studentId: Int,
@ColumnInfo(name = "device_id")
val deviceId: Int,

View File

@ -0,0 +1,15 @@
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 = "MutedMessageSenders")
data class MutedMessageSender(
@ColumnInfo(name = "author")
val author: String,
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View File

@ -9,14 +9,16 @@ import java.time.LocalDate
@Entity(tableName = "SchoolAnnouncements")
data class SchoolAnnouncement(
@ColumnInfo(name = "user_login_id")
val userLoginId: Int,
@ColumnInfo(name = "user_login_id") // todo: change column name
val studentId: Int,
val date: LocalDate,
val subject: String,
val content: String
val content: String,
val author: String? = null,
) : Serializable {
@PrimaryKey(autoGenerate = true)

View File

@ -49,6 +49,7 @@ data class Student(
@ColumnInfo(name = "student_id")
val studentId: Int,
@Deprecated("not available in VULCAN anymore")
@ColumnInfo(name = "user_login_id")
val userLoginId: Int,
@ -78,6 +79,13 @@ data class Student(
@ColumnInfo(name = "registration_date")
val registrationDate: Instant,
@ColumnInfo(name = "is_authorized", defaultValue = "0")
val isAuthorized: Boolean,
@ColumnInfo(name = "is_edu_one", defaultValue = "NULL")
val isEduOne: Boolean?,
) : Serializable {
@PrimaryKey(autoGenerate = true)
@ -88,3 +96,22 @@ data class Student(
@ColumnInfo(name = "avatar_color")
var avatarColor = 0L
}
@Entity
data class StudentIsAuthorized(
@PrimaryKey
var id: Long,
@ColumnInfo(name = "is_authorized", defaultValue = "NULL")
val isAuthorized: Boolean?,
) : Serializable
@Entity
data class StudentIsEduOne(
@PrimaryKey
var id: Long,
@ColumnInfo(name = "is_edu_one", defaultValue = "NULL")
val isEduOne: Boolean?,
) : Serializable

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

@ -5,7 +5,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration10 : Migration(9, 10) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Grades_Summary RENAME TO GradesSummary")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Grades_Summary RENAME TO GradesSummary")
}
}

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration11 : Migration(10, 11) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Grades_temp (
id INTEGER PRIMARY KEY NOT NULL,
is_read INTEGER NOT NULL,
@ -26,9 +27,10 @@ class Migration11 : Migration(10, 11) {
date INTEGER NOT NULL,
teacher TEXT NOT NULL
)
""")
database.execSQL("INSERT INTO Grades_temp SELECT * FROM Grades")
database.execSQL("DROP TABLE Grades")
database.execSQL("ALTER TABLE Grades_temp RENAME TO Grades")
"""
)
db.execSQL("INSERT INTO Grades_temp SELECT * FROM Grades")
db.execSQL("DROP TABLE Grades")
db.execSQL("ALTER TABLE Grades_temp RENAME TO Grades")
}
}

View File

@ -5,16 +5,17 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration12 : Migration(11, 12) {
override fun migrate(database: SupportSQLiteDatabase) {
createTempStudentsTable(database)
replaceStudentTable(database)
updateStudentsWithClassId(database, getStudentsIds(database))
removeStudentsWithNoClassId(database)
ensureThereIsOnlyOneCurrentStudent(database)
override fun migrate(db: SupportSQLiteDatabase) {
createTempStudentsTable(db)
replaceStudentTable(db)
updateStudentsWithClassId(db, getStudentsIds(db))
removeStudentsWithNoClassId(db)
ensureThereIsOnlyOneCurrentStudent(db)
}
private fun createTempStudentsTable(database: SupportSQLiteDatabase) {
database.execSQL("""
private fun createTempStudentsTable(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Students_tmp (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
endpoint TEXT NOT NULL,
@ -30,15 +31,16 @@ class Migration12 : Migration(11, 12) {
registration_date INTEGER NOT NULL,
class_id INTEGER NOT NULL
)
""")
database.execSQL("CREATE UNIQUE INDEX index_Students_email_symbol_student_id_school_id_class_id ON Students_tmp (email, symbol, student_id, school_id, class_id)")
"""
)
db.execSQL("CREATE UNIQUE INDEX index_Students_email_symbol_student_id_school_id_class_id ON Students_tmp (email, symbol, student_id, school_id, class_id)")
}
private fun replaceStudentTable(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL")
database.execSQL("INSERT INTO Students_tmp SELECT * FROM Students")
database.execSQL("DROP TABLE Students")
database.execSQL("ALTER TABLE Students_tmp RENAME TO Students")
private fun replaceStudentTable(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Students ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL")
db.execSQL("INSERT INTO Students_tmp SELECT * FROM Students")
db.execSQL("DROP TABLE Students")
db.execSQL("ALTER TABLE Students_tmp RENAME TO Students")
}
private fun getStudentsIds(database: SupportSQLiteDatabase): List<Int> {
@ -54,18 +56,18 @@ class Migration12 : Migration(11, 12) {
return students
}
private fun updateStudentsWithClassId(database: SupportSQLiteDatabase, students: List<Int>) {
private fun updateStudentsWithClassId(db: SupportSQLiteDatabase, students: List<Int>) {
students.forEach {
database.execSQL("UPDATE Students SET class_id = IFNULL((SELECT class_id FROM Semesters WHERE student_id = $it), 0) WHERE student_id = $it")
db.execSQL("UPDATE Students SET class_id = IFNULL((SELECT class_id FROM Semesters WHERE student_id = $it), 0) WHERE student_id = $it")
}
}
private fun removeStudentsWithNoClassId(database: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Students WHERE class_id = 0")
private fun removeStudentsWithNoClassId(db: SupportSQLiteDatabase) {
db.execSQL("DELETE FROM Students WHERE class_id = 0")
}
private fun ensureThereIsOnlyOneCurrentStudent(database: SupportSQLiteDatabase) {
database.execSQL("UPDATE Students SET is_current = 0")
database.execSQL("UPDATE Students SET is_current = 1 WHERE id = (SELECT MAX(id) FROM Students)")
private fun ensureThereIsOnlyOneCurrentStudent(db: SupportSQLiteDatabase) {
db.execSQL("UPDATE Students SET is_current = 0")
db.execSQL("UPDATE Students SET is_current = 1 WHERE id = (SELECT MAX(id) FROM Students)")
}
}

View File

@ -5,27 +5,30 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration13 : Migration(12, 13) {
override fun migrate(database: SupportSQLiteDatabase) {
addClassNameToStudents(database, getStudentsIds(database))
updateSemestersTable(database)
markAtLeastAndOnlyOneSemesterAtCurrent(database, getStudentsAndClassIds(database))
clearMessagesTable(database)
override fun migrate(db: SupportSQLiteDatabase) {
addClassNameToStudents(db, getStudentsIds(db))
updateSemestersTable(db)
markAtLeastAndOnlyOneSemesterAtCurrent(db, getStudentsAndClassIds(db))
clearMessagesTable(db)
}
private fun addClassNameToStudents(database: SupportSQLiteDatabase, students: List<Pair<Int, String>>) {
database.execSQL("ALTER TABLE Students ADD COLUMN class_name TEXT DEFAULT \"\" NOT NULL")
private fun addClassNameToStudents(
db: SupportSQLiteDatabase,
students: List<Pair<Int, String>>
) {
db.execSQL("ALTER TABLE Students ADD COLUMN class_name TEXT DEFAULT \"\" NOT NULL")
students.forEach { (id, name) ->
val schoolName = name.substringAfter(" - ")
val className = name.substringBefore(" - ", "").replace("Klasa ", "")
database.execSQL("UPDATE Students SET class_name = '$className' WHERE id = '$id'")
database.execSQL("UPDATE Students SET school_name = '$schoolName' WHERE id = '$id'")
db.execSQL("UPDATE Students SET class_name = '$className' WHERE id = '$id'")
db.execSQL("UPDATE Students SET school_name = '$schoolName' WHERE id = '$id'")
}
}
private fun getStudentsIds(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
private fun getStudentsIds(db: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
val students = mutableListOf<Pair<Int, String>>()
database.query("SELECT id, school_name FROM Students").use {
db.query("SELECT id, school_name FROM Students").use {
if (it.moveToFirst()) {
do {
students.add(it.getInt(0) to it.getString(1))
@ -36,15 +39,15 @@ class Migration13 : Migration(12, 13) {
return students
}
private fun updateSemestersTable(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Semesters ADD COLUMN school_year INTEGER DEFAULT 1970 NOT NULL")
database.execSQL("ALTER TABLE Semesters ADD COLUMN start INTEGER DEFAULT 0 NOT NULL")
database.execSQL("ALTER TABLE Semesters ADD COLUMN `end` INTEGER DEFAULT 0 NOT NULL")
private fun updateSemestersTable(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Semesters ADD COLUMN school_year INTEGER DEFAULT 1970 NOT NULL")
db.execSQL("ALTER TABLE Semesters ADD COLUMN start INTEGER DEFAULT 0 NOT NULL")
db.execSQL("ALTER TABLE Semesters ADD COLUMN `end` INTEGER DEFAULT 0 NOT NULL")
}
private fun getStudentsAndClassIds(database: SupportSQLiteDatabase): List<Pair<Int, Int>> {
private fun getStudentsAndClassIds(db: SupportSQLiteDatabase): List<Pair<Int, Int>> {
val students = mutableListOf<Pair<Int, Int>>()
database.query("SELECT student_id, class_id FROM Students").use {
db.query("SELECT student_id, class_id FROM Students").use {
if (it.moveToFirst()) {
do {
students.add(it.getInt(0) to it.getInt(1))
@ -55,14 +58,17 @@ class Migration13 : Migration(12, 13) {
return students
}
private fun markAtLeastAndOnlyOneSemesterAtCurrent(database: SupportSQLiteDatabase, students: List<Pair<Int, Int>>) {
private fun markAtLeastAndOnlyOneSemesterAtCurrent(
db: SupportSQLiteDatabase,
students: List<Pair<Int, Int>>
) {
students.forEach { (studentId, classId) ->
database.execSQL("UPDATE Semesters SET is_current = 0 WHERE student_id = '$studentId' AND class_id = '$classId'")
database.execSQL("UPDATE Semesters SET is_current = 1 WHERE id = (SELECT id FROM Semesters WHERE student_id = '$studentId' AND class_id = '$classId' ORDER BY semester_id DESC)")
db.execSQL("UPDATE Semesters SET is_current = 0 WHERE student_id = '$studentId' AND class_id = '$classId'")
db.execSQL("UPDATE Semesters SET is_current = 1 WHERE id = (SELECT id FROM Semesters WHERE student_id = '$studentId' AND class_id = '$classId' ORDER BY semester_id DESC)")
}
}
private fun clearMessagesTable(database: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Messages")
private fun clearMessagesTable(db: SupportSQLiteDatabase) {
db.execSQL("DELETE FROM Messages")
}
}

View File

@ -5,9 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration14 : Migration(13, 14) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS GradesSummary")
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS GradesSummary")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS GradesSummary (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
semester_id INTEGER NOT NULL,

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration15 : Migration(14, 15) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS MobileDevices (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
@ -14,6 +15,7 @@ class Migration15 : Migration(14, 15) {
name TEXT NOT NULL,
date INTEGER NOT NULL
)
""")
"""
)
}
}

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration16 : Migration(15, 16) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Teachers (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
@ -15,6 +16,7 @@ class Migration16 : Migration(15, 16) {
name TEXT NOT NULL,
short_name TEXT NOT NULL
)
""")
"""
)
}
}

View File

@ -5,13 +5,14 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration17 : Migration(16, 17) {
override fun migrate(database: SupportSQLiteDatabase) {
createGradesPointsStatisticsTable(database)
truncateSemestersTable(database)
override fun migrate(db: SupportSQLiteDatabase) {
createGradesPointsStatisticsTable(db)
truncateSemestersTable(db)
}
private fun createGradesPointsStatisticsTable(database: SupportSQLiteDatabase) {
database.execSQL("""
private fun createGradesPointsStatisticsTable(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS GradesPointsStatistics(
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
@ -20,10 +21,11 @@ class Migration17 : Migration(16, 17) {
others REAL NOT NULL,
student REAL NOT NULL
)
""")
"""
)
}
private fun truncateSemestersTable(database: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Semesters")
private fun truncateSemestersTable(db: SupportSQLiteDatabase) {
db.execSQL("DELETE FROM Semesters")
}
}

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration18 : Migration(17, 18) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS School (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,

View File

@ -6,16 +6,17 @@ import io.github.wulkanowy.data.db.SharedPrefProvider
class Migration19(private val sharedPrefProvider: SharedPrefProvider) : Migration(18, 19) {
override fun migrate(database: SupportSQLiteDatabase) {
migrateMessages(database)
migrateGrades(database)
migrateStudents(database)
override fun migrate(db: SupportSQLiteDatabase) {
migrateMessages(db)
migrateGrades(db)
migrateStudents(db)
migrateSharedPreferences()
}
private fun migrateMessages(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE Messages")
database.execSQL("""
private fun migrateMessages(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE Messages")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Messages (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
is_notified INTEGER NOT NULL,
@ -34,12 +35,14 @@ class Migration19(private val sharedPrefProvider: SharedPrefProvider) : Migratio
read_by INTEGER NOT NULL,
removed INTEGER NOT NULL
)
""")
"""
)
}
private fun migrateGrades(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE Grades")
database.execSQL("""
private fun migrateGrades(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE Grades")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Grades (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
is_read INTEGER NOT NULL,
@ -59,11 +62,13 @@ class Migration19(private val sharedPrefProvider: SharedPrefProvider) : Migratio
date INTEGER NOT NULL,
teacher TEXT NOT NULL
)
""")
"""
)
}
private fun migrateStudents(database: SupportSQLiteDatabase) {
database.execSQL("""
private fun migrateStudents(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Students_tmp (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
scrapper_base_url TEXT NOT NULL,
@ -86,26 +91,29 @@ class Migration19(private val sharedPrefProvider: SharedPrefProvider) : Migratio
is_current INTEGER NOT NULL,
registration_date INTEGER NOT NULL
)
""")
"""
)
database.execSQL("ALTER TABLE Students ADD COLUMN scrapperBaseUrl TEXT NOT NULL DEFAULT \"\";")
database.execSQL("ALTER TABLE Students ADD COLUMN apiBaseUrl TEXT NOT NULL DEFAULT \"\";")
database.execSQL("ALTER TABLE Students ADD COLUMN is_parent INT NOT NULL DEFAULT 0;")
database.execSQL("ALTER TABLE Students ADD COLUMN loginMode TEXT NOT NULL DEFAULT \"\";")
database.execSQL("ALTER TABLE Students ADD COLUMN certificateKey TEXT NOT NULL DEFAULT \"\";")
database.execSQL("ALTER TABLE Students ADD COLUMN privateKey TEXT NOT NULL DEFAULT \"\";")
database.execSQL("ALTER TABLE Students ADD COLUMN user_login_id INTEGER NOT NULL DEFAULT 0;")
db.execSQL("ALTER TABLE Students ADD COLUMN scrapperBaseUrl TEXT NOT NULL DEFAULT \"\";")
db.execSQL("ALTER TABLE Students ADD COLUMN apiBaseUrl TEXT NOT NULL DEFAULT \"\";")
db.execSQL("ALTER TABLE Students ADD COLUMN is_parent INT NOT NULL DEFAULT 0;")
db.execSQL("ALTER TABLE Students ADD COLUMN loginMode TEXT NOT NULL DEFAULT \"\";")
db.execSQL("ALTER TABLE Students ADD COLUMN certificateKey TEXT NOT NULL DEFAULT \"\";")
db.execSQL("ALTER TABLE Students ADD COLUMN privateKey TEXT NOT NULL DEFAULT \"\";")
db.execSQL("ALTER TABLE Students ADD COLUMN user_login_id INTEGER NOT NULL DEFAULT 0;")
database.execSQL("""
db.execSQL(
"""
INSERT INTO Students_tmp(
id, scrapper_base_url, mobile_base_url, is_parent, login_type, login_mode, certificate_key, private_key, email, password, symbol, student_id, user_login_id, student_name, school_id, school_name, school_id, school_name, class_name, class_id, is_current, registration_date)
SELECT
id, endpoint, apiBaseUrl, is_parent, loginType, "SCRAPPER", certificateKey, privateKey, email, password, symbol, student_id, user_login_id, student_name, school_id, school_name, school_id, school_name, class_name, class_id, is_current, registration_date
FROM Students
""")
database.execSQL("DROP TABLE Students")
database.execSQL("ALTER TABLE Students_tmp RENAME TO Students")
database.execSQL("CREATE UNIQUE INDEX index_Students_email_symbol_student_id_school_id_class_id ON Students (email, symbol, student_id, school_id, class_id)")
"""
)
db.execSQL("DROP TABLE Students")
db.execSQL("ALTER TABLE Students_tmp RENAME TO Students")
db.execSQL("CREATE UNIQUE INDEX index_Students_email_symbol_student_id_school_id_class_id ON Students (email, symbol, student_id, school_id, class_id)")
}
private fun migrateSharedPreferences() {

View File

@ -5,14 +5,16 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration2 : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS LuckyNumbers (
id INTEGER PRIMARY KEY NOT NULL,
is_notified INTEGER NOT NULL,
student_id INTEGER NOT NULL,
date INTEGER NOT NULL,
lucky_number INTEGER NOT NULL)
""")
"""
)
}
}

View File

@ -5,14 +5,15 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration20 : Migration(19, 20) {
override fun migrate(database: SupportSQLiteDatabase) {
migrateTimetable(database)
truncateSubjects(database)
override fun migrate(db: SupportSQLiteDatabase) {
migrateTimetable(db)
truncateSubjects(db)
}
private fun migrateTimetable(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE Timetable")
database.execSQL("""
private fun migrateTimetable(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE Timetable")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `Timetable` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`student_id` INTEGER NOT NULL,
@ -33,10 +34,11 @@ class Migration20 : Migration(19, 20) {
`changes` INTEGER NOT NULL,
`canceled` INTEGER NOT NULL
)
""")
"""
)
}
private fun truncateSubjects(database: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Subjects")
private fun truncateSubjects(db: SupportSQLiteDatabase) {
db.execSQL("DELETE FROM Subjects")
}
}

View File

@ -5,11 +5,11 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration21 : Migration(20, 21) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Attendance ADD COLUMN excusable INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE Attendance ADD COLUMN time_id INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE Attendance ADD COLUMN excuse_status TEXT DEFAULT NULL")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Attendance ADD COLUMN excusable INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE Attendance ADD COLUMN time_id INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE Attendance ADD COLUMN excuse_status TEXT DEFAULT NULL")
database.execSQL("DELETE FROM Semesters")
db.execSQL("DELETE FROM Semesters")
}
}

View File

@ -5,7 +5,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration22 : Migration(21, 22) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN school_short TEXT NOT NULL DEFAULT ''")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Students ADD COLUMN school_short TEXT NOT NULL DEFAULT ''")
}
}

View File

@ -5,10 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration23 : Migration(22, 23) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Notes ADD COLUMN teacher_symbol TEXT NOT NULL DEFAULT ''")
database.execSQL("ALTER TABLE Notes ADD COLUMN category_type INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE Notes ADD COLUMN is_points_show INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE Notes ADD COLUMN points INTEGER NOT NULL DEFAULT 0")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Notes ADD COLUMN teacher_symbol TEXT NOT NULL DEFAULT ''")
db.execSQL("ALTER TABLE Notes ADD COLUMN category_type INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE Notes ADD COLUMN is_points_show INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE Notes ADD COLUMN points INTEGER NOT NULL DEFAULT 0")
}
}

View File

@ -5,9 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration24 : Migration(23, 24) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Messages ADD COLUMN has_attachments INTEGER NOT NULL DEFAULT 0")
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Messages ADD COLUMN has_attachments INTEGER NOT NULL DEFAULT 0")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS MessageAttachments (
real_id INTEGER NOT NULL,
message_id INTEGER NOT NULL,
@ -16,6 +17,7 @@ class Migration24 : Migration(23, 24) {
filename TEXT NOT NULL,
PRIMARY KEY(real_id)
)
""")
"""
)
}
}

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration25 : Migration(24, 25) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Homework ADD COLUMN is_done INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE Homework ADD COLUMN attachments TEXT NOT NULL DEFAULT \"[]\"")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Homework ADD COLUMN is_done INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE Homework ADD COLUMN attachments TEXT NOT NULL DEFAULT \"[]\"")
}
}

View File

@ -5,10 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration26 : Migration(25, 26) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN is_predicted_grade_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN is_final_grade_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN predicted_grade_last_change INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN final_grade_last_change INTEGER NOT NULL DEFAULT 0")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE GradesSummary ADD COLUMN is_predicted_grade_notified INTEGER NOT NULL DEFAULT 1")
db.execSQL("ALTER TABLE GradesSummary ADD COLUMN is_final_grade_notified INTEGER NOT NULL DEFAULT 1")
db.execSQL("ALTER TABLE GradesSummary ADD COLUMN predicted_grade_last_change INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE GradesSummary ADD COLUMN final_grade_last_change INTEGER NOT NULL DEFAULT 0")
}
}

View File

@ -5,24 +5,25 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration27 : Migration(26, 27) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN user_name TEXT NOT NULL DEFAULT \"\"")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Students ADD COLUMN user_name TEXT NOT NULL DEFAULT \"\"")
val students = getStudentsIdsAndNames(database)
val units = getReportingUnits(database)
val students = getStudentsIdsAndNames(db)
val units = getReportingUnits(db)
students.forEach { (id, userLoginId, studentName) ->
val userNameFromUnits = units.singleOrNull { (senderId, _) -> senderId == userLoginId }?.second
val userNameFromUnits =
units.singleOrNull { (senderId, _) -> senderId == userLoginId }?.second
val normalizedStudentName = studentName.split(" ").asReversed().joinToString(" ")
val userName = userNameFromUnits ?: normalizedStudentName
database.execSQL("UPDATE Students SET user_name = '$userName' WHERE id = '$id'")
db.execSQL("UPDATE Students SET user_name = '$userName' WHERE id = '$id'")
}
}
private fun getStudentsIdsAndNames(database: SupportSQLiteDatabase): MutableList<Triple<Long, Int, String>> {
private fun getStudentsIdsAndNames(db: SupportSQLiteDatabase): MutableList<Triple<Long, Int, String>> {
val students = mutableListOf<Triple<Long, Int, String>>()
database.query("SELECT id, user_login_id, student_name FROM Students").use {
db.query("SELECT id, user_login_id, student_name FROM Students").use {
if (it.moveToFirst()) {
do {
students.add(Triple(it.getLong(0), it.getInt(1), it.getString(2)))
@ -33,9 +34,9 @@ class Migration27 : Migration(26, 27) {
return students
}
private fun getReportingUnits(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
private fun getReportingUnits(db: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
val units = mutableListOf<Pair<Int, String>>()
database.query("SELECT sender_id, sender_name FROM ReportingUnits").use {
db.query("SELECT sender_id, sender_name FROM ReportingUnits").use {
if (it.moveToFirst()) {
do {
units.add(it.getInt(0) to it.getString(1))

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration28 : Migration(27, 28) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Conferences (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,

View File

@ -5,9 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration29 : Migration(28, 29) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS GradesStatistics")
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS GradesStatistics")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS GradeSemesterStatistics (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
@ -16,8 +17,10 @@ class Migration29 : Migration(28, 29) {
amounts TEXT NOT NULL,
student_grade INTEGER NOT NULL
)
""")
database.execSQL("""
"""
)
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS GradePartialStatistics (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration3 : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS CompletedLesson (
id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL,

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration30 : Migration(29, 30) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE TimetableAdditional (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
@ -16,6 +17,7 @@ class Migration30 : Migration(29, 30) {
date INTEGER NOT NULL,
subject TEXT NOT NULL
)
""")
"""
)
}
}

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration31 : Migration(30, 31) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""CREATE TABLE IF NOT EXISTS StudentInfo (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration32 : Migration(31, 32) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN nick TEXT NOT NULL DEFAULT \"\"")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Students ADD COLUMN nick TEXT NOT NULL DEFAULT \"\"")
}
}

View File

@ -5,10 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration33 : Migration(32, 33) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS StudentInfo")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS StudentInfo")
database.execSQL(
db.execSQL(
"""CREATE TABLE IF NOT EXISTS StudentInfo (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,

View File

@ -5,9 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration34 : Migration(33, 34) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM ReportingUnits")
database.execSQL("DELETE FROM Recipients")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("DELETE FROM ReportingUnits")
db.execSQL("DELETE FROM Recipients")
}
}

View File

@ -7,13 +7,13 @@ import io.github.wulkanowy.utils.AppInfo
class Migration35(private val appInfo: AppInfo) : Migration(34, 35) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN `avatar_color` INTEGER NOT NULL DEFAULT 0")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Students ADD COLUMN `avatar_color` INTEGER NOT NULL DEFAULT 0")
database.query("SELECT * FROM Students").use {
db.query("SELECT * FROM Students").use {
while (it.moveToNext()) {
val studentId = it.getLongOrNull(0)
database.execSQL(
db.execSQL(
"""
UPDATE Students
SET avatar_color = ${appInfo.defaultColorsForAvatar.random()}

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration36 : Migration(35, 36) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Exams ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE Homework ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Exams ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
db.execSQL("ALTER TABLE Homework ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
}
}

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration37 : Migration(36, 37) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS TimetableHeaders (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration38 : Migration(37, 38) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `SchoolAnnouncements` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`student_id` INTEGER NOT NULL,
@ -14,6 +15,7 @@ class Migration38 : Migration(37, 38) {
`subject` TEXT NOT NULL,
`content` TEXT NOT NULL
)
""")
"""
)
}
}

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration39 : Migration(38, 39) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Conferences ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE SchoolAnnouncements ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Conferences ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
db.execSQL("ALTER TABLE SchoolAnnouncements ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
}
}
}

View File

@ -5,9 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration4 : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Messages")
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS Messages")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Messages (
id INTEGER PRIMARY KEY NOT NULL,
is_notified INTEGER NOT NULL,

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration40 : Migration(39, 40) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `Notifications` (
`student_id` INTEGER NOT NULL,
@ -20,4 +20,4 @@ class Migration40 : Migration(39, 40) {
"""
)
}
}
}

View File

@ -7,9 +7,9 @@ import io.github.wulkanowy.data.enums.GradeExpandMode
class Migration41(private val sharedPrefProvider: SharedPrefProvider) : Migration(40, 41) {
override fun migrate(database: SupportSQLiteDatabase) {
override fun migrate(db: SupportSQLiteDatabase) {
migrateSharedPreferences()
database.execSQL("ALTER TABLE Homework ADD COLUMN is_added_by_user INTEGER NOT NULL DEFAULT 0")
db.execSQL("ALTER TABLE Homework ADD COLUMN is_added_by_user INTEGER NOT NULL DEFAULT 0")
}
private fun migrateSharedPreferences() {
@ -18,4 +18,4 @@ class Migration41(private val sharedPrefProvider: SharedPrefProvider) : Migratio
}
sharedPrefProvider.delete("pref_key_expand_grade")
}
}
}

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration42 : Migration(41, 42) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""CREATE TABLE IF NOT EXISTS `AdminMessages` (
`id` INTEGER NOT NULL,
`title` TEXT NOT NULL,
@ -21,4 +21,4 @@ class Migration42 : Migration(41, 42) {
PRIMARY KEY(`id`))"""
)
}
}
}

View File

@ -5,8 +5,8 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration43 : Migration(42, 43) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Timetable ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE Attendance ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Timetable ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
db.execSQL("ALTER TABLE Attendance ADD COLUMN is_notified INTEGER NOT NULL DEFAULT 1")
}
}

View File

@ -5,7 +5,7 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration44 : Migration(43, 44) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE AdminMessages ADD COLUMN is_dismissible INTEGER NOT NULL DEFAULT 0")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE AdminMessages ADD COLUMN is_dismissible INTEGER NOT NULL DEFAULT 0")
}
}

View File

@ -8,65 +8,65 @@ import java.time.ZoneOffset
class Migration46 : Migration(45, 46) {
override fun migrate(database: SupportSQLiteDatabase) {
migrateConferences(database)
migrateMessages(database)
migrateMobileDevices(database)
migrateNotifications(database)
migrateTimetable(database)
migrateTimetableAdditional(database)
override fun migrate(db: SupportSQLiteDatabase) {
migrateConferences(db)
migrateMessages(db)
migrateMobileDevices(db)
migrateNotifications(db)
migrateTimetable(db)
migrateTimetableAdditional(db)
}
private fun migrateConferences(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM Conferences").use {
private fun migrateConferences(db: SupportSQLiteDatabase) {
db.query("SELECT * FROM Conferences").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE Conferences SET date = $timestampUtc WHERE id = $id")
db.execSQL("UPDATE Conferences SET date = $timestampUtc WHERE id = $id")
}
}
}
private fun migrateMessages(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM Messages").use {
private fun migrateMessages(db: SupportSQLiteDatabase) {
db.query("SELECT * FROM Messages").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE Messages SET date = $timestampUtc WHERE id = $id")
db.execSQL("UPDATE Messages SET date = $timestampUtc WHERE id = $id")
}
}
}
private fun migrateMobileDevices(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM MobileDevices").use {
private fun migrateMobileDevices(db: SupportSQLiteDatabase) {
db.query("SELECT * FROM MobileDevices").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE MobileDevices SET date = $timestampUtc WHERE id = $id")
db.execSQL("UPDATE MobileDevices SET date = $timestampUtc WHERE id = $id")
}
}
}
private fun migrateNotifications(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM Notifications").use {
private fun migrateNotifications(db: SupportSQLiteDatabase) {
db.query("SELECT * FROM Notifications").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocal = it.getLong(it.getColumnIndexOrThrow("date"))
val timestampUtc = timestampLocal.timestampLocalToUTC()
database.execSQL("UPDATE Notifications SET date = $timestampUtc WHERE id = $id")
db.execSQL("UPDATE Notifications SET date = $timestampUtc WHERE id = $id")
}
}
}
private fun migrateTimetable(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM Timetable").use {
private fun migrateTimetable(db: SupportSQLiteDatabase) {
db.query("SELECT * FROM Timetable").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocalStart = it.getLong(it.getColumnIndexOrThrow("start"))
@ -74,13 +74,13 @@ class Migration46 : Migration(45, 46) {
val timestampUtcStart = timestampLocalStart.timestampLocalToUTC()
val timestampUtcEnd = timestampLocalEnd.timestampLocalToUTC()
database.execSQL("UPDATE Timetable SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id")
db.execSQL("UPDATE Timetable SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id")
}
}
}
private fun migrateTimetableAdditional(database: SupportSQLiteDatabase) {
database.query("SELECT * FROM TimetableAdditional").use {
private fun migrateTimetableAdditional(db: SupportSQLiteDatabase) {
db.query("SELECT * FROM TimetableAdditional").use {
while (it.moveToNext()) {
val id = it.getLong(it.getColumnIndexOrThrow("id"))
val timestampLocalStart = it.getLong(it.getColumnIndexOrThrow("start"))
@ -88,7 +88,7 @@ class Migration46 : Migration(45, 46) {
val timestampUtcStart = timestampLocalStart.timestampLocalToUTC()
val timestampUtcEnd = timestampLocalEnd.timestampLocalToUTC()
database.execSQL("UPDATE TimetableAdditional SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id")
db.execSQL("UPDATE TimetableAdditional SET start = $timestampUtcStart, end = $timestampUtcEnd WHERE id = $id")
}
}
}

View File

@ -5,10 +5,10 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration49 : Migration(48, 49) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS SchoolAnnouncements")
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS SchoolAnnouncements")
database.execSQL(
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `SchoolAnnouncements` (
`user_login_id` INTEGER NOT NULL,

View File

@ -7,11 +7,16 @@ import java.time.ZoneOffset
class Migration5 : Migration(4, 5) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN registration_date INTEGER DEFAULT 0 NOT NULL")
database.execSQL("UPDATE Students SET registration_date = '${now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli()}'")
database.execSQL("DROP TABLE IF EXISTS Notes")
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("ALTER TABLE Students ADD COLUMN registration_date INTEGER DEFAULT 0 NOT NULL")
db.execSQL(
"UPDATE Students SET registration_date = '${
now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli()
}'"
)
db.execSQL("DROP TABLE IF EXISTS Notes")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Notes (
id INTEGER PRIMARY KEY NOT NULL,
is_read INTEGER NOT NULL,
@ -21,6 +26,7 @@ class Migration5 : Migration(4, 5) {
teacher TEXT NOT NULL,
category TEXT NOT NULL,
content TEXT NOT NULL)
""")
"""
)
}
}

View File

@ -5,9 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration50 : Migration(49, 50) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS MobileDevices")
database.execSQL(
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS MobileDevices")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `MobileDevices` (
`user_login_id` INTEGER NOT NULL,

View File

@ -5,17 +5,17 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration51 : Migration(50, 51) {
override fun migrate(database: SupportSQLiteDatabase) {
createMailboxTable(database)
recreateMessagesTable(database)
recreateMessageAttachmentsTable(database)
recreateRecipientsTable(database)
deleteReportingUnitTable(database)
override fun migrate(db: SupportSQLiteDatabase) {
createMailboxTable(db)
recreateMessagesTable(db)
recreateMessageAttachmentsTable(db)
recreateRecipientsTable(db)
deleteReportingUnitTable(db)
}
private fun createMailboxTable(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Mailboxes")
database.execSQL(
private fun createMailboxTable(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS Mailboxes")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `Mailboxes` (
`globalKey` TEXT NOT NULL,
@ -30,9 +30,9 @@ class Migration51 : Migration(50, 51) {
)
}
private fun recreateMessagesTable(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Messages")
database.execSQL(
private fun recreateMessagesTable(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS Messages")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `Messages` (
`message_global_key` TEXT NOT NULL,
@ -52,9 +52,9 @@ class Migration51 : Migration(50, 51) {
)
}
private fun recreateMessageAttachmentsTable(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS MessageAttachments")
database.execSQL(
private fun recreateMessageAttachmentsTable(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS MessageAttachments")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `MessageAttachments` (
`real_id` INTEGER NOT NULL,
@ -66,9 +66,9 @@ class Migration51 : Migration(50, 51) {
)
}
private fun recreateRecipientsTable(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Recipients")
database.execSQL(
private fun recreateRecipientsTable(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS Recipients")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `Recipients` (
`mailboxGlobalKey` TEXT NOT NULL,
@ -82,7 +82,7 @@ class Migration51 : Migration(50, 51) {
)
}
private fun deleteReportingUnitTable(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS ReportingUnits")
private fun deleteReportingUnitTable(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS ReportingUnits")
}
}

View File

@ -5,14 +5,14 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration53 : Migration(52, 53) {
override fun migrate(database: SupportSQLiteDatabase) {
createMailboxTable(database)
recreateMessagesTable(database)
override fun migrate(db: SupportSQLiteDatabase) {
createMailboxTable(db)
recreateMessagesTable(db)
}
private fun createMailboxTable(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Mailboxes")
database.execSQL(
private fun createMailboxTable(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS Mailboxes")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `Mailboxes` (
`globalKey` TEXT NOT NULL,
@ -29,9 +29,9 @@ class Migration53 : Migration(52, 53) {
)
}
private fun recreateMessagesTable(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Messages")
database.execSQL(
private fun recreateMessagesTable(db: SupportSQLiteDatabase) {
db.execSQL("DROP TABLE IF EXISTS Messages")
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS `Messages` (
`email` TEXT NOT NULL,

View File

@ -5,22 +5,24 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration54 : Migration(53, 54) {
override fun migrate(database: SupportSQLiteDatabase) {
migrateResman(database)
removeTomaszowMazowieckiStudents(database)
override fun migrate(db: SupportSQLiteDatabase) {
migrateResman(db)
removeTomaszowMazowieckiStudents(db)
}
private fun migrateResman(database: SupportSQLiteDatabase) {
database.execSQL("""
private fun migrateResman(db: SupportSQLiteDatabase) {
db.execSQL(
"""
UPDATE Students SET
scrapper_base_url = 'https://vulcan.net.pl',
login_type = 'ADFSLightScoped',
symbol = 'rzeszowprojekt'
WHERE scrapper_base_url = 'https://resman.pl'
""".trimIndent())
""".trimIndent()
)
}
private fun removeTomaszowMazowieckiStudents(database: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Students WHERE symbol = 'tomaszowmazowiecki'")
private fun removeTomaszowMazowieckiStudents(db: SupportSQLiteDatabase) {
db.execSQL("DELETE FROM Students WHERE symbol = 'tomaszowmazowiecki'")
}
}

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 = "is_dismissible",
)
class Migration58 : AutoMigrationSpec

View File

@ -5,8 +5,9 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration6 : Migration(5, 6) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
override fun migrate(db: SupportSQLiteDatabase) {
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS ReportingUnits (
id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL,
@ -15,9 +16,11 @@ class Migration6 : Migration(5, 6) {
sender_id INTEGER NOT NULL,
sender_name TEXT NOT NULL,
roles TEXT NOT NULL)
""")
"""
)
database.execSQL("""
db.execSQL(
"""
CREATE TABLE IF NOT EXISTS Recipients (
id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL,
@ -28,10 +31,11 @@ class Migration6 : Migration(5, 6) {
unit_id INTEGER NOT NULL,
role INTEGER NOT NULL,
hash TEXT NOT NULL)
""")
"""
)
database.execSQL("DELETE FROM Semesters WHERE 1")
database.execSQL("ALTER TABLE Semesters ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL")
database.execSQL("ALTER TABLE Semesters ADD COLUMN unit_id INTEGER DEFAULT 0 NOT NULL")
db.execSQL("DELETE FROM Semesters WHERE 1")
db.execSQL("ALTER TABLE Semesters ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL")
db.execSQL("ALTER TABLE Semesters ADD COLUMN unit_id INTEGER DEFAULT 0 NOT NULL")
}
}

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