mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-22 10:03:03 +02:00
Compare commits
16 Commits
v4.11-rc.3
...
v4.11.4
Author | SHA1 | Date | |
---|---|---|---|
8911ce2bc1 | |||
2990fc5479 | |||
48b7adb564 | |||
f8ac9e793a | |||
148597e578 | |||
6c50a80b42 | |||
1bf0679e92 | |||
5b5dc5cade | |||
98a89b1ca1 | |||
6d1e18cce2 | |||
8fe0f88be4 | |||
aeed735521 | |||
e314fafaff | |||
2ab0dd7546 | |||
aa06868a4e | |||
2b104e6463 |
@ -41,6 +41,7 @@ android {
|
|||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
|
getIsDefault().set(true)
|
||||||
minifyEnabled = false
|
minifyEnabled = false
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
buildTimestamp: 0
|
buildTimestamp: 0
|
||||||
@ -55,7 +56,8 @@ android {
|
|||||||
}
|
}
|
||||||
flavorDimensions "platform"
|
flavorDimensions "platform"
|
||||||
productFlavors {
|
productFlavors {
|
||||||
main {
|
unofficial {
|
||||||
|
getIsDefault().set(true)
|
||||||
versionName "${release.versionName}-${gitInfo.versionSuffix}"
|
versionName "${release.versionName}-${gitInfo.versionSuffix}"
|
||||||
}
|
}
|
||||||
official {}
|
official {}
|
||||||
@ -63,7 +65,18 @@ android {
|
|||||||
}
|
}
|
||||||
variantFilter { variant ->
|
variantFilter { variant ->
|
||||||
def flavors = variant.flavors*.name
|
def flavors = variant.flavors*.name
|
||||||
setIgnore(variant.buildType.name == "debug" && !flavors.contains("main"))
|
setIgnore(variant.buildType.name == "debug" && !flavors.contains("unofficial") || flavors.contains("main"))
|
||||||
|
}
|
||||||
|
sourceSets {
|
||||||
|
unofficial {
|
||||||
|
java.srcDirs = ["src/main/java", "src/play-not/java"]
|
||||||
|
}
|
||||||
|
official {
|
||||||
|
java.srcDirs = ["src/main/java", "src/play-not/java"]
|
||||||
|
}
|
||||||
|
play {
|
||||||
|
java.srcDirs = ["src/main/java", "src/play/java"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
@ -170,7 +183,8 @@ dependencies {
|
|||||||
implementation "eu.szkolny:mhttp:af4b62e6e9"
|
implementation "eu.szkolny:mhttp:af4b62e6e9"
|
||||||
implementation "eu.szkolny:nachos:0e5dfcaceb"
|
implementation "eu.szkolny:nachos:0e5dfcaceb"
|
||||||
implementation "eu.szkolny.selective-dao:annotation:27f8f3f194"
|
implementation "eu.szkolny.selective-dao:annotation:27f8f3f194"
|
||||||
implementation "eu.szkolny:ssl-provider:1.0.0"
|
officialImplementation "eu.szkolny:ssl-provider:1.0.0"
|
||||||
|
unofficialImplementation "eu.szkolny:ssl-provider:1.0.0"
|
||||||
implementation "pl.szczodrzynski:navlib:0.8.0"
|
implementation "pl.szczodrzynski:navlib:0.8.0"
|
||||||
implementation "pl.szczodrzynski:numberslidingpicker:2921225f76"
|
implementation "pl.szczodrzynski:numberslidingpicker:2921225f76"
|
||||||
implementation "pl.szczodrzynski:recyclertablayout:700f980584"
|
implementation "pl.szczodrzynski:recyclertablayout:700f980584"
|
||||||
|
@ -1,23 +1,8 @@
|
|||||||
<h3>Wersja 4.11-rc.3, 2021-10-31</h3>
|
<h3>Wersja 4.11.4, 2022-03-14</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Nowości w module Wiadomości:</li>
|
<li>Poprawiono wyświetlanie ocen w przypadku przedmiotów z nieznaną nazwą.</li>
|
||||||
<li>→ <b>Formatowanie tekstu</b> przy wysyłaniu wiadomości oraz dodawaniu wydarzeń.</li>
|
|
||||||
<li>→ Zapisywanie <b>wersji roboczych</b> wiadomości, do późniejszej edycji i wysłania.</li>
|
|
||||||
<li>→ Możliwość <b>wyszukiwania zadań domowych</b>, podobnie jak wiadomości.</li>
|
|
||||||
<li>→ Dodawanie gwiazdki do wiadomości, w celu "przypięcia" na górę listy.</li>
|
|
||||||
<br>
|
|
||||||
<li>Opcja <b>dodawania notatek</b> do wydarzeń, ocen, lekcji, itp.</li>
|
|
||||||
<li>Możliwość udostępniania notatek w klasie, jako "ogłoszenia" widoczne na ekranie głównym.</li>
|
|
||||||
<br>
|
|
||||||
<li>Dodano <b>listę nauczycieli</b> w menu Więcej. @Antoni-Czaplicki</li>
|
|
||||||
<li>Logowanie: skaner kodów QR, uproszczone pole adresu w Mobidzienniku.</li>
|
|
||||||
<li>Naprawiono filtrowanie powiadomień.</li>
|
|
||||||
<li>Mobidziennik: dodano wyświetlanie lekcji z planów "pozalekcyjnych".</li>
|
|
||||||
<li>Mobidziennik: dodano pobieranie pełnej treści "informacji" w kalendarzu.</li>
|
|
||||||
<li>Mobidziennik: poprawiono wyświetlanie załączników oraz ich wielkości.</li>
|
|
||||||
<li>Dodano tajne funkcje. @Antoni-Czaplicki</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
Dzięki za korzystanie ze Szkolnego!<br>
|
Dzięki za korzystanie ze Szkolnego!<br>
|
||||||
<i>© [Kuba Szczodrzyński](@kuba2k2), [Kacper Ziubryniewicz](@kapi2289) 2021</i>
|
<i>© [Kuba Szczodrzyński](@kuba2k2), [Kacper Ziubryniewicz](@kapi2289) 2022</i>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
/*secret password - removed for source code publication*/
|
/*secret password - removed for source code publication*/
|
||||||
static toys AES_IV[16] = {
|
static toys AES_IV[16] = {
|
||||||
0x89, 0xe6, 0xba, 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
0x3d, 0x32, 0x00, 0x89, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||||
|
|
||||||
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
||||||
|
|
||||||
|
@ -26,8 +26,6 @@ import com.google.firebase.messaging.FirebaseMessaging
|
|||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.hypertrack.hyperlog.HyperLog
|
import com.hypertrack.hyperlog.HyperLog
|
||||||
import com.mikepenz.iconics.Iconics
|
import com.mikepenz.iconics.Iconics
|
||||||
import eu.szkolny.sslprovider.SSLProvider
|
|
||||||
import eu.szkolny.sslprovider.enableSupportedTls
|
|
||||||
import im.wangchao.mhttp.MHttp
|
import im.wangchao.mhttp.MHttp
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import me.leolin.shortcutbadger.ShortcutBadger
|
import me.leolin.shortcutbadger.ShortcutBadger
|
||||||
@ -42,6 +40,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
|||||||
import pl.szczodrzynski.edziennik.ext.DAY
|
import pl.szczodrzynski.edziennik.ext.DAY
|
||||||
import pl.szczodrzynski.edziennik.ext.MS
|
import pl.szczodrzynski.edziennik.ext.MS
|
||||||
import pl.szczodrzynski.edziennik.ext.setLanguage
|
import pl.szczodrzynski.edziennik.ext.setLanguage
|
||||||
|
import pl.szczodrzynski.edziennik.network.SSLProviderInstaller
|
||||||
import pl.szczodrzynski.edziennik.network.cookie.DumbCookieJar
|
import pl.szczodrzynski.edziennik.network.cookie.DumbCookieJar
|
||||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||||
@ -49,7 +48,6 @@ import pl.szczodrzynski.edziennik.ui.base.CrashActivity
|
|||||||
import pl.szczodrzynski.edziennik.utils.*
|
import pl.szczodrzynski.edziennik.utils.*
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import pl.szczodrzynski.edziennik.utils.managers.*
|
import pl.szczodrzynski.edziennik.utils.managers.*
|
||||||
import timber.log.Timber
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
@ -119,7 +117,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
.connectTimeout(15, TimeUnit.SECONDS)
|
.connectTimeout(15, TimeUnit.SECONDS)
|
||||||
.writeTimeout(10, TimeUnit.SECONDS)
|
.writeTimeout(10, TimeUnit.SECONDS)
|
||||||
.readTimeout(30, TimeUnit.SECONDS)
|
.readTimeout(30, TimeUnit.SECONDS)
|
||||||
.enableSupportedTls(enableCleartext = true)
|
|
||||||
|
SSLProviderInstaller.enableSupportedTls(builder, enableCleartext = true)
|
||||||
|
|
||||||
if (devMode) {
|
if (devMode) {
|
||||||
HyperLog.initialize(this)
|
HyperLog.initialize(this)
|
||||||
@ -203,18 +202,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
config.migrate(this@App)
|
config.migrate(this@App)
|
||||||
|
|
||||||
SSLProvider.install(
|
SSLProviderInstaller.install(applicationContext, this@App::buildHttp)
|
||||||
applicationContext,
|
|
||||||
downloadIfNeeded = true,
|
|
||||||
supportTls13 = false,
|
|
||||||
onFinish = {
|
|
||||||
buildHttp()
|
|
||||||
},
|
|
||||||
onError = {
|
|
||||||
Timber.e("Failed to install SSLProvider: $it")
|
|
||||||
it.printStackTrace()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (config.devModePassword != null)
|
if (config.devModePassword != null)
|
||||||
checkDevModePassword()
|
checkDevModePassword()
|
||||||
|
@ -182,10 +182,6 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
data.startProgress(R.string.edziennik_progress_endpoint_pt_meetings)
|
data.startProgress(R.string.edziennik_progress_endpoint_pt_meetings)
|
||||||
LibrusApiPtMeetings(data, lastSync, onSuccess)
|
LibrusApiPtMeetings(data, lastSync, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_day_types)
|
|
||||||
LibrusApiTeacherFreeDayTypes(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS -> {
|
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_days)
|
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_days)
|
||||||
LibrusApiTeacherFreeDays(data, lastSync, onSuccess)
|
LibrusApiTeacherFreeDays(data, lastSync, onSuccess)
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-19
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.TeacherAbsenceType
|
|
||||||
import pl.szczodrzynski.edziennik.ext.*
|
|
||||||
|
|
||||||
class LibrusApiTeacherFreeDayTypes(override val data: DataLibrus,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : LibrusApi(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "LibrusApiTeacherFreeDayTypes"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
apiGet(TAG, "TeacherFreeDays/Types") { json ->
|
|
||||||
val teacherAbsenceTypes = json.getJsonArray("Types")?.asJsonObjectList()
|
|
||||||
|
|
||||||
teacherAbsenceTypes?.forEach { teacherAbsenceType ->
|
|
||||||
val id = teacherAbsenceType.getLong("Id") ?: return@forEach
|
|
||||||
val name = teacherAbsenceType.getString("Name") ?: return@forEach
|
|
||||||
|
|
||||||
val teacherAbsenceTypeObject = TeacherAbsenceType(
|
|
||||||
profileId,
|
|
||||||
id,
|
|
||||||
name
|
|
||||||
)
|
|
||||||
|
|
||||||
data.teacherAbsenceTypes.put(id, teacherAbsenceTypeObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES, 7 * DAY)
|
|
||||||
onSuccess(ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -36,8 +36,6 @@ class LibrusApiTeacherFreeDays(override val data: DataLibrus,
|
|||||||
val id = teacherAbsence.getLong("Id") ?: return@forEach
|
val id = teacherAbsence.getLong("Id") ?: return@forEach
|
||||||
val teacherId = teacherAbsence.getJsonObject("Teacher")?.getLong("Id")
|
val teacherId = teacherAbsence.getJsonObject("Teacher")?.getLong("Id")
|
||||||
?: return@forEach
|
?: return@forEach
|
||||||
val type = teacherAbsence.getJsonObject("Type").getLong("Id") ?: return@forEach
|
|
||||||
val name = data.teacherAbsenceTypes.singleOrNull { it.id == type }?.name
|
|
||||||
val dateFrom = Date.fromY_m_d(teacherAbsence.getString("DateFrom"))
|
val dateFrom = Date.fromY_m_d(teacherAbsence.getString("DateFrom"))
|
||||||
val dateTo = Date.fromY_m_d(teacherAbsence.getString("DateTo"))
|
val dateTo = Date.fromY_m_d(teacherAbsence.getString("DateTo"))
|
||||||
val timeFrom = teacherAbsence.getString("TimeFrom")?.let { Time.fromH_m_s(it) }
|
val timeFrom = teacherAbsence.getString("TimeFrom")?.let { Time.fromH_m_s(it) }
|
||||||
@ -46,8 +44,8 @@ class LibrusApiTeacherFreeDays(override val data: DataLibrus,
|
|||||||
val teacherAbsenceObject = TeacherAbsence(
|
val teacherAbsenceObject = TeacherAbsence(
|
||||||
profileId = profileId,
|
profileId = profileId,
|
||||||
id = id,
|
id = id,
|
||||||
type = type,
|
type = -1L,
|
||||||
name = name,
|
name = null,
|
||||||
dateFrom = dateFrom,
|
dateFrom = dateFrom,
|
||||||
dateTo = dateTo,
|
dateTo = dateTo,
|
||||||
timeFrom = timeFrom,
|
timeFrom = timeFrom,
|
||||||
|
@ -7,10 +7,12 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik
|
|||||||
import android.util.LongSparseArray
|
import android.util.LongSparseArray
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_MOBIDZIENNIK_WEB
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_MOBIDZIENNIK_WEB
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
import pl.szczodrzynski.edziennik.ext.currentTimeUnix
|
import pl.szczodrzynski.edziennik.ext.currentTimeUnix
|
||||||
|
import pl.szczodrzynski.edziennik.ext.get
|
||||||
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
|
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
@ -35,6 +37,31 @@ class DataMobidziennik(app: App, profile: Profile?, loginStore: LoginStore) : Da
|
|||||||
|
|
||||||
override fun generateUserCode() = "$loginServerName:$loginUsername:$studentId"
|
override fun generateUserCode() = "$loginServerName:$loginUsername:$studentId"
|
||||||
|
|
||||||
|
fun parseDateTime(dateStr: String): Pair<Date, Time> {
|
||||||
|
// pt, 4 lut, 09:11
|
||||||
|
val dateParts = dateStr.split(',', ' ').filter { it.isNotEmpty() }
|
||||||
|
// [pt], [4], [lut], [09:11]
|
||||||
|
val date = Date.getToday()
|
||||||
|
date.day = dateParts[1].toIntOrNull() ?: 1
|
||||||
|
date.month = when (dateParts[2]) {
|
||||||
|
"sty" -> 1
|
||||||
|
"lut" -> 2
|
||||||
|
"mar" -> 3
|
||||||
|
"kwi" -> 4
|
||||||
|
"maj" -> 5
|
||||||
|
"cze" -> 6
|
||||||
|
"lip" -> 7
|
||||||
|
"sie" -> 8
|
||||||
|
"wrz" -> 9
|
||||||
|
"paź" -> 10
|
||||||
|
"lis" -> 11
|
||||||
|
"gru" -> 12
|
||||||
|
else -> 1
|
||||||
|
}
|
||||||
|
val time = Time.fromH_m(dateParts[3])
|
||||||
|
return date to time
|
||||||
|
}
|
||||||
|
|
||||||
val teachersMap = LongSparseArray<String>()
|
val teachersMap = LongSparseArray<String>()
|
||||||
val subjectsMap = LongSparseArray<String>()
|
val subjectsMap = LongSparseArray<String>()
|
||||||
|
|
||||||
|
@ -36,6 +36,10 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik,
|
|||||||
|
|
||||||
val doc = Jsoup.parse(text)
|
val doc = Jsoup.parse(text)
|
||||||
|
|
||||||
|
val today = Date.getToday()
|
||||||
|
var currentYear = today.year
|
||||||
|
var currentMonth = today.month
|
||||||
|
|
||||||
val list = doc.getElementsByClass("spis").first()?.getElementsByClass("podswietl")
|
val list = doc.getElementsByClass("spis").first()?.getElementsByClass("podswietl")
|
||||||
list?.forEach { item ->
|
list?.forEach { item ->
|
||||||
val id = item.attr("rel").toLongOrNull() ?: return@forEach
|
val id = item.attr("rel").toLongOrNull() ?: return@forEach
|
||||||
@ -47,15 +51,20 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik,
|
|||||||
}
|
}
|
||||||
val subject = subjectEl?.ownText() ?: ""
|
val subject = subjectEl?.ownText() ?: ""
|
||||||
|
|
||||||
val addedDateEl = item.select("td:eq(1) small").first()
|
val addedDateEl = item.select("td:eq(4)").first()
|
||||||
val addedDate = Date.fromIsoHm(addedDateEl?.text())
|
val (date, time) = data.parseDateTime(addedDateEl?.text()?.trim() ?: "")
|
||||||
|
if (date.month > currentMonth) {
|
||||||
|
currentYear--
|
||||||
|
}
|
||||||
|
currentMonth = date.month
|
||||||
|
date.year = currentYear
|
||||||
|
|
||||||
val senderEl = item.select("td:eq(2)").first()
|
val senderEl = item.select("td:eq(3)").first()
|
||||||
val senderName = senderEl?.ownText().fixName()
|
val senderName = senderEl?.ownText().fixName()
|
||||||
val senderId = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }?.id
|
val senderId = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }?.id
|
||||||
data.messageRecipientIgnoreList.add(MessageRecipient(profileId, -1, id))
|
data.messageRecipientIgnoreList.add(MessageRecipient(profileId, -1, id))
|
||||||
|
|
||||||
val isRead = item.select("td:eq(3) span").first()?.hasClass("wiadomosc_przeczytana") == true
|
val isRead = item.select("td:eq(5) span").first()?.hasClass("wiadomosc_przeczytana") == true
|
||||||
|
|
||||||
val message = Message(
|
val message = Message(
|
||||||
profileId = profileId,
|
profileId = profileId,
|
||||||
@ -64,7 +73,7 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik,
|
|||||||
subject = subject,
|
subject = subject,
|
||||||
body = null,
|
body = null,
|
||||||
senderId = senderId,
|
senderId = senderId,
|
||||||
addedDate = addedDate
|
addedDate = date.combineWith(time)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (hasAttachments)
|
if (hasAttachments)
|
||||||
|
@ -40,23 +40,29 @@ class MobidziennikWebMessagesSent(override val data: DataMobidziennik,
|
|||||||
|
|
||||||
val doc = Jsoup.parse(text)
|
val doc = Jsoup.parse(text)
|
||||||
|
|
||||||
|
val today = Date.getToday()
|
||||||
|
var currentYear = today.year
|
||||||
|
var currentMonth = today.month
|
||||||
|
|
||||||
val list = doc.getElementsByClass("spis").first()?.getElementsByClass("podswietl")
|
val list = doc.getElementsByClass("spis").first()?.getElementsByClass("podswietl")
|
||||||
list?.forEach { item ->
|
list?.forEach { item ->
|
||||||
val id = item.attr("rel").toLongOrNull() ?: return@forEach
|
val id = item.attr("rel").toLongOrNull() ?: return@forEach
|
||||||
|
|
||||||
val subjectEl = item.select("td:eq(0)").first()
|
val subjectEl = item.select("td:eq(0)").first()
|
||||||
var hasAttachments = false
|
|
||||||
if (subjectEl?.getElementsByTag("a")?.size ?: 0 > 0) {
|
|
||||||
hasAttachments = true
|
|
||||||
}
|
|
||||||
val subject = subjectEl?.ownText() ?: ""
|
val subject = subjectEl?.ownText() ?: ""
|
||||||
|
|
||||||
val readByString = item.select("td:eq(2)").first()?.text() ?: ""
|
val attachmentsEl = item.select("td:eq(1)").first()
|
||||||
|
var hasAttachments = false
|
||||||
|
if (attachmentsEl?.getElementsByTag("a")?.size ?: 0 > 0) {
|
||||||
|
hasAttachments = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val readByString = item.select("td:eq(4)").first()?.text() ?: ""
|
||||||
val (readBy, sentTo) = Regexes.MOBIDZIENNIK_MESSAGE_SENT_READ_BY.find(readByString).let {
|
val (readBy, sentTo) = Regexes.MOBIDZIENNIK_MESSAGE_SENT_READ_BY.find(readByString).let {
|
||||||
(it?.get(1)?.toIntOrNull() ?: 0) to (it?.get(2)?.toIntOrNull() ?: 0)
|
(it?.get(1)?.toIntOrNull() ?: 0) to (it?.get(2)?.toIntOrNull() ?: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
val recipientEl = item.select("td:eq(1) a span").first()
|
val recipientEl = item.select("td:eq(2) a span").first()
|
||||||
val recipientNames = recipientEl?.ownText()?.split(", ")
|
val recipientNames = recipientEl?.ownText()?.split(", ")
|
||||||
val readState = when (readBy) {
|
val readState = when (readBy) {
|
||||||
0 -> 0
|
0 -> 0
|
||||||
@ -69,8 +75,13 @@ class MobidziennikWebMessagesSent(override val data: DataMobidziennik,
|
|||||||
data.messageRecipientIgnoreList.add(MessageRecipient(profileId, recipientId, -1, readState, id))
|
data.messageRecipientIgnoreList.add(MessageRecipient(profileId, recipientId, -1, readState, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
val addedDateEl = item.select("td:eq(3) small").first()
|
val addedDateEl = item.select("td:eq(3)").first()
|
||||||
val addedDate = Date.fromIsoHm(addedDateEl?.text())
|
val (date, time) = data.parseDateTime(addedDateEl?.text()?.trim() ?: "")
|
||||||
|
if (date.month > currentMonth) {
|
||||||
|
currentYear--
|
||||||
|
}
|
||||||
|
currentMonth = date.month
|
||||||
|
date.year = currentYear
|
||||||
|
|
||||||
val message = Message(
|
val message = Message(
|
||||||
profileId = profileId,
|
profileId = profileId,
|
||||||
@ -79,7 +90,7 @@ class MobidziennikWebMessagesSent(override val data: DataMobidziennik,
|
|||||||
subject = subject,
|
subject = subject,
|
||||||
body = null,
|
body = null,
|
||||||
senderId = null,
|
senderId = null,
|
||||||
addedDate = addedDate
|
addedDate = date.combineWith(time)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (hasAttachments)
|
if (hasAttachments)
|
||||||
|
@ -46,6 +46,6 @@ object Signing {
|
|||||||
|
|
||||||
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
|
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
|
||||||
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
|
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
|
||||||
return "$param1.MTIzNDU2Nzg5MDoLs15rw+===.$param2".sha256()
|
return "$param1.MTIzNDU2Nzg5MDvXV/n0BA===.$param2".sha256()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message:
|
|||||||
val type = if (event.isHomework) Notification.TYPE_NEW_SHARED_HOMEWORK else Notification.TYPE_NEW_SHARED_EVENT
|
val type = if (event.isHomework) Notification.TYPE_NEW_SHARED_HOMEWORK else Notification.TYPE_NEW_SHARED_EVENT
|
||||||
val notificationFilter = app.config.getFor(event.profileId).sync.notificationFilter
|
val notificationFilter = app.config.getFor(event.profileId).sync.notificationFilter
|
||||||
|
|
||||||
if (!notificationFilter.contains(type) && event.sharedBy != "self") {
|
if (!notificationFilter.contains(type) && event.sharedBy != "self" && event.date >= Date.getToday()) {
|
||||||
val notification = Notification(
|
val notification = Notification(
|
||||||
id = Notification.buildId(event.profileId, type, event.id),
|
id = Notification.buildId(event.profileId, type, event.id),
|
||||||
title = app.getNotificationTitle(type),
|
title = app.getNotificationTitle(type),
|
||||||
|
@ -36,6 +36,7 @@ class GradesAdapter(
|
|||||||
private const val ITEM_TYPE_EMPTY = 2
|
private const val ITEM_TYPE_EMPTY = 2
|
||||||
private const val ITEM_TYPE_GRADE = 3
|
private const val ITEM_TYPE_GRADE = 3
|
||||||
private const val ITEM_TYPE_STATS = 4
|
private const val ITEM_TYPE_STATS = 4
|
||||||
|
private const val ITEM_TYPE_UNKNOWN_SUBJECT = 5
|
||||||
const val STATE_CLOSED = 0
|
const val STATE_CLOSED = 0
|
||||||
const val STATE_OPENED = 1
|
const val STATE_OPENED = 1
|
||||||
}
|
}
|
||||||
@ -58,6 +59,7 @@ class GradesAdapter(
|
|||||||
ITEM_TYPE_EMPTY -> EmptyViewHolder(inflater, parent)
|
ITEM_TYPE_EMPTY -> EmptyViewHolder(inflater, parent)
|
||||||
ITEM_TYPE_GRADE -> GradeViewHolder(inflater, parent)
|
ITEM_TYPE_GRADE -> GradeViewHolder(inflater, parent)
|
||||||
ITEM_TYPE_STATS -> StatsViewHolder(inflater, parent)
|
ITEM_TYPE_STATS -> StatsViewHolder(inflater, parent)
|
||||||
|
ITEM_TYPE_UNKNOWN_SUBJECT -> UnknownSubjectViewHolder(inflater, parent)
|
||||||
else -> throw IllegalArgumentException("Incorrect viewType")
|
else -> throw IllegalArgumentException("Incorrect viewType")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,6 +71,7 @@ class GradesAdapter(
|
|||||||
is GradesEmpty -> ITEM_TYPE_EMPTY
|
is GradesEmpty -> ITEM_TYPE_EMPTY
|
||||||
is Grade -> ITEM_TYPE_GRADE
|
is Grade -> ITEM_TYPE_GRADE
|
||||||
is GradesStats -> ITEM_TYPE_STATS
|
is GradesStats -> ITEM_TYPE_STATS
|
||||||
|
is GradesUnknownSubject -> ITEM_TYPE_UNKNOWN_SUBJECT
|
||||||
else -> throw IllegalArgumentException("Incorrect viewType")
|
else -> throw IllegalArgumentException("Incorrect viewType")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,7 +89,7 @@ class GradesAdapter(
|
|||||||
|
|
||||||
fun expandModel(model: ExpandableItemModel<*>?, view: View?, notifyAdapter: Boolean = true) {
|
fun expandModel(model: ExpandableItemModel<*>?, view: View?, notifyAdapter: Boolean = true) {
|
||||||
model ?: return
|
model ?: return
|
||||||
val position = items.indexOf(model)
|
var position = items.indexOf(model)
|
||||||
if (position == -1)
|
if (position == -1)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -138,9 +141,16 @@ class GradesAdapter(
|
|||||||
else -> model.items
|
else -> model.items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (model is GradesSubject && model.isUnknown) {
|
||||||
|
position++
|
||||||
|
items.add(position, GradesUnknownSubject())
|
||||||
|
if (notifyAdapter) notifyItemInserted(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
position++
|
||||||
model.state = STATE_OPENED
|
model.state = STATE_OPENED
|
||||||
items.addAll(position + 1, subItems.filterNotNull())
|
items.addAll(position, subItems.filterNotNull())
|
||||||
if (notifyAdapter) notifyItemRangeInserted(position + 1, subItems.size)
|
if (notifyAdapter) notifyItemRangeInserted(position, subItems.size)
|
||||||
|
|
||||||
if (model is GradesSubject) {
|
if (model is GradesSubject) {
|
||||||
// auto expand first semester
|
// auto expand first semester
|
||||||
@ -156,9 +166,10 @@ class GradesAdapter(
|
|||||||
else -> semester.grades
|
else -> semester.grades
|
||||||
}
|
}
|
||||||
|
|
||||||
|
position++
|
||||||
semester.state = STATE_OPENED
|
semester.state = STATE_OPENED
|
||||||
items.addAll(position + 2 + semesterIndex, grades)
|
items.addAll(position + semesterIndex, grades)
|
||||||
if (notifyAdapter) notifyItemRangeInserted(position + 2 + semesterIndex, grades.size)
|
if (notifyAdapter) notifyItemRangeInserted(position + semesterIndex, grades.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,6 +209,7 @@ class GradesAdapter(
|
|||||||
is EmptyViewHolder -> ITEM_TYPE_EMPTY
|
is EmptyViewHolder -> ITEM_TYPE_EMPTY
|
||||||
is GradeViewHolder -> ITEM_TYPE_GRADE
|
is GradeViewHolder -> ITEM_TYPE_GRADE
|
||||||
is StatsViewHolder -> ITEM_TYPE_STATS
|
is StatsViewHolder -> ITEM_TYPE_STATS
|
||||||
|
is UnknownSubjectViewHolder -> ITEM_TYPE_UNKNOWN_SUBJECT
|
||||||
else -> throw IllegalArgumentException("Incorrect viewType")
|
else -> throw IllegalArgumentException("Incorrect viewType")
|
||||||
}
|
}
|
||||||
holder.itemView.setTag(R.string.tag_key_view_type, viewType)
|
holder.itemView.setTag(R.string.tag_key_view_type, viewType)
|
||||||
@ -210,6 +222,7 @@ class GradesAdapter(
|
|||||||
holder is EmptyViewHolder && item is GradesEmpty -> holder.onBind(activity, app, item, position, this)
|
holder is EmptyViewHolder && item is GradesEmpty -> holder.onBind(activity, app, item, position, this)
|
||||||
holder is GradeViewHolder && item is GradeFull -> holder.onBind(activity, app, item, position, this)
|
holder is GradeViewHolder && item is GradeFull -> holder.onBind(activity, app, item, position, this)
|
||||||
holder is StatsViewHolder && item is GradesStats -> holder.onBind(activity, app, item, position, this)
|
holder is StatsViewHolder && item is GradesStats -> holder.onBind(activity, app, item, position, this)
|
||||||
|
holder is UnknownSubjectViewHolder && item is GradesUnknownSubject -> holder.onBind(activity, app, item, position, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (holder is SemesterViewHolder && item is GradesSemester) {
|
if (holder is SemesterViewHolder && item is GradesSemester) {
|
||||||
|
@ -182,6 +182,7 @@ class GradesListFragment : Fragment(), CoroutineScope {
|
|||||||
@Suppress("SuspendFunctionOnCoroutineScope")
|
@Suppress("SuspendFunctionOnCoroutineScope")
|
||||||
private fun processGrades(grades: List<GradeFull>): MutableList<Any> {
|
private fun processGrades(grades: List<GradeFull>): MutableList<Any> {
|
||||||
val items = mutableListOf<GradesSubject>()
|
val items = mutableListOf<GradesSubject>()
|
||||||
|
var unknownSubjectItem: GradesSubject? = null
|
||||||
|
|
||||||
var subjectId = -1L
|
var subjectId = -1L
|
||||||
var semesterNumber = 0
|
var semesterNumber = 0
|
||||||
@ -200,17 +201,31 @@ class GradesListFragment : Fragment(), CoroutineScope {
|
|||||||
subjectId = grade.subjectId
|
subjectId = grade.subjectId
|
||||||
semesterNumber = 0
|
semesterNumber = 0
|
||||||
|
|
||||||
subject = items.firstOrNull { it.subjectId == subjectId }
|
subject = items.firstOrNull { it.subjectId == subjectId } ?: run {
|
||||||
?: GradesSubject(grade.subjectId, grade.subjectLongName ?: "").also {
|
if (grade.subjectLongName != null) {
|
||||||
|
return@run GradesSubject(grade.subjectId, grade.subjectLongName!!).also {
|
||||||
items += it
|
items += it
|
||||||
it.semester = 2
|
it.semester = 2
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (unknownSubjectItem == null) {
|
||||||
|
unknownSubjectItem = GradesSubject(-1, "unknown").also {
|
||||||
|
items += it
|
||||||
|
it.semester = 2
|
||||||
|
it.isUnknown = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return@run unknownSubjectItem!!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (grade.semester != semesterNumber) {
|
if (grade.semester != semesterNumber) {
|
||||||
semesterNumber = grade.semester
|
semesterNumber = grade.semester
|
||||||
|
|
||||||
semester = subject.semesters.firstOrNull { it.number == semesterNumber }
|
semester = subject.semesters.firstOrNull { it.number == semesterNumber }
|
||||||
?: GradesSemester(subject.subjectId, grade.semester).also { subject.semesters += it }
|
?: GradesSemester(subject.subjectId, grade.semester).also {
|
||||||
|
subject.semesters += it
|
||||||
|
it.hideEditor = subject.isUnknown
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
grade.showAsUnseen = !grade.seen
|
grade.showAsUnseen = !grade.seen
|
||||||
@ -221,6 +236,11 @@ class GradesListFragment : Fragment(), CoroutineScope {
|
|||||||
semester.hasUnseen = true
|
semester.hasUnseen = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subject.isUnknown) {
|
||||||
|
// unknown subjects may have final grades (i.e. Mobidziennik)
|
||||||
|
grade.type = Grade.TYPE_NORMAL
|
||||||
|
}
|
||||||
|
|
||||||
when (grade.type) {
|
when (grade.type) {
|
||||||
Grade.TYPE_SEMESTER1_PROPOSED,
|
Grade.TYPE_SEMESTER1_PROPOSED,
|
||||||
Grade.TYPE_SEMESTER2_PROPOSED -> semester.proposedGrade = grade
|
Grade.TYPE_SEMESTER2_PROPOSED -> semester.proposedGrade = grade
|
||||||
@ -255,6 +275,10 @@ class GradesListFragment : Fragment(), CoroutineScope {
|
|||||||
val yearlyPoint = mutableListOf<Float>()
|
val yearlyPoint = mutableListOf<Float>()
|
||||||
|
|
||||||
for (item in items) {
|
for (item in items) {
|
||||||
|
if (item.isUnknown) {
|
||||||
|
// do not count averages for "unknown" subjects
|
||||||
|
continue
|
||||||
|
}
|
||||||
item.semesters.forEach { sem ->
|
item.semesters.forEach { sem ->
|
||||||
manager.calculateAverages(sem.averages)
|
manager.calculateAverages(sem.averages)
|
||||||
if (sem.number == 1) {
|
if (sem.number == 1) {
|
||||||
|
@ -14,6 +14,7 @@ data class GradesSemester(
|
|||||||
override var level = 2
|
override var level = 2
|
||||||
|
|
||||||
var hasUnseen = false
|
var hasUnseen = false
|
||||||
|
var hideEditor = false
|
||||||
|
|
||||||
val averages = GradesAverages()
|
val averages = GradesAverages()
|
||||||
var proposedGrade: GradeFull? = null
|
var proposedGrade: GradeFull? = null
|
||||||
|
@ -15,6 +15,7 @@ data class GradesSubject(
|
|||||||
|
|
||||||
var lastAddedDate = 0L
|
var lastAddedDate = 0L
|
||||||
var semester: Int = 1
|
var semester: Int = 1
|
||||||
|
var isUnknown = false
|
||||||
|
|
||||||
var hasUnseen: Boolean = false
|
var hasUnseen: Boolean = false
|
||||||
get() = field || semesters.any { it.hasUnseen }
|
get() = field || semesters.any { it.hasUnseen }
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-3-14.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.grades.models
|
||||||
|
|
||||||
|
class GradesUnknownSubject
|
@ -61,6 +61,8 @@ class SemesterViewHolder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.editButton.isVisible = !item.hideEditor
|
||||||
|
|
||||||
b.average.text = manager.getAverageString(app, item.averages)
|
b.average.text = manager.getAverageString(app, item.averages)
|
||||||
b.proposedGrade.setGrade(item.proposedGrade, manager)
|
b.proposedGrade.setGrade(item.proposedGrade, manager)
|
||||||
b.finalGrade.setGrade(item.finalGrade, manager)
|
b.finalGrade.setGrade(item.finalGrade, manager)
|
||||||
|
@ -19,9 +19,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.databinding.GradesItemSubjectBinding
|
import pl.szczodrzynski.edziennik.databinding.GradesItemSubjectBinding
|
||||||
import pl.szczodrzynski.edziennik.ext.dp
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
import pl.szczodrzynski.edziennik.ext.resolveAttr
|
|
||||||
import pl.szczodrzynski.edziennik.ext.setText
|
|
||||||
import pl.szczodrzynski.edziennik.ui.grades.GradeView
|
import pl.szczodrzynski.edziennik.ui.grades.GradeView
|
||||||
import pl.szczodrzynski.edziennik.ui.grades.GradesAdapter
|
import pl.szczodrzynski.edziennik.ui.grades.GradesAdapter
|
||||||
import pl.szczodrzynski.edziennik.ui.grades.GradesAdapter.Companion.STATE_CLOSED
|
import pl.szczodrzynski.edziennik.ui.grades.GradesAdapter.Companion.STATE_CLOSED
|
||||||
@ -41,7 +39,12 @@ class SubjectViewHolder(
|
|||||||
val manager = app.gradesManager
|
val manager = app.gradesManager
|
||||||
val contextWrapper = ContextThemeWrapper(activity, Themes.appTheme)
|
val contextWrapper = ContextThemeWrapper(activity, Themes.appTheme)
|
||||||
|
|
||||||
b.subjectName.text = item.subjectName
|
if (!item.isUnknown) {
|
||||||
|
b.subjectName.text = item.subjectName
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
b.subjectName.text = R.string.grades_subject_unknown.resolveString(activity).asItalicSpannable()
|
||||||
|
}
|
||||||
b.dropdownIcon.rotation = when (item.state) {
|
b.dropdownIcon.rotation = when (item.state) {
|
||||||
STATE_CLOSED -> 0f
|
STATE_CLOSED -> 0f
|
||||||
else -> 180f
|
else -> 180f
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-3-14.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.grades.viewholder
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.databinding.GradesItemUnknownSubjectBinding
|
||||||
|
import pl.szczodrzynski.edziennik.ui.grades.GradesAdapter
|
||||||
|
import pl.szczodrzynski.edziennik.ui.grades.models.GradesUnknownSubject
|
||||||
|
|
||||||
|
class UnknownSubjectViewHolder(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
parent: ViewGroup,
|
||||||
|
val b: GradesItemUnknownSubjectBinding = GradesItemUnknownSubjectBinding.inflate(inflater, parent, false)
|
||||||
|
) : RecyclerView.ViewHolder(b.root), BindableViewHolder<GradesUnknownSubject, GradesAdapter> {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "UnknownSubjectViewHolder"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(activity: AppCompatActivity, app: App, item: GradesUnknownSubject, position: Int, adapter: GradesAdapter) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -85,6 +85,9 @@ class HomeGradesCard(
|
|||||||
grades.forEach { grade ->
|
grades.forEach { grade ->
|
||||||
val model = ItemGradesSubjectModel.searchModelBySubjectId(subjects, grade.subjectId)
|
val model = ItemGradesSubjectModel.searchModelBySubjectId(subjects, grade.subjectId)
|
||||||
?: run {
|
?: run {
|
||||||
|
if (grade.subjectLongName == null) {
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
subjects.add(ItemGradesSubjectModel(
|
subjects.add(ItemGradesSubjectModel(
|
||||||
profile,
|
profile,
|
||||||
Subject(profile.id, grade.subjectId, grade.subjectLongName, grade.subjectShortName),
|
Subject(profile.id, grade.subjectId, grade.subjectLongName, grade.subjectShortName),
|
||||||
|
@ -62,6 +62,8 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
private var firstEventMinute = 24 * 60
|
private var firstEventMinute = 24 * 60
|
||||||
private var paddingTop = 0
|
private var paddingTop = 0
|
||||||
|
|
||||||
|
private var viewsRemoved = false
|
||||||
|
|
||||||
private val manager
|
private val manager
|
||||||
get() = app.timetableManager
|
get() = app.timetableManager
|
||||||
private val attendanceManager
|
private val attendanceManager
|
||||||
@ -127,6 +129,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
inflater.inflate(R.layout.timetable_no_timetable, b.root) { view, _, _ ->
|
inflater.inflate(R.layout.timetable_no_timetable, b.root) { view, _, _ ->
|
||||||
b.root.removeAllViews()
|
b.root.removeAllViews()
|
||||||
b.root.addView(view)
|
b.root.addView(view)
|
||||||
|
viewsRemoved = true
|
||||||
|
|
||||||
val b = TimetableNoTimetableBinding.bind(view)
|
val b = TimetableNoTimetableBinding.bind(view)
|
||||||
val weekStart = date.weekStart.stringY_m_d
|
val weekStart = date.weekStart.stringY_m_d
|
||||||
@ -151,6 +154,7 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
inflater.inflate(R.layout.timetable_no_lessons, b.root) { view, _, _ ->
|
inflater.inflate(R.layout.timetable_no_lessons, b.root) { view, _, _ ->
|
||||||
b.root.removeAllViews()
|
b.root.removeAllViews()
|
||||||
b.root.addView(view)
|
b.root.addView(view)
|
||||||
|
viewsRemoved = true
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -162,6 +166,13 @@ class TimetableDayFragment : LazyFragment(), CoroutineScope {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the timetable was not synced (the day layout views are removed) and is now available
|
||||||
|
if (viewsRemoved) {
|
||||||
|
viewsRemoved = false
|
||||||
|
activity.sendBroadcast(Intent(TimetableFragment.ACTION_RELOAD_PAGES))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
b.scrollView.isVisible = true
|
b.scrollView.isVisible = true
|
||||||
b.dayFrame.removeView(dayView)
|
b.dayFrame.removeView(dayView)
|
||||||
b.dayFrame.addView(dayView, 0)
|
b.dayFrame.addView(dayView, 0)
|
||||||
|
@ -36,6 +36,7 @@ class TimetableFragment : Fragment(), CoroutineScope {
|
|||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "TimetableFragment"
|
private const val TAG = "TimetableFragment"
|
||||||
const val ACTION_SCROLL_TO_DATE = "pl.szczodrzynski.edziennik.timetable.SCROLL_TO_DATE"
|
const val ACTION_SCROLL_TO_DATE = "pl.szczodrzynski.edziennik.timetable.SCROLL_TO_DATE"
|
||||||
|
const val ACTION_RELOAD_PAGES = "pl.szczodrzynski.edziennik.timetable.RELOAD_PAGES"
|
||||||
const val DEFAULT_START_HOUR = 6
|
const val DEFAULT_START_HOUR = 6
|
||||||
const val DEFAULT_END_HOUR = 19
|
const val DEFAULT_END_HOUR = 19
|
||||||
var pageSelection: Date? = null
|
var pageSelection: Date? = null
|
||||||
@ -66,14 +67,22 @@ class TimetableFragment : Fragment(), CoroutineScope {
|
|||||||
override fun onReceive(context: Context, i: Intent) {
|
override fun onReceive(context: Context, i: Intent) {
|
||||||
if (!isAdded)
|
if (!isAdded)
|
||||||
return
|
return
|
||||||
val dateStr = i.extras?.getString("timetableDate", null) ?: return
|
when (i.action) {
|
||||||
val date = Date.fromY_m_d(dateStr)
|
ACTION_SCROLL_TO_DATE -> {
|
||||||
b.viewPager.setCurrentItem(items.indexOf(date), true)
|
val dateStr = i.extras?.getString("timetableDate", null) ?: return
|
||||||
|
val date = Date.fromY_m_d(dateStr)
|
||||||
|
b.viewPager.setCurrentItem(items.indexOf(date), true)
|
||||||
|
}
|
||||||
|
ACTION_RELOAD_PAGES -> {
|
||||||
|
b.viewPager.adapter?.notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
activity.registerReceiver(broadcastReceiver, IntentFilter(ACTION_SCROLL_TO_DATE))
|
activity.registerReceiver(broadcastReceiver, IntentFilter(ACTION_SCROLL_TO_DATE))
|
||||||
|
activity.registerReceiver(broadcastReceiver, IntentFilter(ACTION_RELOAD_PAGES))
|
||||||
}
|
}
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
@ -47,4 +47,8 @@ class TimetablePagerAdapter(
|
|||||||
}
|
}
|
||||||
return pageTitle
|
return pageTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getItemPosition(`object`: Any): Int {
|
||||||
|
return POSITION_NONE
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,9 @@ class MessageManager(private val app: App) {
|
|||||||
if (sentDate > 0L) {
|
if (sentDate > 0L) {
|
||||||
it.addedDate = sentDate
|
it.addedDate = sentDate
|
||||||
}
|
}
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
it.recipients = app.db.messageRecipientDao().getAllByMessageId(profileId, it.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
|
19
app/src/main/res/layout/grades_item_unknown_subject.xml
Normal file
19
app/src/main/res/layout/grades_item_unknown_subject.xml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (c) Kuba Szczodrzyński 2022-3-14.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.mikepenz.iconics.view.IconicsTextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="8dp"
|
||||||
|
android:text="@string/grades_subject_unknown_help"
|
||||||
|
android:textColor="?android:textColorSecondary" />
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
@ -857,7 +857,7 @@
|
|||||||
<string name="settings_about_licenses_text">Open-Source-Lizenzen</string>
|
<string name="settings_about_licenses_text">Open-Source-Lizenzen</string>
|
||||||
<string name="settings_about_privacy_policy_text">Datenschutzrichtlinie</string>
|
<string name="settings_about_privacy_policy_text">Datenschutzrichtlinie</string>
|
||||||
<string name="settings_card_register_title">E-Klassenbuch</string>
|
<string name="settings_card_register_title">E-Klassenbuch</string>
|
||||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - Oktober 2021</string>
|
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - 2022</string>
|
||||||
<string name="settings_about_update_subtext">Klicken Sie hier, um nach Aktualisierungen zu suchen</string>
|
<string name="settings_about_update_subtext">Klicken Sie hier, um nach Aktualisierungen zu suchen</string>
|
||||||
<string name="settings_about_update_text">Aktualisierung</string>
|
<string name="settings_about_update_text">Aktualisierung</string>
|
||||||
<string name="settings_about_version_text">Version</string>
|
<string name="settings_about_version_text">Version</string>
|
||||||
|
@ -348,7 +348,7 @@
|
|||||||
<string name="event_information">information</string>
|
<string name="event_information">information</string>
|
||||||
<string name="event_list_added_by_format">Added %1$s by %2$s%3$s</string>
|
<string name="event_list_added_by_format">Added %1$s by %2$s%3$s</string>
|
||||||
<string name="event_list_added_by_self_format">Added %1$s by you%3$s</string>
|
<string name="event_list_added_by_self_format">Added %1$s by you%3$s</string>
|
||||||
<string name="event_list_added_by_unknown_format">Adde %1$s%3$s</string>
|
<string name="event_list_added_by_unknown_format">Added %1$s%3$s</string>
|
||||||
<string name="event_list_shared_by_format">{cmd-share-variant} %1$s by %2$s%3$s</string>
|
<string name="event_list_shared_by_format">{cmd-share-variant} %1$s by %2$s%3$s</string>
|
||||||
<string name="event_list_shared_by_self_format">{cmd-share-variant} %1$s by you%3$s</string>
|
<string name="event_list_shared_by_self_format">{cmd-share-variant} %1$s by you%3$s</string>
|
||||||
<string name="event_manual_remove">Removing event…</string>
|
<string name="event_manual_remove">Removing event…</string>
|
||||||
@ -859,7 +859,7 @@
|
|||||||
<string name="settings_about_licenses_text">Open-source licenses</string>
|
<string name="settings_about_licenses_text">Open-source licenses</string>
|
||||||
<string name="settings_about_privacy_policy_text">Privacy policy</string>
|
<string name="settings_about_privacy_policy_text">Privacy policy</string>
|
||||||
<string name="settings_card_register_title">E-register</string>
|
<string name="settings_card_register_title">E-register</string>
|
||||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - October 2021</string>
|
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - 2022</string>
|
||||||
<string name="settings_about_update_subtext">Click to check for updates</string>
|
<string name="settings_about_update_subtext">Click to check for updates</string>
|
||||||
<string name="settings_about_update_text">Update</string>
|
<string name="settings_about_update_text">Update</string>
|
||||||
<string name="settings_about_version_text">Version</string>
|
<string name="settings_about_version_text">Version</string>
|
||||||
|
@ -926,7 +926,7 @@
|
|||||||
<string name="settings_about_licenses_text">Licencje open-source</string>
|
<string name="settings_about_licenses_text">Licencje open-source</string>
|
||||||
<string name="settings_about_privacy_policy_text">Polityka prywatności</string>
|
<string name="settings_about_privacy_policy_text">Polityka prywatności</string>
|
||||||
<string name="settings_card_register_title">E-dziennik</string>
|
<string name="settings_card_register_title">E-dziennik</string>
|
||||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nwrzesień 2018 - październik 2021</string>
|
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nwrzesień 2018 - 2022</string>
|
||||||
<string name="settings_about_update_subtext">Kliknij, aby sprawdzić aktualizacje</string>
|
<string name="settings_about_update_subtext">Kliknij, aby sprawdzić aktualizacje</string>
|
||||||
<string name="settings_about_update_text">Aktualizacja</string>
|
<string name="settings_about_update_text">Aktualizacja</string>
|
||||||
<string name="settings_about_version_text">Wersja</string>
|
<string name="settings_about_version_text">Wersja</string>
|
||||||
@ -1549,4 +1549,6 @@
|
|||||||
<string name="card_notes_header_title">Najnowsze notatki</string>
|
<string name="card_notes_header_title">Najnowsze notatki</string>
|
||||||
<string name="login_summary_account_child">(uczeń)</string>
|
<string name="login_summary_account_child">(uczeń)</string>
|
||||||
<string name="login_summary_account_parent">(rodzic)</string>
|
<string name="login_summary_account_parent">(rodzic)</string>
|
||||||
|
<string name="grades_subject_unknown">- nieznany przedmiot -</string>
|
||||||
|
<string name="grades_subject_unknown_help">{cmd-information-outline} Oceny, których przedmiot nie został podany w dzienniku. Może to być na przykład taki, który nie jest prowadzony w tym roku szkolnym.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-2-21.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.network
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import eu.szkolny.sslprovider.SSLProvider
|
||||||
|
import eu.szkolny.sslprovider.enableSupportedTls
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
object SSLProviderInstaller {
|
||||||
|
|
||||||
|
fun install(applicationContext: Context, rebuildCallback: () -> Unit) {
|
||||||
|
SSLProvider.install(
|
||||||
|
applicationContext,
|
||||||
|
downloadIfNeeded = true,
|
||||||
|
supportTls13 = false,
|
||||||
|
onFinish = {
|
||||||
|
rebuildCallback()
|
||||||
|
},
|
||||||
|
onError = {
|
||||||
|
Timber.e("Failed to install SSLProvider: $it")
|
||||||
|
it.printStackTrace()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enableSupportedTls(builder: OkHttpClient.Builder, enableCleartext: Boolean = true) {
|
||||||
|
builder.enableSupportedTls(enableCleartext)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-2-21.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.network
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
|
||||||
|
object SSLProviderInstaller {
|
||||||
|
|
||||||
|
fun install(applicationContext: Context, rebuildCallback: () -> Unit) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enableSupportedTls(builder: OkHttpClient.Builder, enableCleartext: Boolean = true) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-2-21.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.sync
|
||||||
|
|
||||||
|
import android.app.IntentService
|
||||||
|
import android.content.Intent
|
||||||
|
import android.widget.Toast
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
|
||||||
|
class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.java.simpleName) {
|
||||||
|
|
||||||
|
override fun onHandleIntent(intent: Intent?) {
|
||||||
|
try {
|
||||||
|
Utils.openGooglePlay(this, application.packageName)
|
||||||
|
}
|
||||||
|
catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
Toast.makeText(this, "Nie znaleziono Google Play. Pobierz aktualizację ręcznie.", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,8 +5,8 @@ buildscript {
|
|||||||
kotlin_version = '1.5.30'
|
kotlin_version = '1.5.30'
|
||||||
|
|
||||||
release = [
|
release = [
|
||||||
versionName: "4.11-rc.3",
|
versionName: "4.11.4",
|
||||||
versionCode: 4110030
|
versionCode: 4110499
|
||||||
]
|
]
|
||||||
|
|
||||||
setup = [
|
setup = [
|
||||||
|
Reference in New Issue
Block a user