1
0
Fork 1

Compare commits

..

178 commits
0.6.3 ... 0.9.1

Author SHA1 Message Date
Mikołaj Pich
7a61b233f0
Version 0.9.1 2019-06-04 02:43:50 +02:00
Mikołaj Pich
83dbd9874e
Add option to force calc average by app (#400) 2019-06-04 02:27:15 +02:00
Mikołaj Pich
1d9a49d552 Add githook plugin (#398) 2019-06-04 01:53:20 +02:00
Rafał Borcz
6175081b88 Fix tab layout crash on prelolipop (#399) 2019-06-03 22:47:35 +02:00
Rafał Borcz
116e551186 Merge tag '0.9.0' into develop
0.9.0 0.9.0
2019-06-03 18:15:42 +02:00
Rafał Borcz
713500d892 Merge branch 'release/0.9.0' 2019-06-03 18:15:41 +02:00
Rafał Borcz
dfdbe374c2 Version 0.9.0 2019-06-03 18:15:11 +02:00
Mikołaj Pich
b1e3bab5e7 Add F-Droid flavor (#349) 2019-06-03 14:12:48 +02:00
Rafał Borcz
0b2ef367da Change timeout string (#397) 2019-06-03 13:15:21 +02:00
Mikołaj Pich
28f27db2b5 Add mobile access managment (#344) 2019-06-03 00:43:54 +02:00
Rafał Borcz
5c70cd8b8c Add session expired dialog after password change (#389) 2019-05-31 15:12:10 +02:00
Mikołaj Pich
0f75ff3206 Show grades average from register if exist instead of calculating (#374) 2019-05-31 14:40:53 +02:00
Rafał Borcz
383cab4dae Fix only wifi setting (#394) 2019-05-31 13:46:53 +02:00
dependabot-preview[bot]
e1b0db76c2 Bump material from 1.1.0-alpha06 to 1.1.0-alpha07 (#393) 2019-05-31 11:46:29 +02:00
dependabot-preview[bot]
f10684097c
Bump dagger-compiler from 2.23 to 2.23.1 (#391) 2019-05-31 02:02:09 +00:00
dependabot-preview[bot]
35d4342bec
Bump dagger-android-processor from 2.23 to 2.23.1 (#392) 2019-05-31 01:42:40 +00:00
dependabot-preview[bot]
068aee215a
Bump dagger-android-support from 2.23 to 2.23.1 (#390) 2019-05-31 01:19:26 +00:00
dependabot-preview[bot]
033074c66b Bump room-testing from 2.1.0-beta01 to 2.1.0-rc01 (#377) 2019-05-30 16:46:54 +02:00
dependabot-preview[bot]
0de534cb66 Bump room-rxjava2 from 2.1.0-beta01 to 2.1.0-rc01 (#385) 2019-05-30 16:46:28 +02:00
dependabot-preview[bot]
26e4619dde
Bump room-runtime from 2.1.0-beta01 to 2.1.0-rc01 (#388) 2019-05-30 14:06:06 +00:00
dependabot-preview[bot]
cf08d1ff24
Bump mockito-core from 2.28.1 to 2.28.2 (#387) 2019-05-30 13:58:42 +00:00
dependabot-preview[bot]
96c400a0bd
Bump runner from 1.1.1 to 1.2.0 (#386) 2019-05-30 13:50:28 +00:00
dependabot-preview[bot]
e238f65dde Bump rxjava from 2.2.8 to 2.2.9 (#381) 2019-05-30 15:22:15 +02:00
dependabot-preview[bot]
ba7966125b
Bump dagger-compiler from 2.22.1 to 2.23 (#380) 2019-05-30 12:01:15 +00:00
dependabot-preview[bot]
1536208e45
Bump core from 1.1.0 to 1.2.0 (#383) 2019-05-30 11:46:56 +00:00
dependabot-preview[bot]
24cc07264a
Bump dagger-android-support from 2.22.1 to 2.23 (#384) 2019-05-30 11:31:22 +00:00
dependabot-preview[bot]
1ad5232520
Bump mockito-inline from 2.28.1 to 2.28.2 (#382) 2019-05-30 11:29:13 +00:00
dependabot-preview[bot]
07f3333029
Bump mockito-android from 2.28.1 to 2.28.2 (#379) 2019-05-30 11:12:44 +00:00
dependabot-preview[bot]
214afb82a6
Bump junit from 1.1.0 to 1.1.1 (#378) 2019-05-30 11:05:05 +00:00
dependabot-preview[bot]
7a69710261
Bump dagger-android-processor from 2.22.1 to 2.23 (#376) 2019-05-30 10:54:26 +00:00
dependabot-preview[bot]
64d3afbdb3
Bump room-compiler from 2.1.0-beta01 to 2.1.0-rc01 (#375) 2019-05-30 10:53:35 +00:00
dependabot-preview[bot]
387e46f72d
Bump mockito-inline from 2.27.5 to 2.28.1 (#372) 2019-05-29 00:16:10 +00:00
dependabot-preview[bot]
89acc2f384
Bump mockito-android from 2.27.5 to 2.28.1 (#373) 2019-05-28 23:59:19 +00:00
dependabot-preview[bot]
4ef1439878 Bump mockito-core from 2.27.2 to 2.28.1 (#371) 2019-05-29 01:57:19 +02:00
dependabot-preview[bot]
6efd170e03
Bump mockito-inline from 2.27.0 to 2.27.5 (#367) 2019-05-28 14:57:39 +00:00
dependabot-preview[bot]
82cd39329a
Bump mockito-android from 2.27.0 to 2.27.5 (#354) 2019-05-28 14:22:24 +00:00
dependabot-preview[bot]
b38e0d04e7 Bump threetenbp from 1.3.8 to 1.4.0 (#366) 2019-05-28 14:41:48 +02:00
dependabot-preview[bot]
90b2ffe250 Bump logging-interceptor from 3.12.1 to 3.12.3 (#369)
Bumps logging-interceptor from 3.12.1 to 3.12.3.
2019-05-28 14:41:27 +02:00
dependabot-preview[bot]
33951dff54
Bump crashlytics from 2.9.9 to 2.10.1 (#365) 2019-05-28 11:30:42 +00:00
dependabot-preview[bot]
9ced00c4d7
Bump room-runtime from 2.1.0-alpha07 to 2.1.0-beta01 (#364) 2019-05-28 11:06:56 +00:00
dependabot-preview[bot]
2ac1638911
Bump room-testing from 2.1.0-alpha07 to 2.1.0-beta01 (#363) 2019-05-28 10:48:37 +00:00
dependabot-preview[bot]
463a7e2744 Bump gradle from 1.28.1 to 1.29.0 (#355)
Bumps gradle from 1.28.1 to 1.29.0.
2019-05-28 02:24:36 +02:00
dependabot-preview[bot]
d14382f3b4 Bump firebase-core from 16.0.8 to 16.0.9 (#358)
Bumps firebase-core from 16.0.8 to 16.0.9.
2019-05-28 00:58:09 +02:00
dependabot-preview[bot]
efa0b19cc1 Bump room-rxjava2 from 2.1.0-alpha07 to 2.1.0-beta01 (#357)
Bumps room-rxjava2 from 2.1.0-alpha07 to 2.1.0-beta01.
2019-05-28 00:39:12 +02:00
dependabot-preview[bot]
7cb893a254 Bump play-publisher from 2.2.0 to 2.2.1 (#356)
Bumps play-publisher from 2.2.0 to 2.2.1.
2019-05-28 00:37:06 +02:00
dependabot-preview[bot]
f7371f7b73 Bump room-compiler from 2.1.0-alpha07 to 2.1.0-beta01 (#350)
Bumps room-compiler from 2.1.0-alpha07 to 2.1.0-beta01.
2019-05-27 23:04:12 +02:00
dependabot-preview[bot]
9c626ad517 Bump reactivenetwork-rx2 from 3.0.2 to 3.0.3 (#351)
Bumps [reactivenetwork-rx2](https://github.com/pwittchen/ReactiveNetwork) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/pwittchen/ReactiveNetwork/releases)
- [Changelog](https://github.com/pwittchen/ReactiveNetwork/blob/RxJava2.x/CHANGELOG.md)
- [Commits](https://github.com/pwittchen/ReactiveNetwork/commits)
2019-05-27 22:58:17 +02:00
dependabot-preview[bot]
9c4c6b0192 Bump material from 1.1.0-alpha05 to 1.1.0-alpha06 (#353)
Bumps [material](https://github.com/material-components/material-components-android) from 1.1.0-alpha05 to 1.1.0-alpha06.
- [Release notes](https://github.com/material-components/material-components-android/releases)
- [Commits](https://github.com/material-components/material-components-android/compare/1.1.0-alpha05...1.1.0-alpha06)
2019-05-27 22:49:16 +02:00
dependabot-preview[bot]
8efc4d750d Bump sonarqube-gradle-plugin from 2.7 to 2.7.1 (#352)
Bumps sonarqube-gradle-plugin from 2.7 to 2.7.1.
2019-05-27 22:41:16 +02:00
Mikołaj Pich
e4a6caa13e
Version 0.8.4 2019-05-27 18:13:20 +02:00
Mikołaj Pich
209e75160a Fix network constraint in background sync (#348) 2019-05-25 14:34:17 +02:00
Mikołaj Pich
153e026a8d
Version 0.8.3 2019-05-20 00:21:30 +02:00
Mikołaj Pich
8731c2e1f2 Change help text when entering the symbol to a more precise one (#345) 2019-05-19 22:47:57 +02:00
Rafał Borcz
0977282a4b Fix no current student in services after logout all accounts (#342) 2019-05-18 23:42:47 +02:00
Rafał Borcz
667c4b6af7 Fix empty maybe when loading message content (#343) 2019-05-18 23:32:37 +02:00
Mikołaj Pich
1f5088cfc9 Don't copy teacher from previous lesson to completed (#341) 2019-05-18 13:03:38 +02:00
Rafał Borcz
bf6b857a3e Fix null returns in widgets (#340) 2019-05-18 00:22:07 +02:00
Mikołaj Pich
80cb94c434
Version 0.8.2 2019-05-15 19:26:25 +02:00
Rafał Borcz
0cb4eda32b Fix crash on reselecting fragment (#339) 2019-05-15 15:11:28 +02:00
Rafał Borcz
d169f964f2 Fix crash when no webview activity (#338) 2019-05-14 11:45:27 +02:00
Rafał Borcz
103ab95c80 Fix not attached fragment (#337)
* Add condition for error dialog
* Add safe call of forEach in LuckyNumberWidgetProvider
2019-05-09 22:06:11 +02:00
Mikołaj Pich
a191f03cdf
Version 0.8.1 2019-04-30 23:56:22 +02:00
Mikołaj Pich
63404b8576 Fix entity list comparing (#335) 2019-04-30 19:04:05 +02:00
Rafał Borcz
1b7760ff88 Fix dark theme background with custom theme engine (#334) 2019-04-30 17:45:37 +02:00
Rafał Borcz
24f58835e7 Fix menu view initialization and restoration (#333) 2019-04-30 17:28:09 +02:00
Mikołaj Pich
b032c459d1 Fix theme on release build (#332) 2019-04-30 11:16:23 +02:00
Mikołaj Pich
df0a1e59cc
Version 0.8.0 2019-04-29 20:39:35 +02:00
Kacper Ziubryniewicz
dbbc8069b1 Add showing proper fragment in notifications (#331) 2019-04-29 19:56:23 +02:00
Mikołaj Pich
f84040109c Add lucky number widget (#292) 2019-04-29 14:33:33 +02:00
Dominik Korsa
baf1420193 Improve login student selection layout (#329) 2019-04-29 00:55:30 +02:00
Rafał Borcz
4a36d78709 Add activity and fragment lifecycle logging (#327) 2019-04-26 23:53:02 +02:00
Rafał Borcz
4464812651 Fix configure activity's theme (#325) 2019-04-22 09:27:25 +02:00
Rafał Borcz
72a35481e5 Fix showing last message after update (#326) 2019-04-22 09:13:26 +02:00
Mikołaj Pich
017c200115 Fix grade summary final grade string (#324) 2019-04-20 22:19:06 +02:00
Mikołaj Pich
2bf7755157 Add AMOLED mode (#279) 2019-04-19 23:52:34 +02:00
Rafał Borcz
269af4b7ba Update dependencies (#323) 2019-04-18 16:38:49 +02:00
Rafał Borcz
7431738366 Add a selection of multiple students to login (#318) 2019-04-18 12:18:58 +02:00
Rafał Borcz
034b99c7ab Add counting of the full-year average to the summary of grades (#322) 2019-04-18 00:32:43 +02:00
Rafał Borcz
74e98e4430 Change style of privacy policy link (#321) 2019-04-09 23:33:53 +02:00
Mikołaj Pich
cbf3215dd1
Merge branch '0.7.x' 2019-04-08 13:51:02 +02:00
Rafał Borcz
c18877466f Add account picker for timetable widget (#314)
Close #281
2019-04-08 00:18:45 +02:00
Mikołaj Pich
6cd6cae1e0
Version 0.7.6 2019-04-07 11:08:46 +02:00
Mikołaj Pich
333f7bfa16
Add privacy policy link (#320) 2019-04-07 10:59:27 +02:00
Mikołaj Pich
aa6dcaff94
Merge branch '0.7.x' 2019-04-06 01:18:03 +02:00
Mikołaj Pich
f2fa04105d
Version 0.7.5 2019-04-06 01:06:11 +02:00
Mikołaj Pich
7d97d71066 Fix message loading if student and parent are logged in (#319)
Fixes #316
2019-04-05 19:35:21 +02:00
Mikołaj Pich
8daea5c900 Add class name to student (#315) 2019-04-04 13:00:07 +02:00
Kacper Ziubryniewicz
2bff468e56 Add deleting messages (#290) 2019-03-31 22:01:04 +02:00
Mikołaj Pich
f2855d598d
Merge branch '0.7.x' 2019-03-30 20:19:34 +01:00
Mikołaj Pich
297a2909ba Version 0.7.4 2019-03-30 19:45:57 +01:00
Rafał Borcz
935bec3f5b Add 0,75 grade modifier (#313) 2019-03-30 19:26:19 +01:00
Mikołaj Pich
e71dd55066 Fix more than one current semester (#307) 2019-03-30 18:28:37 +01:00
Rafał Borcz
4e3864f26f Add opening login view on no current student (#312) 2019-03-30 09:31:30 +01:00
Rafał Borcz
8601093725 Again fix rejected execution in sync worker (#310) 2019-03-28 23:30:30 +01:00
Rafał Borcz
b97b94ae29 Fix more than one current student (#311)
Fix #309
2019-03-28 23:07:59 +01:00
Rafał Borcz
c6c7357623 Fix black spinner in login form (#308) 2019-03-28 18:27:17 +01:00
Mikołaj Pich
1ebc296bfe
Merge branch '0.7.x' 2019-03-26 21:22:17 +01:00
Mikołaj Pich
c2ab53cfeb
Version 0.7.3 2019-03-26 19:46:59 +01:00
Rafał Borcz
87268b3ef6 Fix rejected execution in sync worker (#305) 2019-03-26 16:47:14 +01:00
Rafał Borcz
b3cd7e8ac1 Fix undeliverable network exceptions (#306)
* Remove unnecessary this
2019-03-26 14:32:23 +01:00
Mikołaj Pich
a2a18e5652
Merge branch '0.7.x' 2019-03-24 23:22:44 +01:00
Mikołaj Pich
5a997dacb7
Version 0.7.2 2019-03-24 22:42:09 +01:00
Rafał Borcz
ed9458d9a5 Fix more than one current semester in database (#304) 2019-03-24 20:21:05 +01:00
Mikołaj Pich
3656d3161f Fix crash on duplicate items (#303) 2019-03-24 17:31:39 +01:00
Rafał Borcz
d178c15d2f Update dependencies (#302) 2019-03-24 16:03:51 +01:00
Rafał Borcz
1f65b8465e Add logging to sync worker (#300) 2019-03-23 18:35:56 +01:00
Mikołaj Pich
6bb03b3be8 Fix day navigation unevenition (#301) 2019-03-23 17:29:34 +01:00
Rafał Borcz
68b9847927 Fix reselecting root fragments (#299) 2019-03-23 16:35:33 +01:00
Rafał Borcz
e1a83927c4 Fix reset button in timetable widget (#298) 2019-03-23 14:44:52 +01:00
Mikołaj Pich
fc9981aa5d Fix issues when loading lucky number (#297) 2019-03-23 13:01:01 +01:00
Rafał Borcz
2d6610e05c Set max concurrency in sync worker (#296) 2019-03-23 01:12:17 +01:00
Rafał Borcz
316cd2f7f9 Add checking current student in background services (#295) 2019-03-23 00:37:13 +01:00
Rafał Borcz
36785f019a Fix restoring the grade fragment (#293) 2019-03-22 23:54:58 +01:00
Rafał Borcz
4b78862486 Remove retry sync work when completed lessons is disabled (#294) 2019-03-22 23:41:41 +01:00
Kacper Ziubryniewicz
cd1ceea860 Add messages forwarding (#288) 2019-03-21 22:55:47 +01:00
Rafał Borcz
20d0abba29 Fix empty container id in grade fragemnt adapter (#289) 2019-03-21 22:34:41 +01:00
Mikołaj Pich
5add95ece1
Version 0.7.1 2019-03-20 21:02:09 +01:00
Rafał Borcz
575e244b3a Add swipe refresh to grade fragment (#287) 2019-03-20 20:45:26 +01:00
Rafał Borcz
8db73e9459 Fix the application finish after selecting an account (#286) 2019-03-19 18:14:55 +01:00
Mikołaj Pich
040857ba20 Change grade weightValue type to double (#285) 2019-03-19 13:23:52 +01:00
Mikołaj Pich
4b0f0de52c
Version 0.7.0 2019-03-17 21:20:37 +01:00
Kacper Ziubryniewicz
ba76453e45 Add replying to messages (#263) 2019-03-17 21:02:41 +01:00
Dominik Korsa
824ed3f282 Centre the login form (#283) 2019-03-17 19:57:25 +01:00
Mikołaj Pich
d27d069ce2 Change homework view to weekly (#284) 2019-03-17 00:17:16 +01:00
Mikołaj Pich
38aa26a3ff Add homepage button in about fragment (#280) 2019-03-16 14:22:51 +01:00
Rafał Borcz
be807cb6c8 Change settings for checking the internet connection (#282) 2019-03-15 21:33:14 +01:00
Mikołaj Pich
35f1fe8d61 Follow current grade scheme in stats chart (#277) 2019-03-12 17:34:04 +01:00
Mikołaj Pich
2621e5680d Improve the display of changes in the timetable (#275)
Closes #264
2019-03-11 20:56:47 +01:00
Rafał Borcz
475e7dd6a3 Update dependencies (#274) 2019-03-10 20:18:40 +01:00
Mikołaj Pich
feb38b97e4 Change login progress bars (#272) 2019-03-10 11:57:11 +01:00
Mikołaj Pich
f773310cdb Disable swipe to refresh on data loading (#270) 2019-03-09 21:40:20 +01:00
Rafał Borcz
f21feabc49 Add debug notification for worker (#271) 2019-03-09 20:34:30 +01:00
Mikołaj Pich
ca23f92096 Add missing text when no grade description (#269) 2019-03-09 17:16:30 +01:00
Rafał Borcz
919680c766 Migration to WorkManager (#254)
Closes #241
2019-03-09 10:13:36 +01:00
Rafał Borcz
722f8d691a Fix timetable widget automatic day switching (#267) 2019-03-07 16:38:34 +01:00
Mikołaj Pich
4f0021919c Fix grade stats loading issues (#266) 2019-03-07 13:08:59 +01:00
Mikołaj Pich
1b7db4bfbb Mitigate disappearing room numbers in timetable (#265) 2019-03-07 13:08:11 +01:00
Mikołaj Pich
dcab8df4b9 Add grade statistics (#251) 2019-03-04 12:13:37 +01:00
Mikołaj Pich
cae4f140e6 Add option to change grade (background) color scheme (#259) 2019-03-03 15:11:20 +01:00
Dominik Korsa
1b30b00bb8 Settings rename view section (#262) 2019-03-02 19:55:32 +01:00
Dominik Korsa
514d1e11aa Update grade colors (#231) 2019-03-02 19:41:38 +01:00
Dominik Korsa
66bd566526 Update login error message (#260) 2019-03-02 19:18:26 +01:00
Mikołaj Pich
e910c7a48e Mitigate notifications from old grades (#258)
Fixes #257
2019-03-02 19:15:37 +01:00
Kacper Ziubryniewicz
f8ee5cb062 Add lucky number logging (#256) 2019-02-24 19:23:03 +01:00
Kacper Ziubryniewicz
c72c301039 Add sending messages (#232) 2019-02-24 15:11:32 +01:00
Mikołaj Pich
5ba12cf8c6 Fill login credentials with default values upon fakelog selection (#255)
Resolves #245
2019-02-23 14:39:22 +01:00
Mikołaj Pich
82d7cf94e8 Mark as read items older than student registration date (#253) 2019-02-20 15:34:24 +01:00
Dominik Korsa
c365564a77 Login form style fix (#252) 2019-02-17 19:15:26 +01:00
Rafał Borcz
5526691cb6 Fix timetable widget crash on update (#250) 2019-02-17 17:32:22 +01:00
Dominik Korsa
1d7585071d Update login form to Material Design 2 (#229) 2019-02-17 00:42:09 +01:00
Mikołaj Pich
11b6c00e4a Entities unification (#248)
* Remove default entieties params

* Change var to vals

* Fix indent in data classes

* Change message unread to val

* Make all fields in Message non-nullable

* Add destructive db migrations #246

* Fix password decrypting

* Fix tests

* Fix student logout

* Use orEmpty() on nullable strings

* Use var in Student password and Message unread
2019-02-16 21:20:23 +01:00
Mikołaj Pich
c56cfec564 Apply ripple effect on grade details header only if item is expandable (#239)
Resolves #234
2019-02-14 22:23:52 +01:00
Mikołaj Pich
f305a7a599 Sort repositories (#244) 2019-02-13 21:44:40 +01:00
Rafał Borcz
ad9b6d42f0 Fix no current student (#243) 2019-02-13 20:49:19 +01:00
Mikołaj Pich
297502056c Add completed lessons (#236) 2019-02-13 19:21:27 +01:00
Kacper Ziubryniewicz
52ed7dcb6c Fix lucky number crash (#242) 2019-02-13 14:10:21 +01:00
Rafał Borcz
9fcf245ecd Fix uninitialized fragment after restoring the activity (#237) 2019-02-12 00:41:02 +01:00
Rafał Borcz
1b1f2ae3bb Split login form for two fragments (#230) 2019-02-11 02:04:24 +01:00
Kacper Ziubryniewicz
2f87779647 Add Firebase Analytics for the loaded lucky number (#233) 2019-02-05 18:18:49 +01:00
Mikołaj Pich
79093ca6f2
Merge branch '0.6.x' 2019-01-26 00:04:11 +01:00
Mikołaj Pich
7f162441e2
Version 0.6.6 2019-01-25 22:12:19 +01:00
Kacper Ziubryniewicz
4da812af39 Add lucky numbers (#216) 2019-01-25 20:54:27 +01:00
Mikołaj Pich
43f6048c27 Upgrade to Gradle Play Publisher v2 (#228) 2019-01-25 20:41:03 +01:00
Rafał Borcz
ffc2ef9a4e Remove renaming source file in R8 (#227) 2019-01-25 19:20:13 +01:00
Rafał Borcz
d3c13b8fc3 Fix empty fragment list in fragment manager (#226) 2019-01-24 21:16:22 +01:00
Kacper Ziubryniewicz
c78fb83774 Fix receiving a lot of notifications after turning them off for a while (#225) 2019-01-24 18:32:51 +01:00
Rafał Borcz
941765a3a3 Fix empty Maybe in student repository (#224) 2019-01-23 18:28:51 +01:00
Mikołaj Pich
189830e0f4
Version 0.6.5 2019-01-20 23:38:02 +01:00
Mikołaj Pich
2061d6408f
Change icon of semester switch (#223) 2019-01-20 23:36:16 +01:00
Rafał Borcz
e29886560e Disable obfuscate in R8 (#222) 2019-01-20 22:43:50 +01:00
Mikołaj Pich
20d9313257
Version 0.6.4 2019-01-20 15:39:11 +01:00
Rafał Borcz
8476f0e62e Update dependencies (#221) 2019-01-20 15:00:33 +01:00
Rafał Borcz
a174ae998d Add api initialization to the message repository (#220) 2019-01-20 14:16:24 +01:00
Rafał Borcz
c5bab52fa2 Add more logging (#219) 2019-01-19 23:15:14 +01:00
Rafał Borcz
e6d60e670e Fix crash on duplicate notes (#218) 2019-01-18 19:10:14 +01:00
Dominik Korsa
c0ddd82e03 Fix exam_no_items english translation (#217)
Changed `exam_no_items` from **No exams in this week** to **No exams this week**
2019-01-18 12:41:11 +01:00
Rafał Borcz
28f1430be0 Fix crash on Meizu devices (#215) 2019-01-13 23:53:01 +01:00
Rafał Borcz
840b21a213 Fix dialog state (#214) 2019-01-13 23:25:07 +01:00
465 changed files with 19675 additions and 3534 deletions

View file

@ -7,11 +7,11 @@ references:
container_config: &container_config container_config: &container_config
docker: docker:
- image: circleci/android:api-28-alpha - image: circleci/android@sha256:5cdc8626cc6f13efe5ed982cdcdb432b0472f8740fed8743a6461e025ad6cdfc
working_directory: *workspace_root working_directory: *workspace_root
environment: environment:
environment: environment:
JVM_OPTS: -Xmx3200m _JAVA_OPTS: -Xmx3072m
attach_workspace: &attach_workspace attach_workspace: &attach_workspace
attach_workspace: attach_workspace:
@ -35,7 +35,7 @@ jobs:
command: ./gradlew dependencies --no-daemon --stacktrace --console=plain -PdisablePreDex || true command: ./gradlew dependencies --no-daemon --stacktrace --console=plain -PdisablePreDex || true
- run: - run:
name: Initial build name: Initial build
command: ./gradlew build -x test -x lint -x fabricGenerateResourcesRelease -x packageRelease --no-daemon --stacktrace --console=plain -PdisablePreDex command: ./gradlew build -x test -x lint -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease -x packageRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
- run: - run:
name: Run FOSSA name: Run FOSSA
command: fossa --no-ansi || true command: fossa --no-ansi || true
@ -56,7 +56,7 @@ jobs:
<<: *general_cache_key <<: *general_cache_key
- run: - run:
name: Run lint name: Run lint
command: ./gradlew lint -x fabricGenerateResourcesRelease --no-daemon --stacktrace --console=plain -PdisablePreDex command: ./gradlew lint -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
- store_artifacts: - store_artifacts:
path: ./app/build/reports/ path: ./app/build/reports/
destination: lint_reports/app/ destination: lint_reports/app/
@ -75,7 +75,7 @@ jobs:
<<: *general_cache_key <<: *general_cache_key
- run: - run:
name: Run app tests name: Run app tests
command: ./gradlew :app:test :app:jacocoTestReport -x fabricGenerateResourcesRelease --no-daemon --stacktrace --console=plain -PdisablePreDex command: ./gradlew :app:test :app:jacocoTestReport -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease --no-daemon --stacktrace --console=plain -PdisablePreDex
- run: - run:
name: Upload unit code coverage to codecov name: Upload unit code coverage to codecov
command: bash <(curl -s https://codecov.io/bash) -F app command: bash <(curl -s https://codecov.io/bash) -F app
@ -93,6 +93,9 @@ jobs:
<<: *container_config <<: *container_config
steps: steps:
- *attach_workspace - *attach_workspace
- run:
name: Accept licenses
command: yes | sdkmanager --licenses && yes | sdkmanager --update
- run: - run:
name: Setup emulator name: Setup emulator
command: sdkmanager "system-images;android-19;default;armeabi-v7a" && echo "no" | avdmanager create avd -n test -k "system-images;android-19;default;armeabi-v7a" command: sdkmanager "system-images;android-19;default;armeabi-v7a" && echo "no" | avdmanager create avd -n test -k "system-images;android-19;default;armeabi-v7a"
@ -113,7 +116,7 @@ jobs:
adb shell input keyevent 82 adb shell input keyevent 82
- run: - run:
name: Run instrumented tests name: Run instrumented tests
command: ./gradlew clean createDebugCoverageReport jacocoTestReport --no-daemon --stacktrace --console=plain -PdisablePreDex command: ./gradlew clean createPlayDebugCoverageReport jacocoTestReport --no-daemon --stacktrace --console=plain -PdisablePreDex
- run: - run:
name: Collect logs from emulator name: Collect logs from emulator
command: adb logcat -d > ./app/build/reports/logcat_emulator.txt command: adb logcat -d > ./app/build/reports/logcat_emulator.txt
@ -159,7 +162,7 @@ jobs:
openssl aes-256-cbc -d -in ./app/upload-key-encrypted.jks -k $ENCRYPT_KEY >> ./app/upload-key.jks openssl aes-256-cbc -d -in ./app/upload-key-encrypted.jks -k $ENCRYPT_KEY >> ./app/upload-key.jks
- run: - run:
name: Publish release name: Publish release
command: ./gradlew publishRelease --no-daemon --stacktrace --console=plain -PenableCrashlytics -PdisablePreDex command: ./gradlew publishPlayRelease --no-daemon --stacktrace --console=plain -PenableCrashlytics -PdisablePreDex
workflows: workflows:
version: 2 version: 2

1
.gitignore vendored
View file

@ -48,3 +48,4 @@ app/key.p12
app/upload-key.jks app/upload-key.jks
*.log *.log
.idea/assetWizardSettings.xml .idea/assetWizardSettings.xml
.idea/uiDesigner.xml

View file

@ -12,7 +12,7 @@ build:
script: script:
- ./gradlew --no-daemon --stacktrace dependencies || true - ./gradlew --no-daemon --stacktrace dependencies || true
- ./gradlew --no-daemon --stacktrace assembleDebug - ./gradlew --no-daemon --stacktrace assembleDebug
- mv app/build/outputs/apk/debug/app-debug.apk . - mv app/build/outputs/apk/fdroid/debug/app-fdroid-debug.apk .
artifacts: artifacts:
name: "${CI_PROJECT_NAME}_${CI_BUILD_REF_NAME}-${CI_BUILD_ID}" name: "${CI_PROJECT_NAME}_${CI_BUILD_REF_NAME}-${CI_BUILD_ID}"
paths: paths:
@ -26,7 +26,7 @@ tests:
- .gradle - .gradle
policy: pull policy: pull
script: script:
- ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesRelease test - ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease test
artifacts: artifacts:
paths: paths:
- app/build/reports/tests - app/build/reports/tests
@ -39,7 +39,7 @@ lint:
- .gradle - .gradle
policy: pull policy: pull
script: script:
- ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesRelease lint - ./gradlew --no-daemon --stacktrace -x fabricGenerateResourcesFdroidRelease -x fabricGenerateResourcesPlayRelease lint
artifacts: artifacts:
paths: paths:
- app/build/reports - app/build/reports

View file

@ -19,33 +19,8 @@
<option name="CONTINUATION_INDENT_IN_SUPERTYPE_LISTS" value="false" /> <option name="CONTINUATION_INDENT_IN_SUPERTYPE_LISTS" value="false" />
<option name="CONTINUATION_INDENT_IN_IF_CONDITIONS" value="false" /> <option name="CONTINUATION_INDENT_IN_IF_CONDITIONS" value="false" />
<option name="CONTINUATION_INDENT_IN_ELVIS" value="false" /> <option name="CONTINUATION_INDENT_IN_ELVIS" value="false" />
<option name="WRAP_EXPRESSION_BODY_FUNCTIONS" value="1" /> <option name="WRAP_ELVIS_EXPRESSIONS" value="0" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
<XML> <XML>
<option name="XML_KEEP_LINE_BREAKS" value="false" /> <option name="XML_KEEP_LINE_BREAKS" value="false" />
<option name="XML_ALIGN_ATTRIBUTES" value="false" /> <option name="XML_ALIGN_ATTRIBUTES" value="false" />

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

View file

@ -11,6 +11,10 @@ cache:
- $HOME/.gradle/caches/ - $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/ - $HOME/.gradle/wrapper/
#branches:
# only:
# - develop
android: android:
licenses: licenses:
- android-sdk-preview-license-.+ - android-sdk-preview-license-.+
@ -41,22 +45,22 @@ before_script:
- "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | sudo bash" - "curl -H 'Cache-Control: no-cache' https://raw.githubusercontent.com/fossas/fossa-cli/master/install.sh | sudo bash"
script: script:
- ./gradlew build -x test -x lint -x fabricGenerateResourcesRelease -x packageRelease --stacktrace --daemon - ./gradlew dependencies --stacktrace --daemon
- fossa --no-ansi || true - fossa --no-ansi || true
- ./gradlew lint -x fabricGenerateResourcesRelease --stacktrace --daemon #- ./gradlew lintPlayRelease -x fabricGenerateResourcesPlayRelease --stacktrace --daemon
- ./gradlew test -x fabricGenerateResourcesRelease --stacktrace --daemon - ./gradlew testPlayDebugUnitTest -x fabricGenerateResourcesPlay --stacktrace --daemon
- ./gradlew createDebugCoverageReport --stacktrace --daemon - ./gradlew createPlayDebugCoverageReport --stacktrace --daemon
- ./gradlew jacocoTestReport --stacktrace --daemon - ./gradlew jacocoTestReport --stacktrace --daemon
- if [ -z ${SONAR_HOST+x} ]; then echo "sonar scan skipped"; else - if [ -z ${SONAR_HOST+x} ]; then echo "sonar scan skipped"; else
git fetch --unshallow; git fetch --unshallow;
./gradlew sonarqube -x test -x lint -x fabricGenerateResourcesRelease -Dsonar.host.url=$SONAR_HOST -Dsonar.organization=$SONAR_ORG -Dsonar.login=$SONAR_KEY -Dsonar.branch.name=${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} --stacktrace --daemon; ./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 fi
- | - |
if [ $TRAVIS_TAG ]; then if [ $TRAVIS_TAG ]; then
gpg --yes --batch --passphrase=$SERVICES_ENCRYPT_KEY ./app/src/release/google-services.json.gpg; 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/key.p12.gpg;
gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg; gpg --yes --batch --passphrase=$ENCRYPT_KEY ./app/upload-key.jks.gpg;
./gradlew publishRelease -PenableCrashlytics --stacktrace; ./gradlew publishPlayRelease -PenableCrashlytics --stacktrace;
fi fi
after_success: after_success:

View file

@ -1,17 +1,18 @@
# Wulkanowy # Wulkanowy
[![CircleCI](https://img.shields.io/circleci/project/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://circleci.com/gh/wulkanowy/wulkanowy)
[![Travis](https://img.shields.io/travis/com/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://travis-ci.com/wulkanowy/wulkanowy) [![Travis](https://img.shields.io/travis/com/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://travis-ci.com/wulkanowy/wulkanowy)
[![Bitrise](https://img.shields.io/bitrise/daeff1893f3c8128/master.svg?token=Hjm1ACamk86JDeVVJHOeqQ&style=flat-square)](https://www.bitrise.io/app/daeff1893f3c8128) [![Bitrise](https://img.shields.io/bitrise/daeff1893f3c8128/master.svg?token=Hjm1ACamk86JDeVVJHOeqQ&style=flat-square)](https://www.bitrise.io/app/daeff1893f3c8128)
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
[![BCH compliance](https://bettercodehub.com/edge/badge/wulkanowy/wulkanowy?branch=master)](https://bettercodehub.com/) [![BCH compliance](https://bettercodehub.com/edge/badge/wulkanowy/wulkanowy?branch=master)](https://bettercodehub.com/)
[![Sonarcloud](https://sonarcloud.io/api/project_badges/measure?project=io.github.wulkanowy%3Aapp&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=io.github.wulkanowy%3Aapp) [![Sonarcloud](https://sonarcloud.io/api/project_badges/measure?project=io.github.wulkanowy%3Aapp&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=io.github.wulkanowy%3Aapp)
[![FOSSA Status](https://app.fossa.io/api/projects/custom%2B5644%2Fgit%40github.com%3Awulkanowy%2Fwulkanowy.git.svg?type=shield)](https://app.fossa.io/projects/custom%2B5644%2Fgit%40github.com%3Awulkanowy%2Fwulkanowy.git?ref=badge_shield) [![FOSSA Status](https://app.fossa.com/api/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy.svg?type=shield)](https://app.fossa.com/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy?ref=badge_shield)
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr) [![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/vccAQBr)
[![F-Droid](https://img.shields.io/f-droid/v/io.github.wulkanowy.svg)](https://f-droid.org/packages/io.github.wulkanowy/)
[![Last release](https://img.shields.io/github/release/wulkanowy/wulkanowy.svg?logo=github)](https://github.com/wulkanowy/wulkanowy/releases)
[Pobierz wersję beta z Google Play](https://play.google.com/store/apps/details?id=io.github.wulkanowy&amp;utm_source=vcs) [Pobierz wersję beta z Google Play](https://play.google.com/store/apps/details?id=io.github.wulkanowy&amp;utm_source=vcs)
[Pobierz wersję DEV](https://bitrise-redirector.herokuapp.com/v0.1/apps/daeff1893f3c8128/builds/master/artifacts/0) [Pobierz wersję DEV](https://bitrise-redirector.herokuapp.com/v0.1/apps/f841f20d8f8b1dc8/builds/master/artifacts/0)
[(Więcej wersji DEV)](https://wulkanowy.github.io/dev.html) [(Więcej wersji DEV)](https://wulkanowy.github.io/dev.html)
Androidowy klient dziennika VULCAN UONET+. Androidowy klient dziennika VULCAN UONET+.
@ -19,4 +20,4 @@ Androidowy klient dziennika VULCAN UONET+.
## License ## License
[![FOSSA Status](https://app.fossa.io/api/projects/custom%2B5644%2Fgit%40github.com%3Awulkanowy%2Fwulkanowy.git.svg?type=large)](https://app.fossa.io/projects/custom%2B5644%2Fgit%40github.com%3Awulkanowy%2Fwulkanowy.git?ref=badge_large) [![FOSSA Status](https://app.fossa.com/api/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy.svg?type=large)](https://app.fossa.com/projects/custom%2B5644%2Fgithub.com%2Fwulkanowy%2Fwulkanowy?ref=badge_large)

View file

@ -6,33 +6,35 @@ apply plugin: 'io.fabric'
apply plugin: 'com.github.triplet.play' apply plugin: 'com.github.triplet.play'
apply from: 'jacoco.gradle' apply from: 'jacoco.gradle'
apply from: 'sonarqube.gradle' apply from: 'sonarqube.gradle'
apply from: 'hooks.gradle'
android { android {
compileSdkVersion 28 compileSdkVersion 28
buildToolsVersion '28.0.3' buildToolsVersion '28.0.3'
playAccountConfigs {
defaultAccountConfig {
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL")
pk12File = file('key.p12')
}
}
defaultConfig { defaultConfig {
applicationId "io.github.wulkanowy" applicationId "io.github.wulkanowy"
testApplicationId "io.github.tests.wulkanowy" testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 28 targetSdkVersion 28
versionCode 22 versionCode 39
versionName "0.6.3" versionName "0.9.1"
multiDexEnabled true multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
playAccountConfig = playAccountConfigs.defaultAccountConfig
manifestPlaceholders = [ manifestPlaceholders = [
fabric_api_key: System.getenv("FABRIC_API_KEY") ?: "null", fabric_api_key : System.getenv("FABRIC_API_KEY") ?: "null",
crashlytics_enabled: project.hasProperty("enableCrashlytics") crashlytics_enabled: project.hasProperty("enableCrashlytics")
] ]
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
} }
signingConfigs { signingConfigs {
@ -48,7 +50,6 @@ android {
release { release {
buildConfigField "boolean", "CRASHLYTICS_ENABLED", "true" buildConfigField "boolean", "CRASHLYTICS_ENABLED", "true"
minifyEnabled true minifyEnabled true
useProguard false
shrinkResources true shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release signingConfig signingConfigs.release
@ -63,9 +64,26 @@ android {
} }
} }
flavorDimensions "platform"
productFlavors {
play {
dimension "platform"
}
fdroid {
buildConfigField "boolean", "CRASHLYTICS_ENABLED", "false"
dimension "platform"
}
}
lintOptions { lintOptions {
disable 'HardwareIds' disable 'HardwareIds'
} }
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
} }
androidExtensions { androidExtensions {
@ -73,66 +91,83 @@ androidExtensions {
} }
play { play {
serviceAccountEmail = System.getenv("PLAY_SERVICE_ACCOUNT_EMAIL") ?: "jan@fakelog.cf"
serviceAccountCredentials = file('key.p12')
defaultToAppBundles = false
track = 'alpha' track = 'alpha'
uploadImages = false
} }
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation 'io.github.wulkanowy:api:0.9.1'
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation('io.github.wulkanowy:api:0.6.3') { exclude module: "threetenbp" }
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "androidx.legacy:legacy-support-v4:1.0.0" implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation "androidx.appcompat:appcompat:1.0.2" implementation "androidx.appcompat:appcompat:1.0.2"
implementation "androidx.cardview:cardview:1.0.0"
implementation "com.google.android.material:material:1.0.0"
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'com.takisoft.preferencex:preferencex:1.0.0' implementation "androidx.cardview:cardview:1.0.0"
implementation "com.mikepenz:aboutlibraries:6.2.0" implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "com.firebase:firebase-jobdispatcher:0.8.5" implementation "com.google.android.material:material:1.1.0-alpha05"
implementation 'com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f'
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
implementation "com.google.dagger:dagger-android-support:2.19" implementation "androidx.work:work-runtime:2.0.1"
kapt "com.google.dagger:dagger-compiler:2.19" implementation "androidx.work:work-rxjava2:2.0.1"
kapt "com.google.dagger:dagger-android-processor:2.19"
implementation "androidx.room:room-runtime:2.1.0-alpha03" implementation "androidx.room:room-runtime:2.1.0-rc01"
implementation "androidx.room:room-rxjava2:2.1.0-alpha03" implementation "androidx.room:room-rxjava2:2.1.0-rc01"
kapt "androidx.room:room-compiler:2.1.0-alpha03" kapt "androidx.room:room-compiler:2.1.0-rc01"
implementation "com.google.dagger:dagger-android-support:2.23.1"
kapt "com.google.dagger:dagger-compiler:2.23.1"
kapt "com.google.dagger:dagger-android-processor:2.23.1"
implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'
implementation "eu.davidea:flexible-adapter:5.1.0" implementation "eu.davidea:flexible-adapter:5.1.0"
implementation "eu.davidea:flexible-adapter-ui:1.0.0" implementation "eu.davidea:flexible-adapter-ui:1.0.0"
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
implementation 'com.ncapdevi:frag-nav:3.2.0'
implementation "com.aurelhubert:ahbottomnavigation:2.2.0" implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.3'
implementation 'com.ncapdevi:frag-nav:3.0.0' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation "io.reactivex.rxjava2:rxjava:2.2.9"
implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation "io.reactivex.rxjava2:rxjava:2.2.4"
implementation "com.jakewharton.threetenabp:threetenabp:1.1.0"
implementation 'com.google.code.gson:gson:2.8.5'
implementation "com.jakewharton.threetenabp:threetenabp:1.2.0"
implementation "com.jakewharton.timber:timber:4.7.1" implementation "com.jakewharton.timber:timber:4.7.1"
implementation "at.favre.lib:slf4j-timber:1.0.1" implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation "com.squareup.okhttp3:logging-interceptor:3.12.3"
implementation 'com.google.firebase:firebase-core:16.0.6' implementation "com.mikepenz:aboutlibraries:6.2.3"
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.8' implementation 'com.takisoft.preferencex:preferencex:1.0.0'
releaseImplementation 'fr.o80.chucker:library-no-op:2.0.3' playImplementation 'com.google.firebase:firebase-core:16.0.9'
debugImplementation 'fr.o80.chucker:library:2.0.3' playImplementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
debugImplementation "com.amitshekhar.android:debug-db:1.0.4" releaseImplementation 'fr.o80.chucker:library-no-op:2.0.4'
debugImplementation 'fr.o80.chucker:library:2.0.4'
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
testImplementation "junit:junit:4.12" testImplementation "junit:junit:4.12"
testImplementation "io.mockk:mockk:1.8.13.kotlin13" testImplementation "io.mockk:mockk:1.9.2"
testImplementation "org.mockito:mockito-inline:2.23.4" testImplementation 'org.threeten:threetenbp:1.4.0'
testImplementation 'org.threeten:threetenbp:1.3.8' testImplementation "org.mockito:mockito-core:2.28.2"
testImplementation("org.mockito:mockito-inline:2.28.2") {
exclude group: 'org.mockito', module: 'mockito-core'
}
androidTestImplementation 'androidx.test:core:1.1.0' androidTestImplementation 'androidx.test:core:1.2.0'
androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.0' androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'org.mockito:mockito-android:2.23.4' androidTestImplementation "io.mockk:mockk-android:1.9.2"
androidTestImplementation "androidx.room:room-testing:2.1.0-rc01"
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
androidTestImplementation "org.mockito:mockito-core:2.28.2"
androidTestImplementation('org.mockito:mockito-android:2.28.2') {
exclude group: 'org.mockito', module: 'mockito-core'
}
} }
apply plugin: 'com.google.gms.google-services' apply plugin: 'com.google.gms.google-services'

10
app/hooks.gradle Normal file
View file

@ -0,0 +1,10 @@
apply plugin: "com.star-zero.gradle.githook"
githook {
failOnMissingHooksDir = false
hooks {
"pre-push" {
shell = "./app/play-publish-lint.sh"
}
}
}

View file

@ -1,7 +1,7 @@
apply plugin: "jacoco" apply plugin: "jacoco"
jacoco { jacoco {
toolVersion "0.8.2" toolVersion "0.8.3"
reportsDir = file("$buildDir/reports") reportsDir = file("$buildDir/reports")
} }
@ -31,17 +31,20 @@ task jacocoTestReport(type: JacocoReport) {
'**/*_Provide*Factory*.*', '**/*_Provide*Factory*.*',
'**/*_Factory.*'] '**/*_Factory.*']
classDirectories = fileTree( classDirectories.setFrom(fileTree(
dir: "$buildDir/intermediates/classes/debug", dir: "$buildDir/intermediates/classes/debug",
excludes: excludes excludes: excludes
) + fileTree( ) + fileTree(
dir: "$buildDir/tmp/kotlin-classes/debug", dir: "$buildDir/tmp/kotlin-classes/playDebug",
excludes: excludes excludes: excludes
) ))
sourceDirectories = files("$project.projectDir/src/main/java") sourceDirectories.setFrom(files([
executionData = fileTree( "src/main/java",
"src/play/java"
]))
executionData.setFrom(fileTree(
dir: project.projectDir, dir: project.projectDir,
includes: ["**/*.exec", "**/*.ec"] includes: ["**/*.exec", "**/*.ec"]
) ))
} }

7
app/play-publish-lint.sh Executable file
View file

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

View file

@ -5,6 +5,7 @@
-dontskipnonpubliclibraryclasses -dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers -dontskipnonpubliclibraryclassmembers
-dontpreverify -dontpreverify
-dontobfuscate
-allowaccessmodification -allowaccessmodification
-repackageclasses '' -repackageclasses ''
-verbose -verbose
@ -13,7 +14,6 @@
#Config for anallitycs #Config for anallitycs
-keepattributes *Annotation* -keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable -keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile
-keep class com.crashlytics.** {*;} -keep class com.crashlytics.** {*;}
-keep public class * extends java.lang.Exception -keep public class * extends java.lang.Exception
-dontwarn com.crashlytics.** -dontwarn com.crashlytics.**
@ -32,5 +32,8 @@
-dontwarn rx.internal.util.** -dontwarn rx.internal.util.**
-dontwarn sun.misc.Unsafe -dontwarn sun.misc.Unsafe
#Config for MPAndroidChart
-keep class com.github.mikephil.charting.** { *; }
#Config for API #Config for API
-keep class io.github.wulkanowy.api.** {*;} -keep class io.github.wulkanowy.api.** {*;}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -29,5 +29,6 @@ sonarqube {
property "sonar.java.coveragePlugin", "jacoco" property "sonar.java.coveragePlugin", "jacoco"
property "sonar.android.lint.report", "build/reports/lint-results.xml" property "sonar.android.lint.report", "build/reports/lint-results.xml"
property "sonar.jacoco.reportPaths", fileTree(dir: project.projectDir, includes: ['**/*.exec', '**/*.ec']) property "sonar.jacoco.reportPaths", fileTree(dir: project.projectDir, includes: ['**/*.exec', '**/*.ec'])
property "sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacocoTestReport/jacocoTestReport.xml"
} }
} }

View file

@ -0,0 +1,36 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.Room
import androidx.room.testing.MigrationTestHelper
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import androidx.test.core.app.ApplicationProvider
import androidx.test.platform.app.InstrumentationRegistry
import io.github.wulkanowy.data.db.AppDatabase
import org.junit.Rule
abstract class AbstractMigrationTest {
val dbName = "migration-test"
@get:Rule
val helper: MigrationTestHelper = MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(),
AppDatabase::class.java.canonicalName,
FrameworkSQLiteOpenHelperFactory()
)
fun getMigratedRoomDatabase(): AppDatabase {
val database = Room.databaseBuilder(ApplicationProvider.getApplicationContext(),
AppDatabase::class.java, dbName)
.addMigrations(
Migration12(),
Migration13(),
Migration14(),
Migration15()
)
.build()
// close the database and release any stream resources when the test finishes
helper.closeWhenFinished(database)
return database
}
}

View file

@ -0,0 +1,133 @@
package io.github.wulkanowy.data.db.migrations
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase.CONFLICT_FAIL
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class Migration12Test : AbstractMigrationTest() {
@Test
fun twoNotRelatedStudents() {
helper.createDatabase(dbName, 11).apply {
// user 1
createStudent(this, 1, true)
createSemester(this, 1, false, 5, 1)
createSemester(this, 1, true, 5, 2)
// user 2
createStudent(this, 2, true)
createSemester(this, 2, false, 6, 1)
createSemester(this, 2, true, 6, 2)
close()
}
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
assertEquals(2, students.size)
students[0].run {
assertEquals(1, studentId)
assertEquals(5, classId)
}
students[1].run {
assertEquals(2, studentId)
assertEquals(6, classId)
}
}
@Test
fun removeStudentsWithoutClassId() {
helper.createDatabase(dbName, 11).apply {
// user 1
createStudent(this, 1, true)
createSemester(this, 1, false, 0, 2)
createStudent(this, 2, true)
createSemester(this, 2, true, 1, 2)
close()
}
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
assertEquals(1, students.size)
students[0].run {
assertEquals(2, studentId)
assertEquals(1, classId)
}
}
@Test
fun ensureThereIsOnlyOneCurrentStudent() {
helper.createDatabase(dbName, 11).apply {
// user 1
createStudent(this, 1, true)
createSemester(this, 1, true, 5, 2)
createStudent(this, 2, true)
createSemester(this, 2, true, 6, 2)
createStudent(this, 3, true)
createSemester(this, 3, false, 7, 2)
close()
}
helper.runMigrationsAndValidate(dbName, 12, true, Migration12())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
assertEquals(3, students.size)
students[0].run {
assertEquals(studentId, 1)
assertEquals(false, isCurrent)
}
students[1].run {
assertEquals(studentId, 2)
assertEquals(false, isCurrent)
}
students[2].run {
assertEquals(studentId, 3)
assertEquals(true, isCurrent)
}
}
private fun createStudent(db: SupportSQLiteDatabase, studentId: Int, isCurrent: Boolean) {
db.insert("Students", CONFLICT_FAIL, ContentValues().apply {
put("endpoint", "https://fakelog.cf")
put("loginType", "STANDARD")
put("email", "jan@fakelog.cf")
put("password", "******")
put("symbol", "Default")
put("student_id", studentId)
put("student_name", "Jan Kowalski")
put("school_id", "000123")
put("school_name", "")
put("is_current", isCurrent)
put("registration_date", "0")
})
}
private fun createSemester(db: SupportSQLiteDatabase, studentId: Int, isCurrent: Boolean, classId: Int, diaryId: Int) {
db.insert("Semesters", CONFLICT_FAIL, ContentValues().apply {
put("student_id", studentId)
put("diary_id", diaryId)
put("diary_name", "IA")
put("semester_id", diaryId * 5)
put("semester_name", "1")
put("is_current", isCurrent)
put("class_id", classId)
put("unit_id", "99")
})
}
}

View file

@ -0,0 +1,171 @@
package io.github.wulkanowy.data.db.migrations
import android.content.ContentValues
import android.database.sqlite.SQLiteDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Test
import org.threeten.bp.LocalDate.of
import kotlin.test.assertTrue
class Migration13Test : AbstractMigrationTest() {
@Test
fun studentsWithSchoolNameWithClassName() {
helper.createDatabase(dbName, 12).apply {
createStudent(this, 1, "Klasa A - Publiczna szkoła Wulkanowego nr 1 w fakelog.cf", 1, 1)
createStudent(this, 2, "Klasa B - Publiczna szkoła Wulkanowego-fejka nr 1 w fakelog.cf", 2, 1)
createStudent(this, 2, "Klasa C - Publiczna szkoła Wulkanowego-fejka nr 2 w fakelog.cf", 1, 2)
close()
}
helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
assertEquals(3, students.size)
students[0].run {
assertEquals(1, studentId)
assertEquals("A", className)
assertEquals("Publiczna szkoła Wulkanowego nr 1 w fakelog.cf", schoolName)
}
students[1].run {
assertEquals(2, studentId)
assertEquals("B", className)
assertEquals("Publiczna szkoła Wulkanowego-fejka nr 1 w fakelog.cf", schoolName)
}
students[2].run {
assertEquals(2, studentId)
assertEquals("C", className)
assertEquals("Publiczna szkoła Wulkanowego-fejka nr 2 w fakelog.cf", schoolName)
}
}
@Test
fun studentsWithSchoolNameWithoutClassName() {
helper.createDatabase(dbName, 12).apply {
createStudent(this, 1, "Publiczna szkoła Wulkanowego nr 1 w fakelog.cf", 1)
createStudent(this, 2, "Publiczna szkoła Wulkanowego-fejka nr 1 w fakelog.cf", 1)
close()
}
helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
val db = getMigratedRoomDatabase()
val students = db.studentDao.loadAll().blockingGet()
assertEquals(2, students.size)
students[0].run {
assertEquals(1, studentId)
assertEquals("", className)
assertEquals("Publiczna szkoła Wulkanowego nr 1 w fakelog.cf", schoolName)
}
students[1].run {
assertEquals(2, studentId)
assertEquals("", className)
assertEquals("Publiczna szkoła Wulkanowego-fejka nr 1 w fakelog.cf", schoolName)
}
}
@Test
fun markAtLeastAndOnlyOneSemesterAtCurrent() {
helper.createDatabase(dbName, 12).apply {
createStudent(this, 1, "", 5)
createSemester(this, 1, 5, 1, 1, false)
createSemester(this, 1, 5, 2, 1, false)
createSemester(this, 1, 5, 3, 2, false)
createSemester(this, 1, 5, 4, 2, false)
createStudent(this, 2, "", 5)
createSemester(this, 2, 5, 5, 5, true)
createSemester(this, 2, 5, 6, 5, true)
createSemester(this, 2, 5, 7, 55, true)
createSemester(this, 2, 5, 8, 55, true)
createStudent(this, 3, "", 5)
createSemester(this, 3, 5, 11, 99, false)
createSemester(this, 3, 5, 12, 99, false)
createSemester(this, 3, 5, 13, 100, false)
createSemester(this, 3, 5, 14, 100, true)
close()
}
helper.runMigrationsAndValidate(dbName, 13, true, Migration13())
val db = getMigratedRoomDatabase()
val semesters1 = db.semesterDao.loadAll(1, 5).blockingGet()
assertTrue { semesters1.single { it.isCurrent }.isCurrent }
semesters1[0].run {
assertFalse(isCurrent)
assertEquals(1, semesterId)
assertEquals(1, diaryId)
}
semesters1[2].run {
assertFalse(isCurrent)
assertEquals(3, semesterId)
assertEquals(2, diaryId)
}
semesters1[3].run {
assertTrue(isCurrent)
assertEquals(4, semesterId)
assertEquals(2, diaryId)
}
db.semesterDao.loadAll(2, 5).blockingGet().let {
assertTrue { it.single { it.isCurrent }.isCurrent }
assertEquals(1970, it[0].schoolYear)
assertEquals(of(1970, 1, 1), it[0].end)
assertEquals(of(1970, 1, 1), it[0].start)
assertFalse(it[0].isCurrent)
assertFalse(it[1].isCurrent)
assertFalse(it[2].isCurrent)
assertTrue(it[3].isCurrent)
}
db.semesterDao.loadAll(2, 5).blockingGet().let {
assertTrue { it.single { it.isCurrent }.isCurrent }
assertFalse(it[0].isCurrent)
assertFalse(it[1].isCurrent)
assertFalse(it[2].isCurrent)
assertTrue(it[3].isCurrent)
}
}
private fun createStudent(db: SupportSQLiteDatabase, studentId: Int, schoolName: String = "", classId: Int = -1, schoolId: Int = 123) {
db.insert("Students", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
put("endpoint", "https://fakelog.cf")
put("loginType", "STANDARD")
put("email", "jan@fakelog.cf")
put("password", "******")
put("symbol", "Default")
put("student_id", studentId)
put("class_id", classId)
put("student_name", "Jan Kowalski")
put("school_id", schoolId)
put("school_name", schoolName)
put("is_current", false)
put("registration_date", "0")
})
}
private fun createSemester(db: SupportSQLiteDatabase, studentId: Int, classId: Int, semesterId: Int, diaryId: Int, isCurrent: Boolean = false) {
db.insert("Semesters", SQLiteDatabase.CONFLICT_FAIL, ContentValues().apply {
put("student_id", studentId)
put("diary_id", diaryId)
put("diary_name", "IA")
put("semester_id", semesterId)
put("semester_name", "1")
put("is_current", isCurrent)
put("class_id", classId)
put("unit_id", "99")
})
}
}

View file

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

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.attendance
import androidx.room.Room import androidx.room.Room
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
@ -11,6 +11,7 @@ import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.now
import kotlin.test.assertEquals import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@ -34,13 +35,13 @@ class AttendanceLocalTest {
@Test @Test
fun saveAndReadTest() { fun saveAndReadTest() {
attendanceLocal.saveAttendance(listOf( attendanceLocal.saveAttendance(listOf(
Attendance(1, 2, LocalDate.of(2018, 9, 10), 0, "", ""), Attendance(1, 2, LocalDate.of(2018, 9, 10), 0, "", "", false, false, false, false, false, false),
Attendance(1, 2, LocalDate.of(2018, 9, 14), 0, "", ""), Attendance(1, 2, LocalDate.of(2018, 9, 14), 0, "", "", false, false, false, false, false, false),
Attendance(1, 2, LocalDate.of(2018, 9, 17), 0, "", "") Attendance(1, 2, LocalDate.of(2018, 9, 17), 0, "", "", false, false, false, false, false, false)
)) ))
val attendance = attendanceLocal val attendance = attendanceLocal
.getAttendance(Semester(1, 1, 2, "", 3, 1), .getAttendance(Semester(1, 2, "", 1, 3, 2019, true, now(), now(), 1, 1),
LocalDate.of(2018, 9, 10), LocalDate.of(2018, 9, 10),
LocalDate.of(2018, 9, 14) LocalDate.of(2018, 9, 14)
) )

View file

@ -0,0 +1,57 @@
package io.github.wulkanowy.data.repositories.completedlessons
import androidx.room.Room
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.CompletedLesson
import io.github.wulkanowy.data.db.entities.Semester
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class CompletedLessonsLocalTest {
private lateinit var completedLessonsLocal: CompletedLessonsLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
completedLessonsLocal = CompletedLessonsLocal(testDb.completedLessonsDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
completedLessonsLocal.saveCompletedLessons(listOf(
getCompletedLesson(LocalDate.of(2018, 9, 10), 1),
getCompletedLesson(LocalDate.of(2018, 9, 14), 2),
getCompletedLesson(LocalDate.of(2018, 9, 17), 3)
))
val completed = completedLessonsLocal
.getCompletedLessons(Semester(1, 2, "", 1, 3, 2019, true, LocalDate.now(), LocalDate.now(), 1, 1),
LocalDate.of(2018, 9, 10),
LocalDate.of(2018, 9, 14)
)
.blockingGet()
assertEquals(2, completed.size)
assertEquals(completed[0].date, LocalDate.of(2018, 9, 10))
assertEquals(completed[1].date, LocalDate.of(2018, 9, 14))
}
private fun getCompletedLesson(date: LocalDate, number: Int): CompletedLesson {
return CompletedLesson(1, 2, date, number, "", "", "", "", "", "", "")
}
}

View file

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.exam
import androidx.room.Room import androidx.room.Room
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
@ -40,7 +40,7 @@ class ExamLocalTest {
)) ))
val exams = examLocal val exams = examLocal
.getExams(Semester(1, 1, 2, "", 3, 1), .getExams(Semester(1, 2, "", 1, 3, 2019, true, LocalDate.now(), LocalDate.now(), 1, 1),
LocalDate.of(2018, 9, 10), LocalDate.of(2018, 9, 10),
LocalDate.of(2018, 9, 14) LocalDate.of(2018, 9, 14)
) )

View file

@ -0,0 +1,53 @@
package io.github.wulkanowy.data.repositories.grade
import androidx.room.Room
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 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 kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class GradeLocalTest {
private lateinit var gradeLocal: GradeLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
gradeLocal = GradeLocal(testDb.gradeDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
gradeLocal.saveGrades(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)
))
val semester = Semester(1, 2, "", 2019, 2, 1, true, now(), now(), 1, 1)
val grades = gradeLocal
.getGrades(semester)
.blockingGet()
assertEquals(2, grades.size)
assertEquals(grades[0].date, LocalDate.of(2019, 2, 27))
assertEquals(grades[1].date, LocalDate.of(2019, 2, 28))
}
}

View file

@ -0,0 +1,182 @@
package io.github.wulkanowy.data.repositories.grade
import android.os.Build.VERSION_CODES.P
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.api.Api
import io.github.wulkanowy.data.db.AppDatabase
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.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.reactivex.Single
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 kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import io.github.wulkanowy.api.grades.Grade as GradeApi
@SdkSuppress(minSdkVersion = P)
@RunWith(AndroidJUnit4::class)
class GradeRepositoryTest {
@SpyK
private var mockApi = Api()
private val settings = InternetObservingSettings.builder()
.strategy(TestInternetObservingStrategy())
.build()
@MockK
private lateinit var semesterMock: Semester
@MockK
private lateinit var studentMock: Student
private lateinit var gradeRemote: GradeRemote
private lateinit var gradeLocal: GradeLocal
private lateinit var testDb: AppDatabase
@Before
fun initApi() {
MockKAnnotations.init(this)
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
gradeLocal = GradeLocal(testDb.gradeDao)
gradeRemote = GradeRemote(mockApi)
every { mockApi.diaryId } returns 1
every { studentMock.registrationDate } returns LocalDateTime.of(2019, 2, 27, 12, 0)
every { semesterMock.studentId } returns 1
every { semesterMock.semesterId } returns 1
every { semesterMock.diaryId } returns 1
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun markOlderThanRegisterDateAsRead() {
every { mockApi.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")
))
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date }
assertFalse { grades[0].isRead }
assertFalse { grades[1].isRead }
assertTrue { grades[2].isRead }
assertTrue { grades[3].isRead }
}
@Test
fun mitigateOldGradesNotifications() {
gradeLocal.saveGrades(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")
))
every { mockApi.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")
))
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet().sortedByDescending { it.date }
assertFalse { grades[0].isRead }
assertFalse { grades[1].isRead }
assertTrue { grades[2].isRead }
assertTrue { grades[3].isRead }
}
@Test
fun subtractLocaleDuplicateGrades() {
gradeLocal.saveGrades(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")
))
every { mockApi.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")
))
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
assertEquals(2, grades.size)
}
@Test
fun subtractRemoteDuplicateGrades() {
gradeLocal.saveGrades(listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
every { mockApi.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")
))
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
assertEquals(3, grades.size)
}
@Test
fun emptyLocal() {
gradeLocal.saveGrades(listOf())
every { mockApi.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")
))
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
assertEquals(3, grades.size)
}
@Test
fun emptyRemote() {
gradeLocal.saveGrades(listOf(
createGradeLocal(5, 3.0, of(2019, 2, 25), "Taka sama ocena"),
createGradeLocal(3, 5.0, of(2019, 2, 26), "Jakaś inna ocena")
))
every { mockApi.getGrades(1) } returns Single.just(listOf())
val grades = GradeRepository(settings, gradeLocal, gradeRemote)
.getGrades(studentMock, semesterMock, true).blockingGet()
assertEquals(0, grades.size)
}
}

View file

@ -0,0 +1,34 @@
package io.github.wulkanowy.data.repositories.grade
import io.github.wulkanowy.api.toDate
import org.threeten.bp.LocalDate
import io.github.wulkanowy.api.grades.Grade as GradeRemote
import io.github.wulkanowy.data.db.entities.Grade as GradeLocal
fun createGradeLocal(value: Int, weight: Double, date: LocalDate, desc: String, semesterId: Int = 1): GradeLocal {
return GradeLocal(
semesterId = semesterId,
studentId = 1,
modifier = .0,
teacher = "",
subject = "",
date = date,
color = "",
comment = "",
description = desc,
entry = "",
gradeSymbol = "",
value = value,
weight = "",
weightValue = weight
)
}
fun createGradeApi(value: Int, weight: Double, date: LocalDate, desc: String): GradeRemote {
return GradeRemote().apply {
this.value = value
this.weightValue = weight
this.date = date.toDate()
this.description = desc
}
}

View file

@ -0,0 +1,69 @@
package io.github.wulkanowy.data.repositories.gradestatistics
import androidx.room.Room
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.GradeStatistics
import io.github.wulkanowy.data.db.entities.Semester
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class GradeStatisticsLocalTest {
private lateinit var gradeStatisticsLocal: GradeStatisticsLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
gradeStatisticsLocal = GradeStatisticsLocal(testDb.gradeStatistics)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndRead_subject() {
gradeStatisticsLocal.saveGradesStatistics(listOf(
getGradeStatistics("Matematyka", 2, 1),
getGradeStatistics("Fizyka", 1, 2)
))
val stats = gradeStatisticsLocal.getGradesStatistics(
Semester(2, 2, "", 2019, 1, 2, true, LocalDate.now(), LocalDate.now(), 1, 1), false,
"Matematyka"
).blockingGet()
assertEquals(1, stats.size)
assertEquals(stats[0].subject, "Matematyka")
}
@Test
fun saveAndRead_all() {
gradeStatisticsLocal.saveGradesStatistics(listOf(
getGradeStatistics("Matematyka", 2, 1),
getGradeStatistics("Chemia", 2, 1),
getGradeStatistics("Fizyka", 1, 2)
))
val stats = gradeStatisticsLocal.getGradesStatistics(
Semester(2, 2, "", 2019, 1, 2, true, LocalDate.now(), LocalDate.now(), 1, 1), false,
"Wszystkie"
).blockingGet()
assertEquals(1, stats.size)
assertEquals(stats[0].subject, "Wszystkie")
}
private fun getGradeStatistics(subject: String, studentId: Int, semesterId: Int): GradeStatistics {
return GradeStatistics(studentId, semesterId, subject, 5, 5, false)
}
}

View file

@ -0,0 +1,47 @@
package io.github.wulkanowy.data.repositories.luckynumber
import androidx.room.Room
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 org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class LuckyNumberLocalTest {
private lateinit var luckyNumberLocal: LuckyNumberLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
luckyNumberLocal = LuckyNumberLocal(testDb.luckyNumberDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
luckyNumberLocal.saveLuckyNumber(LuckyNumber(1, LocalDate.of(2019, 1, 20), 14))
val luckyNumber = luckyNumberLocal.getLuckyNumber(Semester(1, 1, "", 1, 3, 2019, true, LocalDate.now(), LocalDate.now(), 1, 1),
LocalDate.of(2019, 1, 20)
).blockingGet()
assertEquals(1, luckyNumber.studentId)
assertEquals(LocalDate.of(2019, 1, 20), luckyNumber.date)
assertEquals(14, luckyNumber.luckyNumber)
}
}

View file

@ -0,0 +1,60 @@
package io.github.wulkanowy.data.repositories.recipient
import androidx.room.Room
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.Recipient
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Student
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDateTime
import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class)
class RecipientLocalTest {
private lateinit var recipientLocal: RecipientLocal
private lateinit var testDb: AppDatabase
@Before
fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
recipientLocal = RecipientLocal(testDb.recipientDao)
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun saveAndReadTest() {
recipientLocal.saveRecipients(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")
))
val recipients = recipientLocal.getRecipients(
Student("fakelog.cf", "AUTO", "", "", "", 1, "", "", "", "", 1, true, LocalDateTime.now()),
2,
ReportingUnit(1, 4, "", 0, "", emptyList())
).blockingGet()
assertEquals(2, recipients.size)
assertEquals(1, recipients[0].studentId)
assertEquals("3rPracownik", recipients[1].realId)
assertEquals("Kowalski Jan", recipients[0].name)
assertEquals("Kowalska Karolina [KK] - Pracownik (Fake123456)", recipients[1].realName)
assertEquals(3, recipients[0].loginId)
assertEquals(4, recipients[1].unitId)
assertEquals(2, recipients[0].role)
assertEquals("hash", recipients[1].hash)
}
}

View file

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.student
import android.content.Context import android.content.Context
import androidx.room.Room import androidx.room.Room
@ -11,6 +11,7 @@ import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.threeten.bp.LocalDateTime.now
import kotlin.test.assertEquals import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@ -28,7 +29,7 @@ class StudentLocalTest {
testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java) testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
.build() .build()
sharedHelper = SharedPrefHelper(context.getSharedPreferences("TEST", Context.MODE_PRIVATE)) sharedHelper = SharedPrefHelper(context.getSharedPreferences("TEST", Context.MODE_PRIVATE))
studentLocal = StudentLocal(testDb.studentDao, sharedHelper, context) studentLocal = StudentLocal(testDb.studentDao, context)
} }
@After @After
@ -38,9 +39,8 @@ class StudentLocalTest {
@Test @Test
fun saveAndReadTest() { fun saveAndReadTest() {
studentLocal.saveStudent(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true)) studentLocal.saveStudents(listOf(Student(email = "test", password = "test123", schoolSymbol = "23", endpoint = "fakelog.cf", loginType = "AUTO", isCurrent = true, studentName = "", schoolName = "", studentId = 0, classId = 1, symbol = "", registrationDate = now(), className = "")))
.blockingGet() .blockingGet()
assert(studentLocal.isStudentSaved)
val student = studentLocal.getCurrentStudent(true).blockingGet() val student = studentLocal.getCurrentStudent(true).blockingGet()
assertEquals("23", student.schoolSymbol) assertEquals("23", student.schoolSymbol)

View file

@ -0,0 +1,45 @@
package io.github.wulkanowy.data.repositories.timetable
import io.github.wulkanowy.api.toDate
import io.github.wulkanowy.utils.toDate
import org.threeten.bp.LocalDateTime
import org.threeten.bp.LocalDateTime.now
import io.github.wulkanowy.api.timetable.Timetable as TimetableRemote
import io.github.wulkanowy.data.db.entities.Timetable as TimetableLocal
fun createTimetableLocal(number: Int, start: LocalDateTime, room: String = "", subject: String = "", teacher: String = ""): TimetableLocal {
return TimetableLocal(
studentId = 1,
diaryId = 2,
number = number,
start = start,
end = now(),
date = start.toLocalDate(),
subject = subject,
subjectOld = "",
group = "",
room = room,
roomOld = "",
teacher = teacher,
teacherOld = "",
info = "",
changes = false,
canceled = false
)
}
fun createTimetableRemote(number: Int, start: LocalDateTime, room: String, subject: String = "", teacher: String = ""): TimetableRemote {
return TimetableRemote(
number = number,
start = start.toDate(),
end = start.plusMinutes(45).toDate(),
date = start.toLocalDate().toDate(),
subject = subject,
group = "",
room = room,
teacher = teacher,
info = "",
changes = false,
canceled = false
)
}

View file

@ -1,17 +1,16 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.timetable
import androidx.room.Room import androidx.room.Room
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Timetable
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDateTime import org.threeten.bp.LocalDateTime.of
import kotlin.test.assertEquals import kotlin.test.assertEquals
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@ -23,7 +22,8 @@ class TimetableLocalTest {
@Before @Before
fun createDb() { fun createDb() {
testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java).build() testDb = Room.inMemoryDatabaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java)
.build()
timetableDb = TimetableLocal(testDb.timetableDao) timetableDb = TimetableLocal(testDb.timetableDao)
} }
@ -35,19 +35,17 @@ class TimetableLocalTest {
@Test @Test
fun saveAndReadTest() { fun saveAndReadTest() {
timetableDb.saveTimetable(listOf( timetableDb.saveTimetable(listOf(
Timetable(1, 2, 1, LocalDateTime.now(), LocalDateTime.now(), createTimetableLocal(1, of(2018, 9, 10, 0, 0, 0)),
LocalDate.of(2018, 9, 10), "", "", "", "", ""), createTimetableLocal(1, of(2018, 9, 14, 0, 0, 0)),
Timetable(1, 2, 1, LocalDateTime.now(), LocalDateTime.now(), createTimetableLocal(1, of(2018, 9, 17, 0, 0, 0))
LocalDate.of(2018, 9, 14), "", "", "", "", ""),
Timetable(1, 2, 1, LocalDateTime.now(), LocalDateTime.now(),
LocalDate.of(2018, 9, 17), "", "", "", "", "")
)) ))
val exams = timetableDb.getTimetable( val exams = timetableDb.getTimetable(
Semester(0, 1, 2, "3", 1, 1), Semester(1, 2, "", 1, 1, 2019, true, LocalDate.now(), LocalDate.now(), 1, 1),
LocalDate.of(2018, 9, 10), LocalDate.of(2018, 9, 10),
LocalDate.of(2018, 9, 14) LocalDate.of(2018, 9, 14)
).blockingGet() ).blockingGet()
assertEquals(2, exams.size) assertEquals(2, exams.size)
assertEquals(exams[0].date, LocalDate.of(2018, 9, 10)) assertEquals(exams[0].date, LocalDate.of(2018, 9, 10))
assertEquals(exams[1].date, LocalDate.of(2018, 9, 14)) assertEquals(exams[1].date, LocalDate.of(2018, 9, 14))

View file

@ -0,0 +1,89 @@
package io.github.wulkanowy.data.repositories.timetable
import android.os.Build.VERSION_CODES.P
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.api.Api
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.TestInternetObservingStrategy
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.impl.annotations.SpyK
import io.reactivex.Single
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 kotlin.test.assertEquals
@SdkSuppress(minSdkVersion = P)
@RunWith(AndroidJUnit4::class)
class TimetableRepositoryTest {
@SpyK
private var mockApi = Api()
private val settings = InternetObservingSettings.builder()
.strategy(TestInternetObservingStrategy())
.build()
@MockK
private lateinit var semesterMock: Semester
private lateinit var timetableRemote: TimetableRemote
private lateinit var timetableLocal: TimetableLocal
private lateinit var testDb: AppDatabase
@Before
fun initApi() {
MockKAnnotations.init(this)
testDb = Room.inMemoryDatabaseBuilder(getApplicationContext(), AppDatabase::class.java).build()
timetableLocal = TimetableLocal(testDb.timetableDao)
timetableRemote = TimetableRemote(mockApi)
every { semesterMock.studentId } returns 1
every { semesterMock.diaryId } returns 2
}
@After
fun closeDb() {
testDb.close()
}
@Test
fun copyDetailsToCompletedFromPrevious() {
timetableLocal.saveTimetable(listOf(
createTimetableLocal(1, of(2019, 3, 5, 8, 0), "123", "Przyroda"),
createTimetableLocal(2, of(2019, 3, 5, 8, 50), "321", "Religia"),
createTimetableLocal(3, of(2019, 3, 5, 9, 40), "213", "W-F"),
createTimetableLocal(4, of(2019, 3, 5, 10, 30), "213", "W-F", "Jan Kowalski")
))
every { mockApi.getTimetable(any(), any()) } returns Single.just(listOf(
createTimetableRemote(1, of(2019, 3, 5, 8, 0), "", "Przyroda"),
createTimetableRemote(2, of(2019, 3, 5, 8, 50), "", "Religia"),
createTimetableRemote(3, of(2019, 3, 5, 9, 40), "", "W-F"),
createTimetableRemote(4, of(2019, 3, 5, 10, 30), "", "W-F")
))
val lessons = TimetableRepository(settings, timetableLocal, timetableRemote)
.getTimetable(semesterMock, LocalDate.of(2019, 3, 5), LocalDate.of(2019, 3, 5), true)
.blockingGet()
assertEquals(4, lessons.size)
assertEquals("123", lessons[0].room)
assertEquals("321", lessons[1].room)
assertEquals("213", lessons[2].room)
assertEquals("", lessons[3].teacher)
}
}

View file

@ -0,0 +1,17 @@
@file:Suppress("UNUSED_PARAMETER")
package io.github.wulkanowy.utils
import android.content.Context
import timber.log.Timber
class CrashlyticsTree : Timber.Tree() {
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
// do nothing
}
}
fun initCrashlytics(context: Context) {
// do nothing
}

View file

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

View file

@ -4,7 +4,7 @@
package="io.github.wulkanowy" package="io.github.wulkanowy"
android:installLocation="internalOnly"> android:installLocation="internalOnly">
<uses-sdk tools:overrideLibrary="com.readystatesoftware.chuck"/> <uses-sdk tools:overrideLibrary="com.readystatesoftware.chuck" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@ -20,14 +20,13 @@
android:supportsRtl="false" android:supportsRtl="false"
android:theme="@style/WulkanowyTheme" android:theme="@style/WulkanowyTheme"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning"> tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
<activity <activity
android:name=".ui.modules.splash.SplashActivity" android:name=".ui.modules.splash.SplashActivity"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:theme="@style/WulkanowyTheme.SplashScreen"> android:theme="@style/WulkanowyTheme.SplashScreen">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
@ -35,26 +34,44 @@
android:name=".ui.modules.login.LoginActivity" android:name=".ui.modules.login.LoginActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:label="@string/login_title" android:label="@string/login_title"
android:theme="@style/WulkanowyTheme.NoActionBar"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<activity <activity
android:name=".ui.modules.main.MainActivity" android:name=".ui.modules.main.MainActivity"
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:label="@string/main_title" android:label="@string/main_title"
android:theme="@style/WulkanowyTheme.NoActionBar" /> android:theme="@style/WulkanowyTheme.NoActionBar" />
<activity
<service android:name=".ui.modules.message.send.SendMessageActivity"
android:name=".services.job.SyncWorker" android:configChanges="orientation|screenSize"
android:exported="false"> android:label="@string/send_message_title"
android:theme="@style/WulkanowyTheme.NoActionBar" />
<activity
android:name=".ui.modules.timetablewidget.TimetableWidgetConfigureActivity"
android:excludeFromRecents="true"
android:noHistory="true"
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
<intent-filter> <intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE" /> <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter> </intent-filter>
</service> </activity>
<activity
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetConfigureActivity"
android:excludeFromRecents="true"
android:noHistory="true"
android:theme="@style/WulkanowyTheme.WidgetAccountSwitcher">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<service <service
android:name=".services.widgets.TimetableWidgetService" android:name=".services.widgets.TimetableWidgetService"
android:permission="android.permission.BIND_REMOTEVIEWS" /> android:permission="android.permission.BIND_REMOTEVIEWS" />
<receiver <receiver
android:name=".ui.widgets.timetable.TimetableWidgetProvider" android:name=".ui.modules.timetablewidget.TimetableWidgetProvider"
android:exported="true"
android:label="@string/timetable_title"> android:label="@string/timetable_title">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@ -64,6 +81,23 @@
android:resource="@xml/provider_widget_timetable" /> android:resource="@xml/provider_widget_timetable" />
</receiver> </receiver>
<receiver
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetProvider"
android:label="@string/lucky_number_title">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/provider_widget_lucky_number" />
</receiver>
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
android:exported="false"
tools:node="remove" />
<meta-data <meta-data
android:name="io.fabric.ApiKey" android:name="io.fabric.ApiKey"
android:value="${fabric_api_key}" /> android:value="${fabric_api_key}" />

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View file

@ -1,28 +1,31 @@
package io.github.wulkanowy package io.github.wulkanowy
import android.content.Context import android.content.Context
import androidx.appcompat.app.AppCompatDelegate
import androidx.multidex.MultiDex import androidx.multidex.MultiDex
import com.crashlytics.android.Crashlytics import androidx.work.Configuration
import com.crashlytics.android.core.CrashlyticsCore import androidx.work.WorkManager
import com.jakewharton.threetenabp.AndroidThreeTen import com.jakewharton.threetenabp.AndroidThreeTen
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
import dagger.android.support.DaggerApplication import dagger.android.support.DaggerApplication
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.utils.Log import eu.davidea.flexibleadapter.utils.Log
import io.fabric.sdk.android.Fabric
import io.github.wulkanowy.BuildConfig.DEBUG import io.github.wulkanowy.BuildConfig.DEBUG
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.di.DaggerAppComponent import io.github.wulkanowy.di.DaggerAppComponent
import io.github.wulkanowy.services.sync.SyncWorkerFactory
import io.github.wulkanowy.utils.ActivityLifecycleLogger
import io.github.wulkanowy.utils.CrashlyticsTree import io.github.wulkanowy.utils.CrashlyticsTree
import io.github.wulkanowy.utils.DebugLogTree 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 timber.log.Timber
import java.io.IOException
import javax.inject.Inject import javax.inject.Inject
class WulkanowyApp : DaggerApplication() { class WulkanowyApp : DaggerApplication() {
@Inject @Inject
lateinit var prefRepository: PreferencesRepository lateinit var workerFactory: SyncWorkerFactory
override fun attachBaseContext(base: Context?) { override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base) super.attachBaseContext(base)
@ -32,24 +35,30 @@ class WulkanowyApp : DaggerApplication() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
AndroidThreeTen.init(this) AndroidThreeTen.init(this)
initializeFabric() WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
if (DEBUG) enableDebugLog() RxJavaPlugins.setErrorHandler(::onError)
AppCompatDelegate.setDefaultNightMode(prefRepository.currentTheme)
initCrashlytics(applicationContext)
initLogging()
} }
private fun enableDebugLog() { private fun initLogging() {
Timber.plant(DebugLogTree()) if (DEBUG) {
FlexibleAdapter.enableLogs(Log.Level.DEBUG) Timber.plant(DebugLogTree())
FlexibleAdapter.enableLogs(Log.Level.DEBUG)
} else {
Timber.plant(CrashlyticsTree())
}
registerActivityLifecycleCallbacks(ActivityLifecycleLogger())
} }
private fun initializeFabric() { private fun onError(error: Throwable) {
Fabric.with(Fabric.Builder(this).kits( if (error is UndeliverableException && error.cause is IOException || error.cause is InterruptedException) {
Crashlytics.Builder().core(CrashlyticsCore.Builder().disabled(!BuildConfig.CRASHLYTICS_ENABLED).build()).build() Timber.e(error.cause, "An undeliverable error occurred")
).debuggable(BuildConfig.DEBUG).build()) } else throw error
Timber.plant(CrashlyticsTree())
} }
override fun applicationInjector(): AndroidInjector<out DaggerApplication> { override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerAppComponent.builder().create(this) return DaggerAppComponent.factory().create(this)
} }
} }

View file

@ -14,14 +14,22 @@ class ApiHelper @Inject constructor(private val api: Api) {
symbol = student.symbol symbol = student.symbol
schoolSymbol = student.schoolSymbol schoolSymbol = student.schoolSymbol
studentId = student.studentId studentId = student.studentId
useNewStudent = false classId = student.classId
host = URL(student.endpoint).run { host + ":$port".removeSuffix(":-1") } host = URL(student.endpoint).run { host + ":$port".removeSuffix(":-1") }
ssl = student.endpoint.startsWith("https") ssl = student.endpoint.startsWith("https")
loginType = Api.LoginType.valueOf(student.loginType) loginType = Api.LoginType.valueOf(student.loginType)
useNewStudent = true
} }
} }
fun initApi(email: String, password: String, symbol: String, endpoint: String) { fun initApi(email: String, password: String, symbol: String, endpoint: String) {
initApi(Student(email = email, password = password, symbol = symbol, endpoint = endpoint, loginType = "AUTO")) api.apply {
this.email = email
this.password = password
this.symbol = symbol
host = URL(endpoint).run { host + ":$port".removeSuffix(":-1") }
ssl = endpoint.startsWith("https")
useNewStudent = true
}
} }
} }

View file

@ -5,7 +5,7 @@ import android.content.SharedPreferences
import android.content.res.Resources import android.content.res.Resources
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.SocketInternetObservingStrategy import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy
import com.readystatesoftware.chuck.api.ChuckCollector import com.readystatesoftware.chuck.api.ChuckCollector
import com.readystatesoftware.chuck.api.ChuckInterceptor import com.readystatesoftware.chuck.api.ChuckInterceptor
import com.readystatesoftware.chuck.api.RetentionManager import com.readystatesoftware.chuck.api.RetentionManager
@ -13,7 +13,7 @@ import dagger.Module
import dagger.Provides import dagger.Provides
import io.github.wulkanowy.api.Api import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.repositories.PreferencesRepository import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import okhttp3.logging.HttpLoggingInterceptor.Level.BASIC import okhttp3.logging.HttpLoggingInterceptor.Level.BASIC
import okhttp3.logging.HttpLoggingInterceptor.Level.NONE import okhttp3.logging.HttpLoggingInterceptor.Level.NONE
@ -27,8 +27,7 @@ internal class RepositoryModule {
@Provides @Provides
fun provideInternetObservingSettings(): InternetObservingSettings { fun provideInternetObservingSettings(): InternetObservingSettings {
return InternetObservingSettings.builder() return InternetObservingSettings.builder()
.strategy(SocketInternetObservingStrategy()) .strategy(WalledGardenInternetObservingStrategy())
.host("www.google.com")
.build() .build()
} }
@ -50,7 +49,7 @@ internal class RepositoryModule {
@Provides @Provides
fun provideChuckCollector(context: Context, prefRepository: PreferencesRepository): ChuckCollector { fun provideChuckCollector(context: Context, prefRepository: PreferencesRepository): ChuckCollector {
return ChuckCollector(context) return ChuckCollector(context)
.showNotification(prefRepository.isShowChuckerNotification) .showNotification(prefRepository.isDebugNotificationEnable)
.retentionManager(RetentionManager(context, ChuckCollector.Period.ONE_HOUR)) .retentionManager(RetentionManager(context, ChuckCollector.Period.ONE_HOUR))
} }
@ -82,6 +81,10 @@ internal class RepositoryModule {
@Provides @Provides
fun provideGradeSummaryDao(database: AppDatabase) = database.gradeSummaryDao fun provideGradeSummaryDao(database: AppDatabase) = database.gradeSummaryDao
@Singleton
@Provides
fun provideGradeStatisticsDao(database: AppDatabase) = database.gradeStatistics
@Singleton @Singleton
@Provides @Provides
fun provideMessagesDao(database: AppDatabase) = database.messagesDao fun provideMessagesDao(database: AppDatabase) = database.messagesDao
@ -113,4 +116,24 @@ internal class RepositoryModule {
@Singleton @Singleton
@Provides @Provides
fun provideSubjectDao(database: AppDatabase) = database.subjectDao fun provideSubjectDao(database: AppDatabase) = database.subjectDao
@Singleton
@Provides
fun provideLuckyNumberDao(database: AppDatabase) = database.luckyNumberDao
@Singleton
@Provides
fun provideCompletedLessonsDao(database: AppDatabase) = database.completedLessonsDao
@Singleton
@Provides
fun provideReportingUnitDao(database: AppDatabase) = database.reportingUnitDao
@Singleton
@Provides
fun provideRecipientDao(database: AppDatabase) = database.recipientDao
@Singleton
@Provides
fun provideMobileDevicesDao(database: AppDatabase) = database.mobileDeviceDao
} }

View file

@ -8,28 +8,54 @@ import androidx.room.RoomDatabase.JournalMode.TRUNCATE
import androidx.room.TypeConverters import androidx.room.TypeConverters
import io.github.wulkanowy.data.db.dao.AttendanceDao import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao import io.github.wulkanowy.data.db.dao.AttendanceSummaryDao
import io.github.wulkanowy.data.db.dao.CompletedLessonsDao
import io.github.wulkanowy.data.db.dao.ExamDao import io.github.wulkanowy.data.db.dao.ExamDao
import io.github.wulkanowy.data.db.dao.GradeDao import io.github.wulkanowy.data.db.dao.GradeDao
import io.github.wulkanowy.data.db.dao.GradeStatisticsDao
import io.github.wulkanowy.data.db.dao.GradeSummaryDao import io.github.wulkanowy.data.db.dao.GradeSummaryDao
import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.dao.HomeworkDao import io.github.wulkanowy.data.db.dao.HomeworkDao
import io.github.wulkanowy.data.db.dao.LuckyNumberDao
import io.github.wulkanowy.data.db.dao.MessagesDao
import io.github.wulkanowy.data.db.dao.MobileDeviceDao
import io.github.wulkanowy.data.db.dao.NoteDao import io.github.wulkanowy.data.db.dao.NoteDao
import io.github.wulkanowy.data.db.dao.RecipientDao
import io.github.wulkanowy.data.db.dao.ReportingUnitDao
import io.github.wulkanowy.data.db.dao.SemesterDao import io.github.wulkanowy.data.db.dao.SemesterDao
import io.github.wulkanowy.data.db.dao.StudentDao import io.github.wulkanowy.data.db.dao.StudentDao
import io.github.wulkanowy.data.db.dao.SubjectDao import io.github.wulkanowy.data.db.dao.SubjectDao
import io.github.wulkanowy.data.db.dao.TimetableDao import io.github.wulkanowy.data.db.dao.TimetableDao
import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Attendance
import io.github.wulkanowy.data.db.entities.AttendanceSummary import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.data.db.entities.Exam
import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.github.wulkanowy.data.db.entities.GradeSummary import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Homework import io.github.wulkanowy.data.db.entities.Homework
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.data.db.entities.Note import io.github.wulkanowy.data.db.entities.Note
import io.github.wulkanowy.data.db.entities.Recipient
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Subject import io.github.wulkanowy.data.db.entities.Subject
import io.github.wulkanowy.data.db.entities.Timetable import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.db.migrations.Migration10
import io.github.wulkanowy.data.db.migrations.Migration11
import io.github.wulkanowy.data.db.migrations.Migration12
import io.github.wulkanowy.data.db.migrations.Migration13
import io.github.wulkanowy.data.db.migrations.Migration14
import io.github.wulkanowy.data.db.migrations.Migration15
import io.github.wulkanowy.data.db.migrations.Migration2
import io.github.wulkanowy.data.db.migrations.Migration3
import io.github.wulkanowy.data.db.migrations.Migration4
import io.github.wulkanowy.data.db.migrations.Migration5
import io.github.wulkanowy.data.db.migrations.Migration6
import io.github.wulkanowy.data.db.migrations.Migration7
import io.github.wulkanowy.data.db.migrations.Migration8
import io.github.wulkanowy.data.db.migrations.Migration9
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
@ -43,21 +69,47 @@ import javax.inject.Singleton
AttendanceSummary::class, AttendanceSummary::class,
Grade::class, Grade::class,
GradeSummary::class, GradeSummary::class,
GradeStatistics::class,
Message::class, Message::class,
Note::class, Note::class,
Homework::class, Homework::class,
Subject::class Subject::class,
LuckyNumber::class,
CompletedLesson::class,
ReportingUnit::class,
Recipient::class,
MobileDevice::class
], ],
version = 1, version = AppDatabase.VERSION_SCHEMA,
exportSchema = false exportSchema = true
) )
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
companion object { companion object {
const val VERSION_SCHEMA = 15
fun newInstance(context: Context): AppDatabase { fun newInstance(context: Context): AppDatabase {
return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database") return Room.databaseBuilder(context, AppDatabase::class.java, "wulkanowy_database")
.setJournalMode(TRUNCATE) .setJournalMode(TRUNCATE)
.fallbackToDestructiveMigrationFrom(VERSION_SCHEMA + 1)
.fallbackToDestructiveMigrationOnDowngrade()
.addMigrations(
Migration2(),
Migration3(),
Migration4(),
Migration5(),
Migration6(),
Migration7(),
Migration8(),
Migration9(),
Migration10(),
Migration11(),
Migration12(),
Migration13(),
Migration14(),
Migration15()
)
.build() .build()
} }
} }
@ -78,6 +130,8 @@ abstract class AppDatabase : RoomDatabase() {
abstract val gradeSummaryDao: GradeSummaryDao abstract val gradeSummaryDao: GradeSummaryDao
abstract val gradeStatistics: GradeStatisticsDao
abstract val messagesDao: MessagesDao abstract val messagesDao: MessagesDao
abstract val noteDao: NoteDao abstract val noteDao: NoteDao
@ -85,4 +139,14 @@ abstract class AppDatabase : RoomDatabase() {
abstract val homeworkDao: HomeworkDao abstract val homeworkDao: HomeworkDao
abstract val subjectDao: SubjectDao abstract val subjectDao: SubjectDao
abstract val luckyNumberDao: LuckyNumberDao
abstract val completedLessonsDao: CompletedLessonsDao
abstract val reportingUnitDao: ReportingUnitDao
abstract val recipientDao: RecipientDao
abstract val mobileDeviceDao: MobileDeviceDao
} }

View file

@ -1,6 +1,8 @@
package io.github.wulkanowy.data.db package io.github.wulkanowy.data.db
import androidx.room.TypeConverter import androidx.room.TypeConverter
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import org.threeten.bp.DateTimeUtils import org.threeten.bp.DateTimeUtils
import org.threeten.bp.Instant import org.threeten.bp.Instant
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
@ -36,4 +38,14 @@ class Converters {
@TypeConverter @TypeConverter
fun intToMonth(value: Int?) = value?.let { Month.of(it) } fun intToMonth(value: Int?) = value?.let { Month.of(it) }
@TypeConverter
fun intListToGson(list: List<Int>): String {
return Gson().toJson(list)
}
@TypeConverter
fun gsonToIntList(value: String): List<Int> {
return Gson().fromJson(value, object : TypeToken<List<Int>>() {}.type)
}
} }

View file

@ -6,26 +6,16 @@ import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
@SuppressLint("ApplySharedPref")
class SharedPrefHelper @Inject constructor(private val sharedPref: SharedPreferences) { class SharedPrefHelper @Inject constructor(private val sharedPref: SharedPreferences) {
@SuppressLint("ApplySharedPref")
fun putLong(key: String, value: Long, sync: Boolean = false) { fun putLong(key: String, value: Long, sync: Boolean = false) {
sharedPref.edit().putLong(key, value).apply { sharedPref.edit().putLong(key, value).apply {
if (sync) commit() else apply() if (sync) commit() else apply()
} }
} }
fun getLong(key: String, defaultValue: Long): Long { fun getLong(key: String, defaultValue: Long) = sharedPref.getLong(key, defaultValue)
return sharedPref.getLong(key, defaultValue)
}
fun putBoolean(key: String, value: Boolean) {
sharedPref.edit().putBoolean(key, value).apply()
}
fun getBoolean(key: String, defaultValue: Boolean): Boolean {
return sharedPref.getBoolean(key, defaultValue)
}
fun delete(key: String) { fun delete(key: String) {
sharedPref.edit().remove(key).apply() sharedPref.edit().remove(key).apply()

View file

@ -0,0 +1,24 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.CompletedLesson
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import javax.inject.Singleton
@Singleton
@Dao
interface CompletedLessonsDao {
@Insert
fun insertAll(exams: List<CompletedLesson>)
@Delete
fun deleteAll(exams: List<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>>
}

View file

@ -16,9 +16,6 @@ interface GradeDao {
@Insert @Insert
fun insertAll(grades: List<Grade>) fun insertAll(grades: List<Grade>)
@Update
fun update(grade: Grade)
@Update @Update
fun updateAll(grade: List<Grade>) fun updateAll(grade: List<Grade>)
@ -28,6 +25,4 @@ interface GradeDao {
@Query("SELECT * FROM Grades WHERE semester_id = :semesterId AND student_id = :studentId") @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): Maybe<List<Grade>>
@Query("SELECT * FROM Grades WHERE is_read = 0 AND semester_id = :semesterId AND student_id = :studentId")
fun loadAllNew(semesterId: Int, studentId: Int): Maybe<List<Grade>>
} }

View file

@ -0,0 +1,26 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.GradeStatistics
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@Dao
interface GradeStatisticsDao {
@Insert
fun insertAll(gradesStatistics: List<GradeStatistics>)
@Delete
fun deleteAll(gradesStatistics: List<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>>
@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>>
}

View file

@ -18,6 +18,6 @@ interface GradeSummaryDao {
@Delete @Delete
fun deleteAll(gradesSummary: List<GradeSummary>) fun deleteAll(gradesSummary: List<GradeSummary>)
@Query("SELECT * FROM grades_summary WHERE student_id = :studentId AND semester_id = :semesterId") @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): Maybe<List<GradeSummary>>
} }

View file

@ -19,6 +19,6 @@ interface HomeworkDao {
@Delete @Delete
fun deleteAll(homework: List<Homework>) fun deleteAll(homework: List<Homework>)
@Query("SELECT * FROM Homework WHERE semester_id = :semesterId AND student_id = :studentId AND date = :date") @Query("SELECT * FROM Homework WHERE semester_id = :semesterId AND student_id = :studentId AND date >= :from AND date <= :end")
fun loadAll(semesterId: Int, studentId: Int, date: LocalDate): Maybe<List<Homework>> fun loadAll(semesterId: Int, studentId: Int, from: LocalDate, end: LocalDate): Maybe<List<Homework>>
} }

View file

@ -0,0 +1,29 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Update
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.reactivex.Maybe
import org.threeten.bp.LocalDate
import javax.inject.Singleton
@Singleton
@Dao
interface LuckyNumberDao {
@Insert
fun insert(luckyNumber: LuckyNumber)
@Update
fun update(luckyNumber: LuckyNumber)
@Delete
fun delete(luckyNumber: LuckyNumber)
@Query("SELECT * FROM LuckyNumbers WHERE student_id = :studentId AND date = :date")
fun load(studentId: Int, date: LocalDate): Maybe<LuckyNumber>
}

View file

@ -12,26 +12,20 @@ import io.reactivex.Maybe
interface MessagesDao { interface MessagesDao {
@Insert @Insert
fun insertAll(messages: List<Message>): List<Long> fun insertAll(messages: List<Message>)
@Delete @Delete
fun deleteAll(messages: List<Message>) fun deleteAll(messages: List<Message>)
@Update
fun update(message: Message)
@Update @Update
fun updateAll(messages: List<Message>) fun updateAll(messages: List<Message>)
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND real_id = :id") @Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder AND removed = 0 ORDER BY date DESC")
fun loadOne(studentId: Int, id: Int): Maybe<Message> fun loadAll(studentId: Int, folder: Int): Maybe<List<Message>>
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND folder_id = :folder ORDER BY date DESC") @Query("SELECT * FROM Messages WHERE id = :id")
fun load(studentId: Int, folder: Int): Maybe<List<Message>> fun load(id: Long): Maybe<Message>
@Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC") @Query("SELECT * FROM Messages WHERE student_id = :studentId AND removed = 1 ORDER BY date DESC")
fun loadDeleted(studentId: Int): Maybe<List<Message>> fun loadDeleted(studentId: Int): Maybe<List<Message>>
@Query("SELECT * FROM Messages WHERE unread = 1 AND student_id = :studentId")
fun loadNewMessages(studentId: Int): Maybe<List<Message>>
} }

View file

@ -0,0 +1,21 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.reactivex.Maybe
@Dao
interface MobileDeviceDao {
@Insert
fun insertAll(devices: List<MobileDevice>)
@Delete
fun deleteAll(devices: List<MobileDevice>)
@Query("SELECT * FROM MobileDevices WHERE student_id = :studentId ORDER BY date DESC")
fun loadAll(studentId: Int): Maybe<List<MobileDevice>>
}

View file

@ -16,18 +16,13 @@ interface NoteDao {
@Insert @Insert
fun insertAll(notes: List<Note>) fun insertAll(notes: List<Note>)
@Update
fun update(note: Note)
@Update @Update
fun updateAll(notes: List<Note>) fun updateAll(notes: List<Note>)
@Delete @Delete
fun deleteAll(notes: List<Note>) fun deleteAll(notes: List<Note>)
@Query("SELECT * FROM Notes WHERE semester_id = :semesterId AND student_id = :studentId") @Query("SELECT * FROM Notes WHERE student_id = :studentId")
fun loadAll(semesterId: Int, studentId: Int): Maybe<List<Note>> fun loadAll(studentId: Int): Maybe<List<Note>>
@Query("SELECT * FROM Notes WHERE is_read = 0 AND semester_id = :semesterId AND student_id = :studentId")
fun loadNew(semesterId: Int, studentId: Int): Maybe<List<Note>>
} }

View file

@ -0,0 +1,23 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Recipient
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@Dao
interface RecipientDao {
@Insert
fun insertAll(messages: List<Recipient>)
@Delete
fun deleteAll(messages: List<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>>
}

View file

@ -0,0 +1,26 @@
package io.github.wulkanowy.data.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import io.github.wulkanowy.data.db.entities.ReportingUnit
import io.reactivex.Maybe
import javax.inject.Singleton
@Singleton
@Dao
interface ReportingUnitDao {
@Insert
fun insertAll(reportingUnits: List<ReportingUnit>)
@Delete
fun deleteAll(reportingUnits: List<ReportingUnit>)
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId")
fun load(studentId: Int): Maybe<List<ReportingUnit>>
@Query("SELECT * FROM ReportingUnits WHERE student_id = :studentId AND real_id = :unitId")
fun loadOne(studentId: Int, unitId: Int): Maybe<ReportingUnit>
}

View file

@ -1,8 +1,8 @@
package io.github.wulkanowy.data.db.dao package io.github.wulkanowy.data.db.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy.IGNORE
import androidx.room.Query import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe import io.reactivex.Maybe
@ -12,15 +12,12 @@ import javax.inject.Singleton
@Dao @Dao
interface SemesterDao { interface SemesterDao {
@Insert(onConflict = IGNORE) @Insert
fun insertAll(semester: List<Semester>) fun insertAll(semester: List<Semester>)
@Query("SELECT * FROM Semesters WHERE student_id = :studentId") @Delete
fun loadAll(studentId: Int): Maybe<List<Semester>> fun deleteAll(semester: List<Semester>)
@Query("UPDATE Semesters SET is_current = 1 WHERE semester_id = :semesterId AND diary_id = :diaryId") @Query("SELECT * FROM Semesters WHERE student_id = :studentId AND class_id = :classId")
fun updateCurrent(semesterId: Int, diaryId: Int) fun loadAll(studentId: Int, classId: Int): Maybe<List<Semester>>
@Query("UPDATE Semesters SET is_current = 0 WHERE student_id = :studentId")
fun resetCurrent(studentId: Int)
} }

View file

@ -3,7 +3,7 @@ package io.github.wulkanowy.data.db.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete import androidx.room.Delete
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy.FAIL import androidx.room.OnConflictStrategy.ABORT
import androidx.room.Query import androidx.room.Query
import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.db.entities.Student
import io.reactivex.Maybe import io.reactivex.Maybe
@ -13,8 +13,8 @@ import javax.inject.Singleton
@Dao @Dao
interface StudentDao { interface StudentDao {
@Insert(onConflict = FAIL) @Insert(onConflict = ABORT)
fun insert(student: Student): Long fun insertAll(student: List<Student>): List<Long>
@Delete @Delete
fun delete(student: Student) fun delete(student: Student)
@ -25,8 +25,8 @@ interface StudentDao {
@Query("SELECT * FROM Students") @Query("SELECT * FROM Students")
fun loadAll(): Maybe<List<Student>> fun loadAll(): Maybe<List<Student>>
@Query("UPDATE Students SET is_current = 1 WHERE student_id = :studentId") @Query("UPDATE Students SET is_current = 1 WHERE id = :id")
fun updateCurrent(studentId: Int) fun updateCurrent(id: Long)
@Query("UPDATE Students SET is_current = 0") @Query("UPDATE Students SET is_current = 0")
fun resetCurrent() fun resetCurrent()

View file

@ -10,30 +10,30 @@ import java.io.Serializable
data class Attendance( data class Attendance(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int, val studentId: Int,
@ColumnInfo(name = "diary_id") @ColumnInfo(name = "diary_id")
var diaryId: Int, val diaryId: Int,
var date: LocalDate, val date: LocalDate,
var number: Int, val number: Int,
var subject: String, val subject: String,
var name: String, val name: String,
var presence: Boolean = false, val presence: Boolean,
var absence: Boolean = false, val absence: Boolean,
var exemption: Boolean = false, val exemption: Boolean,
var lateness: Boolean = false, val lateness: Boolean,
var excused: Boolean = false, val excused: Boolean,
var deleted: Boolean = false val deleted: Boolean
) : Serializable { ) : Serializable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)

View file

@ -10,13 +10,13 @@ import java.io.Serializable
data class AttendanceSummary( data class AttendanceSummary(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int, val studentId: Int,
@ColumnInfo(name = "diary_id") @ColumnInfo(name = "diary_id")
var diaryId: Int, val diaryId: Int,
@ColumnInfo(name = "subject_id") @ColumnInfo(name = "subject_id")
var subjectId: Int = 0, val subjectId: Int,
val month: Month, val month: Month,

View file

@ -0,0 +1,40 @@
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
@Entity(tableName = "CompletedLesson")
data class CompletedLesson(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "diary_id")
val diaryId: Int,
val date: LocalDate,
val number: Int,
val subject: String,
val topic: String,
val teacher: String,
@ColumnInfo(name = "teacher_symbol")
val teacherSymbol: String,
val substitution: String,
val absence: String,
val resources: String
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View file

@ -9,29 +9,29 @@ import java.io.Serializable
@Entity(tableName = "Exams") @Entity(tableName = "Exams")
data class Exam( data class Exam(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int, val studentId: Int,
@ColumnInfo(name = "diary_id") @ColumnInfo(name = "diary_id")
var diaryId: Int, val diaryId: Int,
var date: LocalDate, val date: LocalDate,
@ColumnInfo(name = "entry_date") @ColumnInfo(name = "entry_date")
var entryDate: LocalDate = LocalDate.now(), val entryDate: LocalDate,
var subject: String, val subject: String,
var group: String, val group: String,
var type: String, val type: String,
var description: String, val description: String,
var teacher: String, val teacher: String,
@ColumnInfo(name = "teacher_symbol") @ColumnInfo(name = "teacher_symbol")
var teacherSymbol: String val teacherSymbol: String
) : Serializable { ) : Serializable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)

View file

@ -10,35 +10,35 @@ import java.io.Serializable
data class Grade( data class Grade(
@ColumnInfo(name = "semester_id") @ColumnInfo(name = "semester_id")
var semesterId: Int, val semesterId: Int,
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int, val studentId: Int,
var subject: String, val subject: String,
var entry: String, val entry: String,
var value: Int, val value: Int,
var modifier: Double, val modifier: Double,
var comment: String, val comment: String,
var color: String, val color: String,
@ColumnInfo(name = "grade_symbol") @ColumnInfo(name = "grade_symbol")
var gradeSymbol: String, val gradeSymbol: String,
var description: String, val description: String,
var weight: String, val weight: String,
var weightValue: Int, val weightValue: Double,
var date: LocalDate, val date: LocalDate,
var teacher: String val teacher: String
) : Serializable { ) : Serializable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)

View file

@ -0,0 +1,27 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "GradesStatistics")
data class GradeStatistics(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "semester_id")
val semesterId: Int,
val subject: String,
val grade: Int,
val amount: Int,
@ColumnInfo(name = "is_semester")
val semester: Boolean
) {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View file

@ -4,22 +4,36 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
@Entity(tableName = "Grades_Summary") @Entity(tableName = "GradesSummary")
data class GradeSummary( data class GradeSummary(
@ColumnInfo(name = "semester_id") @ColumnInfo(name = "semester_id")
var semesterId: Int, val semesterId: Int,
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int, val studentId: Int,
var subject: String, val position: Int,
var predictedGrade: String, val subject: String,
var finalGrade: String @ColumnInfo(name = "predicted_grade")
val predictedGrade: String,
@ColumnInfo(name = "final_grade")
val finalGrade: String,
@ColumnInfo(name = "proposed_points")
val proposedPoints: String,
@ColumnInfo(name = "final_points")
val finalPoints: String,
@ColumnInfo(name = "points_sum")
val pointsSum: String,
val average: Double
) { ) {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var id: Long = 0 var id: Long = 0
} }

View file

@ -10,24 +10,24 @@ import java.io.Serializable
data class Homework( data class Homework(
@ColumnInfo(name = "semester_id") @ColumnInfo(name = "semester_id")
var semesterId: Int, val semesterId: Int,
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int, val studentId: Int,
var date: LocalDate, val date: LocalDate,
@ColumnInfo(name = "entry_date") @ColumnInfo(name = "entry_date")
var entryDate: LocalDate, val entryDate: LocalDate,
var subject: String, val subject: String,
var content: String, val content: String,
var teacher: String, val teacher: String,
@ColumnInfo(name = "teacher_symbol") @ColumnInfo(name = "teacher_symbol")
var teacherSymbol: String val teacherSymbol: String
) : Serializable { ) : Serializable {

View file

@ -0,0 +1,27 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
import java.io.Serializable
@Entity(tableName = "LuckyNumbers")
data class LuckyNumber (
@ColumnInfo(name = "student_id")
val studentId: Int,
val date: LocalDate,
@ColumnInfo(name = "lucky_number")
val luckyNumber: Int
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
@ColumnInfo(name = "is_notified")
var isNotified: Boolean = true
}

View file

@ -10,40 +10,39 @@ import java.io.Serializable
data class Message( data class Message(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int? = null, val studentId: Int,
@ColumnInfo(name = "real_id") @ColumnInfo(name = "real_id")
val realId: Int? = null, val realId: Int,
@ColumnInfo(name = "message_id") @ColumnInfo(name = "message_id")
val messageId: Int? = null, val messageId: Int,
@ColumnInfo(name = "sender_name") @ColumnInfo(name = "sender_name")
val sender: String? = null, val sender: String,
@ColumnInfo(name = "sender_id") @ColumnInfo(name = "sender_id")
val senderId: Int? = null, val senderId: Int,
@ColumnInfo(name = "recipient_id")
val recipientId: Int? = null,
@ColumnInfo(name = "recipient_name") @ColumnInfo(name = "recipient_name")
val recipient: String? = "", val recipient: String,
val subject: String = "", val subject: String,
val date: LocalDateTime? = null, val date: LocalDateTime,
@ColumnInfo(name = "folder_id") @ColumnInfo(name = "folder_id")
val folderId: Int = 0, val folderId: Int,
var unread: Boolean? = false, var unread: Boolean,
val unreadBy: Int? = 0, @ColumnInfo(name = "unread_by")
val unreadBy: Int,
val readBy: Int? = 0, @ColumnInfo(name = "read_by")
val readBy: Int,
val removed: Boolean = false val removed: Boolean
) : Serializable { ) : Serializable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)

View file

@ -0,0 +1,25 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import org.threeten.bp.LocalDateTime
import java.io.Serializable
@Entity(tableName = "MobileDevices")
data class MobileDevice(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "device_id")
val deviceId: Int,
val name: String,
val date: LocalDateTime
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View file

@ -9,26 +9,23 @@ import java.io.Serializable
@Entity(tableName = "Notes") @Entity(tableName = "Notes")
data class Note( data class Note(
@ColumnInfo(name = "semester_id")
var semesterId: Int,
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int, val studentId: Int,
var date: LocalDate, val date: LocalDate,
var teacher: String, val teacher: String,
var category: String, val category: String,
var content: String val content: String
) : Serializable { ) : Serializable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var id: Long = 0 var id: Long = 0
@ColumnInfo(name = "is_read") @ColumnInfo(name = "is_read")
var isRead: Boolean = false var isRead: Boolean = true
@ColumnInfo(name = "is_notified") @ColumnInfo(name = "is_notified")
var isNotified: Boolean = true var isNotified: Boolean = true

View file

@ -0,0 +1,38 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
@Entity(tableName = "Recipients")
data class Recipient(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "real_id")
val realId: String,
val name: String,
@ColumnInfo(name = "real_name")
val realName: String,
@ColumnInfo(name = "login_id")
val loginId: Int,
@ColumnInfo(name = "unit_id")
val unitId: Int,
val role: Int,
val hash: String
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
override fun toString() = name
}

View file

@ -0,0 +1,32 @@
package io.github.wulkanowy.data.db.entities
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import java.io.Serializable
@Entity(tableName = "ReportingUnits")
data class ReportingUnit(
@ColumnInfo(name = "student_id")
val studentId: Int,
@ColumnInfo(name = "real_id")
val realId: Int,
@ColumnInfo(name = "short")
val shortName: String,
@ColumnInfo(name = "sender_id")
val senderId: Int,
@ColumnInfo(name = "sender_name")
val senderName: String,
val roles: List<Int>
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View file

@ -4,28 +4,43 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Index import androidx.room.Index
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import org.threeten.bp.LocalDate
@Entity(tableName = "Semesters", indices = [Index(value = ["student_id", "diary_id", "semester_id"], unique = true)]) @Entity(tableName = "Semesters", indices = [Index(value = ["student_id", "diary_id", "semester_id"], unique = true)])
data class Semester( data class Semester(
@PrimaryKey(autoGenerate = true)
var id: Long = 0,
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int, val studentId: Int,
@ColumnInfo(name = "diary_id") @ColumnInfo(name = "diary_id")
var diaryId: Int, val diaryId: Int,
@ColumnInfo(name = "diary_name") @ColumnInfo(name = "diary_name")
var diaryName: String, val diaryName: String,
@ColumnInfo(name = "school_year")
val schoolYear: Int,
@ColumnInfo(name = "semester_id") @ColumnInfo(name = "semester_id")
var semesterId: Int, val semesterId: Int,
@ColumnInfo(name = "semester_name") @ColumnInfo(name = "semester_name")
var semesterName: Int, val semesterName: Int,
@ColumnInfo(name = "is_current") @ColumnInfo(name = "is_current")
var isCurrent: Boolean = false val isCurrent: Boolean,
)
val start: LocalDate,
val end: LocalDate,
@ColumnInfo(name = "class_id")
val classId: Int,
@ColumnInfo(name = "unit_id")
val unitId: Int
) {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View file

@ -4,35 +4,47 @@ import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Index import androidx.room.Index
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import org.threeten.bp.LocalDateTime
import java.io.Serializable
@Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id"], unique = true)]) @Entity(tableName = "Students", indices = [Index(value = ["email", "symbol", "student_id", "school_id", "class_id"], unique = true)])
data class Student( data class Student(
@PrimaryKey(autoGenerate = true) val endpoint: String,
var id: Long = 0,
var endpoint: String, val loginType: String,
var loginType: String, val email: String,
var email: String,
var password: String, var password: String,
var symbol: String = "", val symbol: String,
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int = 0, val studentId: Int,
@ColumnInfo(name = "student_name") @ColumnInfo(name = "student_name")
var studentName: String = "", val studentName: String,
@ColumnInfo(name = "school_id") @ColumnInfo(name = "school_id")
var schoolSymbol: String = "", val schoolSymbol: String,
@ColumnInfo(name = "school_name") @ColumnInfo(name = "school_name")
var schoolName: String = "", val schoolName: String,
@ColumnInfo(name = "class_name")
val className: String,
@ColumnInfo(name = "class_id")
val classId: Int,
@ColumnInfo(name = "is_current") @ColumnInfo(name = "is_current")
var isCurrent: Boolean = false val isCurrent: Boolean,
)
@ColumnInfo(name = "registration_date")
val registrationDate: LocalDateTime
) : Serializable {
@PrimaryKey(autoGenerate = true)
var id: Long = 0
}

View file

@ -9,15 +9,15 @@ import java.io.Serializable
data class Subject( data class Subject(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int, val studentId: Int,
@ColumnInfo(name = "diary_id") @ColumnInfo(name = "diary_id")
var diaryId: Int, val diaryId: Int,
@ColumnInfo(name = "real_id") @ColumnInfo(name = "real_id")
var realId: Int, val realId: Int,
var name: String val name: String
) : Serializable { ) : Serializable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)

View file

@ -10,33 +10,39 @@ import java.io.Serializable
@Entity(tableName = "Timetable") @Entity(tableName = "Timetable")
data class Timetable( data class Timetable(
@ColumnInfo(name = "student_id") @ColumnInfo(name = "student_id")
var studentId: Int, val studentId: Int,
@ColumnInfo(name = "diary_id") @ColumnInfo(name = "diary_id")
var diaryId: Int, val diaryId: Int,
val number: Int = 0, val number: Int,
val start: LocalDateTime = LocalDateTime.now(), val start: LocalDateTime,
val end: LocalDateTime = LocalDateTime.now(), val end: LocalDateTime,
val date: LocalDate, val date: LocalDate,
val subject: String, val subject: String,
val group: String, val subjectOld: String,
val room: String, val group: String,
val teacher: String, val room: String,
val info: String, val roomOld: String,
val changes: Boolean = false, val teacher: String,
val canceled: Boolean = false val teacherOld: String,
val info: String,
val changes: Boolean,
val canceled: Boolean
) : Serializable { ) : Serializable {
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)

View file

@ -0,0 +1,11 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration10 : Migration(9, 10) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Grades_Summary RENAME TO GradesSummary")
}
}

View file

@ -0,0 +1,34 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration11 : Migration(10, 11) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS Grades_temp (
id INTEGER PRIMARY KEY NOT NULL,
is_read INTEGER NOT NULL,
is_notified INTEGER NOT NULL,
semester_id INTEGER NOT NULL,
student_id INTEGER NOT NULL,
subject TEXT NOT NULL,
entry TEXT NOT NULL,
value INTEGER NOT NULL,
modifier REAL NOT NULL,
comment TEXT NOT NULL,
color TEXT NOT NULL,
grade_symbol TEXT NOT NULL,
description TEXT NOT NULL,
weight TEXT NOT NULL,
weightValue REAL NOT NULL,
date INTEGER NOT NULL,
teacher TEXT NOT NULL
)
""")
database.execSQL("INSERT INTO Grades_temp SELECT * FROM Grades")
database.execSQL("DROP TABLE Grades")
database.execSQL("ALTER TABLE Grades_temp RENAME TO Grades")
}
}

View file

@ -0,0 +1,69 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration12 : Migration(11, 12) {
override fun migrate(database: SupportSQLiteDatabase) {
createTempStudentsTable(database)
replaceStudentTable(database)
updateStudentsWithClassId(database, getStudentsIds(database))
removeStudentsWithNoClassId(database)
ensureThereIsOnlyOneCurrentStudent(database)
}
private fun createTempStudentsTable(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS Students_tmp (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
endpoint TEXT NOT NULL,
loginType TEXT NOT NULL,
email TEXT NOT NULL,
password TEXT NOT NULL,
symbol TEXT NOT NULL,
student_id INTEGER NOT NULL,
student_name TEXT NOT NULL,
school_id TEXT NOT NULL,
school_name TEXT NOT NULL,
is_current INTEGER NOT NULL,
registration_date INTEGER NOT NULL,
class_id INTEGER NOT NULL
)
""")
database.execSQL("CREATE UNIQUE INDEX index_Students_email_symbol_student_id_school_id_class_id ON Students_tmp (email, symbol, student_id, school_id, class_id)")
}
private fun replaceStudentTable(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL")
database.execSQL("INSERT INTO Students_tmp SELECT * FROM Students")
database.execSQL("DROP TABLE Students")
database.execSQL("ALTER TABLE Students_tmp RENAME TO Students")
}
private fun getStudentsIds(database: SupportSQLiteDatabase): List<Int> {
val students = mutableListOf<Int>()
val studentsCursor = database.query("SELECT student_id FROM Students")
if (studentsCursor.moveToFirst()) {
do {
students.add(studentsCursor.getInt(0))
} while (studentsCursor.moveToNext())
}
return students
}
private fun updateStudentsWithClassId(database: SupportSQLiteDatabase, students: List<Int>) {
students.forEach {
database.execSQL("UPDATE Students SET class_id = IFNULL((SELECT class_id FROM Semesters WHERE student_id = $it), 0) WHERE student_id = $it")
}
}
private fun removeStudentsWithNoClassId(database: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM Students WHERE class_id = 0")
}
private fun ensureThereIsOnlyOneCurrentStudent(database: SupportSQLiteDatabase) {
database.execSQL("UPDATE Students SET is_current = 0")
database.execSQL("UPDATE Students SET is_current = 1 WHERE id = (SELECT MAX(id) FROM Students)")
}
}

View file

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

View file

@ -0,0 +1,26 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration14 : Migration(13, 14) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS GradesSummary")
database.execSQL("""
CREATE TABLE IF NOT EXISTS GradesSummary (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
semester_id INTEGER NOT NULL,
student_id INTEGER NOT NULL,
position INTEGER NOT NULL,
subject TEXT NOT NULL,
predicted_grade TEXT NOT NULL,
final_grade TEXT NOT NULL,
proposed_points TEXT NOT NULL,
final_points TEXT NOT NULL,
points_sum TEXT NOT NULL,
average REAL NOT NULL
)
""")
}
}

View file

@ -0,0 +1,19 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration15 : Migration(14, 15) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS MobileDevices (
id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
student_id INTEGER NOT NULL,
device_id INTEGER NOT NULL,
name TEXT NOT NULL,
date INTEGER NOT NULL
)
""")
}
}

View file

@ -0,0 +1,18 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration2 : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS LuckyNumbers (
id INTEGER PRIMARY KEY NOT NULL,
is_notified INTEGER NOT NULL,
student_id INTEGER NOT NULL,
date INTEGER NOT NULL,
lucky_number INTEGER NOT NULL)
""")
}
}

View file

@ -0,0 +1,25 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration3 : Migration(2, 3) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS CompletedLesson (
id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL,
diary_id INTEGER NOT NULL,
date INTEGER NOT NULL,
number INTEGER NOT NULL,
subject TEXT NOT NULL,
topic TEXT NOT NULL,
teacher TEXT NOT NULL,
teacher_symbol TEXT NOT NULL,
substitution TEXT NOT NULL,
absence TEXT NOT NULL,
resources TEXT NOT NULL)
""")
}
}

View file

@ -0,0 +1,31 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration4 : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Messages")
database.execSQL("""
CREATE TABLE IF NOT EXISTS Messages (
id INTEGER PRIMARY KEY NOT NULL,
is_notified INTEGER NOT NULL,
content TEXT,
student_id INTEGER NOT NULL,
real_id INTEGER NOT NULL,
message_id INTEGER NOT NULL,
sender_name TEXT NOT NULL,
sender_id INTEGER NOT NULL,
recipient_id INTEGER NOT NULL,
recipient_name TEXT NOT NULL,
subject TEXT NOT NULL,
date INTEGER NOT NULL,
folder_id INTEGER NOT NULL,
unread INTEGER NOT NULL,
unreadBy INTEGER NOT NULL,
readBy INTEGER NOT NULL,
removed INTEGER NOT NULL)
""")
}
}

View file

@ -0,0 +1,26 @@
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
class Migration5 : Migration(4, 5) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Students ADD COLUMN registration_date INTEGER DEFAULT 0 NOT NULL")
database.execSQL("UPDATE Students SET registration_date = '${now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli()}'")
database.execSQL("DROP TABLE IF EXISTS Notes")
database.execSQL("""
CREATE TABLE IF NOT EXISTS Notes (
id INTEGER PRIMARY KEY NOT NULL,
is_read INTEGER NOT NULL,
is_notified INTEGER NOT NULL,
student_id INTEGER NOT NULL,
date INTEGER NOT NULL,
teacher TEXT NOT NULL,
category TEXT NOT NULL,
content TEXT NOT NULL)
""")
}
}

View file

@ -0,0 +1,37 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration6 : Migration(5, 6) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS ReportingUnits (
id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL,
real_id INTEGER NOT NULL,
short TEXT NOT NULL,
sender_id INTEGER NOT NULL,
sender_name TEXT NOT NULL,
roles TEXT NOT NULL)
""")
database.execSQL("""
CREATE TABLE IF NOT EXISTS Recipients (
id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL,
real_id TEXT NOT NULL,
name TEXT NOT NULL,
real_name TEXT NOT NULL,
login_id INTEGER NOT NULL,
unit_id INTEGER NOT NULL,
role INTEGER NOT NULL,
hash TEXT NOT NULL)
""")
database.execSQL("DELETE FROM Semesters WHERE 1")
database.execSQL("ALTER TABLE Semesters ADD COLUMN class_id INTEGER DEFAULT 0 NOT NULL")
database.execSQL("ALTER TABLE Semesters ADD COLUMN unit_id INTEGER DEFAULT 0 NOT NULL")
}
}

View file

@ -0,0 +1,20 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration7 : Migration(6, 7) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("""
CREATE TABLE IF NOT EXISTS GradesStatistics (
id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL,
semester_id INTEGER NOT NULL,
subject TEXT NOT NULL,
grade INTEGER NOT NULL,
amount INTEGER NOT NULL,
is_semester INTEGER NOT NULL)
""")
}
}

View file

@ -0,0 +1,13 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration8 : Migration(7, 8) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Timetable ADD COLUMN subjectOld TEXT DEFAULT \"\" NOT NULL")
database.execSQL("ALTER TABLE Timetable ADD COLUMN roomOld TEXT DEFAULT \"\" NOT NULL")
database.execSQL("ALTER TABLE Timetable ADD COLUMN teacherOld TEXT DEFAULT \"\" NOT NULL")
}
}

View file

@ -0,0 +1,30 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration9 : Migration(8, 9) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE IF EXISTS Messages")
database.execSQL("""
CREATE TABLE IF NOT EXISTS Messages (
id INTEGER PRIMARY KEY NOT NULL,
student_id INTEGER NOT NULL,
real_id INTEGER NOT NULL,
message_id INTEGER NOT NULL,
sender_name TEXT NOT NULL,
sender_id INTEGER NOT NULL,
recipient_name TEXT NOT NULL,
subject TEXT NOT NULL,
date INTEGER NOT NULL,
folder_id INTEGER NOT NULL,
unread INTEGER NOT NULL,
unread_by INTEGER NOT NULL,
read_by INTEGER NOT NULL,
removed INTEGER NOT NULL,
is_notified INTEGER NOT NULL,
content TEXT)
""")
}
}

View file

@ -0,0 +1,3 @@
package io.github.wulkanowy.data.exceptions
class NoCurrentStudentException : Exception("There no set current student in database")

View file

@ -0,0 +1,12 @@
package io.github.wulkanowy.data.pojos
data class MobileDeviceToken(
val token: String,
val symbol: String,
val pin: String,
val qr: String
)

View file

@ -1,52 +0,0 @@
package io.github.wulkanowy.data.repositories
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.Grade
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.local.GradeLocal
import io.github.wulkanowy.data.repositories.remote.GradeRemote
import io.reactivex.Completable
import io.reactivex.Single
import java.net.UnknownHostException
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class GradeRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: GradeLocal,
private val remote: GradeRemote
) {
fun getGrades(semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single<List<Grade>> {
return local.getGrades(semester).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getGrades(semester)
else Single.error(UnknownHostException())
}.flatMap { newGrades ->
local.getGrades(semester).toSingle(emptyList())
.doOnSuccess { oldGrades ->
local.deleteGrades(oldGrades - newGrades)
local.saveGrades((newGrades - oldGrades)
.onEach {
if (oldGrades.isNotEmpty()) it.isRead = false
if (notify) it.isNotified = false
})
}
}.flatMap { local.getGrades(semester).toSingle(emptyList()) })
}
fun getNewGrades(semester: Semester): Single<List<Grade>> {
return local.getNewGrades(semester).toSingle(emptyList())
}
fun updateGrade(grade: Grade): Completable {
return local.updateGrade(grade)
}
fun updateGrades(grades: List<Grade>): Completable {
return local.updateGrades(grades)
}
}

View file

@ -1,36 +0,0 @@
package io.github.wulkanowy.data.repositories
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.Homework
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.local.HomeworkLocal
import io.github.wulkanowy.data.repositories.remote.HomeworkRemote
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.net.UnknownHostException
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class HomeworkRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: HomeworkLocal,
private val remote: HomeworkRemote
) {
fun getHomework(semester: Semester, date: LocalDate, forceRefresh: Boolean = false): Single<List<Homework>> {
return local.getHomework(semester, date).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getHomework(semester, date)
else Single.error(UnknownHostException())
}.flatMap { newGrades ->
local.getHomework(semester, date).toSingle(emptyList())
.doOnSuccess { oldGrades ->
local.deleteHomework(oldGrades - newGrades)
local.saveHomework(newGrades - oldGrades)
}
}.flatMap { local.getHomework(semester, date).toSingle(emptyList()) })
}
}

View file

@ -1,79 +0,0 @@
package io.github.wulkanowy.data.repositories
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.Message
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.local.MessagesLocal
import io.github.wulkanowy.data.repositories.remote.MessagesRemote
import io.reactivex.Completable
import io.reactivex.Single
import java.net.UnknownHostException
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class MessagesRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: MessagesLocal,
private val remote: MessagesRemote
) {
enum class MessageFolder(val id: Int = 1) {
RECEIVED(1),
SENT(2),
TRASHED(3)
}
fun getMessages(studentId: Int, folder: MessageFolder, forceRefresh: Boolean = false, notify: Boolean = false): Single<List<Message>> {
return local.getMessages(studentId, folder).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getMessages(studentId, folder)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getMessages(studentId, folder).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteMessages(old - new)
local.saveMessages((new - old)
.onEach {
it.isNotified = !notify
})
}
}.flatMap { local.getMessages(studentId, folder).toSingle(emptyList()) }
)
}
fun getMessage(studentId: Int, messageId: Int, markAsRead: Boolean = false): Single<Message> {
return local.getMessage(studentId, messageId)
.filter { !it.content.isNullOrEmpty() }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) local.getMessage(studentId, messageId).toSingle()
else Single.error(UnknownHostException())
}
.flatMap { dbMessage ->
remote.getMessagesContent(dbMessage, markAsRead).doOnSuccess {
local.updateMessage(dbMessage.copy(unread = false).apply {
id = dbMessage.id
content = it
})
}
}.flatMap {
local.getMessage(studentId, messageId).toSingle()
}
)
}
fun getNewMessages(student: Student): Single<List<Message>> {
return local.getNewMessages(student).toSingle(emptyList())
}
fun updateMessage(message: Message): Completable {
return Completable.fromCallable { local.updateMessage(message) }
}
fun updateMessages(messages: List<Message>): Completable {
return Completable.fromCallable { local.updateMessages(messages) }
}
}

View file

@ -1,52 +0,0 @@
package io.github.wulkanowy.data.repositories
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.Note
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.local.NoteLocal
import io.github.wulkanowy.data.repositories.remote.NoteRemote
import io.reactivex.Completable
import io.reactivex.Single
import java.net.UnknownHostException
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class NoteRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: NoteLocal,
private val remote: NoteRemote
) {
fun getNotes(semester: Semester, forceRefresh: Boolean = false, notify: Boolean = false): Single<List<Note>> {
return local.getNotes(semester).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getNotes(semester)
else Single.error(UnknownHostException())
}.flatMap { new ->
local.getNotes(semester).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteNotes(old - new)
local.saveNotes((new - old)
.onEach {
if (notify) it.isNotified = false
})
}
}.flatMap { local.getNotes(semester).toSingle(emptyList()) }
)
}
fun getNewNotes(semester: Semester): Single<List<Note>> {
return local.getNewNotes(semester).toSingle(emptyList())
}
fun updateNote(note: Note): Completable {
return local.updateNote(note)
}
fun updateNotes(notes: List<Note>): Completable {
return local.updateNotes(notes)
}
}

View file

@ -1,46 +0,0 @@
package io.github.wulkanowy.data.repositories
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.Semester
import io.github.wulkanowy.data.db.entities.Timetable
import io.github.wulkanowy.data.repositories.local.TimetableLocal
import io.github.wulkanowy.data.repositories.remote.TimetableRemote
import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday
import io.reactivex.Single
import org.threeten.bp.LocalDate
import java.net.UnknownHostException
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class TimetableRepository @Inject constructor(
private val settings: InternetObservingSettings,
private val local: TimetableLocal,
private val remote: TimetableRemote
) {
fun getTimetable(semester: Semester, startDate: LocalDate, endDate: LocalDate, forceRefresh: Boolean = false)
: Single<List<Timetable>> {
return Single.fromCallable { startDate.monday to endDate.friday }
.flatMap { dates ->
local.getTimetable(semester, dates.first, dates.second).filter { !forceRefresh }
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getTimetable(semester, dates.first, dates.second)
else Single.error(UnknownHostException())
}.flatMap { newTimetable ->
local.getTimetable(semester, dates.first, dates.second)
.toSingle(emptyList())
.doOnSuccess { oldTimetable ->
local.deleteTimetable(oldTimetable - newTimetable)
local.saveTimetable(newTimetable - oldTimetable)
}
}.flatMap {
local.getTimetable(semester, dates.first, dates.second)
.toSingle(emptyList())
}).map { list -> list.filter { it.date in startDate..endDate } }
}
}
}

View file

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.local package io.github.wulkanowy.data.repositories.attendance
import io.github.wulkanowy.data.db.dao.AttendanceDao import io.github.wulkanowy.data.db.dao.AttendanceDao
import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Attendance
@ -6,14 +6,11 @@ import io.github.wulkanowy.data.db.entities.Semester
import io.reactivex.Maybe import io.reactivex.Maybe
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class AttendanceLocal @Inject constructor(private val attendanceDb: AttendanceDao) { class AttendanceLocal @Inject constructor(private val attendanceDb: AttendanceDao) {
fun getAttendance(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Attendance>> {
return attendanceDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate)
.filter { !it.isEmpty() }
}
fun saveAttendance(attendance: List<Attendance>) { fun saveAttendance(attendance: List<Attendance>) {
attendanceDb.insertAll(attendance) attendanceDb.insertAll(attendance)
} }
@ -21,4 +18,8 @@ class AttendanceLocal @Inject constructor(private val attendanceDb: AttendanceDa
fun deleteAttendance(attendance: List<Attendance>) { fun deleteAttendance(attendance: List<Attendance>) {
attendanceDb.deleteAll(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() }
}
} }

View file

@ -1,4 +1,4 @@
package io.github.wulkanowy.data.repositories.remote package io.github.wulkanowy.data.repositories.attendance
import io.github.wulkanowy.api.Api import io.github.wulkanowy.api.Api
import io.github.wulkanowy.data.db.entities.Attendance import io.github.wulkanowy.data.db.entities.Attendance

View file

@ -1,13 +1,12 @@
package io.github.wulkanowy.data.repositories package io.github.wulkanowy.data.repositories.attendance
import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings 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.Attendance
import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.repositories.local.AttendanceLocal
import io.github.wulkanowy.data.repositories.remote.AttendanceRemote
import io.github.wulkanowy.utils.friday import io.github.wulkanowy.utils.friday
import io.github.wulkanowy.utils.monday import io.github.wulkanowy.utils.monday
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Single import io.reactivex.Single
import org.threeten.bp.LocalDate import org.threeten.bp.LocalDate
import java.net.UnknownHostException import java.net.UnknownHostException
@ -33,8 +32,8 @@ class AttendanceRepository @Inject constructor(
local.getAttendance(semester, dates.first, dates.second) local.getAttendance(semester, dates.first, dates.second)
.toSingle(emptyList()) .toSingle(emptyList())
.doOnSuccess { oldAttendance -> .doOnSuccess { oldAttendance ->
local.deleteAttendance(oldAttendance - newAttendance) local.deleteAttendance(oldAttendance.uniqueSubtract(newAttendance))
local.saveAttendance(newAttendance - oldAttendance) local.saveAttendance(newAttendance.uniqueSubtract(oldAttendance))
} }
}.flatMap { }.flatMap {
local.getAttendance(semester, dates.first, dates.second) local.getAttendance(semester, dates.first, dates.second)

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