Compare commits

...

8 Commits
v4.4 ... v4.4.2

18 changed files with 185 additions and 123 deletions

View File

@ -64,6 +64,6 @@
-keep class pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing { public final byte[] pleaseStopRightNow(java.lang.String, long); } -keep class pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing { public final byte[] pleaseStopRightNow(java.lang.String, long); }
-keepclassmembernames class pl.szczodrzynski.edziennik.data.api.szkolny.request.** { *; } -keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.request.** { *; }
-keepclassmembernames class pl.szczodrzynski.edziennik.data.api.szkolny.response.** { *; } -keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.response.** { *; }
-keepclassmembernames class pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo.Platform { *; } -keepclassmembernames class pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo.Platform { *; }

View File

@ -1,6 +1,9 @@
<h3>Wersja 4.4, 2020-08-27</h3> <h3>Wersja 4.4.2, 2020-09-05</h3>
<ul> <ul>
<li>Poprawione komunikaty o aktualizacjach aplikacji.</li> <li>Poprawione komunikaty o aktualizacjach aplikacji.</li>
<li>Mobidziennik: poprawione wyświetlanie przedmiotu w planie lekcji.</li>
<li>Mobidziennik: naprawiony moduł frekwencji.</li>
<li>Naprawione zatrzymanie aplikacji na ekranie logowania.</li>
</ul> </ul>
<br> <br>
<br> <br>

View File

@ -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] = {
0x85, 0xd2, 0x0d, 0x9e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 0x1a, 0xcd, 0xf0, 0x80, 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);

View File

@ -647,7 +647,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
app.profile.registerName?.let { registerName -> app.profile.registerName?.let { registerName ->
var status = app.config.sync.registerAvailability[registerName] var status = app.config.sync.registerAvailability[registerName]
if (status == null || status.nextCheck < currentTimeUnix()) { if (status == null || status.nextCheckAt < currentTimeUnix()) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val api = SzkolnyApi(app) val api = SzkolnyApi(app)
api.runCatching(this@MainActivity) { api.runCatching(this@MainActivity) {

View File

@ -80,6 +80,15 @@ object Regexes {
val MOBIDZIENNIK_ATTENDANCE_ENTRIES by lazy { val MOBIDZIENNIK_ATTENDANCE_ENTRIES by lazy {
"""font-size:.+?class=".*?">(.*?)</td>""".toRegex(DOT_MATCHES_ALL) """font-size:.+?class=".*?">(.*?)</td>""".toRegex(DOT_MATCHES_ALL)
} }
val MOBIDZIENNIK_ATTENDANCE_COLUMNS by lazy {
"""<tr><td class="border-right1".+?/td>(.+?)</tr>""".toRegex(DOT_MATCHES_ALL)
}
val MOBIDZIENNIK_ATTENDANCE_COLUMN by lazy {
"""(<td.+?>)(.*?)</td>""".toRegex(DOT_MATCHES_ALL)
}
val MOBIDZIENNIK_ATTENDANCE_COLUMN_SPAN by lazy {
"""colspan="(\d+)"""".toRegex()
}
val MOBIDZIENNIK_ATTENDANCE_RANGE by lazy { val MOBIDZIENNIK_ATTENDANCE_RANGE by lazy {
"""<span>([0-9:]+) - .+? (.+?)</span></a>""".toRegex(DOT_MATCHES_ALL) """<span>([0-9:]+) - .+? (.+?)</span></a>""".toRegex(DOT_MATCHES_ALL)
} }

View File

@ -93,7 +93,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
profile.registerName?.let { registerName -> profile.registerName?.let { registerName ->
var status = app.config.sync.registerAvailability[registerName] var status = app.config.sync.registerAvailability[registerName]
if (status == null || status.nextCheck < currentTimeUnix()) { if (status == null || status.nextCheckAt < currentTimeUnix()) {
val api = SzkolnyApi(app) val api = SzkolnyApi(app)
api.runCatching({ api.runCatching({
val availability = getRegisterAvailability() val availability = getRegisterAvailability()

View File

@ -44,7 +44,7 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
dataDays.remove(date.value) dataDays.remove(date.value)
val subjectId = data.subjectList.singleOrNull { it.longName == lesson[5] }?.id ?: -1 val subjectId = data.subjectList.singleOrNull { it.longName == lesson[5].trim() }?.id ?: -1
val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == (lesson[7]+" "+lesson[6]).fixName() }?.id ?: -1 val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == (lesson[7]+" "+lesson[6]).fixName() }?.id ?: -1
val teamId = data.teamList.singleOrNull { it.name == lesson[8]+lesson[9] }?.id ?: -1 val teamId = data.teamList.singleOrNull { it.name == lesson[8]+lesson[9] }?.id ?: -1
val classroom = lesson[11] val classroom = lesson[11]

View File

@ -91,8 +91,11 @@ class MobidziennikWebAttendance(override val data: DataMobidziennik,
Regexes.MOBIDZIENNIK_ATTENDANCE_TABLE.findAll(text).forEach { tableResult -> Regexes.MOBIDZIENNIK_ATTENDANCE_TABLE.findAll(text).forEach { tableResult ->
val table = tableResult[1] val table = tableResult[1]
val lessonDates = mutableListOf<Date>() val lessonDates = mutableListOf<Date>()
val entries = mutableListOf<String>() val entries = mutableListOf<String>()
val ranges = mutableListOf<MatchResult?>()
Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON_COUNT.findAll(table).forEach { Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON_COUNT.findAll(table).forEach {
val date = Date.fromY_m_d(it[1]) val date = Date.fromY_m_d(it[1])
for (i in 0 until (it[2].toIntOrNull() ?: 0)) { for (i in 0 until (it[2].toIntOrNull() ?: 0)) {
@ -101,102 +104,52 @@ class MobidziennikWebAttendance(override val data: DataMobidziennik,
} }
Regexes.MOBIDZIENNIK_ATTENDANCE_ENTRIES.findAll(table).mapTo(entries) { it[1] } Regexes.MOBIDZIENNIK_ATTENDANCE_ENTRIES.findAll(table).mapTo(entries) { it[1] }
Regexes.MOBIDZIENNIK_ATTENDANCE_COLUMNS.findAll(table).forEach { columns ->
var index = 0
Regexes.MOBIDZIENNIK_ATTENDANCE_COLUMN.findAll(columns[1]).forEach { column ->
if (column[1].contains("colspan")) {
val colspan =
Regexes.MOBIDZIENNIK_ATTENDANCE_COLUMN_SPAN.find(column[1])
?.get(1)
?.toIntOrNull() ?: 0
entries.addAll(index, List(colspan) { "" })
ranges.addAll(List(colspan) { null })
index += colspan
}
else {
val range = Regexes.MOBIDZIENNIK_ATTENDANCE_RANGE.find(column[2])
ranges.add(range)
index++
}
}
}
val dateIterator = lessonDates.iterator() val dateIterator = lessonDates.iterator()
val entriesIterator = entries.iterator() val entriesIterator = entries.iterator()
Regexes.MOBIDZIENNIK_ATTENDANCE_RANGE.findAll(table).let { ranges ->
val count = ranges.count() val count = ranges.count()
// verify the lesson count is the same as dates & entries // verify the lesson count is the same as dates & entries
if (count != lessonDates.count() || count != entries.count()) if (count != lessonDates.count() || count != entries.count())
return@forEach
ranges.forEach { range ->
val lessonDate = dateIterator.next()
val entry = entriesIterator.next()
if (range == null || entry.isBlank())
return@forEach return@forEach
ranges.forEach { range -> val startTime = Time.fromH_m(range[1])
val lessonDate = dateIterator.next()
var entry = entriesIterator.next()
if (entry.isBlank())
return@forEach
val startTime = Time.fromH_m(range[1])
range[2].split(" / ").mapNotNull { Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON.find(it) }.forEachIndexed { index, lesson -> range[2].split(" / ").mapNotNull {
val topic = lesson[1].substringAfter(" - ", missingDelimiterValue = "").takeIf { it.isNotBlank() } Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON.find(it)
if (topic?.startsWith("Lekcja odwołana: ") == true || entry.isEmpty()) }.forEachIndexed { index, lesson ->
return@forEachIndexed processEntry(
val subjectName = lesson[1].substringBefore(" - ") index,
//val team = lesson[3] lesson,
val teacherName = lesson[3].fixName() lessonDate,
startTime,
val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == teacherName }?.id ?: -1 entry,
val subjectId = data.subjectList.singleOrNull { it.longName == subjectName }?.id ?: -1 types,
typeSymbols
var typeSymbol = "" )
for (symbol in typeSymbols) {
if (entry.startsWith(symbol) && symbol.length > typeSymbol.length)
typeSymbol = symbol
}
entry = entry.removePrefix(typeSymbol)
var isCounted = true
val baseType = when (typeSymbol) {
"." -> TYPE_PRESENT
"|" -> TYPE_ABSENT
"+" -> TYPE_ABSENT_EXCUSED
"s" -> TYPE_BELATED
"z" -> TYPE_RELEASED
else -> {
isCounted = false
when (typeSymbol) {
"e" -> TYPE_PRESENT_CUSTOM
"en" -> TYPE_ABSENT
"ep" -> TYPE_PRESENT_CUSTOM
else -> TYPE_UNKNOWN
}
}
}
val typeName = types?.get(typeSymbol) ?: ""
val typeColor = when (typeSymbol) {
"e" -> 0xff673ab7
"en" -> 0xffec407a
"ep" -> 0xff4caf50
else -> null
}?.toInt()
val typeShort = if (isCounted)
data.app.attendanceManager.getTypeShort(baseType)
else
typeSymbol
val semester = data.profile?.dateToSemester(lessonDate) ?: 1
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson[0].hashCode() and 0xFFFF) + index
val attendanceObject = Attendance(
profileId = profileId,
id = id,
baseType = baseType,
typeName = typeName,
typeShort = typeShort,
typeSymbol = typeSymbol,
typeColor = typeColor,
date = lessonDate,
startTime = startTime,
semester = semester,
teacherId = teacherId,
subjectId = subjectId
).also {
it.lessonTopic = topic
it.isCounted = isCounted
}
data.attendanceList.add(attendanceObject)
if (baseType != TYPE_PRESENT) {
data.metadataList.add(
Metadata(
data.profileId,
Metadata.TYPE_ATTENDANCE,
id,
data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN,
data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN
))
}
}
} }
} }
} }
@ -206,4 +159,97 @@ class MobidziennikWebAttendance(override val data: DataMobidziennik,
onSuccess() onSuccess()
} }
} }
private fun processEntry(
index: Int,
lesson: MatchResult,
lessonDate: Date,
startTime: Time,
entry: String,
types: Map<String?, String?>?,
typeSymbols: List<String>
) {
var entry = entry
val topic = lesson[1].substringAfter(" - ", missingDelimiterValue = "").takeIf { it.isNotBlank() }
if (topic?.startsWith("Lekcja odwołana: ") == true || entry.isEmpty())
return
val subjectName = lesson[1].substringBefore(" - ")
//val team = lesson[3]
val teacherName = lesson[3].fixName()
val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == teacherName }?.id ?: -1
val subjectId = data.subjectList.singleOrNull { it.longName == subjectName }?.id ?: -1
var typeSymbol = ""
for (symbol in typeSymbols) {
if (entry.startsWith(symbol) && symbol.length > typeSymbol.length)
typeSymbol = symbol
}
entry = entry.removePrefix(typeSymbol)
var isCounted = true
val baseType = when (typeSymbol) {
"." -> TYPE_PRESENT
"|" -> TYPE_ABSENT
"+" -> TYPE_ABSENT_EXCUSED
"s" -> TYPE_BELATED
"z" -> TYPE_RELEASED
else -> {
isCounted = false
when (typeSymbol) {
"e" -> TYPE_PRESENT_CUSTOM
"en" -> TYPE_ABSENT
"ep" -> TYPE_PRESENT_CUSTOM
else -> TYPE_UNKNOWN
}
}
}
val typeName = types?.get(typeSymbol) ?: ""
val typeColor = when (typeSymbol) {
"e" -> 0xff673ab7
"en" -> 0xffec407a
"ep" -> 0xff4caf50
else -> null
}?.toInt()
val typeShort = if (isCounted)
data.app.attendanceManager.getTypeShort(baseType)
else
typeSymbol
val semester = data.profile?.dateToSemester(lessonDate) ?: 1
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson[0].hashCode() and 0xFFFF) + index
val attendanceObject = Attendance(
profileId = profileId,
id = id,
baseType = baseType,
typeName = typeName,
typeShort = typeShort,
typeSymbol = typeSymbol,
typeColor = typeColor,
date = lessonDate,
startTime = startTime,
semester = semester,
teacherId = teacherId,
subjectId = subjectId
).also {
it.lessonTopic = topic
it.isCounted = isCounted
}
data.attendanceList.add(attendanceObject)
if (baseType != TYPE_PRESENT) {
data.metadataList.add(
Metadata(
data.profileId,
Metadata.TYPE_ATTENDANCE,
id,
data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN,
data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN
))
}
}
} }

View File

@ -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.MTIzNDU2Nzg5MDSA64wjse===.$param2".sha256() return "$param1.MTIzNDU2Nzg5MDx45DzIF8===.$param2".sha256()
} }
} }

View File

@ -11,8 +11,8 @@ import pl.szczodrzynski.edziennik.currentTimeUnix
data class RegisterAvailabilityStatus( data class RegisterAvailabilityStatus(
val available: Boolean, val available: Boolean,
val name: String?, val name: String?,
val message: Message?, val userMessage: Message?,
val nextCheck: Long = currentTimeUnix() + 7 * DAY, val nextCheckAt: Long = currentTimeUnix() + 7 * DAY,
val minVersionCode: Int = BuildConfig.VERSION_CODE val minVersionCode: Int = BuildConfig.VERSION_CODE
) { ) {
data class Message( data class Message(

View File

@ -4,6 +4,7 @@
package pl.szczodrzynski.edziennik.ui.dialogs package pl.szczodrzynski.edziennik.ui.dialogs
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
@ -46,16 +47,17 @@ class RegisterUnavailableDialog(
onShowListener?.invoke(TAG) onShowListener?.invoke(TAG)
app = activity.applicationContext as App app = activity.applicationContext as App
if (!status.available && status.message != null) { if (!status.available && status.userMessage != null) {
val b = DialogRegisterUnavailableBinding.inflate(LayoutInflater.from(activity), null, false) val b = DialogRegisterUnavailableBinding.inflate(LayoutInflater.from(activity), null, false)
b.message = status.message b.message = status.userMessage
if (status.message.image != null) if (status.userMessage.image != null)
b.image.load(status.message.image) b.image.load(status.userMessage.image)
if (status.message.url != null) { if (status.userMessage.url != null) {
b.readMore.onClick { b.readMore.onClick {
Utils.openUrl(activity, status.message.url) Utils.openUrl(activity, status.userMessage.url)
} }
} }
b.text.movementMethod = LinkMovementMethod.getInstance()
dialog = MaterialAlertDialogBuilder(activity) dialog = MaterialAlertDialogBuilder(activity)
.setView(b.root) .setView(b.root)
.setPositiveButton(R.string.close) { dialog, _ -> .setPositiveButton(R.string.close) { dialog, _ ->
@ -65,6 +67,7 @@ class RegisterUnavailableDialog(
onDismissListener?.invoke(TAG) onDismissListener?.invoke(TAG)
} }
.show() .show()
return@run
} }
val update = app.config.update val update = app.config.update

View File

@ -8,6 +8,7 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.core.text.HtmlCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.plusAssign import androidx.core.view.plusAssign
import androidx.core.view.setMargins import androidx.core.view.setMargins
@ -57,13 +58,13 @@ class HomeAvailabilityCard(
var onInfoClick = { _: View -> } var onInfoClick = { _: View -> }
if (status != null && !status.available && status.message != null) { if (status != null && !status.available && status.userMessage != null) {
b.homeAvailabilityTitle.text = status.message.title b.homeAvailabilityTitle.text = HtmlCompat.fromHtml(status.userMessage.title, HtmlCompat.FROM_HTML_MODE_LEGACY)
b.homeAvailabilityText.text = status.message.contentShort b.homeAvailabilityText.text = HtmlCompat.fromHtml(status.userMessage.contentShort, HtmlCompat.FROM_HTML_MODE_LEGACY)
b.homeAvailabilityUpdate.isVisible = false b.homeAvailabilityUpdate.isVisible = false
b.homeAvailabilityIcon.setImageResource(R.drawable.ic_sync) b.homeAvailabilityIcon.setImageResource(R.drawable.ic_sync)
if (status.message.icon != null) if (status.userMessage.icon != null)
b.homeAvailabilityIcon.load(status.message.icon) b.homeAvailabilityIcon.load(status.userMessage.icon)
onInfoClick = { onInfoClick = {
RegisterUnavailableDialog(activity, status) RegisterUnavailableDialog(activity, status)
} }

View File

@ -117,7 +117,7 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
else -> null else -> null
}?.let { registerName -> }?.let { registerName ->
var status = app.config.sync.registerAvailability[registerName] var status = app.config.sync.registerAvailability[registerName]
if (status == null || status.nextCheck < currentTimeUnix()) { if (status == null || status.nextCheckAt < currentTimeUnix()) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val api = SzkolnyApi(app) val api = SzkolnyApi(app)
api.runCatching(activity) { api.runCatching(activity) {

View File

@ -8,7 +8,7 @@
<data> <data>
<import type="android.view.View" /> <import type="android.view.View" />
<import type="android.text.Html" /> <import type="androidx.core.text.HtmlCompat" />
<variable <variable
name="message" name="message"
type="pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus.Message" /> type="pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus.Message" />
@ -45,7 +45,7 @@
android:id="@+id/title" android:id="@+id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@{message.title}" android:text="@{HtmlCompat.fromHtml(message.title, HtmlCompat.FROM_HTML_MODE_LEGACY)}"
android:textAppearance="@style/NavView.TextView.Title" android:textAppearance="@style/NavView.TextView.Title"
tools:text="Dziennik nie działa" /> tools:text="Dziennik nie działa" />
@ -54,7 +54,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:text="@{Html.fromHtml(message.contentLong)}" android:text="@{HtmlCompat.fromHtml(message.contentLong, HtmlCompat.FROM_HTML_MODE_LEGACY)}"
tools:text="Dziennik się zepsuł i nie działa, szkoda\n\n\nwiele linijek ma ten tekst" /> tools:text="Dziennik się zepsuł i nie działa, szkoda\n\n\nwiele linijek ma ten tekst" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton

View File

@ -854,7 +854,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_about_register_title_text">E-Klassenbuch</string> <string name="settings_about_register_title_text">E-Klassenbuch</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nSeptember 2018 - August 2020</string> <string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nSeptember 2018 - 2020</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>

View File

@ -856,7 +856,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_about_register_title_text">E-register</string> <string name="settings_about_register_title_text">E-register</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nSeptember 2018 - August 2020</string> <string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nSeptember 2018 - 2020</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>

View File

@ -919,7 +919,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_about_register_title_text">E-dziennik</string> <string name="settings_about_register_title_text">E-dziennik</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nwrzesień 2018 - sierpień 2020</string> <string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nwrzesień 2018 - 2020</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>
@ -1368,7 +1368,7 @@
<string name="home_archive_close_no_target_title">Brak aktualnego profilu</string> <string name="home_archive_close_no_target_title">Brak aktualnego profilu</string>
<string name="home_archive_close_no_target_text">Uczeń %s nie posiada profilu na tym koncie w aktualnym roku szkolnym. Prawdopodobnie ten profil został usunięty lub uczeń nie uczęszcza już do tej klasy.\n\nAby przejść do aktualnego profilu, wybierz ucznia z listy lub zaloguj się na jego konto przyciskiem Dodaj ucznia.</string> <string name="home_archive_close_no_target_text">Uczeń %s nie posiada profilu na tym koncie w aktualnym roku szkolnym. Prawdopodobnie ten profil został usunięty lub uczeń nie uczęszcza już do tej klasy.\n\nAby przejść do aktualnego profilu, wybierz ucznia z listy lub zaloguj się na jego konto przyciskiem Dodaj ucznia.</string>
<string name="login_copyright_notice">Znaki towarowe zamieszczone w tej aplikacji należą do ich prawowitych właścicieli i są używane wyłącznie w celach informacyjnych.</string> <string name="login_copyright_notice">Znaki towarowe zamieszczone w tej aplikacji należą do ich prawowitych właścicieli i są używane wyłącznie w celach informacyjnych.</string>
<string name="update_available_title">Dostępna aktualiacja aplikacji</string> <string name="update_available_title">Dostępna aktualizacja aplikacji</string>
<string name="update_available_format">Używasz starej wersji aplikacji Szkolny.eu (%s). Aby móc korzystać z aplikacji oraz zapewnić najlepsze działanie, zaktualizuj aplikację do wersji %s.\n\nDziennik zmian:\n%s</string> <string name="update_available_format">Używasz starej wersji aplikacji Szkolny.eu (%s). Aby móc korzystać z aplikacji oraz zapewnić najlepsze działanie, zaktualizuj aplikację do wersji %s.\n\nDziennik zmian:\n%s</string>
<string name="update_available_fallback">Posiadasz nieaktualną wersję aplikacji Szkolny.eu. Aby móc dalej synchronizować dane, musisz zaktualizować aplikację.</string> <string name="update_available_fallback">Posiadasz nieaktualną wersję aplikacji Szkolny.eu. Aby móc dalej synchronizować dane, musisz zaktualizować aplikację.</string>
<string name="update_available_button">Aktualizuj</string> <string name="update_available_button">Aktualizuj</string>

View File

@ -5,8 +5,8 @@ buildscript {
kotlin_version = '1.3.61' kotlin_version = '1.3.61'
release = [ release = [
versionName: "4.4", versionName: "4.4.2",
versionCode: 4040099 versionCode: 4040299
] ]
setup = [ setup = [