1
0
mirror of https://github.com/wulkanowy/wulkanowy.git synced 2024-09-20 02:19:08 -05:00

Merge branch 'release/0.19.0'

This commit is contained in:
Mikołaj Pich 2020-06-14 22:44:36 +02:00
commit 9f87b92937
61 changed files with 2805 additions and 221 deletions

View File

@ -14,7 +14,7 @@ cache:
branches:
only:
- develop
- 0.18.3
- 0.19.0
android:
licenses:

View File

@ -17,8 +17,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 17
targetSdkVersion 29
versionCode 62
versionName "0.18.3"
versionCode 63
versionName "0.19.0"
multiDexEnabled true
resValue "string", "app_name", "Wulkanowy"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -77,8 +77,8 @@ android {
}
}
viewBinding {
enabled = true
buildFeatures {
viewBinding = true
}
lintOptions {
@ -124,14 +124,14 @@ configurations.all {
}
dependencies {
implementation "io.github.wulkanowy:sdk:0.18.3"
implementation "io.github.wulkanowy:sdk:0.19.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "androidx.core:core-ktx:1.2.0"
implementation "androidx.activity:activity-ktx:1.1.0"
implementation "androidx.appcompat:appcompat:1.2.0-rc01"
implementation "androidx.appcompat:appcompat-resources:1.1.0"
implementation "androidx.fragment:fragment-ktx:1.2.4"
implementation "androidx.fragment:fragment-ktx:1.2.5"
implementation "androidx.annotation:annotation:1.1.0"
implementation "androidx.multidex:multidex:2.0.1"
@ -142,7 +142,7 @@ dependencies {
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "com.google.android.material:material:1.1.0"
implementation "com.github.wulkanowy:material-chips-input:2.0.1"
implementation "com.github.wulkanowy:material-chips-input:2.1.1"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation "me.zhanghai.android.materialprogressbar:library:1.6.1"
@ -180,12 +180,13 @@ dependencies {
implementation 'com.wdullaer:materialdatetimepicker:4.2.3'
implementation "io.coil-kt:coil:0.11.0"
implementation "io.github.wulkanowy:AppKillerManager:3.0.0"
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
playImplementation 'com.google.firebase:firebase-analytics:17.4.2'
playImplementation 'com.google.firebase:firebase-analytics:17.4.3'
playImplementation 'com.google.firebase:firebase-inappmessaging-display-ktx:19.0.7'
playImplementation "com.google.firebase:firebase-inappmessaging-ktx:19.0.7"
playImplementation 'com.google.firebase:firebase-messaging:20.2.0'
playImplementation 'com.google.firebase:firebase-crashlytics:17.0.0'
playImplementation 'com.google.firebase:firebase-crashlytics:17.0.1'
playImplementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:$chucker"

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -120,23 +120,23 @@ class Migration13Test : AbstractMigrationTest() {
assertEquals(2, first.diaryId)
}
getSemesters(db, "SELECT * FROM Semesters WHERE student_id = 2 AND class_id = 5").let {
assertTrue { it.single { it.second }.second }
assertEquals(1970, it[0].first.schoolYear)
assertEquals(of(1970, 1, 1), it[0].first.end)
assertEquals(of(1970, 1, 1), it[0].first.start)
assertFalse(it[0].second)
assertFalse(it[1].second)
assertFalse(it[2].second)
assertTrue(it[3].second)
getSemesters(db, "SELECT * FROM Semesters WHERE student_id = 2 AND class_id = 5").let { semesters ->
assertTrue { semesters.single { it.second }.second }
assertEquals(1970, semesters[0].first.schoolYear)
assertEquals(of(1970, 1, 1), semesters[0].first.end)
assertEquals(of(1970, 1, 1), semesters[0].first.start)
assertFalse(semesters[0].second)
assertFalse(semesters[1].second)
assertFalse(semesters[2].second)
assertTrue(semesters[3].second)
}
getSemesters(db, "SELECT * FROM Semesters WHERE student_id = 2 AND class_id = 5").let {
assertTrue { it.single { it.second }.second }
assertFalse(it[0].second)
assertFalse(it[1].second)
assertFalse(it[2].second)
assertTrue(it[3].second)
getSemesters(db, "SELECT * FROM Semesters WHERE student_id = 2 AND class_id = 5").let { semesters ->
assertTrue { semesters.single { it.second }.second }
assertFalse(semesters[0].second)
assertFalse(semesters[1].second)
assertFalse(semesters[2].second)
assertTrue(semesters[3].second)
}
}

View File

@ -10,6 +10,7 @@ import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.now
import org.threeten.bp.LocalDate.of
import kotlin.test.assertEquals
@ -35,9 +36,18 @@ class AttendanceLocalTest {
@Test
fun saveAndReadTest() {
attendanceLocal.saveAttendance(listOf(
Attendance(1, 2, 3, of(2018, 9, 10), 0, "", "", false, false, false, false, false, false, false, SentExcuseStatus.ACCEPTED.name),
Attendance(1, 2, 3, of(2018, 9, 14), 0, "", "", false, false, false, false, false, false, false, SentExcuseStatus.WAITING.name),
Attendance(1, 2, 3, of(2018, 9, 17), 0, "", "", false, false, false, false, false, false, false, SentExcuseStatus.ACCEPTED.name)
getAttendanceEntity(
of(2018, 9, 10),
SentExcuseStatus.ACCEPTED
),
getAttendanceEntity(
of(2018, 9, 14),
SentExcuseStatus.WAITING
),
getAttendanceEntity(
of(2018, 9, 17),
SentExcuseStatus.ACCEPTED
)
))
val attendance = attendanceLocal
@ -50,4 +60,25 @@ class AttendanceLocalTest {
assertEquals(attendance[0].date, of(2018, 9, 10))
assertEquals(attendance[1].date, of(2018, 9, 14))
}
private fun getAttendanceEntity(
date: LocalDate,
excuseStatus: SentExcuseStatus
) = Attendance(
studentId = 1,
diaryId = 2,
timeId = 3,
date = date,
number = 0,
subject = "",
name = "",
presence = false,
absence = false,
exemption = false,
lateness = false,
excused = false,
deleted = false,
excusable = false,
excuseStatus = excuseStatus.name
)
}

View File

@ -5,7 +5,6 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.github.wulkanowy.data.db.AppDatabase
import io.github.wulkanowy.data.db.entities.LuckyNumber
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import org.junit.After
import org.junit.Before

View File

@ -2,7 +2,6 @@
package io.github.wulkanowy.utils
import android.content.Context
import timber.log.Timber
open class TimberTreeNoOp : Timber.Tree() {

View File

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

View File

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

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,17 +1,15 @@
package io.github.wulkanowy.data
import android.app.AlarmManager
import android.content.Context
import android.content.SharedPreferences
import android.content.res.AssetManager
import android.content.res.Resources
import androidx.core.content.getSystemService
import androidx.preference.PreferenceManager
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy
import com.chuckerteam.chucker.api.ChuckerCollector
import com.chuckerteam.chucker.api.ChuckerInterceptor
import com.chuckerteam.chucker.api.RetentionManager
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings
import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.strategy.WalledGardenInternetObservingStrategy
import dagger.Module
import dagger.Provides
import io.github.wulkanowy.data.db.AppDatabase

View File

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

View File

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

View File

@ -0,0 +1,14 @@
package io.github.wulkanowy.data.db.migrations
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
class Migration26 : Migration(25, 26) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN is_predicted_grade_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN is_final_grade_notified INTEGER NOT NULL DEFAULT 1")
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN predicted_grade_last_change INTEGER NOT NULL DEFAULT 0")
database.execSQL("ALTER TABLE GradesSummary ADD COLUMN final_grade_last_change INTEGER NOT NULL DEFAULT 0")
}
}

View File

@ -10,7 +10,7 @@ import javax.inject.Singleton
@Singleton
class AppCreatorRepository @Inject constructor(private val assets: AssetManager) {
fun getAppCreators(): Single<List<Contributor>> {
return Single.fromCallable<List<Contributor>> {
return Single.fromCallable {
Gson().fromJson(
assets.open("contributors.json").bufferedReader().use { it.readText() },
Array<Contributor>::class.java

View File

@ -13,7 +13,7 @@ class ExamLocal @Inject constructor(private val examDb: ExamDao) {
fun getExams(semester: Semester, startDate: LocalDate, endDate: LocalDate): Maybe<List<Exam>> {
return examDb.loadAll(semester.diaryId, semester.studentId, startDate, endDate)
.filter { !it.isEmpty() }
.filter { it.isNotEmpty() }
}
fun saveExams(exams: List<Exam>) {

View File

@ -27,6 +27,10 @@ class GradeLocal @Inject constructor(
gradeDb.updateAll(grades)
}
fun updateGradesSummary(gradesSummary: List<GradeSummary>) {
gradeSummaryDb.updateAll(gradesSummary)
}
fun getGradesDetails(semester: Semester): Maybe<List<Grade>> {
return gradeDb.loadAll(semester.semesterId, semester.studentId).filter { it.isNotEmpty() }
}

View File

@ -9,6 +9,7 @@ import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.utils.uniqueSubtract
import io.reactivex.Completable
import io.reactivex.Single
import org.threeten.bp.LocalDateTime
import java.net.UnknownHostException
import javax.inject.Inject
import javax.inject.Singleton
@ -43,7 +44,31 @@ class GradeRepository @Inject constructor(
local.getGradesSummary(semester).toSingle(emptyList())
.doOnSuccess { old ->
local.deleteGradesSummary(old.uniqueSubtract(newSummary))
local.saveGradesSummary(newSummary.uniqueSubtract(old))
local.saveGradesSummary(newSummary.uniqueSubtract(old)
.onEach { summary ->
val oldSummary = old.find { oldSummary -> oldSummary.subject == summary.subject }
summary.isPredictedGradeNotified = when {
summary.predictedGrade.isEmpty() -> true
notify && oldSummary?.predictedGrade != summary.predictedGrade -> false
else -> true
}
summary.isFinalGradeNotified = when {
summary.finalGrade.isEmpty() -> true
notify && oldSummary?.finalGrade != summary.finalGrade -> false
else -> true
}
summary.predictedGradeLastChange = when {
oldSummary == null -> LocalDateTime.now()
summary.predictedGrade != oldSummary.predictedGrade -> LocalDateTime.now()
else -> oldSummary.predictedGradeLastChange
}
summary.finalGradeLastChange = when {
oldSummary == null -> LocalDateTime.now()
summary.finalGrade != oldSummary.finalGrade -> LocalDateTime.now()
else -> oldSummary.finalGradeLastChange
}
})
}
}
}.flatMap {
@ -63,6 +88,14 @@ class GradeRepository @Inject constructor(
return local.getGradesDetails(semester).map { it.filter { grade -> !grade.isNotified } }.toSingle(emptyList())
}
fun getNotNotifiedPredictedGrades(semester: Semester): Single<List<GradeSummary>> {
return local.getGradesSummary(semester).map { it.filter { gradeSummary -> !gradeSummary.isPredictedGradeNotified } }.toSingle(emptyList())
}
fun getNotNotifiedFinalGrades(semester: Semester): Single<List<GradeSummary>> {
return local.getGradesSummary(semester).map { it.filter { gradeSummary -> !gradeSummary.isFinalGradeNotified } }.toSingle(emptyList())
}
fun updateGrade(grade: Grade): Completable {
return Completable.fromCallable { local.updateGrades(listOf(grade)) }
}
@ -70,4 +103,8 @@ class GradeRepository @Inject constructor(
fun updateGrades(grades: List<Grade>): Completable {
return Completable.fromCallable { local.updateGrades(grades) }
}
fun updateGradesSummary(gradesSummary: List<GradeSummary>): Completable {
return Completable.fromCallable { local.updateGradesSummary(gradesSummary) }
}
}

View File

@ -12,7 +12,7 @@ import javax.inject.Singleton
class RecipientLocal @Inject constructor(private val recipientDb: RecipientDao) {
fun getRecipients(student: Student, role: Int, unit: ReportingUnit): Maybe<List<Recipient>> {
return recipientDb.load(student.studentId, role, unit.realId).filter { !it.isEmpty() }
return recipientDb.load(student.studentId, role, unit.realId).filter { it.isNotEmpty() }
}
fun saveRecipients(recipients: List<Recipient>): List<Long> {

View File

@ -11,7 +11,7 @@ import javax.inject.Singleton
class ReportingUnitLocal @Inject constructor(private val reportingUnitDb: ReportingUnitDao) {
fun getReportingUnits(student: Student): Maybe<List<ReportingUnit>> {
return reportingUnitDb.load(student.studentId).filter { !it.isEmpty() }
return reportingUnitDb.load(student.studentId).filter { it.isNotEmpty() }
}
fun getReportingUnit(student: Student, unitId: Int): Maybe<ReportingUnit> {

View File

@ -14,7 +14,7 @@ class StudentRemote @Inject constructor(private val sdk: Sdk) {
private fun mapStudents(students: List<SdkStudent>, email: String, password: String): List<Student> {
return students.map { student ->
Student(
email = email,
email = email.ifBlank { student.email },
password = password,
isParent = student.isParent,
symbol = student.symbol,

View File

@ -9,7 +9,7 @@ import javax.inject.Inject
class GradeStatisticsWork @Inject constructor(private val gradeStatisticsRepository: GradeStatisticsRepository) : Work {
override fun create(student: Student, semester: Semester): Completable {
return gradeStatisticsRepository.getGradesStatistics(student, semester, "Wszystkie", false, true)
return gradeStatisticsRepository.getGradesStatistics(student, semester, "Wszystkie", false, forceRefresh = true)
.ignoreElement()
}
}

View File

@ -9,6 +9,7 @@ import androidx.core.app.NotificationCompat.PRIORITY_HIGH
import androidx.core.app.NotificationManagerCompat
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Grade
import io.github.wulkanowy.data.db.entities.GradeSummary
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.grade.GradeRepository
@ -30,17 +31,21 @@ class GradeWork @Inject constructor(
override fun create(student: Student, semester: Semester): Completable {
return gradeRepository.getGrades(student, semester, true, preferencesRepository.isNotificationsEnable)
.flatMap { gradeRepository.getNotNotifiedGrades(semester) }
.flatMapCompletable {
if (it.isNotEmpty()) notify(it)
.ignoreElement()
.concatWith(Completable.concatArray(gradeRepository.getNotNotifiedGrades(semester).flatMapCompletable {
if (it.isNotEmpty()) notifyDetails(it)
gradeRepository.updateGrades(it.onEach { grade -> grade.isNotified = true })
}
}, gradeRepository.getNotNotifiedPredictedGrades(semester).flatMapCompletable {
if (it.isNotEmpty()) notifyPredicted(it)
gradeRepository.updateGradesSummary(it.onEach { grade -> grade.isPredictedGradeNotified = true })
}, gradeRepository.getNotNotifiedFinalGrades(semester).flatMapCompletable {
if (it.isNotEmpty()) notifyFinal(it)
gradeRepository.updateGradesSummary(it.onEach { grade -> grade.isFinalGradeNotified = true })
}))
}
private fun notify(grades: List<Grade>) {
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), NotificationCompat.Builder(context, NewGradesChannel.CHANNEL_ID)
.setContentTitle(context.resources.getQuantityString(R.plurals.grade_new_items, grades.size, grades.size))
.setContentText(context.resources.getQuantityString(R.plurals.grade_notify_new_items, grades.size, grades.size))
private fun getNotificationBuilder(): NotificationCompat.Builder {
return NotificationCompat.Builder(context, NewGradesChannel.CHANNEL_ID)
.setSmallIcon(R.drawable.ic_stat_grade)
.setAutoCancel(true)
.setPriority(PRIORITY_HIGH)
@ -49,6 +54,12 @@ class GradeWork @Inject constructor(
.setContentIntent(
PendingIntent.getActivity(context, MainView.Section.GRADE.id,
MainActivity.getStartIntent(context, MainView.Section.GRADE, true), FLAG_UPDATE_CURRENT))
}
private fun notifyDetails(grades: List<Grade>) {
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), getNotificationBuilder()
.setContentTitle(context.resources.getQuantityString(R.plurals.grade_new_items, grades.size, grades.size))
.setContentText(context.resources.getQuantityString(R.plurals.grade_notify_new_items, grades.size, grades.size))
.setStyle(NotificationCompat.InboxStyle().run {
setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, grades.size, grades.size))
grades.forEach { addLine("${it.subject}: ${it.entry}") }
@ -57,4 +68,30 @@ class GradeWork @Inject constructor(
.build()
)
}
private fun notifyPredicted(gradesSummary: List<GradeSummary>) {
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), getNotificationBuilder()
.setContentTitle(context.resources.getQuantityString(R.plurals.grade_new_items_predicted, gradesSummary.size, gradesSummary.size))
.setContentText(context.resources.getQuantityString(R.plurals.grade_notify_new_items_predicted, gradesSummary.size, gradesSummary.size))
.setStyle(NotificationCompat.InboxStyle().run {
setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, gradesSummary.size, gradesSummary.size))
gradesSummary.forEach { addLine("${it.subject}: ${it.predictedGrade}") }
this
})
.build()
)
}
private fun notifyFinal(gradesSummary: List<GradeSummary>) {
notificationManager.notify(Random.nextInt(Int.MAX_VALUE), getNotificationBuilder()
.setContentTitle(context.resources.getQuantityString(R.plurals.grade_new_items_final, gradesSummary.size, gradesSummary.size))
.setContentText(context.resources.getQuantityString(R.plurals.grade_notify_new_items_final, gradesSummary.size, gradesSummary.size))
.setStyle(NotificationCompat.InboxStyle().run {
setSummaryText(context.resources.getQuantityString(R.plurals.grade_number_item, gradesSummary.size, gradesSummary.size))
gradesSummary.forEach { addLine("${it.subject}: ${it.finalGrade}") }
this
})
.build()
)
}
}

View File

@ -25,9 +25,9 @@ class LogViewerPresenter @Inject constructor(
disposable.add(loggerRepository.getLogFiles()
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.subscribe({
Timber.i("Loading logs files result: ${it.joinToString { it.name }}")
view?.shareLogs(it)
.subscribe({ files ->
Timber.i("Loading logs files result: ${files.joinToString { it.name }}")
view?.shareLogs(files)
}, {
Timber.i("Loading logs files result: An exception occurred")
errorHandler.dispatch(it)

View File

@ -0,0 +1,3 @@
package io.github.wulkanowy.ui.modules.account
data class Account(val email: String, val isParent: Boolean)

View File

@ -3,33 +3,72 @@ package io.github.wulkanowy.ui.modules.account
import android.annotation.SuppressLint
import android.graphics.PorterDuff
import android.view.LayoutInflater
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.databinding.HeaderAccountBinding
import io.github.wulkanowy.databinding.ItemAccountBinding
import io.github.wulkanowy.sdk.Sdk
import io.github.wulkanowy.utils.getThemeAttrColor
import javax.inject.Inject
class AccountAdapter @Inject constructor() : RecyclerView.Adapter<AccountAdapter.ItemViewHolder>() {
class AccountAdapter @Inject constructor() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var items = emptyList<Student>()
var items = emptyList<AccountItem<*>>()
var onClickListener: (Student) -> Unit = {}
override fun getItemCount() = items.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
ItemAccountBinding.inflate(LayoutInflater.from(parent.context), parent, false)
)
override fun getItemViewType(position: Int) = items[position].viewType.id
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
AccountItem.ViewType.HEADER.id -> HeaderViewHolder(HeaderAccountBinding.inflate(inflater, parent, false))
AccountItem.ViewType.ITEM.id -> ItemViewHolder(ItemAccountBinding.inflate(inflater, parent, false))
else -> throw IllegalStateException()
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is HeaderViewHolder -> bindHeaderViewHolder(holder.binding, items[position].value as Account)
is ItemViewHolder -> bindItemViewHolder(holder.binding, items[position].value as Student)
}
}
private fun bindHeaderViewHolder(binding: HeaderAccountBinding, account: Account) {
with(binding) {
accountHeaderEmail.text = account.email
accountHeaderType.setText(if (account.isParent) R.string.account_type_parent else R.string.account_type_student)
}
}
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val student = items[position]
with(holder.binding) {
private fun bindItemViewHolder(binding: ItemAccountBinding, student: Student) {
with(binding) {
accountItemName.text = "${student.studentName} ${student.className}"
accountItemSchool.text = student.schoolName
with(accountItemLoginMode) {
visibility = when (Sdk.Mode.valueOf(student.loginMode)) {
Sdk.Mode.API -> {
setText(R.string.account_login_mobile_api)
VISIBLE
}
Sdk.Mode.HYBRID -> {
setText(R.string.account_login_hybrid)
VISIBLE
}
Sdk.Mode.SCRAPPER -> {
GONE
}
}
}
with(accountItemImage) {
val colorImage = if (student.isCurrent) context.getThemeAttrColor(R.attr.colorPrimary)
@ -42,5 +81,8 @@ class AccountAdapter @Inject constructor() : RecyclerView.Adapter<AccountAdapter
}
}
class HeaderViewHolder(val binding: HeaderAccountBinding) :
RecyclerView.ViewHolder(binding.root)
class ItemViewHolder(val binding: ItemAccountBinding) : RecyclerView.ViewHolder(binding.root)
}

View File

@ -9,7 +9,6 @@ import android.widget.Toast.LENGTH_LONG
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.databinding.DialogAccountBinding
import io.github.wulkanowy.ui.base.BaseDialogFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
@ -54,7 +53,7 @@ class AccountDialog : BaseDialogFragment<DialogAccountBinding>(), AccountView {
}
}
override fun updateData(data: List<Student>) {
override fun updateData(data: List<AccountItem<*>>) {
with(accountAdapter) {
items = data
notifyDataSetChanged()

View File

@ -0,0 +1,9 @@
package io.github.wulkanowy.ui.modules.account
data class AccountItem<out T>(val value: T, val viewType: ViewType) {
enum class ViewType(val id: Int) {
HEADER(1),
ITEM(2)
}
}

View File

@ -83,11 +83,20 @@ class AccountPresenter @Inject constructor(
}
}
private fun createAccountItems(items: List<Student>): List<AccountItem<*>> {
return items.groupBy { Account(it.email, it.isParent) }.map { (account, students) ->
listOf(AccountItem(account, AccountItem.ViewType.HEADER)) + students.map { student ->
AccountItem(student, AccountItem.ViewType.ITEM)
}
}.flatten()
}
private fun loadData() {
Timber.i("Loading account data started")
disposable.add(studentRepository.getSavedStudents(false)
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.map { createAccountItems(it) }
.subscribe({
Timber.i("Loading account result: Success")
view?.updateData(it)

View File

@ -1,13 +1,12 @@
package io.github.wulkanowy.ui.modules.account
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.ui.base.BaseView
interface AccountView : BaseView {
fun initView()
fun updateData(data: List<Student>)
fun updateData(data: List<AccountItem<*>>)
fun dismissView()

View File

@ -20,7 +20,6 @@ import org.threeten.bp.LocalDate
import org.threeten.bp.LocalDate.now
import org.threeten.bp.LocalDate.ofEpochDay
import timber.log.Timber
import java.util.concurrent.TimeUnit.MILLISECONDS
import javax.inject.Inject
class AttendancePresenter @Inject constructor(

View File

@ -98,7 +98,7 @@ class GradeAverageProvider @Inject constructor(
}
private fun List<GradeSummary>.emulateEmptySummaries(student: Student, semester: Semester, grades: List<Pair<String, List<Grade>>>, calcAverage: Boolean): List<GradeSummary> {
if (isNotEmpty() && size == grades.size) return this
if (isNotEmpty() && size > grades.size) return this
return grades.mapIndexed { i, (subject, details) ->
singleOrNull { it.subject == subject }?.let { return@mapIndexed it }

View File

@ -63,7 +63,7 @@ class MessagePreviewAdapter @Inject constructor() :
@SuppressLint("SetTextI18n")
private fun bindMessage(holder: MessageViewHolder, message: Message) {
with(holder.binding) {
messagePreviewSubject.text = if (message.subject.isNotBlank()) message.subject else root.context.getString(R.string.message_no_subject)
messagePreviewSubject.text = message.subject.ifBlank { root.context.getString(R.string.message_no_subject) }
messagePreviewDate.text = root.context.getString(R.string.message_date, message.date.toFormattedString("yyyy-MM-dd HH:mm:ss"))
messagePreviewContent.text = message.content
messagePreviewAuthor.text = if (message.folderId == MessageFolder.SENT.id) "${root.context.getString(R.string.message_to)} ${message.recipient}"

View File

@ -1,12 +1,20 @@
package io.github.wulkanowy.ui.modules.message.preview
import android.os.Build
import android.os.Bundle
import android.print.PrintAttributes
import android.print.PrintManager
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.annotation.RequiresApi
import androidx.core.content.getSystemService
import androidx.recyclerview.widget.LinearLayoutManager
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Message
@ -17,6 +25,8 @@ import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.ui.modules.message.MessageFragment
import io.github.wulkanowy.ui.modules.message.send.SendMessageActivity
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.shareText
import javax.inject.Inject
class MessagePreviewFragment :
@ -29,18 +39,31 @@ class MessagePreviewFragment :
@Inject
lateinit var previewAdapter: MessagePreviewAdapter
@Inject
lateinit var appInfo: AppInfo
private var menuReplyButton: MenuItem? = null
private var menuForwardButton: MenuItem? = null
private var menuDeleteButton: MenuItem? = null
private var menuShareButton: MenuItem? = null
private var menuPrintButton: MenuItem? = null
override val titleStringId: Int
get() = R.string.message_title
override val deleteMessageSuccessString: String
get() = getString(R.string.message_delete_success)
override val messageNoSubjectString: String
get() = getString(R.string.message_no_subject)
override val printHTML: String
get() = requireContext().assets.open("message-print-page.html").bufferedReader().use { it.readText() }
companion object {
const val MESSAGE_ID_KEY = "message_id"
@ -77,6 +100,8 @@ class MessagePreviewFragment :
menuReplyButton = menu.findItem(R.id.messagePreviewMenuReply)
menuForwardButton = menu.findItem(R.id.messagePreviewMenuForward)
menuDeleteButton = menu.findItem(R.id.messagePreviewMenuDelete)
menuShareButton = menu.findItem(R.id.messagePreviewMenuShare)
menuPrintButton = menu.findItem(R.id.messagePreviewMenuPrint)
presenter.onCreateOptionsMenu()
}
@ -85,6 +110,8 @@ class MessagePreviewFragment :
R.id.messagePreviewMenuReply -> presenter.onReply()
R.id.messagePreviewMenuForward -> presenter.onForward()
R.id.messagePreviewMenuDelete -> presenter.onMessageDelete()
R.id.messagePreviewMenuShare -> presenter.onShare()
R.id.messagePreviewMenuPrint -> presenter.onPrint()
else -> false
}
}
@ -108,6 +135,8 @@ class MessagePreviewFragment :
menuReplyButton?.isVisible = show
menuForwardButton?.isVisible = show
menuDeleteButton?.isVisible = show
menuShareButton?.isVisible = show
menuPrintButton?.isVisible = show && appInfo.systemVersion >= Build.VERSION_CODES.LOLLIPOP
}
override fun setDeletedOptionsLabels() {
@ -138,6 +167,38 @@ class MessagePreviewFragment :
context?.let { it.startActivity(SendMessageActivity.getStartIntent(it, message)) }
}
override fun shareText(text: String, subject: String) {
context?.shareText(text, subject)
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
override fun printDocument(html: String, jobName: String) {
val webView = WebView(activity)
webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest) = false
override fun onPageFinished(view: WebView, url: String) {
createWebPrintJob(view, jobName)
}
}
webView.loadDataWithBaseURL("file:///android_asset/", html, "text/HTML", "UTF-8", null)
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun createWebPrintJob(webView: WebView, jobName: String) {
activity?.getSystemService<PrintManager>()?.let { printManager ->
val printAdapter = webView.createPrintDocumentAdapter(jobName)
printManager.print(
jobName,
printAdapter,
PrintAttributes.Builder().build()
)
}
}
override fun popView() {
(activity as MainActivity).popView()
}

View File

@ -1,12 +1,17 @@
package io.github.wulkanowy.ui.modules.message.preview
import android.annotation.SuppressLint
import android.os.Build
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageAttachment
import io.github.wulkanowy.data.repositories.message.MessageRepository
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
import io.github.wulkanowy.utils.toFormattedString
import timber.log.Timber
import javax.inject.Inject
@ -15,11 +20,14 @@ class MessagePreviewPresenter @Inject constructor(
errorHandler: ErrorHandler,
studentRepository: StudentRepository,
private val messageRepository: MessageRepository,
private val analytics: FirebaseAnalyticsHelper
private val analytics: FirebaseAnalyticsHelper,
private var appInfo: AppInfo
) : BasePresenter<MessagePreviewView>(errorHandler, studentRepository, schedulers) {
var message: Message? = null
var attachments: List<MessageAttachment>? = null
private lateinit var lastError: Throwable
private var retryCallback: () -> Unit = {}
@ -56,6 +64,7 @@ class MessagePreviewPresenter @Inject constructor(
.subscribe({ message ->
Timber.i("Loading message ${message.message.messageId} preview result: Success ")
this@MessagePreviewPresenter.message = message.message
this@MessagePreviewPresenter.attachments = message.attachments
view?.apply {
setMessageWithAttachment(message)
initOptions()
@ -87,6 +96,60 @@ class MessagePreviewPresenter @Inject constructor(
} else false
}
fun onShare(): Boolean {
message?.let {
var text = "Temat: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }}\n" + when (it.sender.isNotEmpty()) {
true -> "Od: ${it.sender}\n"
false -> "Do: ${it.recipient}\n"
} + "Data: ${it.date.toFormattedString("yyyy-MM-dd HH:mm:ss")}\n\n${it.content}"
attachments?.let { attachments ->
if (attachments.isNotEmpty()) {
text += "\n\nZałączniki:"
attachments.forEach { attachment ->
text += "\n${attachment.filename}: ${attachment.url}"
}
}
}
view?.shareText(text, "FW: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }}")
return true
}
return false
}
@SuppressLint("NewApi")
fun onPrint(): Boolean {
if (appInfo.systemVersion < Build.VERSION_CODES.LOLLIPOP) return false
message?.let {
val dateString = it.date.toFormattedString("yyyy-MM-dd HH:mm:ss")
val infoContent = "<div><h4>Data wysłania</h4>$dateString</div>" + when {
it.sender.isNotEmpty() -> "<div><h4>Od</h4>${it.sender}</div>"
else -> "<div><h4>Do</h4>${it.recipient}</div>"
}
val messageContent = "<p>${it.content}</p>"
.replace(Regex("[\\n\\r]{2,}"), "</p><p>")
.replace(Regex("[\\n\\r]"), "<br>")
val jobName = "Wiadomość " + when {
it.sender.isNotEmpty() -> "od ${it.sender}"
else -> "do ${it.recipient}"
} + " $dateString: ${it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() }} | Wulkanowy"
view?.apply {
val html = printHTML
.replace("%SUBJECT%", it.subject.ifBlank { view?.messageNoSubjectString.orEmpty() })
.replace("%CONTENT%", messageContent)
.replace("%INFO%", infoContent)
printDocument(html, jobName)
}
return true
}
return false
}
private fun deleteMessage() {
message?.let { message ->
disposable.add(studentRepository.getCurrentStudent()

View File

@ -1,5 +1,7 @@
package io.github.wulkanowy.ui.modules.message.preview
import android.os.Build
import androidx.annotation.RequiresApi
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.MessageWithAttachment
import io.github.wulkanowy.ui.base.BaseView
@ -8,6 +10,10 @@ interface MessagePreviewView : BaseView {
val deleteMessageSuccessString: String
val messageNoSubjectString: String
val printHTML: String
fun initView()
fun setMessageWithAttachment(item: MessageWithAttachment)
@ -34,5 +40,10 @@ interface MessagePreviewView : BaseView {
fun openMessageForward(message: Message?)
fun shareText(text: String, subject: String)
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun printDocument(html: String, jobName: String)
fun popView()
}

View File

@ -4,10 +4,9 @@ import android.graphics.Typeface
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.NO_POSITION
import androidx.recyclerview.widget.SortedList
import androidx.recyclerview.widget.SortedListAdapterCallback
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.repositories.message.MessageFolder
@ -20,39 +19,23 @@ class MessageTabAdapter @Inject constructor() :
var onClickListener: (Message, position: Int) -> Unit = { _, _ -> }
private val items = SortedList(Message::class.java, object :
SortedListAdapterCallback<Message>(this) {
private var items = mutableListOf<Message>()
override fun compare(item1: Message, item2: Message): Int {
return item2.date.compareTo(item1.date)
}
override fun areContentsTheSame(oldItem: Message?, newItem: Message?): Boolean {
return oldItem == newItem
}
override fun areItemsTheSame(item1: Message, item2: Message): Boolean {
return item1 == item2
}
})
fun replaceAll(models: List<Message>) {
items.beginBatchedUpdates()
for (i in items.size() - 1 downTo 0) {
val model = items.get(i)
if (model !in models) {
items.remove(model)
}
}
items.addAll(models)
items.endBatchedUpdates()
fun setDataItems(data: List<Message>) {
val diffResult = DiffUtil.calculateDiff(MessageTabDiffUtil(items, data))
items = data.toMutableList()
diffResult.dispatchUpdatesTo(this)
}
fun updateItem(position: Int, item: Message) {
items.updateItemAt(position, item)
val currentItem = items[position]
items[position] = item
if (item != currentItem) {
notifyItemChanged(position)
}
}
override fun getItemCount() = items.size()
override fun getItemCount() = items.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ItemViewHolder(
ItemMessageBinding.inflate(LayoutInflater.from(parent.context), parent, false)
@ -85,4 +68,19 @@ class MessageTabAdapter @Inject constructor() :
}
class ItemViewHolder(val binding: ItemMessageBinding) : RecyclerView.ViewHolder(binding.root)
private class MessageTabDiffUtil(private val old: List<Message>, private val new: List<Message>) :
DiffUtil.Callback() {
override fun getOldListSize(): Int = old.size
override fun getNewListSize(): Int = new.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return old[oldItemPosition].id == new[newItemPosition].id
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return old[oldItemPosition] == new[newItemPosition]
}
}
}

View File

@ -90,7 +90,7 @@ class MessageTabFragment : BaseFragment<FragmentMessageTabBinding>(R.layout.frag
}
override fun updateData(data: List<Message>) {
tabAdapter.replaceAll(data)
tabAdapter.setDataItems(data)
}
override fun updateItem(item: Message, position: Int) {

View File

@ -1,6 +1,5 @@
package io.github.wulkanowy.ui.modules.message.tab
import android.annotation.SuppressLint
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.repositories.message.MessageFolder
import io.github.wulkanowy.data.repositories.message.MessageRepository
@ -11,8 +10,13 @@ import io.github.wulkanowy.ui.base.ErrorHandler
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
import io.github.wulkanowy.utils.toFormattedString
import io.reactivex.subjects.PublishSubject
import me.xdrop.fuzzywuzzy.FuzzySearch
import timber.log.Timber
import java.util.Locale
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import kotlin.math.pow
class MessageTabPresenter @Inject constructor(
schedulers: SchedulersProvider,
@ -31,9 +35,12 @@ class MessageTabPresenter @Inject constructor(
private var messages = emptyList<Message>()
private val searchQuery = PublishSubject.create<String>()
fun onAttachView(view: MessageTabView, folder: MessageFolder) {
super.onAttachView(view)
view.initView()
initializeSearchStream()
errorHandler.showErrorMessage = ::showErrorViewOnError
this.folder = folder
}
@ -76,38 +83,35 @@ class MessageTabPresenter @Inject constructor(
private fun loadData(forceRefresh: Boolean) {
Timber.i("Loading $folder message data started")
disposable.apply {
clear()
add(studentRepository.getCurrentStudent()
.flatMap { student ->
semesterRepository.getCurrentSemester(student)
.flatMap { messageRepository.getMessages(student, it, folder, forceRefresh) }
disposable.add(studentRepository.getCurrentStudent()
.flatMap { student ->
semesterRepository.getCurrentSemester(student)
.flatMap { messageRepository.getMessages(student, it, folder, forceRefresh) }
}
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.doFinally {
view?.run {
showRefresh(false)
showProgress(false)
enableSwipe(true)
notifyParentDataLoaded()
}
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.doFinally {
view?.run {
showRefresh(false)
showProgress(false)
enableSwipe(true)
notifyParentDataLoaded()
}
}
.subscribe({
Timber.i("Loading $folder message result: Success")
messages = it
onSearchQueryTextChange(lastSearchQuery)
analytics.logEvent(
"load_data",
"type" to "messages",
"items" to it.size,
"folder" to folder.name
)
}) {
Timber.i("Loading $folder message result: An exception occurred")
errorHandler.dispatch(it)
})
}
}
.subscribe({
Timber.i("Loading $folder message result: Success")
messages = it
view?.updateData(getFilteredData(lastSearchQuery))
analytics.logEvent(
"load_data",
"type" to "messages",
"items" to it.size,
"folder" to folder.name
)
}) {
Timber.i("Loading $folder message result: An exception occurred")
errorHandler.dispatch(it)
})
}
private fun showErrorViewOnError(message: String, error: Throwable) {
@ -121,25 +125,36 @@ class MessageTabPresenter @Inject constructor(
}
}
@SuppressLint("DefaultLocale")
fun onSearchQueryTextChange(query: String) {
lastSearchQuery = query
if (query != searchQuery.toString())
searchQuery.onNext(query)
}
val lowerCaseQuery = query.toLowerCase()
val filteredList = mutableListOf<Message>()
messages.forEach {
if (lowerCaseQuery in it.subject.toLowerCase() ||
lowerCaseQuery in it.sender.toLowerCase() ||
lowerCaseQuery in it.recipient.toLowerCase() ||
lowerCaseQuery in it.date.toFormattedString()
) {
filteredList.add(it)
private fun initializeSearchStream() {
disposable.add(searchQuery
.debounce(250, TimeUnit.MILLISECONDS)
.map { query ->
lastSearchQuery = query
getFilteredData(query)
}
.subscribeOn(schedulers.backgroundThread)
.observeOn(schedulers.mainThread)
.subscribe({
Timber.d("Applying filter. Full list: ${messages.size}, filtered: ${it.size}")
updateData(it)
}) { Timber.e(it) })
}
private fun getFilteredData(query: String): List<Message> {
return if (query.trim().isEmpty()) {
messages.sortedByDescending { it.date }
} else {
messages
.map { it to calculateMatchRatio(it, query) }
.sortedByDescending { it.second }
.filter { it.second > 5000 }
.map { it.first }
}
Timber.d("Applying filter. Full list: ${messages.size}, filtered: ${filteredList.size}")
updateData(filteredList)
}
private fun updateData(data: List<Message>) {
@ -151,4 +166,42 @@ class MessageTabPresenter @Inject constructor(
resetListPosition()
}
}
private fun calculateMatchRatio(message: Message, query: String): Int {
val subjectRatio = FuzzySearch.tokenSortPartialRatio(
query.toLowerCase(Locale.getDefault()),
message.subject
)
val senderOrRecipientRatio = FuzzySearch.tokenSortPartialRatio(
query.toLowerCase(Locale.getDefault()),
if (message.sender.isNotEmpty()) message.sender.toLowerCase(Locale.getDefault())
else message.recipient.toLowerCase(Locale.getDefault())
)
val dateRatio = listOf(
FuzzySearch.ratio(
query.toLowerCase(Locale.getDefault()),
message.date.toFormattedString("dd.MM").toLowerCase(Locale.getDefault())
),
FuzzySearch.ratio(
query.toLowerCase(Locale.getDefault()),
message.date.toFormattedString("dd.MM.yyyy").toLowerCase(Locale.getDefault())
),
FuzzySearch.ratio(
query.toLowerCase(Locale.getDefault()),
message.date.toFormattedString("d MMMM").toLowerCase(Locale.getDefault())
),
FuzzySearch.ratio(
query.toLowerCase(Locale.getDefault()),
message.date.toFormattedString("d MMMM yyyy").toLowerCase(Locale.getDefault())
)
).max() ?: 0
return (subjectRatio.toDouble().pow(2)
+ senderOrRecipientRatio.toDouble().pow(2)
+ dateRatio.toDouble().pow(2) * 2
).toInt()
}
}

View File

@ -43,7 +43,7 @@ class CompletedLessonsPresenter @Inject constructor(
completedLessonsErrorHandler.showErrorMessage = ::showErrorViewOnError
completedLessonsErrorHandler.onFeatureDisabled = {
this.view?.showFeatureDisabled()
this.view?.showEmpty(true);
this.view?.showEmpty(true)
Timber.i("Completed lessons feature disabled by school")
}
loadData(ofEpochDay(date ?: baseDate.toEpochDay()))

View File

@ -71,4 +71,17 @@ fun Context.openDialer(phone: String) {
startActivity(intent)
}
fun Context.shareText(text: String, subject: String?) {
val sendIntent: Intent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, text)
if (subject != null) {
putExtra(Intent.EXTRA_SUBJECT, subject)
}
type = "text/plain"
}
val shareIntent = Intent.createChooser(sendIntent, null)
startActivity(shareIntent)
}
fun Context.dpToPx(dp: Float) = dp * resources.displayMetrics.densityDpi / DENSITY_DEFAULT

View File

@ -52,4 +52,4 @@ class LifecycleAwareVariableActivity<T : Any> : ReadWriteProperty<AppCompatActiv
@Suppress("unused")
fun <T : Any> Fragment.lifecycleAwareVariable() = LifecycleAwareVariable<T>()
fun <T : Any> AppCompatActivity.lifecycleAwareVariable() = LifecycleAwareVariableActivity<T>()
fun <T : Any> lifecycleAwareVariable() = LifecycleAwareVariableActivity<T>()

View File

@ -23,6 +23,8 @@ fun Sdk.init(student: Student): Sdk {
certKey = student.certificateKey
privateKey = student.privateKey
emptyCookieJarInterceptor = true
Timber.d("Sdk in ${student.loginMode} mode reinitialized")
return this

View File

@ -1,6 +1,8 @@
Wersja 0.18.3
- poprawiliśmy liczenie średniej i dodaliśmy nowy sposób jej liczenia w ustawieniach
- naprawiliśmy usuwanie wiadomości
- naprawiliśmy wysyłanie wiadomości na Lubelskim Portalu Oświatowym
Wersja 0.19.0
- naprawiliśmy pokazywanie brakujących przedmiotów na liście podsumowania ocen
- ulepszyliśmy wygląd menadżera kont
- ulepszyliśmy wyszukiwarkę wiadomości
- dodaliśmy powiadomienia o proponowanych i końcowych ocenach
- dodaliśmy opcję udostępniania i drukowania wiadomości
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19,8h-1L18,3L6,3v5L5,8c-1.66,0 -3,1.34 -3,3v6h4v4h12v-4h4v-6c0,-1.66 -1.34,-3 -3,-3zM8,5h8v3L8,8L8,5zM16,17v2L8,19v-4h8v2zM18,15v-2L6,13v2L4,15v-4c0,-0.55 0.45,-1 1,-1h14c0.55,0 1,0.45 1,1v4h-2z" />
<path
android:fillColor="@android:color/white"
android:pathData="M18,11.5m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92s2.92,-1.31 2.92,-2.92c0,-1.61 -1.31,-2.92 -2.92,-2.92zM18,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM6,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM18,20.02c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z" />
</vector>

View File

@ -5,45 +5,60 @@
android:layout_width="300dp"
android:layout_height="wrap_content">
<TextView
android:id="@+id/accountDialogTitle"
android:layout_width="match_parent"
android:layout_height="64dp"
android:paddingStart="24dp"
android:paddingLeft="24dp"
android:paddingEnd="24dp"
android:paddingRight="24dp"
android:text="@string/account_title"
android:textSize="20sp"
android:textStyle="bold"
app:firstBaselineToTopHeight="40dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/accountDialogRecycler"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/accountDialogTitle"
android:overScrollMode="never"
tools:itemCount="3"
tools:listitem="@layout/item_account" />
android:orientation="vertical">
<com.google.android.material.button.MaterialButton
android:id="@+id/accountDialogAdd"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/accountDialogRecycler"
android:layout_margin="8dp"
android:text="@string/account_add_new"
android:textColor="?android:textColorPrimary" />
<TextView
android:id="@+id/accountDialogTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingLeft="24dp"
android:paddingEnd="24dp"
android:paddingRight="24dp"
android:text="@string/account_title"
android:textSize="20sp"
android:textStyle="bold"
app:firstBaselineToTopHeight="40dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/accountDialogRemove"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/accountDialogRecycler"
android:layout_alignParentEnd="true"
android:layout_margin="8dp"
android:text="@string/account_logout" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/accountDialogRecycler"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_weight="1"
android:overScrollMode="never"
tools:itemCount="3"
tools:listitem="@layout/item_account" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/accountDialogAdd"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/account_add_new"
android:textColor="?android:textColorPrimary" />
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<com.google.android.material.button.MaterialButton
android:id="@+id/accountDialogRemove"
style="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="@string/account_logout" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="24dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
tools:context=".ui.modules.account.AccountAdapter">
<TextView
android:id="@+id/accountHeaderEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?android:textColorPrimary"
android:textSize="14sp"
tools:text="jan@fakelog.cf" />
<TextView
android:id="@+id/accountHeaderType"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
tools:text="Konto ucznia" />
</LinearLayout>

View File

@ -3,20 +3,17 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:orientation="horizontal"
android:paddingStart="24dp"
android:paddingLeft="24dp"
android:paddingEnd="24dp"
android:paddingRight="24dp"
android:paddingVertical="8dp"
android:paddingHorizontal="16dp"
tools:context=".ui.modules.account.AccountAdapter">
<ImageView
android:id="@+id/accountItemImage"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_all_account"
@ -27,7 +24,7 @@
android:id="@+id/accountItemName"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginStart="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textSize="16sp"
@ -40,7 +37,7 @@
android:id="@+id/accountItemSchool"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginStart="16dp"
android:layout_marginTop="3dp"
android:ellipsize="end"
android:maxLines="1"
@ -50,4 +47,21 @@
app:layout_constraintStart_toEndOf="@id/accountItemImage"
app:layout_constraintTop_toBottomOf="@id/accountItemName"
tools:text="@tools:sample/lorem/random" />
<TextView
android:id="@+id/accountItemLoginMode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="3dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="12sp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/accountItemImage"
app:layout_constraintTop_toBottomOf="@id/accountItemSchool"
tools:text="Tryb API mobilne"
tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -22,4 +22,18 @@
android:title="@string/message_delete"
app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="ifRoom" />
<item
android:id="@+id/messagePreviewMenuShare"
android:icon="@drawable/ic_menu_message_share"
android:orderInCategory="1"
android:title="@string/message_share"
app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="ifRoom" />
<item
android:id="@+id/messagePreviewMenuPrint"
android:icon="@drawable/ic_menu_message_print"
android:orderInCategory="1"
android:title="@string/message_print"
app:iconTint="@color/material_on_surface_emphasis_medium"
app:showAsAction="ifRoom" />
</menu>

View File

@ -36,8 +36,8 @@
</string-array>
<string-array name="grade_average_mode_entries">
<item>Durchschnittsnote für das 2. Semester</item>
<item>Average of grades from both semesters</item>
<item>Durchschnitt der Bewertungen für das ganze Jahr</item>
<item>Durchschnitt der Noten aus beiden Semestern</item>
<item>Durchschnitt der Noten aus dem ganzen Jahr</item>
</string-array>
<string-array name="timetable_show_whole_class_entries">
<item>Nicht zeigen</item>

View File

@ -103,10 +103,26 @@
<item quantity="one">Neue Note</item>
<item quantity="other">Neue Noten</item>
</plurals>
<plurals name="grade_new_items_predicted">
<item quantity="one">New predicted grade</item>
<item quantity="other">New predicted grades</item>
</plurals>
<plurals name="grade_new_items_final">
<item quantity="one">New final grade</item>
<item quantity="other">New final grades</item>
</plurals>
<plurals name="grade_notify_new_items">
<item quantity="one">Du hast %1$d Note bekommen</item>
<item quantity="other">Du hast %1$d Noten bekommen</item>
</plurals>
<plurals name="grade_notify_new_items_predicted">
<item quantity="one">You received %1$d predicted grade</item>
<item quantity="other">You received %1$d predicted grades</item>
</plurals>
<plurals name="grade_notify_new_items_final">
<item quantity="one">You received %1$d final grade</item>
<item quantity="other">You received %1$d final grades</item>
</plurals>
<!--Timetable-->
<string name="timetable_lesson">Lektion</string>
<string name="timetable_room">Klassenzimmer</string>
@ -172,6 +188,8 @@
<string name="message_move_to_bin">In den Korb wandern</string>
<string name="message_delete_forever">Dauerhaft löschen</string>
<string name="message_delete_success">Nachricht erfolgreich gelöscht</string>
<string name="message_share">Share</string>
<string name="message_print">Print</string>
<string name="message_subject">Thema</string>
<string name="message_content">Inhalt</string>
<string name="message_send_successful">Nachricht erfolgreich gesendet</string>
@ -214,7 +232,7 @@
<string name="lucky_number_header">Die heutige Glücksnummer ist </string>
<string name="lucky_number_empty">Keine Information über die Glücksnummer.</string>
<string name="lucky_number_notify_new_item_title">Glücksnummer für heute</string>
<string name="lucky_number_notify_new_item">Die heutige Glücksnummer ist: </string>
<string name="lucky_number_notify_new_item">Die heutige Glücksnummer ist: %d</string>
<!--Mobile devices-->
<string name="mobile_devices_title">Mobile Geräte</string>
<string name="mobile_devices_no_items">Keine Geräte</string>
@ -245,6 +263,10 @@
<string name="account_logout">Abmelden</string>
<string name="account_confirm">Wollen Sie sich von einem aktiven Studenten abmelden?</string>
<string name="account_logout_student">Abmeldung von Student</string>
<string name="account_type_student">Student account</string>
<string name="account_type_parent">Parent account</string>
<string name="account_login_mobile_api">Mobile API mode</string>
<string name="account_login_hybrid">Hybrid mode</string>
<!--About-->
<string name="about_version">Version der App</string>
<string name="about_contributor">Mitarbeiter</string>
@ -270,8 +292,8 @@
<string name="logviewer_share">Logs teilen</string>
<string name="logviewer_refresh">Aktualisieren</string>
<!--Error dialog-->
<string name="dialog_error_check_update">Check for updates</string>
<string name="dialog_error_check_update_message">Before reporting a bug, check first if an update with the bug fix is available</string>
<string name="dialog_error_check_update">Auf Updates prüfen</string>
<string name="dialog_error_check_update_message">Bevor Sie einen Fehler melden, prüfen Sie zuerst, ob ein Update mit der Fehlerbehebung verfügbar ist</string>
<!--Generic-->
<string name="all_content">Inhalt</string>
<string name="all_retry">Wiederhol</string>
@ -289,7 +311,7 @@
<string name="all_prev">Zurück</string>
<string name="all_next">Nächste</string>
<string name="all_search">Suchen</string>
<string name="all_search_hint">Suchen...</string>
<string name="all_search_hint">Suchen</string>
<!--Timetable Widget-->
<string name="widget_timetable_no_items">Keine Lektionen</string>
<string name="widget_timetable_theme_title">Thema wählen</string>

View File

@ -107,12 +107,36 @@
<item quantity="many">Nowe oceny</item>
<item quantity="other">Nowe oceny</item>
</plurals>
<plurals name="grade_new_items_predicted">
<item quantity="one">Nowa ocena przewidywana</item>
<item quantity="few">Nowe oceny przewidywane</item>
<item quantity="many">Nowe oceny przewidywane</item>
<item quantity="other">Nowe oceny przewidywane</item>
</plurals>
<plurals name="grade_new_items_final">
<item quantity="one">Nowa ocena końcowa</item>
<item quantity="few">Nowe oceny końcowe</item>
<item quantity="many">Nowe oceny końcowe</item>
<item quantity="other">Nowe oceny końcowe</item>
</plurals>
<plurals name="grade_notify_new_items">
<item quantity="one">Masz %1$d nową ocenę</item>
<item quantity="few">Masz %1$d nowe oceny</item>
<item quantity="many">Masz %1$d nowych ocen</item>
<item quantity="other">Masz %1$d nowych ocen</item>
</plurals>
<plurals name="grade_notify_new_items_predicted">
<item quantity="one">Masz %1$d nową przewidywaną ocenę</item>
<item quantity="few">Masz %1$d nowe przewidywane oceny</item>
<item quantity="many">Masz %1$d nowych przewidywanych ocen</item>
<item quantity="other">Masz %1$d nowych przewidywanych ocen</item>
</plurals>
<plurals name="grade_notify_new_items_final">
<item quantity="one">Masz %1$d nową końcową ocenę</item>
<item quantity="few">Masz %1$d nowe końcowe oceny</item>
<item quantity="many">Masz %1$d nowych końcowych ocen</item>
<item quantity="other">Masz %1$d nowych końcowych ocen</item>
</plurals>
<!--Timetable-->
<string name="timetable_lesson">Lekcja</string>
<string name="timetable_room">Sala</string>
@ -180,6 +204,8 @@
<string name="message_move_to_bin">Przenieś do kosza</string>
<string name="message_delete_forever">Usuń trwale</string>
<string name="message_delete_success">Wiadomość usunięta pomyślnie</string>
<string name="message_share">Udostępnij</string>
<string name="message_print">Drukuj</string>
<string name="message_subject">Temat</string>
<string name="message_content">Treść</string>
<string name="message_send_successful">Wiadomość wysłana pomyślnie</string>
@ -265,6 +291,10 @@
<string name="account_logout">Wyloguj</string>
<string name="account_confirm">Czy chcesz wylogować aktualnego ucznia?</string>
<string name="account_logout_student">Wylogowanie ucznia</string>
<string name="account_type_student">Konto ucznia</string>
<string name="account_type_parent">Konto rodzica</string>
<string name="account_login_mobile_api">Tryb API mobilne</string>
<string name="account_login_hybrid">Tryb hybrydowy</string>
<!--About-->
<string name="about_version">Wersja aplikacji</string>
<string name="about_contributor">Twórcy</string>
@ -309,7 +339,7 @@
<string name="all_prev">Poprzedni</string>
<string name="all_next">Następny</string>
<string name="all_search">Szukaj</string>
<string name="all_search_hint">Szukaj...</string>
<string name="all_search_hint">Szukaj</string>
<!--Timetable Widget-->
<string name="widget_timetable_no_items">Brak lekcji</string>
<string name="widget_timetable_theme_title">Wybierz motyw</string>

View File

@ -37,7 +37,7 @@
<string-array name="grade_average_mode_entries">
<item>Средняя оценка со 2 семестра</item>
<item>Average of grades from both semesters</item>
<item>Средняя оценка с целого года</item>
<item>Average of grades from the whole year</item>
</string-array>
<string-array name="timetable_show_whole_class_entries">
<item>Не показывать</item>

View File

@ -107,12 +107,36 @@
<item quantity="many">Новые оценки</item>
<item quantity="other">Новые оценки</item>
</plurals>
<plurals name="grade_new_items_predicted">
<item quantity="one">New predicted grade</item>
<item quantity="few">New predicted grades</item>
<item quantity="many">New predicted grades</item>
<item quantity="other">New predicted grades</item>
</plurals>
<plurals name="grade_new_items_final">
<item quantity="one">New final grade</item>
<item quantity="few">New final grades</item>
<item quantity="many">New final grades</item>
<item quantity="other">New final grades</item>
</plurals>
<plurals name="grade_notify_new_items">
<item quantity="one">Вы получили %1$d оценку</item>
<item quantity="few">Вы получили %1$d оценки</item>
<item quantity="many">Вы получили %1$d оценок</item>
<item quantity="other">Вы получили %1$d оценок</item>
</plurals>
<plurals name="grade_notify_new_items_predicted">
<item quantity="one">You received %1$d predicted grade</item>
<item quantity="few">You received %1$d predicted grades</item>
<item quantity="many">You received %1$d predicted grades</item>
<item quantity="other">You received %1$d predicted grades</item>
</plurals>
<plurals name="grade_notify_new_items_final">
<item quantity="one">You received %1$d final grade</item>
<item quantity="few">You received %1$d final grades</item>
<item quantity="many">You received %1$d final grades</item>
<item quantity="other">You received %1$d final grades</item>
</plurals>
<!--Timetable-->
<string name="timetable_lesson">Урок</string>
<string name="timetable_room">Аудитория</string>
@ -180,6 +204,8 @@
<string name="message_move_to_bin">Перенести в корзину</string>
<string name="message_delete_forever">Удалить навсегда</string>
<string name="message_delete_success">Сообщение успешно удалено</string>
<string name="message_share">Share</string>
<string name="message_print">Print</string>
<string name="message_subject">Тема</string>
<string name="message_content">Текст</string>
<string name="message_send_successful">Сообщение успешно отправлено</string>
@ -265,6 +291,10 @@
<string name="account_logout">Выйти</string>
<string name="account_confirm">Вы точно хотите выйти из данного аккаунта?</string>
<string name="account_logout_student">Выйти</string>
<string name="account_type_student">Student account</string>
<string name="account_type_parent">Parent account</string>
<string name="account_login_mobile_api">Mobile API mode</string>
<string name="account_login_hybrid">Hybrid mode</string>
<!--About-->
<string name="about_version">Версия приложения</string>
<string name="about_contributor">Разработчики</string>
@ -309,7 +339,7 @@
<string name="all_prev">Предыдущий</string>
<string name="all_next">Следующий</string>
<string name="all_search">Поиск</string>
<string name="all_search_hint">Поиск...</string>
<string name="all_search_hint">Поиск</string>
<!--Timetable Widget-->
<string name="widget_timetable_no_items">Нет уроков</string>
<string name="widget_timetable_theme_title">Выбрать тему</string>

View File

@ -37,7 +37,7 @@
<string-array name="grade_average_mode_entries">
<item>Середня оцінка з 2 семестру</item>
<item>Average of grades from both semesters</item>
<item>Середня оцінка за весь рік</item>
<item>Average of grades from the whole year</item>
</string-array>
<string-array name="timetable_show_whole_class_entries">
<item>Не показувати</item>

View File

@ -107,12 +107,36 @@
<item quantity="many">Нові оцінки</item>
<item quantity="other">Нові оцінки</item>
</plurals>
<plurals name="grade_new_items_predicted">
<item quantity="one">New predicted grade</item>
<item quantity="few">New predicted grades</item>
<item quantity="many">New predicted grades</item>
<item quantity="other">New predicted grades</item>
</plurals>
<plurals name="grade_new_items_final">
<item quantity="one">New final grade</item>
<item quantity="few">New final grades</item>
<item quantity="many">New final grades</item>
<item quantity="other">New final grades</item>
</plurals>
<plurals name="grade_notify_new_items">
<item quantity="one">Ви отримали %1$d оцінку</item>
<item quantity="few">Ви отримали %1$d оцінки</item>
<item quantity="many">Ви отримали %1$d оцінок</item>
<item quantity="other">Ви отримали %1$d оцінок</item>
</plurals>
<plurals name="grade_notify_new_items_predicted">
<item quantity="one">You received %1$d predicted grade</item>
<item quantity="few">You received %1$d predicted grades</item>
<item quantity="many">You received %1$d predicted grades</item>
<item quantity="other">You received %1$d predicted grades</item>
</plurals>
<plurals name="grade_notify_new_items_final">
<item quantity="one">You received %1$d final grade</item>
<item quantity="few">You received %1$d final grades</item>
<item quantity="many">You received %1$d final grades</item>
<item quantity="other">You received %1$d final grades</item>
</plurals>
<!--Timetable-->
<string name="timetable_lesson">Урок</string>
<string name="timetable_room">Аудиторія</string>
@ -180,6 +204,8 @@
<string name="message_move_to_bin">Перемістити у кошик</string>
<string name="message_delete_forever">Видалити назавжди</string>
<string name="message_delete_success">Повідомлення було успішно видалено</string>
<string name="message_share">Share</string>
<string name="message_print">Print</string>
<string name="message_subject">Тема</string>
<string name="message_content">Зміст</string>
<string name="message_send_successful">Повідомлення було успішно відправлено</string>
@ -265,6 +291,10 @@
<string name="account_logout">Вийти</string>
<string name="account_confirm">Ви впевнені, що хочете вийти з цього аккаунту?</string>
<string name="account_logout_student">Вийти з аккаунту учня</string>
<string name="account_type_student">Student account</string>
<string name="account_type_parent">Parent account</string>
<string name="account_login_mobile_api">Mobile API mode</string>
<string name="account_login_hybrid">Hybrid mode</string>
<!--About-->
<string name="about_version">Версія додатка</string>
<string name="about_contributor">Розробники</string>
@ -309,7 +339,7 @@
<string name="all_prev">Попередній</string>
<string name="all_next">Наступний</string>
<string name="all_search">Пошук</string>
<string name="all_search_hint">Пошук...</string>
<string name="all_search_hint">Пошук</string>
<!--Timetable Widget-->
<string name="widget_timetable_no_items">Брак уроків</string>
<string name="widget_timetable_theme_title">Увібрати тему</string>

View File

@ -113,10 +113,26 @@
<item quantity="one">New grade</item>
<item quantity="other">New grades</item>
</plurals>
<plurals name="grade_new_items_predicted">
<item quantity="one">New predicted grade</item>
<item quantity="other">New predicted grades</item>
</plurals>
<plurals name="grade_new_items_final">
<item quantity="one">New final grade</item>
<item quantity="other">New final grades</item>
</plurals>
<plurals name="grade_notify_new_items">
<item quantity="one">You received %1$d grade</item>
<item quantity="other">You received %1$d grades</item>
</plurals>
<plurals name="grade_notify_new_items_predicted">
<item quantity="one">You received %1$d predicted grade</item>
<item quantity="other">You received %1$d predicted grades</item>
</plurals>
<plurals name="grade_notify_new_items_final">
<item quantity="one">You received %1$d final grade</item>
<item quantity="other">You received %1$d final grades</item>
</plurals>
<!--Timetable-->
@ -194,6 +210,8 @@
<string name="message_move_to_bin">Move to trash</string>
<string name="message_delete_forever">Delete permanently</string>
<string name="message_delete_success">Message deleted successfully</string>
<string name="message_share">Share</string>
<string name="message_print">Print</string>
<string name="message_subject">Subject</string>
<string name="message_content">Content</string>
<string name="message_send_successful">Message sent successfully</string>
@ -282,6 +300,10 @@
<string name="account_logout">Logout</string>
<string name="account_confirm">Do you want to log out of an active student?</string>
<string name="account_logout_student">Student logout</string>
<string name="account_type_student">Student account</string>
<string name="account_type_parent">Parent account</string>
<string name="account_login_mobile_api">Mobile API mode</string>
<string name="account_login_hybrid">Hybrid mode</string>
<!--About-->
@ -339,7 +361,7 @@
<string name="all_prev">Prev</string>
<string name="all_next">Next</string>
<string name="all_search">Search</string>
<string name="all_search_hint">Search...</string>
<string name="all_search_hint">Search</string>
<!--Timetable Widget-->

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy
import io.github.wulkanowy.data.db.entities.Message
import io.github.wulkanowy.data.db.entities.Semester
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.db.entities.Timetable
@ -72,3 +73,25 @@ fun getTimetableEntity(
teacher = "",
teacherOld = ""
)
fun getMessageEntity(
messageId: Int,
content: String,
unread: Boolean
) = Message(
studentId = 1,
realId = 1,
messageId = messageId,
sender = "",
senderId = 1,
recipient = "",
subject = "",
content = content,
date = now(),
folderId = 1,
unread = unread,
unreadBy = 1,
readBy = 1,
removed = false,
hasAttachments = false
)

View File

@ -2,10 +2,10 @@ package io.github.wulkanowy.data.repositories.message
import androidx.room.EmptyResultSetException
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.MessageWithAttachment
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.UnitTestInternetObservingStrategy
import io.github.wulkanowy.getMessageEntity
import io.reactivex.Single
import io.reactivex.observers.TestObserver
import org.junit.Assert.assertEquals
@ -15,7 +15,6 @@ import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.threeten.bp.LocalDateTime.now
import java.net.UnknownHostException
class MessageRepositoryTest {
@ -44,7 +43,7 @@ class MessageRepositoryTest {
@Test
fun `throw error when message is not in the db`() {
val testMessage = Message(1, 1, 1, "", 1, "", "", "", now(), 1, false, 1, 1, false, false)
val testMessage = getMessageEntity(1, "", false)
`when`(local.getMessageWithAttachment(student, testMessage)).thenReturn(Single.error(EmptyResultSetException("No message in database")))
val message = repo.getMessage(student, testMessage)
@ -55,7 +54,7 @@ class MessageRepositoryTest {
@Test
fun `get message when content already in db`() {
val testMessage = Message(1, 1, 123, "", 1, "", "", "Test", now(), 1, false, 1, 1, false, false)
val testMessage = getMessageEntity(123, "Test", false)
val messageWithAttachment = MessageWithAttachment(testMessage, emptyList())
`when`(local.getMessageWithAttachment(student, testMessage)).thenReturn(Single.just(messageWithAttachment))
@ -67,7 +66,7 @@ class MessageRepositoryTest {
@Test
fun `get message when content in db is empty`() {
val testMessage = Message(1, 1, 123, "", 1, "", "", "", now(), 1, true, 1, 1, false, false)
val testMessage = getMessageEntity(123, "", true)
val testMessageWithContent = testMessage.copy(content = "Test")
val mWa = MessageWithAttachment(testMessage, emptyList())
@ -86,7 +85,7 @@ class MessageRepositoryTest {
@Test
fun `get message when content in db is empty and there is no internet connection`() {
val testMessage = Message(1, 1, 123, "", 1, "", "", "", now(), 1, false, 1, 1, false, false)
val testMessage = getMessageEntity(123, "", false)
val messageWithAttachment = MessageWithAttachment(testMessage, emptyList())
testObservingStrategy.isInternetConnection = false
@ -100,7 +99,7 @@ class MessageRepositoryTest {
@Test
fun `get message when content in db is empty, unread and there is no internet connection`() {
val testMessage = Message(1, 1, 123, "", 1, "", "", "", now(), 1, true, 1, 1, false, false)
val testMessage = getMessageEntity(123, "", true)
val messageWithAttachment = MessageWithAttachment(testMessage, emptyList())
testObservingStrategy.isInternetConnection = false

View File

@ -1,6 +1,6 @@
buildscript {
ext.kotlin_version = '1.3.72'
ext.about_libraries = '8.1.6'
ext.about_libraries = '8.2.0'
repositories {
mavenCentral()
google()
@ -13,7 +13,7 @@ buildscript {
classpath 'com.google.gms:google-services:4.3.3'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.1.1'
classpath "com.github.triplet.gradle:play-publisher:2.7.5"
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.8"
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.0"
classpath "gradle.plugin.com.star-zero.gradle:githook:1.2.0"
classpath "com.mikepenz.aboutlibraries.plugin:aboutlibraries-plugin:${about_libraries}"
}