1
0
Fork 1

Compare commits

...

188 commits

Author SHA1 Message Date
Mikołaj Pich
42515fd084 Merge branch 'release/0.20.3' into master 2020-09-04 23:42:07 +02:00
Mikołaj Pich
9a7c04fe7b Version 0.20.3 2020-09-04 23:42:01 +02:00
Mikołaj Pich
debb21f5f9
Add full stacktrace to errors list in sync now (#945) 2020-09-03 21:10:39 +02:00
Mikołaj Pich
18b9bf42e1
Fix crash in flowWithResourceIn() (#944) 2020-09-03 20:54:28 +02:00
Mikołaj Pich
6ded83d132
Fix attendance item description (#943) 2020-09-03 20:52:24 +02:00
Mikołaj Pich
71d37a1c6c Merge tag '0.20.2' into develop
Version 0.20.2
2020-09-02 00:23:49 +02:00
Mikołaj Pich
3975d06cde Merge branch 'release/0.20.2' into master 2020-09-02 00:23:45 +02:00
Mikołaj Pich
ee168bafe0 Version 0.20.2 2020-09-02 00:23:41 +02:00
Mikołaj Pich
42ed7e0ae1 Merge tag '0.20.1' into develop
Version 0.20.1
2020-09-02 00:14:35 +02:00
Mikołaj Pich
0e92447974 Merge branch 'release/0.20.1' into master 2020-09-02 00:14:23 +02:00
Mikołaj Pich
40492e6c01 Version 0.20.1 2020-09-02 00:14:18 +02:00
Mikołaj Pich
69a1193154
Fix semester list refresh on no current semester found (#940) 2020-09-01 23:58:18 +02:00
Mikołaj Pich
0f65af8958
Fix grade summary empty view (#941) 2020-09-01 23:57:56 +02:00
Rafał Borcz
2ad1d086e0
Fix lucky number notification (#937) 2020-09-01 15:39:34 +02:00
Rafał Borcz
f8b7baef24
Remove force sync dialog (#938) 2020-09-01 14:58:45 +02:00
Mateusz Idziejczak
90be9d1add
Disable notification sound (#936) 2020-09-01 12:57:45 +02:00
Mikołaj Pich
20f931c5cc
Fix recaptcha loading in password recover (#935) 2020-09-01 09:33:14 +02:00
Mikołaj Pich
9997b1adbb
Add skarzyskokamienna vulcan register (#934) 2020-09-01 09:31:36 +02:00
Mikołaj Pich
eb616eedc7
Fix crash in flowWithResourceIn() (#933) 2020-09-01 09:31:01 +02:00
Rafał Borcz
a5de39a366
Update UI dependencies (#927) 2020-08-31 12:55:51 +02:00
dependabot-preview[bot]
57bc2b2533
Bump firebase-crashlytics from 17.1.1 to 17.2.1 (#931) 2020-08-31 10:09:37 +00:00
dependabot-preview[bot]
d1ce16d2b1
Bump runner from 1.2.0 to 1.3.0 (#932) 2020-08-31 10:03:20 +00:00
dependabot-preview[bot]
54fb01cd0d
Bump firebase-inappmessaging-display-ktx from 19.1.0 to 19.1.1 (#930) 2020-08-31 09:42:25 +00:00
dependabot-preview[bot]
370cfbf22a
Bump core from 1.2.0 to 1.3.0 (#929) 2020-08-31 09:42:18 +00:00
Mikołaj Pich
d198a2ba21 Merge tag '0.20.0' into develop
Version 0.20.0
2020-08-29 23:57:20 +02:00
Mikołaj Pich
580ad58dd6 Merge branch 'release/0.20.0' into master 2020-08-29 23:57:14 +02:00
Mikołaj Pich
b5f7c5f318 Version 0.20.0 2020-08-29 23:57:06 +02:00
Mikołaj Pich
7e2de594a4
Fix messages after 20.09 update (#916) 2020-08-29 23:53:55 +02:00
dependabot-preview[bot]
36984e08b5
Bump coil from 0.11.0 to 1.0.0-rc1 (#920) 2020-08-29 11:12:27 +00:00
dependabot-preview[bot]
f8031e1eca
Bump appcompat from 1.2.0-rc02 to 1.2.0 (#926) 2020-08-29 09:39:31 +00:00
dependabot-preview[bot]
5bc49b2e74
Bump firebase-inappmessaging-ktx from 19.1.0 to 19.1.1 (#918) 2020-08-29 09:29:00 +00:00
dependabot-preview[bot]
ba81b4b465
Bump junit from 1.1.1 to 1.1.2 (#924) 2020-08-29 09:20:43 +00:00
dependabot-preview[bot]
5cc31a7c5e
Bump firebase-crashlytics-gradle from 2.2.0 to 2.2.1 (#923) 2020-08-29 09:14:35 +00:00
dependabot-preview[bot]
de70719d38
Bump appcompat-resources from 1.1.0 to 1.2.0 (#922) 2020-08-29 09:09:41 +00:00
dependabot-preview[bot]
9f315b3af1
Bump firebase-analytics from 17.4.4 to 17.5.0 (#917) 2020-08-29 08:50:49 +00:00
Mikołaj Pich
d5187d1808
Save semesters with students during registration (#915) 2020-08-26 10:25:01 +02:00
dependabot-preview[bot]
ca7d977342
Bump work_manager from 2.3.4 to 2.4.0 (#910)
Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-08-02 18:41:22 +02:00
dependabot-preview[bot]
062985c5a0
Bump firebase-messaging from 20.2.3 to 20.2.4 (#912) 2020-08-02 16:30:31 +00:00
dependabot-preview[bot]
8922d7d48d
Bump core-ktx from 1.3.0 to 1.3.1 (#911) 2020-08-02 16:30:06 +00:00
Mikołaj Pich
3ba16f2903
Migrate to dagger hilt (#909) 2020-08-02 18:29:41 +02:00
Mikołaj Pich
6a1a347579
Migrate workers and app widgets to coroutines (#907) 2020-07-27 13:20:45 +02:00
Mikołaj Pich
6c4f27aff5
Remove threetenabp (#908) 2020-07-27 11:44:30 +02:00
dependabot-preview[bot]
f6dce0fbda
Bump kotlinx-coroutines-rx2 from 1.3.7 to 1.3.8 (#901) 2020-07-19 12:00:08 +00:00
Mikołaj Pich
1ac42bb56d
Migrate presenters from rxjava to coroutines flow (#894) 2020-07-19 13:30:29 +02:00
dependabot-preview[bot]
b0a674b471
Bump kotlinx-coroutines-core from 1.3.7 to 1.3.8 (#903) 2020-07-19 11:25:48 +00:00
dependabot-preview[bot]
1c1a90c12f
Bump firebase-inappmessaging-display-ktx from 19.0.7 to 19.1.0 (#905) 2020-07-18 23:51:24 +00:00
dependabot-preview[bot]
d4ee1f8b98
Bump firebase-crashlytics from 17.1.0 to 17.1.1 (#902) 2020-07-18 23:32:38 +00:00
dependabot-preview[bot]
152382a0c9
Bump firebase-analytics from 17.4.3 to 17.4.4 (#906) 2020-07-18 23:31:27 +00:00
dependabot-preview[bot]
776972514a
Bump firebase-inappmessaging-ktx from 19.0.7 to 19.1.0 (#904) 2020-07-18 23:00:03 +00:00
dependabot-preview[bot]
e072bf9fe3
Bump gradle from 4.0.0 to 4.0.1 (#900) 2020-07-18 22:42:05 +00:00
dependabot-preview[bot]
927415f9a3
Bump dagger from 2.28.1 to 2.28.3 (#899) 2020-07-18 22:41:41 +00:00
dependabot-preview[bot]
76b2ab1f25
Bump firebase-messaging from 20.2.1 to 20.2.3 (#898) 2020-07-18 22:40:01 +00:00
Rafał Borcz
c9a0bbda01
New Crowdin updates (#888) 2020-07-12 17:55:27 +02:00
dependabot-preview[bot]
cbabe44461
Bump about_libraries from 8.2.0 to 8.3.0 (#896) 2020-07-11 09:41:12 +00:00
dependabot-preview[bot]
5c313f986c
Bump swiperefreshlayout from 1.1.0-rc01 to 1.1.0 (#897) 2020-07-02 10:15:34 +00:00
dependabot-preview[bot]
f2682c6d30
Bump dagger from 2.28 to 2.28.1 (#895) 2020-07-02 10:15:28 +00:00
dependabot-preview[bot]
3571f8bd04
Bump firebase-crashlytics from 17.0.1 to 17.1.0 (#892) 2020-06-20 16:00:47 +00:00
dependabot-preview[bot]
dfcd5fc4d0
Bump firebase-crashlytics-gradle from 2.1.1 to 2.2.0 (#889) 2020-06-20 15:38:08 +00:00
dependabot-preview[bot]
b8ea0ab0f9
Bump firebase-messaging from 20.2.0 to 20.2.1 (#890) 2020-06-20 15:37:34 +00:00
Mikołaj Pich
4434d6f024
Migrate repositories from rxjava to coroutines (#885) 2020-06-20 15:07:57 +02:00
Mikołaj Pich
8cee882c08 Merge tag '0.19.0' into develop
Version 0.19.0
2020-06-14 22:44:41 +02:00
Mikołaj Pich
9f87b92937 Merge branch 'release/0.19.0' 2020-06-14 22:44:36 +02:00
Mikołaj Pich
c13f12f729 Version 0.19.0 2020-06-14 22:40:36 +02:00
Rafał Borcz
dfe7981e7f
New Crowdin translations (#874)
Co-authored-by: Mikołaj Pich <m.pich@outlook.com>
2020-06-14 22:37:58 +02:00
Dominik Korsa
6e1ddb482e
Message fuzzy search (#869) 2020-06-14 14:05:24 +02:00
Dominik Korsa
924bcb0d64
Message sharing and printing (#866) 2020-06-14 00:50:09 +02:00
Dominik Korsa
a6682c9b73
Add predicted and final grade notifications (#872) 2020-06-13 17:11:18 +02:00
Dominik Korsa
a529836937
Fix lint errors (#873) 2020-06-13 14:12:01 +02:00
Dominik Korsa
a05da2656a
Add account headers in student picker (#871) 2020-06-12 21:35:51 +02:00
Mikołaj Pich
30af77614e
Fix showing summary summary for subjects without partial grades (#877) 2020-06-11 14:38:04 +02:00
dependabot-preview[bot]
eedaa63771
Bump sonarqube-gradle-plugin from 2.8 to 3.0 (#882) 2020-06-11 12:05:54 +00:00
dependabot-preview[bot]
f151f7bd62
Bump about_libraries from 8.1.6 to 8.2.0 (#879) 2020-06-11 12:05:30 +00:00
dependabot-preview[bot]
00943717a2
Bump firebase-crashlytics from 17.0.0 to 17.0.1 (#880) 2020-06-11 12:02:38 +00:00
dependabot-preview[bot]
8cce81585a
Bump firebase-analytics from 17.4.2 to 17.4.3 (#881) 2020-06-11 12:02:10 +00:00
dependabot-preview[bot]
5529ffcf73
Bump fragment-ktx from 1.2.4 to 1.2.5 (#878) 2020-06-11 12:01:52 +00:00
Mikołaj Pich
7e6f892e23 Merge tag '0.18.3' into develop
Version 0.18.3
2020-06-10 19:18:31 +02:00
Mikołaj Pich
d3a6ea5acf Merge branch 'release/0.18.3' 2020-06-10 19:18:23 +02:00
Mikołaj Pich
674a78b661 Version 0.18.3 2020-06-10 19:18:09 +02:00
Mikołaj Pich
5c84c8d5b1
Fix force average calc from two semesters (#870) 2020-06-10 17:28:49 +02:00
Mikołaj Pich
522a36d670
Fix message deleting (#875) 2020-06-10 16:26:45 +02:00
Mikołaj Pich
2d0cfc3e8e Merge tag '0.18.2' into develop
Version 0.18.2
2020-06-02 17:08:02 +02:00
Mikołaj Pich
4b6b722f87 Merge branch 'release/0.18.2' 2020-06-02 17:07:58 +02:00
Mikołaj Pich
419675066f Version 0.18.2 2020-06-02 17:07:52 +02:00
Mikołaj Pich
191b1ad022
Emulate summaries from grade list when summaries are empty (#855) 2020-06-02 15:51:15 +02:00
Mikołaj Pich
792e44a9d0
Fix login button state in student select login fragment (#863) 2020-06-02 15:50:32 +02:00
Rafał Borcz
ff5a47b0df
New Crowdin translations (#856) 2020-06-02 15:18:41 +02:00
Mikołaj Pich
7bf0acb703
Revert "Bump sonarqube-gradle-plugin from 2.8 to 3.0" (#864)
This reverts commit ab7d30c995.
2020-06-02 15:13:41 +02:00
Mikołaj Pich
ba5dbf90d8
Fixes in updating adapter items (#854) 2020-06-02 01:04:41 +02:00
Mikołaj Pich
54f41aaa63
Fix too many alarms on samsung devices (#859) 2020-06-02 01:04:02 +02:00
dependabot-preview[bot]
1db42210e8
Bump about_libraries from 8.1.4 to 8.1.6 (#861)
Bumps `about_libraries` from 8.1.4 to 8.1.6.

Updates `aboutlibraries-plugin` from 8.1.4 to 8.1.6
- [Release notes](https://github.com/mikepenz/AboutLibraries/releases)
- [Changelog](https://github.com/mikepenz/AboutLibraries/blob/develop/gradle-release.gradle)
- [Commits](https://github.com/mikepenz/AboutLibraries/compare/v8.1.4...v8.1.6)

Updates `aboutlibraries-core` from 8.1.4 to 8.1.6
- [Release notes](https://github.com/mikepenz/AboutLibraries/releases)
- [Changelog](https://github.com/mikepenz/AboutLibraries/blob/develop/gradle-release.gradle)
- [Commits](https://github.com/mikepenz/AboutLibraries/compare/v8.1.4...v8.1.6)

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

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-06-02 01:02:16 +02:00
Mikołaj Pich
fb554a4a3b
Fix capitalization in new message activity (#860) 2020-06-02 01:01:58 +02:00
Mikołaj Pich
d8d13c73fb
Filter out empty items in grade summary (#857) 2020-06-02 01:01:02 +02:00
Mikołaj Pich
5c0160a24d
Don't capture click on login student select checkbox (#862) 2020-06-02 00:57:22 +02:00
dependabot-preview[bot]
ab7d30c995
Bump sonarqube-gradle-plugin from 2.8 to 3.0 (#853) 2020-05-30 12:19:52 +00:00
dependabot-preview[bot]
1cfa1f15c0
Bump gradle from 3.6.3 to 4.0.0 (#852) 2020-05-30 11:33:43 +00:00
dependabot-preview[bot]
2149a4db9f
Bump about_libraries from 8.1.3 to 8.1.4 (#851) 2020-05-30 11:17:22 +00:00
dependabot-preview[bot]
df57d16d21
Bump dagger from 2.27 to 2.28 (#850) 2020-05-30 11:16:58 +00:00
Piotr Romanowski
2ff031005e
Fix displaying the feature disabled message in completed lessons (#849) 2020-05-30 13:15:28 +02:00
Mikołaj Pich
b9ab85ee55 Merge tag '0.18.1' into develop
Version 0.18.1
2020-05-24 21:20:28 +02:00
Mikołaj Pich
064998129e Merge branch 'release/0.18.1' 2020-05-24 21:20:23 +02:00
Mikołaj Pich
4044cdd9a5 Version 0.18.1 2020-05-24 21:20:17 +02:00
Rafał Borcz
1ee10a5902
New Crowdin translations (#847) 2020-05-24 21:18:49 +02:00
dependabot-preview[bot]
27b1d076c7
Bump firebase-inappmessaging-ktx from 19.0.6 to 19.0.7 (#844) 2020-05-24 21:03:35 +02:00
dependabot-preview[bot]
c8b32fdb3b
Bump firebase-analytics from 17.4.1 to 17.4.2 (#843) 2020-05-24 21:02:42 +02:00
dependabot-preview[bot]
0b4434fdb6
Bump firebase-crashlytics-gradle from 2.1.0 to 2.1.1 (#841) 2020-05-24 20:53:59 +02:00
Rafał Borcz
699fbff082
Fix debug channel (#846) 2020-05-24 20:53:23 +02:00
dependabot-preview[bot]
4c295f2ab4
Bump firebase-messaging from 20.1.7 to 20.2.0 (#839) 2020-05-24 18:42:24 +00:00
dependabot-preview[bot]
dcbaa170db
Bump about_libraries from 8.1.2 to 8.1.3 (#845) 2020-05-24 20:36:09 +02:00
dependabot-preview[bot]
c71b533645
Bump firebase-inappmessaging-display-ktx from 19.0.6 to 19.0.7 (#838) 2020-05-24 18:10:47 +00:00
Mikołaj Pich
63f2576ff1
Hide advanced login options button (#837) 2020-05-24 20:07:24 +02:00
Mikołaj Pich
b744a4182b
Open dontkillmyapp.com if no action found in app killer manager (#835) 2020-05-24 20:04:09 +02:00
Mikołaj Pich
0c4364609b
Show check for updates dialog before report a bug (#834) 2020-05-24 20:03:46 +02:00
Mikołaj Pich
3308d7fe6f
Wrap long preference titles (#836) 2020-05-24 19:52:01 +02:00
Mikołaj Pich
2cdde78c54
Allow access to saturday in timetable and attendance (#833) 2020-05-24 19:48:56 +02:00
Mikołaj Pich
428b599be0
Improve firebase logging (#832) 2020-05-24 19:48:14 +02:00
Mikołaj Pich
3541ab81b8
Destroy webview in password recover before setting binding to null (#829) 2020-05-24 19:47:20 +02:00
Mikołaj Pich
7fa14e5077
Set app_name in build.gradle (#830) 2020-05-24 19:36:40 +02:00
Mikołaj Pich
cec1068f2e
Fix crash in timetable time left (#826) 2020-05-24 19:34:10 +02:00
Mikołaj Pich
f737018548
Add debug statements to get/update methods in grade details adapter (#827) 2020-05-24 19:33:04 +02:00
Mikołaj Pich
9c01316178
Fix mark message as read in search mode (#828) 2020-05-24 19:24:01 +02:00
Mikołaj Pich
c3a6f8253a
Fix grade sorting (#825) 2020-05-24 19:23:35 +02:00
Rafał Borcz
d558c4db66
New Crowdin translations (#817) 2020-05-23 16:34:26 +02:00
Mikołaj Pich
722886aaf2 Merge tag '0.18.0' into develop
Version 0.18.0
2020-05-21 00:59:19 +02:00
Mikołaj Pich
31902a7667 Merge branch 'release/0.18.0' 2020-05-21 00:59:13 +02:00
Mikołaj Pich
4c1c4f8a43 Version 0.18.0 2020-05-21 00:59:05 +02:00
Mikołaj Pich
7850412ba9
Fix crash in timetable on api < 21 (#816) 2020-05-20 23:08:32 +02:00
Rafał Borcz
4f0ff5f49c
New Crowdin translations (#813) 2020-05-20 22:48:09 +02:00
Mikołaj Pich
131ba7dbb1
Add app killer manager to settings (#808) 2020-05-20 16:59:26 +02:00
Dominik Korsa
b95b529015
Add lesson time left display (#550) 2020-05-20 16:06:24 +02:00
Mikołaj Pich
29226dd93e
Add notification about upcoming lesson (#578) 2020-05-20 15:11:01 +02:00
Mikołaj Pich
115da64167
Add search in messages (#804) 2020-05-20 14:12:32 +02:00
Mikołaj Pich
6cd1877af7
Fix notifications on android 8.0 (#814) 2020-05-20 12:34:29 +02:00
dependabot-preview[bot]
78a90591fd
Bump coil from 0.10.1 to 0.11.0 (#812) 2020-05-16 21:06:45 +00:00
dependabot-preview[bot]
45265d025d
Bump appcompat from 1.2.0-beta01 to 1.2.0-rc01 (#811) 2020-05-16 20:52:37 +00:00
dependabot-preview[bot]
9bf5c2dc40
Bump firebase-crashlytics-gradle from 2.0.0 to 2.1.0 (#810) 2020-05-16 20:48:15 +00:00
dependabot-preview[bot]
ee4bdd2a9a
Bump firebase-analytics from 17.4.0 to 17.4.1 (#809) 2020-05-16 20:46:11 +00:00
Mikołaj Pich
0b75635ad5
Add option to hide/show chart list in grade class stats (#807) 2020-05-16 22:21:14 +02:00
Mikołaj Pich
f7b5b9c413
Add fullscreen mode to homework dialog (#806) 2020-05-16 22:06:00 +02:00
Rafał Borcz
52d66ac30b
New Crowdin translations (#797) 2020-05-13 11:25:50 +02:00
Mateusz Idziejczak
6ac5c6a0b4
Add widget system theme option (#759) 2020-05-10 12:00:21 +02:00
Rafał Borcz
45fc76a9a5
Update translations (#794) 2020-05-10 11:34:54 +02:00
Mikołaj Pich
6d1fa0cf05
Optimize grade average provider (#792) 2020-05-10 10:51:01 +02:00
Mikołaj Pich
8eb0c0351b
Use view binding instead of kotlin synthetics (#791) 2020-05-10 10:39:10 +02:00
Rafał Borcz
ec80f939f1 Update Crowdin configuration file 2020-05-06 23:10:19 +02:00
Rafał Borcz
70fc51a0b5 Update Crowdin configuration file 2020-05-06 23:07:13 +02:00
Rafał Borcz
bd700a88bf
Add nav bar color in night style (#790) 2020-05-03 15:06:49 +02:00
Mikołaj Pich
98f2f0e74f
Migrate from fabric to firebase crashlytics (#789) 2020-05-01 19:00:42 +02:00
Mikołaj Pich
4a3b746d48
Remove flexible adapter (#781) 2020-05-01 17:38:19 +02:00
Rafał Borcz
a1f864b35e
Add importantForAutofill to login fields (#788) 2020-05-01 12:54:01 +02:00
dependabot-preview[bot]
17ac3cfd52
Bump firebase-analytics from 17.3.0 to 17.4.0 (#787) 2020-04-30 22:40:38 +00:00
dependabot-preview[bot]
c6c2b1c6a3
Bump coil from 0.9.5 to 0.10.1 (#785) 2020-04-29 14:40:12 +00:00
dependabot-preview[bot]
5fba3d5775
Bump firebase-inappmessaging-ktx from 19.0.5 to 19.0.6 (#782) 2020-04-28 21:25:27 +00:00
dependabot-preview[bot]
6fe62edd63
Bump firebase-inappmessaging-display-ktx from 19.0.5 to 19.0.6 (#786) 2020-04-28 21:04:54 +00:00
dependabot-preview[bot]
87af3da1ad
Bump threetenabp from 1.2.3 to 1.2.4 (#783) 2020-04-28 20:57:14 +00:00
dependabot-preview[bot]
155f0cc347
Bump threetenbp from 1.4.3 to 1.4.4 (#784) 2020-04-28 20:56:55 +00:00
Mikołaj Pich
2de1ad5334 Merge tag '0.17.4' into develop
Version 0.17.4
2020-04-23 19:24:59 +02:00
Mikołaj Pich
763543a16e Merge branch 'release/0.17.4' 2020-04-23 19:24:54 +02:00
Mikołaj Pich
acabe90c9f Version 0.17.4 2020-04-23 19:24:49 +02:00
Mikołaj Pich
f79da9003a Merge tag '0.17.3' into develop
Version 0.17.3
2020-04-23 16:22:49 +02:00
Mikołaj Pich
fc9e558cd6 Merge branch 'release/0.17.3' 2020-04-23 16:22:44 +02:00
Mikołaj Pich
68140bd544 Version 0.17.3 2020-04-23 16:22:39 +02:00
Mikołaj Pich
2c4c2d1f49
Fix injector of ErrorDialog (#780) 2020-04-23 11:07:18 +02:00
dependabot-preview[bot]
4894086d9d
Bump about_libraries from 8.1.1 to 8.1.2 (#779) 2020-04-21 16:21:44 +00:00
Mikołaj Pich
1d29ef5fe3 Merge tag '0.17.2' into develop
Version 0.17.2
2020-04-19 23:42:00 +02:00
Mikołaj Pich
7fa333cff2 Merge branch 'release/0.17.2' 2020-04-19 23:41:53 +02:00
Mikołaj Pich
c1ffc2ae72 Version 0.17.2 2020-04-19 23:37:29 +02:00
Mikołaj Pich
9c0e2dc533
Refresh semesters if previous list was downloaded in different m… (#776) 2020-04-19 23:21:59 +02:00
Mikołaj Pich
9b18e3669d
Fix crash after send message when activity is in background (#777) 2020-04-19 23:21:25 +02:00
Mikołaj Pich
366ebc781d
Add error message and bug report button to error dialog (#778) 2020-04-19 23:20:55 +02:00
Mikołaj Pich
4bd0459155
Don't log common errors to crashlytics (#775) 2020-04-18 23:07:20 +02:00
Mikołaj Pich
b19084cb57
Fix visibility of dialog close button when homework content is l… (#774) 2020-04-18 23:06:05 +02:00
dependabot-preview[bot]
69be7ca412
Bump kotlin_version from 1.3.71 to 1.3.72 (#773) 2020-04-17 21:01:41 +00:00
dependabot-preview[bot]
07307b9709
Bump swiperefreshlayout from 1.1.0-beta01 to 1.1.0-rc01 (#770) 2020-04-17 20:59:02 +00:00
dependabot-preview[bot]
ee4a5e56a9
Bump gradle from 3.6.2 to 3.6.3 (#772) 2020-04-17 20:37:38 +00:00
dependabot-preview[bot]
c8f8ec77a9
Bump preference-ktx from 1.1.0 to 1.1.1 (#771) 2020-04-17 20:35:24 +00:00
Mikołaj Pich
be46a43427 Merge tag '0.17.1' into develop
Version 0.17.1
2020-04-12 19:20:59 +02:00
Mikołaj Pich
183e379223 Merge branch 'release/0.17.1' 2020-04-12 19:20:53 +02:00
Mikołaj Pich
2350fc2ddf Version 0.17.1 2020-04-12 19:20:44 +02:00
dependabot-preview[bot]
152f966a66
Bump firebase-inappmessaging-display-ktx from 19.0.4 to 19.0.5 (#767) 2020-04-12 17:19:06 +00:00
dependabot-preview[bot]
85ee7fad1d
Bump firebase-inappmessaging-ktx from 19.0.4 to 19.0.5 (#768) 2020-04-12 16:58:23 +00:00
Mikołaj Pich
3ac085573f
Show all known adfslight registers in register list (#766) 2020-04-12 18:55:16 +02:00
dependabot-preview[bot]
64a19d9627
Bump about_libraries from 8.1.0 to 8.1.1 (#769) 2020-04-12 15:14:08 +00:00
Mikołaj Pich
76af623c94
Add Sdk.init(student) call in all remote repositories (#764) 2020-04-12 15:13:35 +02:00
Mikołaj Pich
11c285be01
Fix homework dialog size (#765) 2020-04-12 15:12:25 +02:00
Mikołaj Pich
a0528496eb
Fix crash caused by updating view in not attached fragment (#763) 2020-04-09 23:46:42 +02:00
Mikołaj Pich
299345b864
Fix crash in message preview (#762) 2020-04-09 23:30:56 +02:00
Mikołaj Pich
0a18fefb1f
Use recycler view in homework details dialog (#761) 2020-04-08 18:17:20 +02:00
Mikołaj Pich
a26f0ec8c8 Merge tag '0.17.0' into develop
Version 0.17.0
2020-04-05 18:42:42 +02:00
505 changed files with 15105 additions and 9544 deletions

View file

@ -1,3 +1,3 @@
component_depth: 8
component_depth: 10
languages:
- kotlin

View file

@ -4,7 +4,16 @@
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="NAME_COUNT_TO_USE_STAR_IMPORT" value="2147483647" />

View file

@ -14,7 +14,7 @@ cache:
branches:
only:
- develop
- 0.17.0
- 0.20.3
android:
licenses:
@ -48,20 +48,15 @@ before_script:
script:
- ./gradlew dependencies --stacktrace --daemon
- fossa --no-ansi || true
#- ./gradlew lintPlayRelease -x fabricGenerateResourcesPlayRelease --stacktrace --daemon
- ./gradlew -Pcoverage testPlayDebugUnitTest -x fabricGenerateResourcesPlay --stacktrace --daemon
- ./gradlew -Pcoverage testPlayDebugUnitTest --stacktrace --daemon
- ./gradlew -Pcoverage createFdroidDebugCoverageReport --stacktrace --daemon
- ./gradlew -Pcoverage jacocoTestReport --stacktrace --daemon
- if [ -z ${SONAR_HOST+x} ]; then echo "sonar scan skipped"; else
git fetch --unshallow;
./gradlew sonarqube -x test -x lint -x fabricGenerateResourcesPlayRelease -x fabricGenerateResourcesFdroidRelease -Dsonar.host.url=$SONAR_HOST -Dsonar.organization=$SONAR_ORG -Dsonar.login=$SONAR_KEY -Dsonar.branch.name=${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} --stacktrace --daemon;
fi
- |
if [ $TRAVIS_TAG ]; then
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg;
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/key.p12.gpg;
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg;
./gradlew publishPlayRelease -PenableCrashlytics --stacktrace;
./gradlew publishPlayRelease -PenableFirebase --stacktrace;
fi
after_success:

View file

@ -47,7 +47,6 @@ You can also download a [development version](https://wulkanowy.github.io/#downl
* [Wulkanowy SDK](https://github.com/wulkanowy/sdk)
* [RxJava 2](https://github.com/ReactiveX/RxJava)
* [Dagger 2](https://github.com/google/dagger)
* [Room](https://developer.android.com/topic/libraries/architecture/room)
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)

View file

@ -48,7 +48,6 @@ Możesz także pobrać [wersję rozwojową](https://wulkanowy.github.io/#downloa
## Zbudowana za pomocą
* [Wulkanowy SDK](https://github.com/wulkanowy/SDK)
* [RxJava 2](https://github.com/ReactiveX/RxJava)
* [Dagger 2](https://github.com/google/dagger)
* [Room](https://developer.android.com/topic/libraries/architecture/room)
* [WorkManager](https://developer.android.com/topic/libraries/architecture/workmanager)

View file

@ -1,8 +1,8 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'io.fabric'
apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'com.github.triplet.play'
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
apply from: 'jacoco.gradle'
@ -18,18 +18,18 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 17
targetSdkVersion 29
versionCode 54
versionName "0.17.0"
versionCode 67
versionName "0.20.3"
multiDexEnabled true
resValue "string", "app_name", "Wulkanowy"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
manifestPlaceholders = [
fabric_api_key : System.getenv("FABRIC_API_KEY") ?: "null",
crashlytics_enabled: project.hasProperty("enableCrashlytics")
firebase_enabled: project.hasProperty("enableFirebase")
]
javaCompileOptions {
annotationProcessorOptions {
arguments = [
arguments += [
"room.schemaLocation": "$projectDir/schemas".toString(),
"room.incremental" : "true"
]
@ -52,18 +52,17 @@ android {
buildTypes {
release {
buildConfigField "boolean", "CRASHLYTICS_ENABLED", "true"
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
debug {
buildConfigField "boolean", "CRASHLYTICS_ENABLED", project.hasProperty("enableCrashlytics") ? "true" : "false"
resValue "string", "app_name", "Wulkanowy DEV " + defaultConfig.versionCode
applicationIdSuffix ".dev"
versionNameSuffix "-dev"
testCoverageEnabled = project.hasProperty('coverage')
ext.enableCrashlytics = project.hasProperty("enableCrashlytics")
ext.enableCrashlytics = project.hasProperty("enableFirebase")
}
}
@ -75,22 +74,27 @@ android {
}
fdroid {
buildConfigField "boolean", "CRASHLYTICS_ENABLED", "false"
dimension "platform"
}
}
buildFeatures {
viewBinding = true
}
lintOptions {
disable 'HardwareIds'
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs += ["-Xopt-in=kotlin.RequiresOptIn", "-Xjvm-default=all"]
}
packagingOptions {
@ -103,10 +107,6 @@ android {
}
}
androidExtensions {
experimental = true
}
play {
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
serviceAccountCredentials = file('key.p12')
@ -115,12 +115,10 @@ play {
}
ext {
work_manager = "2.3.4"
work_manager = "2.4.0"
room = "2.2.5"
dagger = "2.27"
// don't update https://github.com/ChuckerTeam/chucker/issues/242
chucker = "3.2.0"
mockk = "1.9.2"
mockk = "1.10.0"
}
configurations.all {
@ -128,69 +126,65 @@ configurations.all {
}
dependencies {
implementation "io.github.wulkanowy:sdk:0.17.0"
implementation "io.github.wulkanowy:sdk:0.20.3"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "androidx.core:core-ktx:1.2.0"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
implementation "androidx.core:core-ktx:1.3.1"
implementation "androidx.activity:activity-ktx:1.1.0"
implementation "androidx.appcompat:appcompat:1.2.0-beta01"
implementation "androidx.appcompat:appcompat-resources:1.1.0"
implementation "androidx.fragment:fragment-ktx:1.2.4"
implementation "androidx.appcompat:appcompat:1.2.0"
implementation "androidx.appcompat:appcompat-resources:1.2.0"
implementation "androidx.fragment:fragment-ktx:1.2.5"
implementation "androidx.annotation:annotation:1.1.0"
implementation "androidx.multidex:multidex:2.0.1"
implementation "androidx.preference:preference-ktx:1.1.0"
implementation "androidx.preference:preference-ktx:1.1.1"
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.viewpager:viewpager:1.0.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-beta01"
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "androidx.constraintlayout:constraintlayout:2.0.1"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "com.google.android.material:material:1.1.0"
implementation "com.github.wulkanowy:material-chips-input:2.0.1"
implementation "com.google.android.material:material:1.2.0"
implementation "com.github.wulkanowy:material-chips-input:2.1.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation "me.zhanghai.android.materialprogressbar:library:1.6.1"
implementation "androidx.work:work-runtime-ktx:$work_manager"
implementation "androidx.work:work-rxjava2:$work_manager"
implementation "androidx.work:work-gcm:$work_manager"
implementation 'com.github.PaulinaSadowska:RxWorkManagerObservers:1.0.0'
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"
implementation "androidx.room:room-runtime:$room"
implementation "androidx.room:room-rxjava2:$room"
implementation "androidx.room:room-ktx:$room"
kapt "androidx.room:room-compiler:$room"
implementation "com.google.dagger:dagger-android-support:$dagger"
kapt "com.google.dagger:dagger-compiler:$dagger"
kapt "com.google.dagger:dagger-android-processor:$dagger"
implementation "com.squareup.inject:assisted-inject-annotations-dagger2:0.5.2"
kapt "com.squareup.inject:assisted-inject-processor-dagger2:0.5.2"
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
implementation 'androidx.hilt:hilt-work:1.0.0-alpha02'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02'
implementation "eu.davidea:flexible-adapter:5.1.0"
implementation "eu.davidea:flexible-adapter-ui:1.0.0"
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
implementation "com.ncapdevi:frag-nav:3.3.0"
implementation "com.github.YarikSOffice:lingver:1.2.1"
implementation "com.github.pwittchen:reactivenetwork-rx2:3.0.6"
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
implementation "io.reactivex.rxjava2:rxjava:2.2.19"
implementation "com.github.YarikSOffice:lingver:1.2.2"
implementation "com.google.code.gson:gson:2.8.6"
implementation "com.jakewharton.threetenabp:threetenabp:1.2.3"
implementation "com.jakewharton.timber:timber:4.7.1"
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation "fr.bipi.treessence:treessence:0.3.2"
implementation "com.mikepenz:aboutlibraries-core:$about_libraries"
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
implementation "io.coil-kt:coil:0.9.5"
implementation "io.coil-kt:coil:1.0.0-rc1"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
playImplementation 'com.google.firebase:firebase-analytics:17.3.0'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.0.4'
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.0.4"
playImplementation "com.google.firebase:firebase-messaging:20.1.0"
playImplementation "com.crashlytics.sdk.android:crashlytics:2.10.1"
playImplementation 'com.google.firebase:firebase-analytics:17.5.0'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.1.1'
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.1.1"
playImplementation 'com.google.firebase:firebase-messaging:20.2.4'
playImplementation 'com.google.firebase:firebase-crashlytics:17.2.1'
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"
@ -200,16 +194,14 @@ dependencies {
testImplementation "junit:junit:4.13"
testImplementation "io.mockk:mockk:$mockk"
testImplementation "org.threeten:threetenbp:1.4.3"
testImplementation "org.mockito:mockito-inline:3.3.3"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.9'
androidTestImplementation "androidx.test:core:1.2.0"
androidTestImplementation "androidx.test:runner:1.2.0"
androidTestImplementation "androidx.test.ext:junit:1.1.1"
androidTestImplementation "androidx.test:core:1.3.0"
androidTestImplementation "androidx.test:runner:1.3.0"
androidTestImplementation "androidx.test.ext:junit:1.1.2"
androidTestImplementation "io.mockk:mockk-android:$mockk"
androidTestImplementation "androidx.room:room-testing:$room"
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
androidTestImplementation "org.mockito:mockito-android:3.3.3"
}
apply plugin: 'com.google.gms.google-services'

View file

@ -30,13 +30,6 @@
-dontwarn javax.annotation.**
#Config for ReactiveNetwork
-dontwarn com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
-dontwarn io.reactivex.functions.Function
-dontwarn rx.internal.util.**
-dontwarn sun.misc.Unsafe
#Config for MPAndroidChart
-keep class com.github.mikephil.charting.** { *; }

View file

@ -1741,4 +1741,4 @@
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd101f5a26a024f62e6fee161e421b882')"
]
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
package io.github.wulkanowy.data
import io.github.wulkanowy.utils.DispatchersProvider
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
class TestDispatchersProvider : DispatchersProvider() {
override val backgroundThread: CoroutineDispatcher
get() = Dispatchers.Unconfined
}

View file

@ -4,6 +4,7 @@ import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase.CONFLICT_FAIL
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
@ -29,7 +30,7 @@ class Migration12Test : AbstractMigrationTest() {
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(2, students.size)
@ -58,7 +59,7 @@ class Migration12Test : AbstractMigrationTest() {
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(1, students.size)
@ -84,7 +85,7 @@ class Migration12Test : AbstractMigrationTest() {
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(3, students.size)

View file

@ -5,10 +5,11 @@ import android.database.sqlite.SQLiteDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import io.github.wulkanowy.data.db.Converters
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import org.threeten.bp.LocalDate.of
import java.time.LocalDate.of
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@ -26,7 +27,7 @@ class Migration13Test : AbstractMigrationTest() {
helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(3, students.size)
@ -60,7 +61,7 @@ class Migration13Test : AbstractMigrationTest() {
helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(2, students.size)
@ -120,23 +121,23 @@ class Migration13Test : AbstractMigrationTest() {
assertEquals(2, first.diaryId)
}
getSemesters(db, "SELECT * FROM Semesters WHERE student_id = 2 AND class_id = 5").let {
assertTrue { it.single { it.second }.second }
assertEquals(1970, it[0].first.schoolYear)
assertEquals(of(1970, 1, 1), it[0].first.end)
assertEquals(of(1970, 1, 1), it[0].first.start)
assertFalse(it[0].second)
assertFalse(it[1].second)
assertFalse(it[2].second)
assertTrue(it[3].second)
getSemesters(db, "SELECT * FROM Semesters WHERE student_id = 2 AND class_id = 5").let { semesters ->
assertTrue { semesters.single { it.second }.second }
assertEquals(1970, semesters[0].first.schoolYear)
assertEquals(of(1970, 1, 1), semesters[0].first.end)
assertEquals(of(1970, 1, 1), semesters[0].first.start)
assertFalse(semesters[0].second)
assertFalse(semesters[1].second)
assertFalse(semesters[2].second)
assertTrue(semesters[3].second)
}
getSemesters(db, "SELECT * FROM Semesters WHERE student_id = 2 AND class_id = 5").let {
assertTrue { it.single { it.second }.second }
assertFalse(it[0].second)
assertFalse(it[1].second)
assertFalse(it[2].second)
assertTrue(it[3].second)
getSemesters(db, "SELECT * FROM Semesters WHERE student_id = 2 AND class_id = 5").let { semesters ->
assertTrue { semesters.single { it.second }.second }
assertFalse(semesters[0].second)
assertFalse(semesters[1].second)
assertFalse(semesters[2].second)
assertTrue(semesters[3].second)
}
}

View file

@ -0,0 +1,124 @@
package io.github.wulkanowy.data.db.migrations
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Test
import kotlin.random.Random
class Migration27Test : AbstractMigrationTest() {
@Test
fun userWithoutCorrespondingUnit() {
with(helper.createDatabase(dbName, 26)) {
createStudent(this, 321, 123, "Jan Student")
createUnit(this, 9999, "Unit Jan")
close()
}
helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(1, students.size)
with(students[0]) {
assertEquals(321, id)
assertEquals(123, userLoginId)
assertEquals("Student Jan", userName)
}
}
@Test
fun userWithCorrespondingUnit() {
with(helper.createDatabase(dbName, 26)) {
createStudent(this, 1, 2, "Jan Kowalski Student")
createUnit(this, 2, "Unit Jan")
close()
}
helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(1, students.size)
with(students[0]) {
assertEquals(1, id)
assertEquals(2, userLoginId)
assertEquals("Unit Jan", userName)
}
}
@Test
fun studentAccountAndParentAccountWithCorrespondingUnits() {
with(helper.createDatabase(dbName, 26)) {
createStudent(this, 1, 222, "Jan Student")
createStudent(this, 2, 333, "Jan Parent")
createUnit(this, 222, "Unit Jan")
createUnit(this, 333, "Unit Tomasz")
close()
}
helper.runMigrationsAndValidate(dbName, 27, true, Migration27())
val db = getMigratedRoomDatabase()
val students = runBlocking { db.studentDao.loadAll() }
assertEquals(2, students.size)
with(students[0]) {
assertEquals(1, id)
assertEquals(222, userLoginId)
assertEquals("Unit Jan", userName)
}
with(students[1]) {
assertEquals(2, id)
assertEquals(333, userLoginId)
assertEquals("Unit Tomasz", userName)
}
}
private fun createStudent(db: SupportSQLiteDatabase, id: Long, userLoginId: Int, studentName: String) {
db.insert("Students", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
put("id", id)
put("scrapper_base_url", "https://fakelog.cf")
put("mobile_base_url", "")
put("login_mode", "SCRAPPER")
put("login_type", "STANDARD")
put("certificate_key", "")
put("private_key", "")
put("is_parent", false)
put("email", "jan@fakelog.cf")
put("password", "******")
put("symbol", "Default")
put("school_short", "")
put("class_name", "")
put("student_id", Random.nextInt())
put("class_id", Random.nextInt())
put("school_id", "123")
put("school_name", "Wulkan first class school")
put("is_current", false)
put("registration_date", "0")
put("user_login_id", userLoginId)
put("student_name", studentName)
})
}
private fun createUnit(db: SupportSQLiteDatabase, senderId: Int, senderName: String) {
db.insert("ReportingUnits", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
put("student_id", Random.nextInt())
put("real_id", Random.nextInt())
put("short", "SHORT")
put("roles", "[0]")
put("sender_id", senderId)
put("sender_name", senderName)
})
}
}

View file

@ -0,0 +1,45 @@
package io.github.wulkanowy.data.repositories
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import java.time.LocalDate.now
import java.time.LocalDateTime
fun getStudent(): Student {
return Student(
email = "test",
password = "test123",
schoolSymbol = "23",
scrapperBaseUrl = "fakelog.cf",
loginType = "AUTO",
isCurrent = true,
userName = "",
studentName = "",
schoolShortName = "",
schoolName = "",
studentId = 0,
classId = 1,
symbol = "",
registrationDate = LocalDateTime.now(),
className = "",
loginMode = "API",
certificateKey = "",
privateKey = "",
mobileBaseUrl = "",
userLoginId = 0,
isParent = false
)
}
fun getSemester() = Semester(
semesterId = 1,
studentId = 1,
classId = 1,
diaryId = 2,
diaryName = "",
end = now(),
schoolYear = 2019,
semesterName = 1,
start = now(),
unitId = 1
)

View file

@ -1,19 +0,0 @@
package io.github.wulkanowy.data.repositories
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingStrategy
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.error.ErrorHandler
import io.reactivex.Observable
import io.reactivex.Single
class TestInternetObservingStrategy : InternetObservingStrategy {
override fun checkInternetConnectivity(host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Single<Boolean> {
return Single.just(true)
}
override fun observeInternetConnectivity(initialIntervalInMs: Int, intervalInMs: Int, host: String?, port: Int, timeoutInMs: Int, httpResponse: Int, errorHandler: ErrorHandler?): Observable<Boolean> {
return Observable.just(true)
}
override fun getDefaultPingHost() = "localhost"
}

View file

@ -6,12 +6,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate.now
import org.threeten.bp.LocalDate.of
import java.time.LocalDate
import java.time.LocalDate.now
import java.time.LocalDate.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -34,20 +37,47 @@ class AttendanceLocalTest {
@Test
fun saveAndReadTest() {
attendanceLocal.saveAttendance(listOf(
Attendance(1, 2, 3, of(2018, 9, 10), 0, "", "", false, false, false, false, false, false, false, SentExcuseStatus.ACCEPTED.name),
Attendance(1, 2, 3, of(2018, 9, 14), 0, "", "", false, false, false, false, false, false, false, SentExcuseStatus.WAITING.name),
Attendance(1, 2, 3, of(2018, 9, 17), 0, "", "", false, false, false, false, false, false, false, SentExcuseStatus.ACCEPTED.name)
))
val attendance = attendanceLocal
.getAttendance(Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1),
val list = listOf(
getAttendanceEntity(
of(2018, 9, 10),
of(2018, 9, 14)
SentExcuseStatus.ACCEPTED
),
getAttendanceEntity(
of(2018, 9, 14),
SentExcuseStatus.WAITING
),
getAttendanceEntity(
of(2018, 9, 17),
SentExcuseStatus.ACCEPTED
)
.blockingGet()
)
runBlocking { attendanceLocal.saveAttendance(list) }
val semester = Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1)
val attendance = runBlocking { attendanceLocal.getAttendance(semester, of(2018, 9, 10), of(2018, 9, 14)).first() }
assertEquals(2, attendance.size)
assertEquals(attendance[0].date, of(2018, 9, 10))
assertEquals(attendance[1].date, of(2018, 9, 14))
}
private fun getAttendanceEntity(
date: LocalDate,
excuseStatus: SentExcuseStatus
) = Attendance(
studentId = 1,
diaryId = 2,
timeId = 3,
date = date,
number = 0,
subject = "",
name = "",
presence = false,
absence = false,
exemption = false,
lateness = false,
excused = false,
deleted = false,
excusable = false,
excuseStatus = excuseStatus.name
)
}

View file

@ -6,13 +6,15 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.now
import org.threeten.bp.LocalDate.of
import java.time.LocalDate
import java.time.LocalDate.now
import java.time.LocalDate.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -24,7 +26,8 @@ class CompletedLessonsLocalTest {
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
testDb = Room
.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
completedLessonsLocal = CompletedLessonsLocal(testDb.completedLessonsDao)
}
@ -36,18 +39,15 @@ class CompletedLessonsLocalTest {
@Test
fun saveAndReadTest() {
completedLessonsLocal.saveCompletedLessons(listOf(
val list = listOf(
getCompletedLesson(of(2018, 9, 10), 1),
getCompletedLesson(of(2018, 9, 14), 2),
getCompletedLesson(of(2018, 9, 17), 3)
))
)
runBlocking { completedLessonsLocal.saveCompletedLessons(list) }
val completed = completedLessonsLocal
.getCompletedLessons(Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1),
of(2018, 9, 10),
of(2018, 9, 14)
)
.blockingGet()
val semester = Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1)
val completed = runBlocking { completedLessonsLocal.getCompletedLessons(semester, of(2018, 9, 10), of(2018, 9, 14)).first() }
assertEquals(2, completed.size)
assertEquals(completed[0].date, of(2018, 9, 10))
assertEquals(completed[1].date, of(2018, 9, 14))

View file

@ -6,12 +6,14 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate.now
import org.threeten.bp.LocalDate.of
import java.time.LocalDate.now
import java.time.LocalDate.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -34,18 +36,15 @@ class ExamLocalTest {
@Test
fun saveAndReadTest() {
examLocal.saveExams(listOf(
val list = listOf(
Exam(1, 2, of(2018, 9, 10), now(), "", "", "", "", "", ""),
Exam(1, 2, of(2018, 9, 14), now(), "", "", "", "", "", ""),
Exam(1, 2, of(2018, 9, 17), now(), "", "", "", "", "", "")
))
)
runBlocking { examLocal.saveExams(list) }
val exams = examLocal
.getExams(Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1),
of(2018, 9, 10),
of(2018, 9, 14)
)
.blockingGet()
val semester = Semester(1, 2, "", 1, 3, 2019, now(), now(), 1, 1)
val exams = runBlocking { examLocal.getExams(semester, of(2018, 9, 10), of(2018, 9, 14)).first() }
assertEquals(2, exams.size)
assertEquals(exams[0].date, of(2018, 9, 10))
assertEquals(exams[1].date, of(2018, 9, 14))

View file

@ -5,12 +5,14 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.now
import java.time.LocalDate
import java.time.LocalDate.now
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -22,9 +24,10 @@ class GradeLocalTest {
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
testDb = Room
.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
gradeLocal = GradeLocal(testDb.gradeDao)
gradeLocal = GradeLocal(testDb.gradeDao, testDb.gradeSummaryDao)
}
@After
@ -34,17 +37,16 @@ class GradeLocalTest {
@Test
fun saveAndReadTest() {
gradeLocal.saveGrades(listOf(
val list = listOf(
createGradeLocal(5, 3.0, LocalDate.of(2018, 9, 10), "", 1),
createGradeLocal(4, 4.0, LocalDate.of(2019, 2, 27), "", 2),
createGradeLocal(3, 5.0, LocalDate.of(2019, 2, 28), "", 2)
))
)
runBlocking { gradeLocal.saveGrades(list) }
val semester = Semester(1, 2, "", 2019, 2, 1, now(), now(), 1, 1)
val grades = gradeLocal
.getGrades(semester)
.blockingGet()
val grades = runBlocking { gradeLocal.getGradesDetails(semester).first() }
assertEquals(2, grades.size)
assertEquals(grades[0].date, LocalDate.of(2019, 2, 27))

View file

@ -5,22 +5,25 @@ import androidx.room.Room
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy
import io.github.wulkanowy.sdk.Sdk
import io.mockk.MockKAnnotations
import io.mockk.coEvery
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.reactivex.Single
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate.of
import org.threeten.bp.LocalDateTime
import java.time.LocalDate.of
import java.time.LocalDateTime
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@ -29,19 +32,12 @@ import kotlin.test.assertTrue
@RunWith(AndroidJUnit4::class)
class GradeRepositoryTest {
@MockK
private lateinit var mockSdk: Sdk
private val settings = InternetObservingSettings.builder()
.strategy(TestInternetObservingStrategy())
.build()
@MockK
private lateinit var semesterMock: Semester
@MockK
private lateinit var studentMock: Student
@MockK
private lateinit var gradeRemote: GradeRemote
private lateinit var gradeLocal: GradeLocal
@ -52,15 +48,13 @@ class GradeRepositoryTest {
fun initApi() {
MockKAnnotations.init(this)
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
gradeLocal = GradeLocal(testDb.gradeDao)
gradeRemote = GradeRemote(mockSdk)
gradeLocal = GradeLocal(testDb.gradeDao, testDb.gradeSummaryDao)
studentMock = getStudentMock()
every { studentMock.registrationDate } returns LocalDateTime.of(2019, 2, 27, 12, 0)
every { semesterMock.studentId } returns 1
every { semesterMock.diaryId } returns 1
every { semesterMock.schoolYear } returns 2019
every { semesterMock.semesterId } returns 1
every { mockSdk.switchDiary(any(), any()) } returns mockSdk
}
@After
@ -70,15 +64,18 @@ class GradeRepositoryTest {
@Test
fun markOlderThanRegisterDateAsRead() {
every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 4.0, of(2019, 2, 25), "Ocena pojawiła się"),
createGradeApi(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
createGradeApi(5, 4.0, of(2019, 2, 27), "Ocena z dnia logowania"),
createGradeApi(5, 4.0, of(2019, 2, 28), "Ocena jeszcze nowsza")
))
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 4.0, of(2019, 2, 25), "Ocena pojawiła się"),
createGradeLocal(5, 4.0, of(2019, 2, 26), "przed zalogowanie w aplikacji"),
createGradeLocal(5, 4.0, of(2019, 2, 27), "Ocena z dnia logowania"),
createGradeLocal(5, 4.0, of(2019, 2, 28), "Ocena jeszcze nowsza")
) to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date }
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!.first.sortedByDescending { it.date }
}
assertFalse { grades[0].isRead }
assertFalse { grades[1].isRead }
@ -88,21 +85,25 @@ class GradeRepositoryTest {
@Test
fun mitigateOldGradesNotifications() {
gradeLocal.saveGrades(listOf(
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Jedna ocena"),
createGradeLocal(4, 4.0, of(2019, 2, 26), "Druga"),
createGradeLocal(3, 5.0, of(2019, 2, 27), "Trzecia")
))
)
runBlocking { gradeLocal.saveGrades(list) }
every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 2.0, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
createGradeApi(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
createGradeApi(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
createGradeApi(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa")
))
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 2.0, of(2019, 2, 25), "Ocena ma datę, jest inna, ale nie zostanie powiadomiona"),
createGradeLocal(4, 3.0, of(2019, 2, 26), "starszą niż ostatnia lokalnie"),
createGradeLocal(3, 4.0, of(2019, 2, 27), "Ta jest z tego samego dnia co ostatnia lokalnie"),
createGradeLocal(2, 5.0, of(2019, 2, 28), "Ta jest już w ogóle nowa")
) to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date }
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!.first.sortedByDescending { it.date }
}
assertFalse { grades[0].isRead }
assertFalse { grades[1].isRead }
@ -112,70 +113,109 @@ class GradeRepositoryTest {
@Test
fun subtractLocaleDuplicateGrades() {
gradeLocal.saveGrades(listOf(
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
)
runBlocking { gradeLocal.saveGrades(list) }
every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
) to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(2, grades.size)
assertEquals(2, grades.first.size)
}
@Test
fun subtractRemoteDuplicateGrades() {
gradeLocal.saveGrades(listOf(
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
)
runBlocking { gradeLocal.saveGrades(list) }
every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
) to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(3, grades.size)
assertEquals(3, grades.first.size)
}
@Test
fun emptyLocal() {
gradeLocal.saveGrades(listOf())
runBlocking { gradeLocal.saveGrades(listOf()) }
every { mockSdk.getGrades(1) } returns Single.just(listOf(
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeApi(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
) to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(3, grades.size)
assertEquals(3, grades.first.size)
}
@Test
fun emptyRemote() {
gradeLocal.saveGrades(listOf(
val list = listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
)
runBlocking { gradeLocal.saveGrades(list) }
every { mockSdk.getGrades(1) } returns Single.just(listOf())
coEvery { gradeRemote.getGrades(studentMock, semesterMock) } returns (emptyList<Grade>() to emptyList())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
val grades = runBlocking {
GradeRepository(gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true)
.filter { it.status == Status.SUCCESS }.first().data!!
}
assertEquals(0, grades.size)
assertEquals(0, grades.first.size)
}
private fun getStudentMock() = Student(
scrapperBaseUrl = "http://fakelog.cf",
email = "jan@fakelog.cf",
certificateKey = "",
classId = 0,
className = "",
isCurrent = false,
isParent = false,
loginMode = Sdk.Mode.SCRAPPER.name,
loginType = "STANDARD",
mobileBaseUrl = "",
password = "",
privateKey = "",
registrationDate = LocalDateTime.of(2019, 2, 27, 12, 0),
schoolName = "",
schoolShortName = "test",
schoolSymbol = "",
studentId = 0,
studentName = "",
symbol = "",
userLoginId = 0,
userName = ""
)
}

View file

@ -1,6 +1,6 @@
package io.github.wulkanowy.data.repositories.grade
import org.threeten.bp.LocalDate
import java.time.LocalDate
import io.github.wulkanowy.sdk.pojo.Grade as GradeRemote
import io.github.wulkanowy.data.db.entities.Grade as GradeLocal

View file

@ -7,11 +7,13 @@ import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate.now
import java.time.LocalDate.now
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -35,40 +37,44 @@ class GradeStatisticsLocalTest {
@Test
fun saveAndRead_subject() {
gradeStatisticsLocal.saveGradesStatistics(listOf(
val list = listOf(
getGradeStatistics("Matematyka", 2, 1),
getGradeStatistics("Fizyka", 1, 2)
))
)
runBlocking { gradeStatisticsLocal.saveGradesStatistics(list) }
val stats = gradeStatisticsLocal.getGradesStatistics(getSemester(), false, "Matematyka").blockingGet()
val stats = runBlocking { gradeStatisticsLocal.getGradesStatistics(getSemester(), false).first() }
assertEquals(1, stats.size)
assertEquals(stats[0].subject, "Matematyka")
}
@Test
fun saveAndRead_all() {
gradeStatisticsLocal.saveGradesStatistics(listOf(
val list = listOf(
getGradeStatistics("Matematyka", 2, 1),
getGradeStatistics("Chemia", 2, 1),
getGradeStatistics("Fizyka", 1, 2)
))
)
runBlocking { gradeStatisticsLocal.saveGradesStatistics(list) }
val stats = gradeStatisticsLocal.getGradesStatistics(getSemester(), false, "Wszystkie").blockingGet()
assertEquals(3, stats.size)
assertEquals(stats[0].subject, "Wszystkie")
assertEquals(stats[1].subject, "Matematyka")
assertEquals(stats[2].subject, "Chemia")
val stats = runBlocking { gradeStatisticsLocal.getGradesStatistics(getSemester(), false).first() }
assertEquals(2, stats.size)
// assertEquals(3, stats.size)
// assertEquals(stats[0].subject, "Wszystkie") // now in main repo
assertEquals(stats[0].subject, "Matematyka")
assertEquals(stats[1].subject, "Chemia")
}
@Test
fun saveAndRead_points() {
gradeStatisticsLocal.saveGradesPointsStatistics(listOf(
val list = listOf(
getGradePointsStatistics("Matematyka", 2, 1),
getGradePointsStatistics("Chemia", 2, 1),
getGradePointsStatistics("Fizyka", 1, 2)
))
)
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(list) }
val stats = gradeStatisticsLocal.getGradesPointsStatistics(getSemester(), "Matematyka").blockingGet()
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() }
with(stats[0]) {
assertEquals(subject, "Matematyka")
assertEquals(others, 5.0)
@ -78,18 +84,18 @@ class GradeStatisticsLocalTest {
@Test
fun saveAndRead_subjectEmpty() {
gradeStatisticsLocal.saveGradesPointsStatistics(listOf())
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(listOf()) }
val stats = gradeStatisticsLocal.getGradesPointsStatistics(getSemester(), "Matematyka").blockingGet()
assertEquals(null, stats)
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() }
assertEquals(emptyList(), stats)
}
@Test
fun saveAndRead_allEmpty() {
gradeStatisticsLocal.saveGradesPointsStatistics(listOf())
runBlocking { gradeStatisticsLocal.saveGradesPointsStatistics(listOf()) }
val stats = gradeStatisticsLocal.getGradesPointsStatistics(getSemester(), "Wszystkie").blockingGet()
assertEquals(null, stats)
val stats = runBlocking { gradeStatisticsLocal.getGradesPointsStatistics(getSemester()).first() }
assertEquals(emptyList(), stats)
}
private fun getSemester(): Semester {

View file

@ -5,14 +5,15 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime.now
import java.time.LocalDate
import java.time.LocalDateTime.now
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -24,7 +25,8 @@ class LuckyNumberLocalTest {
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
testDb = Room
.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
luckyNumberLocal = LuckyNumberLocal(testDb.luckyNumberDao)
}
@ -36,14 +38,14 @@ class LuckyNumberLocalTest {
@Test
fun saveAndReadTest() {
luckyNumberLocal.saveLuckyNumber(LuckyNumber(1, LocalDate.of(2019, 1, 20), 14))
val number = LuckyNumber(1, LocalDate.of(2019, 1, 20), 14)
runBlocking { luckyNumberLocal.saveLuckyNumber(number) }
val luckyNumber = luckyNumberLocal.getLuckyNumber(Student("", "", "", "", "", "", false, "", "", "", 1, 1, "", "", "", "", "", 1, false, now()),
LocalDate.of(2019, 1, 20)
).blockingGet()
val student = Student("", "", "", "", "", "", false, "", "", "", 1, 1, "", "", "", "", "", "", 1, false, now())
val luckyNumber = runBlocking { luckyNumberLocal.getLuckyNumber(student, LocalDate.of(2019, 1, 20)).first() }
assertEquals(1, luckyNumber.studentId)
assertEquals(LocalDate.of(2019, 1, 20), luckyNumber.date)
assertEquals(14, luckyNumber.luckyNumber)
assertEquals(1, luckyNumber?.studentId)
assertEquals(LocalDate.of(2019, 1, 20), luckyNumber?.date)
assertEquals(14, luckyNumber?.luckyNumber)
}
}

View file

@ -7,11 +7,12 @@ import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDateTime
import java.time.LocalDateTime
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -35,17 +36,21 @@ class RecipientLocalTest {
@Test
fun saveAndReadTest() {
recipientLocal.saveRecipients(listOf(
val list = listOf(
Recipient(1, "2rPracownik", "Kowalski Jan", "Kowalski Jan [KJ] - Pracownik (Fake123456)", 3, 4, 2, "hash"),
Recipient(1, "3rPracownik", "Kowalska Karolina", "Kowalska Karolina [KK] - Pracownik (Fake123456)", 4, 4, 2, "hash"),
Recipient(1, "4rPracownik", "Krupa Stanisław", "Krupa Stanisław [KS] - Uczeń (Fake123456)", 5, 4, 1, "hash")
))
)
runBlocking { recipientLocal.saveRecipients(list) }
val recipients = recipientLocal.getRecipients(
Student("fakelog.cf", "AUTO", "", "", "", "", false, "", "", "", 1, 0, "", "", "", "", "", 1, true, LocalDateTime.now()),
2,
ReportingUnit(1, 4, "", 0, "", emptyList())
).blockingGet()
val student = Student("fakelog.cf", "AUTO", "", "", "", "", false, "", "", "", 1, 0, "", "", "", "", "", "", 1, true, LocalDateTime.now())
val recipients = runBlocking {
recipientLocal.getRecipients(
student = student,
role = 2,
unit = ReportingUnit(1, 4, "", 0, "", emptyList())
)
}
assertEquals(2, recipients.size)
assertEquals(1, recipients[0].studentId)

View file

@ -4,14 +4,14 @@ import android.content.Context
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.TestDispatchersProvider
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.getStudent
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDateTime.now
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -21,15 +21,14 @@ class StudentLocalTest {
private lateinit var testDb: AppDatabase
private lateinit var sharedProvider: SharedPrefProvider
private val student = getStudent()
@Before
fun createDb() {
val context = ApplicationProvider.getApplicationContext<Context>()
testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
.build()
sharedProvider = SharedPrefProvider(context.getSharedPreferences("TEST", Context.MODE_PRIVATE))
studentLocal = StudentLocal(testDb.studentDao, context)
studentLocal = StudentLocal(testDb.studentDao, TestDispatchersProvider(), context)
}
@After
@ -39,10 +38,9 @@ class StudentLocalTest {
@Test
fun saveAndReadTest() {
studentLocal.saveStudents(listOf(Student(email = "test", password = "test123", schoolSymbol = "23", scrapperBaseUrl = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolShortName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = "", loginMode = "API", certificateKey = "", privateKey = "", mobileBaseUrl = "", userLoginId = 0, isParent = false)))
.blockingGet()
runBlocking { studentLocal.saveStudents(listOf(student)) }
val student = studentLocal.getCurrentStudent(true).blockingGet()
assertEquals("23", student.schoolSymbol)
val student = runBlocking { studentLocal.getCurrentStudent(true) }
assertEquals("23", student?.schoolSymbol)
}
}

View file

@ -1,7 +1,7 @@
package io.github.wulkanowy.data.repositories.timetable
import org.threeten.bp.LocalDateTime
import org.threeten.bp.LocalDateTime.now
import java.time.LocalDateTime
import java.time.LocalDateTime.now
import io.github.wulkanowy.data.db.entities.Timetable as TimetableLocal
import io.github.wulkanowy.sdk.pojo.Timetable as TimetableRemote

View file

@ -5,12 +5,14 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime.of
import java.time.LocalDate
import java.time.LocalDateTime.of
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
@ -34,17 +36,21 @@ class TimetableLocalTest {
@Test
fun saveAndReadTest() {
timetableDb.saveTimetable(listOf(
val list = listOf(
createTimetableLocal(of(2018, 9, 10, 0, 0, 0), 1),
createTimetableLocal(of(2018, 9, 14, 0, 0, 0), 1),
createTimetableLocal(of(2018, 9, 17, 0, 0, 0), 1)
))
)
runBlocking { timetableDb.saveTimetable(list) }
val exams = timetableDb.getTimetable(
Semester(1, 2, "", 1, 1, 2019, LocalDate.now(), LocalDate.now(), 1, 1),
LocalDate.of(2018, 9, 10),
LocalDate.of(2018, 9, 14)
).blockingGet()
val semester = Semester(1, 2, "", 1, 1, 2019, LocalDate.now(), LocalDate.now(), 1, 1)
val exams = runBlocking {
timetableDb.getTimetable(
semester = semester,
startDate = LocalDate.of(2018, 9, 10),
endDate = LocalDate.of(2018, 9, 14)
).first()
}
assertEquals(2, exams.size)
assertEquals(exams[0].date, LocalDate.of(2018, 9, 10))

View file

@ -5,55 +5,48 @@ import androidx.room.Room
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SdkSuppress
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.Status
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.data.repositories.getSemester
import io.github.wulkanowy.data.repositories.getStudent
import io.github.wulkanowy.services.alarm.TimetableNotificationSchedulerHelper
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.coEvery
import io.mockk.impl.annotations.MockK
import io.reactivex.Single
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime.of
import java.time.LocalDate
import java.time.LocalDateTime.of
import kotlin.test.assertEquals
@SdkSuppress(minSdkVersion = P)
@RunWith(AndroidJUnit4::class)
class TimetableRepositoryTest {
@MockK
private lateinit var mockSdk: Sdk
private val settings = InternetObservingSettings.builder()
.strategy(TestInternetObservingStrategy())
.build()
@MockK(relaxed = true)
private lateinit var timetableNotificationSchedulerHelper: TimetableNotificationSchedulerHelper
@MockK
private lateinit var semesterMock: Semester
private lateinit var timetableRemote: TimetableRemote
private lateinit var timetableLocal: TimetableLocal
private lateinit var testDb: AppDatabase
private val student = getStudent()
private val semester = getSemester()
@Before
fun initApi() {
MockKAnnotations.init(this)
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
timetableLocal = TimetableLocal(testDb.timetableDao)
timetableRemote = TimetableRemote(mockSdk)
every { semesterMock.studentId } returns 1
every { semesterMock.diaryId } returns 2
every { semesterMock.schoolYear } returns 2019
every { semesterMock.semesterId } returns 1
every { mockSdk.switchDiary(any(), any()) } returns mockSdk
}
@After
@ -63,23 +56,31 @@ class TimetableRepositoryTest {
@Test
fun copyRoomToCompletedFromPrevious() {
timetableLocal.saveTimetable(listOf(
createTimetableLocal(of(2019, 3, 5, 8, 0), 1, "123", "Przyroda"),
createTimetableLocal(of(2019, 3, 5, 8, 50), 2, "321", "Religia"),
createTimetableLocal(of(2019, 3, 5, 9, 40), 3, "213", "W-F"),
createTimetableLocal(of(2019, 3, 5, 10, 30),3, "213", "W-F", "Jan Kowalski")
))
runBlocking {
timetableLocal.saveTimetable(listOf(
createTimetableLocal(of(2019, 3, 5, 8, 0), 1, "123", "Przyroda"),
createTimetableLocal(of(2019, 3, 5, 8, 50), 2, "321", "Religia"),
createTimetableLocal(of(2019, 3, 5, 9, 40), 3, "213", "W-F"),
createTimetableLocal(of(2019, 3, 5, 10, 30), 3, "213", "W-F", "Jan Kowalski")
))
}
every { mockSdk.getTimetable(any(), any()) } returns Single.just(listOf(
createTimetableRemote(of(2019, 3, 5, 8, 0), 1, "", "Przyroda"),
createTimetableRemote(of(2019, 3, 5, 8, 50), 2, "", "Religia"),
createTimetableRemote(of(2019, 3, 5, 9, 40), 3, "", "W-F"),
createTimetableRemote(of(2019, 3, 5, 10, 30), 4, "", "W-F")
))
coEvery { timetableRemote.getTimetable(student, semester, any(), any()) } returns listOf(
createTimetableLocal(of(2019, 3, 5, 8, 0), 1, "", "Przyroda"),
createTimetableLocal(of(2019, 3, 5, 8, 50), 2, "", "Religia"),
createTimetableLocal(of(2019, 3, 5, 9, 40), 3, "", "W-F"),
createTimetableLocal(of(2019, 3, 5, 10, 30), 4, "", "W-F")
)
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
.getTimetable(semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true)
.blockingGet()
val lessons = runBlocking {
TimetableRepository(timetableLocal, timetableRemote, timetableNotificationSchedulerHelper).getTimetable(
student = student,
semester = semester,
start = LocalDate.of(2019, 3, 5),
end = LocalDate.of(2019, 3, 5),
forceRefresh = true
).filter { it.status == Status.SUCCESS }.first().data.orEmpty()
}
assertEquals(4, lessons.size)
assertEquals("123", lessons[0].room)
@ -89,7 +90,7 @@ class TimetableRepositoryTest {
@Test
fun copyTeacherToCompletedFromPrevious() {
timetableLocal.saveTimetable(listOf(
val list = listOf(
createTimetableLocal(of(2019, 12, 23, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
createTimetableLocal(of(2019, 12, 23, 8, 50), 2, "124", "Matematyka", "Paweł Poniedziałkowski", false),
createTimetableLocal(of(2019, 12, 23, 9, 40), 3, "125", "Język polski", "Joanna Wtorkowska", true),
@ -104,28 +105,35 @@ class TimetableRepositoryTest {
createTimetableLocal(of(2019, 12, 25, 8, 50), 2, "124", "Matematyka", "", false),
createTimetableLocal(of(2019, 12, 25, 9, 40), 3, "125", "Matematyka", "", true),
createTimetableLocal(of(2019, 12, 25, 10, 40), 4, "126", "Matematyka", "", true)
))
)
runBlocking { timetableLocal.saveTimetable(list) }
every { mockSdk.getTimetable(any(), any()) } returns Single.just(listOf(
createTimetableRemote(of(2019, 12, 23, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
createTimetableRemote(of(2019, 12, 23, 8, 50), 2, "124", "Matematyka", "Jakub Wtorkowski", true),
createTimetableRemote(of(2019, 12, 23, 9, 40), 3, "125", "Język polski", "Joanna Poniedziałkowska", false),
createTimetableRemote(of(2019, 12, 23, 10, 40), 4, "126", "Język polski", "Joanna Wtorkowska", true),
coEvery { timetableRemote.getTimetable(student, semester, any(), any()) } returns listOf(
createTimetableLocal(of(2019, 12, 23, 8, 0), 1, "123", "Matematyka", "Paweł Poniedziałkowski", false),
createTimetableLocal(of(2019, 12, 23, 8, 50), 2, "124", "Matematyka", "Jakub Wtorkowski", true),
createTimetableLocal(of(2019, 12, 23, 9, 40), 3, "125", "Język polski", "Joanna Poniedziałkowska", false),
createTimetableLocal(of(2019, 12, 23, 10, 40), 4, "126", "Język polski", "Joanna Wtorkowska", true),
createTimetableRemote(of(2019, 12, 24, 8, 0), 1, "123", "Język polski", "", false),
createTimetableRemote(of(2019, 12, 24, 8, 50), 2, "124", "Język polski", "", true),
createTimetableRemote(of(2019, 12, 24, 9, 40), 3, "125", "Język polski", "", false),
createTimetableRemote(of(2019, 12, 24, 10, 40), 4, "126", "Język polski", "", true),
createTimetableLocal(of(2019, 12, 24, 8, 0), 1, "123", "Język polski", "", false),
createTimetableLocal(of(2019, 12, 24, 8, 50), 2, "124", "Język polski", "", true),
createTimetableLocal(of(2019, 12, 24, 9, 40), 3, "125", "Język polski", "", false),
createTimetableLocal(of(2019, 12, 24, 10, 40), 4, "126", "Język polski", "", true),
createTimetableRemote(of(2019, 12, 25, 8, 0), 1, "123", "Matematyka", "Paweł Środowski", false),
createTimetableRemote(of(2019, 12, 25, 8, 50), 2, "124", "Matematyka", "Paweł Czwartkowski", true),
createTimetableRemote(of(2019, 12, 25, 9, 40), 3, "125", "Matematyka", "Paweł Środowski", false),
createTimetableRemote(of(2019, 12, 25, 10, 40), 4, "126", "Matematyka", "Paweł Czwartkowski", true)
))
createTimetableLocal(of(2019, 12, 25, 8, 0), 1, "123", "Matematyka", "Paweł Środowski", false),
createTimetableLocal(of(2019, 12, 25, 8, 50), 2, "124", "Matematyka", "Paweł Czwartkowski", true),
createTimetableLocal(of(2019, 12, 25, 9, 40), 3, "125", "Matematyka", "Paweł Środowski", false),
createTimetableLocal(of(2019, 12, 25, 10, 40), 4, "126", "Matematyka", "Paweł Czwartkowski", true)
)
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
.getTimetable(semesterMock, LocalDate.of(2019, 12, 23), LocalDate.of(2019, 12, 25), true)
.blockingGet()
val lessons = runBlocking {
TimetableRepository(timetableLocal, timetableRemote, timetableNotificationSchedulerHelper).getTimetable(
student = student,
semester = semester,
start = LocalDate.of(2019, 12, 23),
end = LocalDate.of(2019, 12, 25),
forceRefresh = true
).filter { it.status == Status.SUCCESS }.first().data.orEmpty()
}
assertEquals(12, lessons.size)

View file

@ -1,3 +0,0 @@
<resources>
<string name="app_name">Wulkanowy DEV</string>
</resources>

View file

@ -2,11 +2,8 @@
package io.github.wulkanowy.utils
import android.content.Context
import timber.log.Timber
fun initCrashlytics(context: Context, appInfo: AppInfo) {}
open class TimberTreeNoOp : Timber.Tree() {
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {}
}

View file

@ -1,13 +1,18 @@
package io.github.wulkanowy.utils
import android.app.Activity
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
@Suppress("UNUSED_PARAMETER")
class FirebaseAnalyticsHelper @Inject constructor() {
@Suppress("UNUSED_PARAMETER")
fun logEvent(name: String, vararg params: Pair<String, Any?>) {
// do nothing
}
fun setCurrentScreen(activity: Activity, name: String?) {
// do nothing
}
}

View file

@ -39,7 +39,8 @@
android:name=".ui.modules.main.MainActivity"
android:configChanges="orientation|screenSize"
android:label="@string/main_title"
android:theme="@style/WulkanowyTheme.NoActionBar" />
android:theme="@style/WulkanowyTheme.NoActionBar"
android:windowSoftInputMode="adjustPan" />
<activity
android:name=".ui.modules.message.send.SendMessageActivity"
android:configChanges="orientation|screenSize"
@ -91,6 +92,8 @@
android:resource="@xml/provider_widget_lucky_number" />
</receiver>
<receiver android:name=".services.alarm.TimetableNotificationReceiver" />
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
@ -107,12 +110,33 @@
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" />
<meta-data
android:name="io.fabric.ApiKey"
android:value="${fabric_api_key}" />
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="${crashlytics_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"

View file

@ -0,0 +1,94 @@
<!doctype html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>%SUBJECT% | Wulkanowy</title>
<style>
@page {
margin: 2.5cm;
size: A4;
}
body {
margin: 0;
font-family: sans-serif;
}
.title {
line-height: 1.5;
letter-spacing: 1pt;
font-size: 24pt;
font-weight: 200;
margin: 0 0 0.5cm;
}
.info {
margin: 0.5cm 0;
}
.info div {
font-size: 14pt;
font-weight: 400;
margin: 0.5cm 0;
}
h4 {
font-weight: 200;
text-transform: uppercase;
letter-spacing: 1pt;
font-size: 10pt;
margin: 0;
margin-bottom: 0.25cm;
font-family: sans-serif;
}
.content {
margin-top: 0.5cm;
font-size: 14pt;
font-weight: 400;
text-align: justify;
font-family: serif;
line-height: 1.5;
}
.content p {
page-break-after: auto;
page-break-inside: auto;
margin-bottom: 0.6cm;
}
.footer {
font-size: 11pt;
font-weight: 200;
display: flex;
align-items: center;
color: rgba(0, 0, 0, 0.5)
margin: 0;
margin-bottom: 0.5cm;
}
.footer .logo {
height: 0.5cm;
width: 0.5cm;
display: block;
margin-right: 0.2cm;
}
</style>
</head>
<body>
<h1 class="title">%SUBJECT%</h1>
<hr>
<div class="info">
%INFO%
</div>
<div class="footer">
<img src="wulkanowy-logo-black.svg" class="logo">
Wulkanowy Dzienniczek
</div>
<hr>
<div class="content">
<h4>Treść wiadomości</h4>
%CONTENT%
</div>
</body>
</html>

View file

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 1024 1024"
xml:space="preserve"
width="1024"
height="1024"><metadata
id="metadata15"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs13" /><style
type="text/css"
id="style2">
.st0{fill:#D32F2F;}
.st1{fill:#AD2A2A;}
.st2{fill:#FFFFFF;}
</style><g
id="layer4"
style="display:none;fill:#808080"><rect
id="XMLID_57_"
x="0"
y="0"
class="st0"
width="3584"
height="1024"
style="display:inline;fill:#808080;stroke-width:1.02195609" /></g><g
id="layer3"
style="display:none;fill:#808080"><path
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#808080;fill-opacity:1;stroke:none"
d="M 3046.8164,390.66602 3134.3164,542 v 91.33398 L 3524.9824,1024 H 3584 V 732.18359 L 3242.4824,390.66602 h -23.666 l -53.0352,94.63086 -94.6308,-94.63086 z"
id="path18992" /><path
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#808080;fill-opacity:1;stroke:none"
d="m 2746.9824,390.66602 62,242.66796 L 3199.6484,1024 H 3584 V 940.68359 L 3033.9824,390.66602 h -21 l -21.9043,90.92773 -90.9277,-90.92773 h -18.5 l -25.4043,88.26367 -88.2637,-88.26367 z"
id="path18990" /><path
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#808080;fill-opacity:1;stroke:none"
d="m 2620.8164,387.33398 c -18.6667,0 -35.1667,4.60982 -49.5,13.83204 -14.3333,9.11111 -25.4451,22.22287 -33.334,39.33398 -7.7778,17 -11.666,36.5549 -11.666,58.66602 v 25 c 0,34.44444 8.7216,61.83463 26.166,82.16796 L 2970.1484,1024 h 323.168 l -623.166,-623.16602 c -14.2222,-9 -30.6673,-13.5 -49.334,-13.5 z"
id="path18988" /><path
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#808080;fill-opacity:1;stroke:none"
d="M 2293.4824,390.66602 V 633.33398 L 2684.1484,1024 h 423.336 l -633.334,-633.33398 h -20.334 v 139.66601 l -139.666,-139.66601 z"
id="path18984" /><path
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#808080;fill-opacity:1;stroke:none"
d="M 1864.8164,390.66602 V 633.33398 L 2255.4824,1024 h 413.334 l -633.334,-633.33398 h -25.832 l -60.584,63.75 -63.75,-63.75 z"
id="path18978" /><path
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#808080;fill-opacity:1;stroke:none"
d="M 1684.8164,390.66602 V 633.33398 L 2075.4824,1024 h 263.334 l -633.334,-633.33398 z"
id="path18976" /><path
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#808080;fill-opacity:1;stroke:none"
d="m 1133.6504,390.66602 62,242.66796 L 1586.3164,1024 h 467.668 l -633.334,-633.33398 h -21 l -21.9043,90.92773 -90.9277,-90.92773 h -18.5 l -25.4043,88.26367 -88.2637,-88.26367 z"
id="path19059" /><path
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#808080;fill-opacity:1;stroke:none"
d="m 1456.4824,390.66602 v 167.16796 c 0.5556,24.66667 8.5007,44 23.834,58 L 1888.4824,1024 h 372.168 l -633.334,-633.33398 h -20.666 V 520.5 l -129.834,-129.83398 z"
id="path18966" /><path
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;display:inline;fill:#808080;fill-opacity:1;stroke:none"
d="M 2146.3164,390.66602 2054.4824,633.33398 2445.1484,1024 h 354.002 l -633.334,-633.33398 z"
id="path18982" /><path
style="display:inline;fill:#808080;stroke-width:0.78179646"
d="M 637.15234,214.95703 487.75,364.35742 466.01562,386.0918 c 0.31273,0.31271 0.54872,0.54666 0.70508,0.85937 0.0782,0.23454 0.23432,0.54671 0.3125,0.78125 0.31272,0.54726 0.47071,1.17339 0.47071,1.79883 0.0782,0.54726 -0.0799,1.01725 -0.31446,1.48633 -0.23454,0.54725 -0.70285,1.40597 -1.09375,1.79687 l 150.8086,149.71485 -23.68946,23.6875 -12.74414,-12.74219 -13.44726,-13.44727 -78.80469,-78.80664 -11.17969,-11.17968 -7.5039,-7.50391 -35.41602,-35.17969 -3.08984,-0.98047 -4.33594,4.26367 v 0.46876 c 0,7.34888 0.38998,15.00865 -1.48633,22.20117 -0.85998,3.28355 -2.34444,6.25595 -4.14258,8.91406 -0.15636,0.15636 -0.23627,0.23426 -0.31445,0.39062 -1.87631,2.57993 -4.06471,4.84619 -6.48828,6.95704 -5.3944,4.53442 -11.25752,8.67896 -17.27734,12.50976 -0.15637,0.0782 -0.23427,0.1562 -0.39063,0.23438 -2.11085,1.40723 -4.3012,2.7354 -6.49023,4.06445 -8.91248,5.39439 -18.37192,10.08772 -28.37891,13.13672 -1.25087,0.31272 -2.42317,-0.001 -3.36133,-0.70508 l -6.01953,5.94141 c 1.25087,0.62543 2.03136,1.87776 1.875,3.51953 -10e-6,0.15636 -0.0762,0.23231 -0.0762,0.38867 0,0.0782 -0.0781,0.23628 -0.0781,0.31445 -1.32905,4.45624 -2.34505,8.98897 -3.2832,13.60156 -0.15636,0.70363 -0.23622,1.33154 -0.39258,2.03516 -0.85997,4.37806 -1.64209,8.83288 -2.3457,13.21094 0.23453,5.3944 0.39263,11.0234 0.31445,16.65234 v 0.39258 c -0.0782,7.66161 -0.78373,15.32114 -2.8164,22.51367 -2.26721,8.28704 -6.64376,15.63728 -10.55274,23.22071 -0.0782,0.15636 -0.15815,0.23426 -0.23633,0.39062 -1.25088,2.42357 -2.49924,4.92399 -3.59375,7.50391 -4.84714,11.33605 -7.42749,23.92328 -10.55468,35.88476 -0.23454,0.70362 -0.39046,1.48578 -0.625,2.26758 0,0.15636 -0.0801,0.23427 -0.0801,0.39063 -2.97082,11.10151 -6.09819,22.28173 -10.94532,32.75781 -1.40724,2.97082 -2.81531,5.86322 -4.3789,8.75586 -0.15636,0.23454 -0.23231,0.46858 -0.38867,0.70312 -0.62544,1.09451 -1.25152,2.26871 -1.87696,3.44141 -0.0782,0.15636 -0.15619,0.23426 -0.23437,0.39062 -3.51809,6.25438 -7.27098,12.43118 -10.78906,18.68555 -5.0035,8.8343 -8.99075,18.13635 -13.83789,27.04883 -0.0782,0.15636 -0.1562,0.23426 -0.23438,0.39062 -0.70362,1.32905 -1.48579,2.65728 -2.26758,3.98633 -5.0035,8.20887 -10.63256,16.0279 -16.57422,23.61133 -0.15635,0.15636 -0.23426,0.3124 -0.39062,0.46875 -0.7818,1.01634 -1.48578,1.95443 -2.26758,2.89258 -3.90898,4.92532 -7.97378,9.85009 -11.96094,14.77539 -0.0782,0.15637 -0.23432,0.23622 -0.3125,0.39258 -8.75612,10.71061 -17.35628,21.49761 -24.54883,33.30273 0,0.70362 -0.15602,1.33159 -0.46874,1.95703 -1.25087,2.42357 -2.65734,4.68971 -3.90821,7.11328 -0.0782,0.15636 0.62511,1.24989 0.46875,1.40625 L 429.86133,1024 H 1463.0215 L 661.85547,222.92969 c -0.93816,2.11087 -5.23681,1.40935 -7.34766,-0.23242 -1.71995,-1.32906 -3.12603,-3.05147 -4.45508,-4.84961 -0.62544,-0.31271 -1.25168,-0.62288 -1.64257,-0.85743 -2.89265,-1.40723 -6.09933,-1.48632 -9.30469,-1.48632 -0.7818,-0.0782 -1.40588,-0.23416 -1.95313,-0.54688 z m -206.12304,191.41992 0.11914,-0.11523 -0.23438,0.0781 z"
id="XMLID_64_" /></g><g
id="layer2"
style="display:inline;fill:#000000;fill-opacity:0.49803922"><path
id="XMLID_42_"
d="m 295.17362,965.05417 c 1.0692,3.47527 0.5346,7.21786 -1.3367,10.29214 l -25.7972,41.83679 c -2.5396,4.1436 -7.2178,6.8169 -12.297,6.8169 H 14.345318 C 3.1176178,1024 -3.6991822,1012.2376 2.3157178,1003.4158 L 157.76692,774.44928 c 0.9356,-1.33663 1.4704,-2.80694 1.8713,-4.27723 l 71.2428,-304.21933 c 0.8021,-3.60893 3.2081,-6.6832 6.6833,-8.55449 l 96.5054,-52.93096 c 3.4753,-1.8713 5.8812,-4.94557 6.6832,-8.68816 l 12.9654,-56.53988 c 2.6733,-11.76242 19.5151,-14.30205 26.1981,-4.00991 l 4.6783,7.48519 c 2.0049,3.20793 2.5396,7.21785 1.2031,10.82678 l -87.9511,254.22895 c -0.6683,2.00497 -0.9355,4.1436 -0.5346,6.28223 l 21.9209,121.63426 c 0.401,2.40595 0.1334,4.94556 -0.9357,7.21785 l -52.2625,117.357 c -1.203,2.80696 -1.4704,5.88123 -0.5347,8.68817 z M 1009.7413,1024 H 843.46322 c -4.8117,0 -9.2228,-2.4059 -11.8959,-6.1485 L 719.69042,860.52891 c -0.6683,-1.0693 -1.3366,-2.13861 -1.7375,-3.3416 l -55.4707,-162.00078 c -1.0692,-3.20793 -3.6088,-6.01489 -6.8169,-7.61886 l -135.8026,-68.56965 c -3.7426,-1.87127 -6.4159,-5.34655 -7.2179,-9.22281 l -20.0495,-99.44603 c -0.2674,-1.60396 -0.9357,-3.20793 -2.005,-4.67824 l -46.1141,-67.76766 c -2.5396,-3.74259 -2.9405,-8.28717 -1.0693,-12.2971 l 28.0694,-60.01513 c 2.1387,-4.54457 6.817,-7.61886 12.1634,-7.88619 l 52.129,-3.07427 c 3.0742,-0.1337 5.8812,-1.20296 8.1536,-3.07427 l 38.3615,-29.80707 c 7.2178,-5.61388 18.1784,-3.20794 22.0546,4.67824 l 132.1937,268.93201 c 0.5346,1.20297 0.9357,2.40595 1.2029,3.60894 l 16.3072,108.13418 c 0.4009,2.53963 1.4701,4.8119 3.2079,6.6832 l 263.31808,288.17958 c 7.7525,8.5545 1.203,22.0546 -10.8269,22.0546 z M 363.20852,182.58501 c 0,-30.60907 19.3812,-56.94088 47.1834,-69.23798 -2.005,-3.3416 -3.2079,-6.95052 -3.2079,-10.82678 0,-14.836705 17.109,-26.866465 38.0942,-26.866465 0.5346,0 0.9356,0 1.4704,0 8.688,-14.43572 25.2624,-24.19318 44.2426,-24.19318 1.3367,0 2.6733,0 4.01,0.1337 1.7377,0.13369 3.4753,-0.66833 4.4109,-2.00497 14.0347,-21.38624 49.5894,-36.62394 91.159,-36.62394 15.3712,0 29.9406,2.13863 42.906,5.74756 3.0744,-5.07924 9.8911,-8.5545 17.7773,-8.5545 8.9556,0 16.5744,4.54458 18.8466,10.82678 10.9606,-12.69809 29.5398,-20.98524 50.6587,-20.98524 33.6834,0 60.9508,21.25257 60.9508,47.45072 0,3.20793 -0.401,6.2822 -1.203,9.35647 -0.5346,2.13864 0.6683,4.27725 2.9407,5.07924 21.5199,7.88618 36.0893,22.85655 36.0893,39.965535 0,19.51495 -18.8466,36.22296 -45.4458,42.77249 -2.1387,0.53466 -3.4753,2.40595 -3.4753,4.41092 0,0.1337 0,0.26731 0,0.40098 0,15.10404 -14.9704,27.5348 -34.218,28.87144 0.1333,0.66833 0.1333,1.33663 0.1333,2.13862 0,29.00509 -55.2031,52.3963 -123.2382,52.3963 -14.7029,0 -28.7377,-1.06932 -41.7031,-3.07427 0,0.26733 0,0.40099 0,0.66832 0,12.02975 -15.5051,21.78723 -34.4854,21.78723 -1.0692,0 -2.0049,0 -2.9405,-0.13369 1.3367,2.9406 2.005,6.01487 2.005,9.22281 0,18.71296 -23.6586,33.81699 -52.9311,33.81699 -3.2079,0 -6.2821,-0.1337 -9.3563,-0.53466 -2.4061,-0.26731 -4.6783,1.20299 -5.2131,3.47529 -2.5396,9.35647 -10.693,16.17333 -20.4504,16.17333 -11.7625,0 -21.119,-10.0248 -21.119,-22.32189 0,-5.74755 2.005,-10.96045 5.3466,-14.83671 1.203,-1.33663 1.6039,-3.20793 0.8019,-4.81191 -1.8713,-3.47526 -2.6733,-7.08419 -2.6733,-10.96044 v 0 c 0,-2.13862 -1.7376,-3.87626 -3.8763,-4.4109 -36.2228,-8.01985 -63.4903,-38.22792 -63.4903,-74.3172 z m 306.8925,726.06294 c 0.5348,1.60398 0.6683,3.20796 0.6683,4.94558 l -7.7525,97.97577 c -0.5346,6.9505 -6.6832,12.4307 -14.1683,12.4307 h -250.219 c -5.3466,0 -10.2921,-3.0743 -12.6982,-7.4852 l -41.3021,-76.72312 c -0.2673,-0.401 -0.401,-0.80199 -0.5347,-1.20298 l -38.8962,-94.23313 c -1.4702,-3.3416 -1.203,-7.21785 0.4011,-10.42581 l 64.5596,-126.31249 c 1.604,-3.07427 1.8712,-6.6832 0.6683,-9.89114 l -31.5447,-87.41626 c -1.0693,-3.07428 -0.9356,-6.54955 0.4011,-9.49015 l 52.6636,-112.14412 c 5.3464,-11.22778 22.8565,-10.29212 26.5991,1.47031 l 16.4407,51.05965 50.124,134.19868 c 1.3367,3.7426 4.5446,6.6832 8.5545,8.01985 l 106.9312,36.49027 c 4.1435,1.47032 7.3516,4.54458 8.6881,8.42084 z"
style="fill:#000000;stroke-width:0.78179646;fill-opacity:0.49803922" /><g
aria-label="WULKANOWY"
style="font-style:normal;font-variant:normal;font-weight:300;font-stretch:normal;font-size:341.33334351px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:'Roboto Light';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:0.49803922;stroke:none"
id="text4752" /></g></svg>

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -1,37 +1,30 @@
package io.github.wulkanowy
import android.app.Application
import android.content.Context
import android.util.Log.DEBUG
import android.util.Log.INFO
import android.util.Log.VERBOSE
import androidx.hilt.work.HiltWorkerFactory
import androidx.multidex.MultiDex
import androidx.work.Configuration
import com.jakewharton.threetenabp.AndroidThreeTen
import com.yariksoffice.lingver.Lingver
import dagger.android.AndroidInjector
import dagger.android.support.DaggerApplication
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.utils.Log
import dagger.hilt.android.HiltAndroidApp
import fr.bipi.tressence.file.FileLoggerTree
import io.github.wulkanowy.di.DaggerAppComponent
import io.github.wulkanowy.services.sync.SyncWorkerFactory
import io.github.wulkanowy.ui.base.ThemeManager
import io.github.wulkanowy.utils.ActivityLifecycleLogger
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.CrashlyticsExceptionTree
import io.github.wulkanowy.utils.CrashlyticsTree
import io.github.wulkanowy.utils.DebugLogTree
import io.github.wulkanowy.utils.initCrashlytics
import io.reactivex.exceptions.UndeliverableException
import io.reactivex.plugins.RxJavaPlugins
import timber.log.Timber
import java.io.IOException
import javax.inject.Inject
class WulkanowyApp : DaggerApplication(), Configuration.Provider {
@HiltAndroidApp
class WulkanowyApp : Application(), Configuration.Provider {
@Inject
lateinit var workerFactory: SyncWorkerFactory
lateinit var workerFactory: HiltWorkerFactory
@Inject
lateinit var themeManager: ThemeManager
@ -46,18 +39,14 @@ class WulkanowyApp : DaggerApplication(), Configuration.Provider {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
RxJavaPlugins.setErrorHandler(::onError)
Lingver.init(this)
themeManager.applyDefaultTheme()
initLogging()
initCrashlytics(this, appInfo)
}
private fun initLogging() {
if (appInfo.isDebug) {
FlexibleAdapter.enableLogs(Log.Level.DEBUG)
Timber.plant(DebugLogTree())
Timber.plant(FileLoggerTree.Builder()
.withFileName("wulkanowy.%g.log")
@ -73,18 +62,6 @@ class WulkanowyApp : DaggerApplication(), Configuration.Provider {
registerActivityLifecycleCallbacks(ActivityLifecycleLogger())
}
private fun onError(error: Throwable) {
//RxJava's too deep stack traces may cause SOE on older android devices
val cause = error.cause
if (error is UndeliverableException && cause is IOException || cause is InterruptedException || cause is StackOverflowError) {
Timber.e(cause, "An undeliverable error occurred")
} else throw error
}
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerAppComponent.factory().create(this)
}
override fun getWorkManagerConfiguration() = Configuration.Builder()
.setWorkerFactory(workerFactory)
.setMinimumLoggingLevel(if (appInfo.isDebug) VERBOSE else INFO)

View file

@ -5,13 +5,14 @@ import android.content.SharedPreferences
import android.content.res.AssetManager
import android.content.res.Resources
import androidx.preference.PreferenceManager
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy
import com.chuckerteam.chucker.api.ChuckerCollector
import com.chuckerteam.chucker.api.ChuckerInterceptor
import com.chuckerteam.chucker.api.RetentionManager
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.SharedPrefProvider
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
@ -20,19 +21,12 @@ import timber.log.Timber
import javax.inject.Singleton
@Module
@InstallIn(ApplicationComponent::class)
internal class RepositoryModule {
@Singleton
@Provides
fun provideInternetObservingSettings(): InternetObservingSettings {
return InternetObservingSettings.builder()
.strategy(WalledGardenInternetObservingStrategy())
.build()
}
@Singleton
@Provides
fun provideSdk(chuckerCollector: ChuckerCollector, context: Context): Sdk {
fun provideSdk(chuckerCollector: ChuckerCollector, @ApplicationContext context: Context): Sdk {
return Sdk().apply {
androidVersion = android.os.Build.VERSION.RELEASE
buildTag = android.os.Build.MODEL
@ -45,7 +39,7 @@ internal class RepositoryModule {
@Singleton
@Provides
fun provideChuckerCollector(context: Context, prefRepository: PreferencesRepository): ChuckerCollector {
fun provideChuckerCollector(@ApplicationContext context: Context, prefRepository: PreferencesRepository): ChuckerCollector {
return ChuckerCollector(
context = context,
showNotification = prefRepository.isDebugNotificationEnable,
@ -55,19 +49,19 @@ internal class RepositoryModule {
@Singleton
@Provides
fun provideDatabase(context: Context, sharedPrefProvider: SharedPrefProvider) = AppDatabase.newInstance(context, sharedPrefProvider)
fun provideDatabase(@ApplicationContext context: Context, sharedPrefProvider: SharedPrefProvider) = AppDatabase.newInstance(context, sharedPrefProvider)
@Singleton
@Provides
fun provideResources(context: Context): Resources = context.resources
fun provideResources(@ApplicationContext context: Context): Resources = context.resources
@Singleton
@Provides
fun provideAssets(context: Context): AssetManager = context.assets
fun provideAssets(@ApplicationContext context: Context): AssetManager = context.assets
@Singleton
@Provides
fun provideSharedPref(context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
fun provideSharedPref(@ApplicationContext context: Context): SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
@Singleton
@Provides

View file

@ -0,0 +1,23 @@
package io.github.wulkanowy.data
data class Resource<out T>(val status: Status, val data: T?, val error: Throwable?) {
companion object {
fun <T> success(data: T?): Resource<T> {
return Resource(Status.SUCCESS, data, null)
}
fun <T> error(error: Throwable?, data: T? = null): Resource<T> {
return Resource(Status.ERROR, data, error)
}
fun <T> loading(data: T? = null): Resource<T> {
return Resource(Status.LOADING, data, null)
}
}
}
enum class Status {
LOADING,
SUCCESS,
ERROR
}

View file

@ -1,30 +0,0 @@
package io.github.wulkanowy.data
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import javax.inject.Inject
class SdkHelper @Inject constructor(private val sdk: Sdk) {
fun init(student: Student) {
sdk.apply {
email = student.email
password = student.password
symbol = student.symbol
schoolSymbol = student.schoolSymbol
studentId = student.studentId
classId = student.classId
if (Sdk.Mode.valueOf(student.loginMode) != Sdk.Mode.API) {
scrapperBaseUrl = student.scrapperBaseUrl
loginType = Sdk.ScrapperLoginType.valueOf(student.loginType)
}
loginId = student.userLoginId
mode = Sdk.Mode.valueOf(student.loginMode)
mobileBaseUrl = student.mobileBaseUrl
certKey = student.certificateKey
privateKey = student.privateKey
}
}
}

View file

@ -68,6 +68,8 @@ 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.Migration3
import io.github.wulkanowy.data.db.migrations.Migration4
import io.github.wulkanowy.data.db.migrations.Migration5
@ -110,7 +112,7 @@ import javax.inject.Singleton
abstract class AppDatabase : RoomDatabase() {
companion object {
const val VERSION_SCHEMA = 25
const val VERSION_SCHEMA = 27
fun getMigrations(sharedPrefProvider: SharedPrefProvider): Array<Migration> {
return arrayOf(
@ -137,7 +139,9 @@ abstract class AppDatabase : RoomDatabase() {
Migration22(),
Migration23(),
Migration24(),
Migration25()
Migration25(),
Migration26(),
Migration27(),
)
}

View file

@ -3,19 +3,18 @@ package io.github.wulkanowy.data.db
import androidx.room.TypeConverter
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import org.threeten.bp.DateTimeUtils
import org.threeten.bp.Instant
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime
import org.threeten.bp.Month
import org.threeten.bp.ZoneOffset
import java.time.Instant
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.Month
import java.time.ZoneOffset
import java.util.Date
class Converters {
@TypeConverter
fun timestampToDate(value: Long?): LocalDate? = value?.run {
DateTimeUtils.toInstant(Date(value)).atZone(ZoneOffset.UTC).toLocalDate()
Date(value).toInstant().atZone(ZoneOffset.UTC).toLocalDate()
}
@TypeConverter

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Attendance
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface AttendanceDao : BaseDao<Attendance> {
@Query("SELECT * FROM Attendance WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Attendance>>
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Attendance>>
}

View file

@ -3,11 +3,11 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
@Dao
interface AttendanceSummaryDao : BaseDao<AttendanceSummary> {
@Query("SELECT * FROM AttendanceSummary WHERE diary_id = :diaryId AND student_id = :studentId AND subject_id = :subjectId")
fun loadAll(diaryId: Int, studentId: Int, subjectId: Int): Maybe<List<AttendanceSummary>>
fun loadAll(diaryId: Int, studentId: Int, subjectId: Int): Flow<List<AttendanceSummary>>
}

View file

@ -7,11 +7,11 @@ import androidx.room.Update
interface BaseDao<T> {
@Insert
fun insertAll(items: List<T>): List<Long>
suspend fun insertAll(items: List<T>): List<Long>
@Update
fun updateAll(items: List<T>)
suspend fun updateAll(items: List<T>)
@Delete
fun deleteAll(items: List<T>)
suspend fun deleteAll(items: List<T>)
}

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface CompletedLessonsDao : BaseDao<CompletedLesson> {
@Query("SELECT * FROM CompletedLesson WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<CompletedLesson>>
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<CompletedLesson>>
}

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Exam
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface ExamDao : BaseDao<Exam> {
@Query("SELECT * FROM Exams WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Exam>>
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Exam>>
}

View file

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Grade
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,6 +11,5 @@ import javax.inject.Singleton
interface GradeDao : BaseDao<Grade> {
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId")
fun loadAll(semesterId: Int, studentId: Int): Maybe<List<Grade>>
fun loadAll(semesterId: Int, studentId: Int): Flow<List<Grade>>
}

View file

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,8 +11,8 @@ import javax.inject.Singleton
interface GradePointsStatisticsDao : BaseDao<GradePointsStatistics> {
@Query("SELECT * FROM GradesPointsStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND subject = :subjectName")
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String): Maybe<List<GradePointsStatistics>>
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String): Flow<List<GradePointsStatistics>>
@Query("SELECT * FROM GradesPointsStatistics WHERE student_id = :studentId AND semester_id = :semesterId")
fun loadAll(semesterId: Int, studentId: Int): Maybe<List<GradePointsStatistics>>
fun loadAll(semesterId: Int, studentId: Int): Flow<List<GradePointsStatistics>>
}

View file

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,8 +11,8 @@ import javax.inject.Singleton
interface GradeStatisticsDao : BaseDao<GradeStatistics> {
@Query("SELECT * FROM GradesStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND subject = :subjectName AND is_semester = :isSemester")
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String, isSemester: Boolean): Maybe<List<GradeStatistics>>
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String, isSemester: Boolean): Flow<List<GradeStatistics>>
@Query("SELECT * FROM GradesStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND is_semester = :isSemester")
fun loadAll(semesterId: Int, studentId: Int, isSemester: Boolean): Maybe<List<GradeStatistics>>
fun loadAll(semesterId: Int, studentId: Int, isSemester: Boolean): Flow<List<GradeStatistics>>
}

View file

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,5 +11,5 @@ import javax.inject.Singleton
interface GradeSummaryDao : BaseDao<GradeSummary> {
@Query("SELECT * FROM GradesSummary WHERE student_id = :studentId AND semester_id = :semesterId")
fun loadAll(semesterId: Int, studentId: Int): Maybe<List<GradeSummary>>
fun loadAll(semesterId: Int, studentId: Int): Flow<List<GradeSummary>>
}

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Homework
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface HomeworkDao : BaseDao<Homework> {
@Query("SELECT * FROM Homework WHERE semester_id = :semesterId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(semesterId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Homework>>
fun loadAll(semesterId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Homework>>
}

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface LuckyNumberDao : BaseDao<LuckyNumber> {
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date")
fun load(studentId: Int, date: LocalDate): Maybe<LuckyNumber>
fun load(studentId: Int, date: LocalDate): Flow<LuckyNumber?>
}

View file

@ -9,5 +9,5 @@ import io.github.wulkanowy.data.db.entities.MessageAttachment
interface MessageAttachmentDao : BaseDao<MessageAttachment> {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAttachments(items: List<MessageAttachment>): List<Long>
suspend fun insertAttachments(items: List<MessageAttachment>): List<Long>
}

View file

@ -5,19 +5,15 @@ 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.reactivex.Maybe
import io.reactivex.Single
import kotlinx.coroutines.flow.Flow
@Dao
interface MessagesDao : BaseDao<Message> {
@Transaction
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND message_id = :messageId")
fun loadMessageWithAttachment(studentId: Int, messageId: Int): Single<MessageWithAttachment>
fun loadMessageWithAttachment(studentId: Int, messageId: Int): Flow<MessageWithAttachment>
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder AND removed = 0 ORDER BY date DESC")
fun loadAll(studentId: Int, folder: Int): Maybe<List<Message>>
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC")
fun loadDeleted(studentId: Int): Maybe<List<Message>>
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder ORDER BY date DESC")
fun loadAll(studentId: Int, folder: Int): Flow<List<Message>>
}

View file

@ -3,11 +3,11 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
@Dao
interface MobileDeviceDao : BaseDao<MobileDevice> {
@Query("SELECT * FROM MobileDevices WHERE student_id = :studentId ORDER BY date DESC")
fun loadAll(studentId: Int): Maybe<List<MobileDevice>>
fun loadAll(studentId: Int): Flow<List<MobileDevice>>
}

View file

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Note
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,5 +11,5 @@ import javax.inject.Singleton
interface NoteDao : BaseDao<Note> {
@Query("SELECT * FROM Notes WHERE student_id = :studentId")
fun loadAll(studentId: Int): Maybe<List<Note>>
fun loadAll(studentId: Int): Flow<List<Note>>
}

View file

@ -3,7 +3,6 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Recipient
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@ -11,5 +10,5 @@ import javax.inject.Singleton
interface RecipientDao : BaseDao<Recipient> {
@Query("SELECT * FROM Recipients WHERE student_id = :studentId AND role = :role AND unit_id = :unitId")
fun load(studentId: Int, role: Int, unitId: Int): Maybe<List<Recipient>>
suspend fun load(studentId: Int, role: Int, unitId: Int): List<Recipient>
}

View file

@ -3,7 +3,6 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@ -11,8 +10,8 @@ import javax.inject.Singleton
interface ReportingUnitDao : BaseDao<ReportingUnit> {
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId")
fun load(studentId: Int): Maybe<List<ReportingUnit>>
suspend fun load(studentId: Int): List<ReportingUnit>
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId AND real_id = :unitId")
fun loadOne(studentId: Int, unitId: Int): Maybe<ReportingUnit>
suspend fun loadOne(studentId: Int, unitId: Int): ReportingUnit?
}

View file

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.School
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,5 +11,5 @@ import javax.inject.Singleton
interface SchoolDao : BaseDao<School> {
@Query("SELECT * FROM School WHERE student_id = :studentId AND class_id = :classId")
fun load(studentId: Int, classId: Int): Maybe<School>
fun load(studentId: Int, classId: Int): Flow<School?>
}

View file

@ -1,15 +1,19 @@
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.Semester
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@Dao
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")
fun loadAll(studentId: Int, classId: Int): Maybe<List<Semester>>
suspend fun loadAll(studentId: Int, classId: Int): List<Semester>
}

View file

@ -5,8 +5,9 @@ import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy.ABORT
import androidx.room.Query
import androidx.room.Transaction
import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Maybe
import io.github.wulkanowy.data.db.entities.StudentWithSemesters
import javax.inject.Singleton
@Singleton
@ -14,20 +15,27 @@ import javax.inject.Singleton
interface StudentDao {
@Insert(onConflict = ABORT)
fun insertAll(student: List<Student>): List<Long>
suspend fun insertAll(student: List<Student>): List<Long>
@Delete
fun delete(student: Student)
suspend fun delete(student: Student)
@Query("SELECT * FROM Students WHERE is_current = 1")
fun loadCurrent(): Maybe<Student>
suspend fun loadCurrent(): Student?
@Query("SELECT * FROM Students WHERE id = :id")
suspend fun loadById(id: Int): Student?
@Query("SELECT * FROM Students")
fun loadAll(): Maybe<List<Student>>
suspend fun loadAll(): List<Student>
@Transaction
@Query("SELECT * FROM Students")
suspend fun loadStudentsWithSemesters(): List<StudentWithSemesters>
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
fun updateCurrent(id: Long)
suspend fun updateCurrent(id: Long)
@Query("UPDATE Students SET is_current = 0")
fun resetCurrent()
suspend fun resetCurrent()
}

View file

@ -3,11 +3,11 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Subject
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
@Dao
interface SubjectDao : BaseDao<Subject> {
@Query("SELECT * FROM Subjects WHERE diary_id = :diaryId AND student_id = :studentId")
fun loadAll(diaryId: Int, studentId: Int): Maybe<List<Subject>>
fun loadAll(diaryId: Int, studentId: Int): Flow<List<Subject>>
}

View file

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Teacher
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Singleton
@Singleton
@ -11,5 +11,5 @@ import javax.inject.Singleton
interface TeacherDao : BaseDao<Teacher> {
@Query("SELECT * FROM Teachers WHERE student_id = :studentId AND class_id = :classId")
fun loadAll(studentId: Int, classId: Int): Maybe<List<Teacher>>
fun loadAll(studentId: Int, classId: Int): Flow<List<Teacher>>
}

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Timetable
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Singleton
@Singleton
@ -12,5 +12,5 @@ import javax.inject.Singleton
interface TimetableDao : BaseDao<Timetable> {
@Query("SELECT * FROM Timetable WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Timetable>>
fun loadAll(diaryId: Int, studentId: Int, from: LocalDate, end: LocalDate): Flow<List<Timetable>>
}

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Attendance")
data class Attendance(

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.Month
import java.io.Serializable
import java.time.Month
@Entity(tableName = "AttendanceSummary")
data class AttendanceSummary(

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "CompletedLesson")
data class CompletedLesson(

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Exams")
data class Exam(

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Grades")
data class Grade(

View file

@ -3,6 +3,7 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.time.LocalDateTime
@Entity(tableName = "GradesSummary")
data class GradeSummary(
@ -36,4 +37,16 @@ data class GradeSummary(
) {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
@ColumnInfo(name = "is_predicted_grade_notified")
var isPredictedGradeNotified: Boolean = true
@ColumnInfo(name = "is_final_grade_notified")
var isFinalGradeNotified: Boolean = true
@ColumnInfo(name = "predicted_grade_last_change")
var predictedGradeLastChange: LocalDateTime = LocalDateTime.now()
@ColumnInfo(name = "final_grade_last_change")
var finalGradeLastChange: LocalDateTime = LocalDateTime.now()
}

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Homework")
data class Homework(

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "LuckyNumbers")
data class LuckyNumber (

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDateTime
import java.io.Serializable
import java.time.LocalDateTime
@Entity(tableName = "Messages")
data class Message(
@ -29,8 +29,6 @@ data class Message(
val subject: String,
var content: String,
val date: LocalDateTime,
@ColumnInfo(name = "folder_id")
@ -55,4 +53,6 @@ data class Message(
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
var content: String = ""
}

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDateTime
import java.io.Serializable
import java.time.LocalDateTime
@Entity(tableName = "MobileDevices")
data class MobileDevice(

View file

@ -3,8 +3,8 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Notes")
data class Note(

View file

@ -4,7 +4,8 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
import java.time.LocalDate
@Entity(tableName = "Semesters", indices = [Index(value = ["student_id", "diary_id", "semester_id"], unique = true)])
data class Semester(
@ -36,7 +37,7 @@ data class Semester(
@ColumnInfo(name = "unit_id")
val unitId: Int
) {
): Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0

View file

@ -4,8 +4,8 @@ import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDateTime
import java.io.Serializable
import java.time.LocalDateTime
@Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id", "class_id"], unique = true)])
data class Student(
@ -43,6 +43,9 @@ data class Student(
@ColumnInfo(name = "user_login_id")
val userLoginId: Int,
@ColumnInfo(name = "user_name")
val userName: String,
@ColumnInfo(name = "student_name")
val studentName: String,

View file

@ -0,0 +1,13 @@
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

@ -3,9 +3,9 @@ package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime
import java.io.Serializable
import java.time.LocalDate
import java.time.LocalDateTime
@Entity(tableName = "Timetable")
data class Timetable(

View file

@ -0,0 +1,14 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
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")
}
}

View file

@ -0,0 +1,45 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
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 \"\"")
val students = getStudentsIdsAndNames(database)
val units = getReportingUnits(database)
students.forEach { (id, userLoginId, studentName) ->
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'")
}
}
private fun getStudentsIdsAndNames(database: SupportSQLiteDatabase): MutableList<Triple<Long, Int, String>> {
val students = mutableListOf<Triple<Long, Int, String>>()
val studentsCursor = database.query("SELECT id, user_login_id, student_name FROM Students")
if (studentsCursor.moveToFirst()) {
do {
students.add(Triple(studentsCursor.getLong(0), studentsCursor.getInt(1), studentsCursor.getString(2)))
} while (studentsCursor.moveToNext())
}
return students
}
private fun getReportingUnits(database: SupportSQLiteDatabase): MutableList<Pair<Int, String>> {
val units = mutableListOf<Pair<Int, String>>()
val unitsCursor = database.query("SELECT sender_id, sender_name FROM ReportingUnits")
if (unitsCursor.moveToFirst()) {
do {
units.add(unitsCursor.getInt(0) to unitsCursor.getString(1))
} while (unitsCursor.moveToNext())
}
return units
}
}

View file

@ -2,8 +2,8 @@ package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import org.threeten.bp.LocalDateTime.now
import org.threeten.bp.ZoneOffset
import java.time.LocalDateTime.now
import java.time.ZoneOffset
class Migration5 : Migration(4, 5) {

View file

@ -0,0 +1,19 @@
package io.github.wulkanowy.data.mappers
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.sdk.pojo.Semester as SdkSemester
fun List<SdkSemester>.mapToEntities(studentId: Int) = map {
Semester(
studentId = studentId,
diaryId = it.diaryId,
diaryName = it.diaryName,
schoolYear = it.schoolYear,
semesterId = it.semesterId,
semesterName = it.semesterNumber,
start = it.start,
end = it.end,
classId = it.classId,
unitId = it.unitId
)
}

View file

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

View file

@ -1,3 +0,0 @@
package io.github.wulkanowy.data.pojos
class AppCreator(val displayName: String, val githubUsername: String)

View file

@ -0,0 +1,3 @@
package io.github.wulkanowy.data.pojos
class Contributor(val displayName: String, val githubUsername: String)

View file

@ -2,19 +2,22 @@ package io.github.wulkanowy.data.repositories.appcreator
import android.content.res.AssetManager
import com.google.gson.Gson
import io.github.wulkanowy.data.pojos.AppCreator
import io.reactivex.Single
import io.github.wulkanowy.data.pojos.Contributor
import io.github.wulkanowy.utils.DispatchersProvider
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AppCreatorRepository @Inject constructor(private val assets: AssetManager) {
fun getAppCreators(): Single<List<AppCreator>> {
return Single.fromCallable<List<AppCreator>> {
Gson().fromJson(
assets.open("contributors.json").bufferedReader().use { it.readText() },
Array<AppCreator>::class.java
).toList()
}
class AppCreatorRepository @Inject constructor(
private val assets: AssetManager,
private val dispatchers: DispatchersProvider
) {
suspend fun getAppCreators() = withContext(dispatchers.backgroundThread) {
Gson().fromJson(
assets.open("contributors.json").bufferedReader().use { it.readText() },
Array<Contributor>::class.java
).toList()
}
}

View file

@ -3,23 +3,23 @@ package io.github.wulkanowy.data.repositories.attendance
import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceLocal @Inject constructor(private val attendanceDb: AttendanceDao) {
fun saveAttendance(attendance: List<Attendance>) {
suspend fun saveAttendance(attendance: List<Attendance>) {
attendanceDb.insertAll(attendance)
}
fun deleteAttendance(attendance: List<Attendance>) {
suspend fun deleteAttendance(attendance: List<Attendance>) {
attendanceDb.deleteAll(attendance)
}
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Attendance>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate).filter { it.isNotEmpty() }
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Flow<List<Attendance>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate)
}
}

View file

@ -2,45 +2,45 @@ package io.github.wulkanowy.data.repositories.attendance
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.sdk.pojo.Absent
import io.reactivex.Single
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime
import org.threeten.bp.LocalTime
import io.github.wulkanowy.utils.init
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceRemote @Inject constructor(private val sdk: Sdk) {
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Attendance>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getAttendance(startDate, endDate, semester.semesterId)
.map { attendance ->
attendance.map {
Attendance(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
timeId = it.timeId,
number = it.number,
subject = it.subject,
name = it.name,
presence = it.presence,
absence = it.absence,
exemption = it.exemption,
lateness = it.lateness,
excused = it.excused,
deleted = it.deleted,
excusable = it.excusable,
excuseStatus = it.excuseStatus?.name
)
}
suspend fun getAttendance(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): List<Attendance> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getAttendance(startDate, endDate, semester.semesterId)
.map {
Attendance(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
timeId = it.timeId,
number = it.number,
subject = it.subject,
name = it.name,
presence = it.presence,
absence = it.absence,
exemption = it.exemption,
lateness = it.lateness,
excused = it.excused,
deleted = it.deleted,
excusable = it.excusable,
excuseStatus = it.excuseStatus?.name
)
}
}
fun excuseAbsence(semester: Semester, absenceList: List<Attendance>, reason: String?): Single<Boolean> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance ->
suspend fun excuseAbsence(student: Student, semester: Semester, absenceList: List<Attendance>, reason: String?): Boolean {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear).excuseForAbsence(absenceList.map { attendance ->
Absent(
date = LocalDateTime.of(attendance.date, LocalTime.of(0, 0)),
timeId = attendance.timeId

View file

@ -1,48 +1,34 @@
package io.github.wulkanowy.data.repositories.attendance
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.net.UnknownHostException
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: AttendanceLocal,
private val remote: AttendanceRemote
) {
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean)
: Single<List<Attendance>> {
return Single.fromCallable { startDate.monday to endDate.friday }
.flatMap { dates ->
local.getAttendance(semester, dates.first, dates.second).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings).flatMap {
if (it) remote.getAttendance(semester, dates.first, dates.second)
else Single.error(UnknownHostException())
}.flatMap { newAttendance ->
local.getAttendance(semester, dates.first, dates.second)
.toSingle(emptyList())
.doOnSuccess { oldAttendance ->
local.deleteAttendance(oldAttendance.uniqueSubtract(newAttendance))
local.saveAttendance(newAttendance.uniqueSubtract(oldAttendance))
}
}.flatMap {
local.getAttendance(semester, dates.first, dates.second)
.toSingle(emptyList())
}).map { list -> list.filter { it.date in startDate..endDate } }
}
}
fun getAttendance(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getAttendance(semester, start.monday, end.sunday) },
fetch = { remote.getAttendance(student, semester, start.monday, end.sunday) },
saveFetchResult = { old, new ->
local.deleteAttendance(old uniqueSubtract new)
local.saveAttendance(new uniqueSubtract old)
},
filterResult = { it.filter { item -> item.date in start..end } }
)
fun excuseForAbsence(semester: Semester, attendanceList: List<Attendance>, reason: String? = null): Single<Boolean> {
return remote.excuseAbsence(semester, attendanceList, reason)
suspend fun excuseForAbsence(student: Student, semester: Semester, attendanceList: List<Attendance>, reason: String? = null) {
remote.excuseAbsence(student, semester, attendanceList, reason)
}
}

View file

@ -3,22 +3,22 @@ package io.github.wulkanowy.data.repositories.attendancesummary
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceSummaryLocal @Inject constructor(private val attendanceDb: AttendanceSummaryDao) {
fun saveAttendanceSummary(attendance: List<AttendanceSummary>) {
suspend fun saveAttendanceSummary(attendance: List<AttendanceSummary>) {
attendanceDb.insertAll(attendance)
}
fun deleteAttendanceSummary(attendance: List<AttendanceSummary>) {
suspend fun deleteAttendanceSummary(attendance: List<AttendanceSummary>) {
attendanceDb.deleteAll(attendance)
}
fun getAttendanceSummary(semester: Semester, subjectId: Int): Maybe<List<AttendanceSummary>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId).filter { it.isNotEmpty() }
fun getAttendanceSummary(semester: Semester, subjectId: Int): Flow<List<AttendanceSummary>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, subjectId)
}
}

View file

@ -2,32 +2,32 @@ package io.github.wulkanowy.data.repositories.attendancesummary
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import io.github.wulkanowy.utils.init
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceSummaryRemote @Inject constructor(private val sdk: Sdk) {
fun getAttendanceSummary(semester: Semester, subjectId: Int): Single<List<AttendanceSummary>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getAttendanceSummary(subjectId)
.map { attendance ->
attendance.map {
AttendanceSummary(
studentId = semester.studentId,
diaryId = semester.diaryId,
subjectId = subjectId,
month = it.month,
presence = it.presence,
absence = it.absence,
absenceExcused = it.absenceExcused,
absenceForSchoolReasons = it.absenceForSchoolReasons,
lateness = it.lateness,
latenessExcused = it.latenessExcused,
exemption = it.exemption
)
}
suspend fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int): List<AttendanceSummary> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getAttendanceSummary(subjectId)
.map {
AttendanceSummary(
studentId = semester.studentId,
diaryId = semester.diaryId,
subjectId = subjectId,
month = it.month,
presence = it.presence,
absence = it.absence,
absenceExcused = it.absenceExcused,
absenceForSchoolReasons = it.absenceForSchoolReasons,
lateness = it.lateness,
latenessExcused = it.latenessExcused,
exemption = it.exemption
)
}
}
}

View file

@ -1,34 +1,25 @@
package io.github.wulkanowy.data.repositories.attendancesummary
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single
import java.net.UnknownHostException
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceSummaryRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: AttendanceSummaryLocal,
private val remote: AttendanceSummaryRemote
) {
fun getAttendanceSummary(semester: Semester, subjectId: Int, forceRefresh: Boolean = false): Single<List<AttendanceSummary>> {
return local.getAttendanceSummary(semester, subjectId).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getAttendanceSummary(semester, subjectId)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getAttendanceSummary(semester, subjectId).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteAttendanceSummary(old.uniqueSubtract(new))
local.saveAttendanceSummary(new.uniqueSubtract(old))
}
}.flatMap { local.getAttendanceSummary(semester, subjectId).toSingle(emptyList()) })
}
fun getAttendanceSummary(student: Student, semester: Semester, subjectId: Int, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getAttendanceSummary(semester, subjectId) },
fetch = { remote.getAttendanceSummary(student, semester, subjectId) },
saveFetchResult = { old, new ->
local.deleteAttendanceSummary(old uniqueSubtract new)
local.saveAttendanceSummary(new uniqueSubtract old)
}
)
}

View file

@ -3,23 +3,23 @@ package io.github.wulkanowy.data.repositories.completedlessons
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class CompletedLessonsLocal @Inject constructor(private val completedLessonsDb: CompletedLessonsDao) {
fun saveCompletedLessons(completedLessons: List<CompletedLesson>) {
suspend fun saveCompletedLessons(completedLessons: List<CompletedLesson>) {
completedLessonsDb.insertAll(completedLessons)
}
fun deleteCompleteLessons(completedLessons: List<CompletedLesson>) {
suspend fun deleteCompleteLessons(completedLessons: List<CompletedLesson>) {
completedLessonsDb.deleteAll(completedLessons)
}
fun getCompletedLessons(semester: Semester, start: LocalDate, end: LocalDate): Maybe<List<CompletedLesson>> {
return completedLessonsDb.loadAll(semester.diaryId, semester.studentId, start, end).filter { it.isNotEmpty() }
fun getCompletedLessons(semester: Semester, start: LocalDate, end: LocalDate): Flow<List<CompletedLesson>> {
return completedLessonsDb.loadAll(semester.diaryId, semester.studentId, start, end)
}
}

View file

@ -2,34 +2,34 @@ package io.github.wulkanowy.data.repositories.completedlessons
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import org.threeten.bp.LocalDate
import io.github.wulkanowy.utils.init
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class CompletedLessonsRemote @Inject constructor(private val sdk: Sdk) {
fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<CompletedLesson>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getCompletedLessons(startDate, endDate)
.map { lessons ->
lessons.map {
it.absence
CompletedLesson(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
number = it.number,
subject = it.subject,
topic = it.topic,
teacher = it.teacher,
teacherSymbol = it.teacherSymbol,
substitution = it.substitution,
absence = it.absence,
resources = it.resources
)
}
suspend fun getCompletedLessons(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): List<CompletedLesson> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getCompletedLessons(startDate, endDate)
.map {
it.absence
CompletedLesson(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
number = it.number,
subject = it.subject,
topic = it.topic,
teacher = it.teacher,
teacherSymbol = it.teacherSymbol,
substitution = it.substitution,
absence = it.absence,
resources = it.resources
)
}
}
}

View file

@ -1,44 +1,29 @@
package io.github.wulkanowy.data.repositories.completedlessons
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.net.UnknownHostException
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class CompletedLessonsRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: CompletedLessonsLocal,
private val remote: CompletedLessonsRemote
) {
fun getCompletedLessons(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<CompletedLesson>> {
return Single.fromCallable { startDate.monday to endDate.friday }
.flatMap { dates ->
local.getCompletedLessons(semester, dates.first, dates.second).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getCompletedLessons(semester, dates.first, dates.second)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getCompletedLessons(semester, dates.first, dates.second)
.toSingle(emptyList())
.doOnSuccess { old ->
local.deleteCompleteLessons(old.uniqueSubtract(new))
local.saveCompletedLessons(new.uniqueSubtract(old))
}
}.flatMap {
local.getCompletedLessons(semester, dates.first, dates.second)
.toSingle(emptyList())
}).map { list -> list.filter { it.date in startDate..endDate } }
}
}
fun getCompletedLessons(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getCompletedLessons(semester, start.monday, end.sunday) },
fetch = { remote.getCompletedLessons(student, semester, start.monday, end.sunday) },
saveFetchResult = { old, new ->
local.deleteCompleteLessons(old uniqueSubtract new)
local.saveCompletedLessons(new uniqueSubtract old)
},
filterResult = { it.filter { item -> item.date in start..end } }
)
}

View file

@ -3,24 +3,23 @@ package io.github.wulkanowy.data.repositories.exam
import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import kotlinx.coroutines.flow.Flow
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ExamLocal @Inject constructor(private val examDb: ExamDao) {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Exam>> {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Flow<List<Exam>> {
return examDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate)
.filter { !it.isEmpty() }
}
fun saveExams(exams: List<Exam>) {
suspend fun saveExams(exams: List<Exam>) {
examDb.insertAll(exams)
}
fun deleteExams(exams: List<Exam>) {
suspend fun deleteExams(exams: List<Exam>) {
examDb.deleteAll(exams)
}
}

View file

@ -2,32 +2,32 @@ package io.github.wulkanowy.data.repositories.exam
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.sdk.Sdk
import io.reactivex.Single
import org.threeten.bp.LocalDate
import io.github.wulkanowy.utils.init
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ExamRemote @Inject constructor(private val sdk: Sdk) {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Single<List<Exam>> {
return sdk.switchDiary(semester.diaryId, semester.schoolYear).getExams(startDate, endDate, semester.semesterId)
.map { exams ->
exams.map {
Exam(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
entryDate = it.entryDate,
subject = it.subject,
group = it.group,
type = it.type,
description = it.description,
teacher = it.teacher,
teacherSymbol = it.teacherSymbol
)
}
suspend fun getExams(student: Student, semester: Semester, startDate: LocalDate, endDate: LocalDate): List<Exam> {
return sdk.init(student).switchDiary(semester.diaryId, semester.schoolYear)
.getExams(startDate, endDate, semester.semesterId)
.map {
Exam(
studentId = semester.studentId,
diaryId = semester.diaryId,
date = it.date,
entryDate = it.entryDate,
subject = it.subject,
group = it.group,
type = it.type,
description = it.description,
teacher = it.teacher,
teacherSymbol = it.teacherSymbol
)
}
}
}

View file

@ -1,44 +1,29 @@
package io.github.wulkanowy.data.repositories.exam
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.networkBoundResource
import io.github.wulkanowy.utils.sunday
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.net.UnknownHostException
import java.time.LocalDate
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class ExamRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: ExamLocal,
private val remote: ExamRemote
) {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false): Single<List<Exam>> {
return Single.fromCallable { startDate.monday to endDate.friday }
.flatMap { dates ->
local.getExams(semester, dates.first, dates.second).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getExams(semester, dates.first, dates.second)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getExams(semester, dates.first, dates.second)
.toSingle(emptyList())
.doOnSuccess { old ->
local.deleteExams(old.uniqueSubtract(new))
local.saveExams(new.uniqueSubtract(old))
}
}.flatMap {
local.getExams(semester, dates.first, dates.second)
.toSingle(emptyList())
}).map { list -> list.filter { it.date in startDate..endDate } }
}
}
fun getExams(student: Student, semester: Semester, start: LocalDate, end: LocalDate, forceRefresh: Boolean) = networkBoundResource(
shouldFetch = { it.isEmpty() || forceRefresh },
query = { local.getExams(semester, start.monday, end.sunday) },
fetch = { remote.getExams(student, semester, start.monday, end.sunday) },
saveFetchResult = { old, new ->
local.deleteExams(old uniqueSubtract new)
local.saveExams(new uniqueSubtract old)
},
filterResult = { it.filter { item -> item.date in start..end } }
)
}

View file

@ -1,28 +1,49 @@
package io.github.wulkanowy.data.repositories.grade
import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.dao.GradeSummaryDao
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class GradeLocal @Inject constructor(private val gradeDb: GradeDao) {
class GradeLocal @Inject constructor(
private val gradeDb: GradeDao,
private val gradeSummaryDb: GradeSummaryDao
) {
fun saveGrades(grades: List<Grade>) {
suspend fun saveGrades(grades: List<Grade>) {
gradeDb.insertAll(grades)
}
fun deleteGrades(grades: List<Grade>) {
suspend fun deleteGrades(grades: List<Grade>) {
gradeDb.deleteAll(grades)
}
fun updateGrades(grades: List<Grade>) {
suspend fun updateGrades(grades: List<Grade>) {
gradeDb.updateAll(grades)
}
fun getGrades(semester: Semester): Maybe<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() }
suspend fun updateGradesSummary(gradesSummary: List<GradeSummary>) {
gradeSummaryDb.updateAll(gradesSummary)
}
fun getGradesDetails(semester: Semester): Flow<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId)
}
suspend fun saveGradesSummary(gradesSummary: List<GradeSummary>) {
gradeSummaryDb.insertAll(gradesSummary)
}
suspend fun deleteGradesSummary(gradesSummary: List<GradeSummary>) {
gradeSummaryDb.deleteAll(gradesSummary)
}
fun getGradesSummary(semester: Semester): Flow<List<GradeSummary>> {
return gradeSummaryDb.loadAll(semester.semesterId, semester.studentId)
}
}

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