Compare commits

..

7 Commits

15 changed files with 82 additions and 48 deletions

View File

@ -1,4 +1,4 @@
<h3>Wersja 4.0-beta.6, 2020-01-28</h3> <h3>Wersja 4.0-beta.7, 2020-02-08</h3>
<ul> <ul>
<li><b>Przebudowaliśmy cały moduł synchronizacji</b>, co oznacza większą stabilność aplikacji, szybkosć oraz poprawność pobieranych danych.</li> <li><b>Przebudowaliśmy cały moduł synchronizacji</b>, co oznacza większą stabilność aplikacji, szybkosć oraz poprawność pobieranych danych.</li>
<li><b><u>Wysyłanie wiadomości</u></b> - funkcja, na którą czekał każdy. Od teraz w Szkolnym można wysyłać oraz odpowiadać na wiadomości do nauczycieli &#x1F44F;</li> <li><b><u>Wysyłanie wiadomości</u></b> - funkcja, na którą czekał każdy. Od teraz w Szkolnym można wysyłać oraz odpowiadać na wiadomości do nauczycieli &#x1F44F;</li>
@ -32,10 +32,5 @@ Staramy się usuwać takie przypadki, jednak na chwilę obecną mogą występowa
<br> <br>
<br> <br>
<br> <br>
<br>
<i>Okazja ograniczona czasowo:</i> Poczuj prawdziwą zimę, włączając w Ustawieniach widok padającego śniegu!
<br>
<br>
<br>
Dzięki za korzystanie ze Szkolnego!<br> Dzięki za korzystanie ze Szkolnego!<br>
<i>&copy; Kuba Szczodrzyński, Kacper Ziubryniewicz 2020</i> <i>&copy; Kuba Szczodrzyński, Kacper Ziubryniewicz 2020</i>

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] = {
0x4a, 0x83, 0xba, 0x71, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 0x21, 0xd7, 0x64, 0x86, 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

@ -7,7 +7,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan
import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.models.Feature import pl.szczodrzynski.edziennik.data.api.models.Feature
const val ENDPOINT_VULCAN_API_STUDENT_LIST = 1000 const val ENDPOINT_VULCAN_API_UPDATE_SEMESTER = 1000
const val ENDPOINT_VULCAN_API_DICTIONARIES = 1010 const val ENDPOINT_VULCAN_API_DICTIONARIES = 1010
const val ENDPOINT_VULCAN_API_TIMETABLE = 1020 const val ENDPOINT_VULCAN_API_TIMETABLE = 1020
const val ENDPOINT_VULCAN_API_EVENTS = 1030 const val ENDPOINT_VULCAN_API_EVENTS = 1030
@ -54,7 +54,7 @@ val VulcanFeatures = listOf(
), listOf(LOGIN_METHOD_VULCAN_API)), ), listOf(LOGIN_METHOD_VULCAN_API)),
Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf( Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf(
ENDPOINT_VULCAN_API_STUDENT_LIST to LOGIN_METHOD_VULCAN_API, ENDPOINT_VULCAN_API_UPDATE_SEMESTER to LOGIN_METHOD_VULCAN_API,
ENDPOINT_VULCAN_API_DICTIONARIES to LOGIN_METHOD_VULCAN_API ENDPOINT_VULCAN_API_DICTIONARIES to LOGIN_METHOD_VULCAN_API
), listOf(LOGIN_METHOD_VULCAN_API)) ), listOf(LOGIN_METHOD_VULCAN_API))
/*Feature(LOGIN_TYPE_VULCAN, FEATURE_STUDENT_INFO, listOf( /*Feature(LOGIN_TYPE_VULCAN, FEATURE_STUDENT_INFO, listOf(

View File

@ -36,6 +36,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
private fun useEndpoint(endpointId: Int, onSuccess: () -> Unit) { private fun useEndpoint(endpointId: Int, onSuccess: () -> Unit) {
Utils.d(TAG, "Using endpoint $endpointId") Utils.d(TAG, "Using endpoint $endpointId")
when (endpointId) { when (endpointId) {
ENDPOINT_VULCAN_API_UPDATE_SEMESTER -> {
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
VulcanApiUpdateSemester(data, onSuccess)
}
ENDPOINT_VULCAN_API_DICTIONARIES -> { ENDPOINT_VULCAN_API_DICTIONARIES -> {
data.startProgress(R.string.edziennik_progress_endpoint_dictionaries) data.startProgress(R.string.edziennik_progress_endpoint_dictionaries)
VulcanApiDictionaries(data, onSuccess) VulcanApiDictionaries(data, onSuccess)

View File

@ -1,13 +1,14 @@
/* /*
* Copyright (c) Kuba Szczodrzyński 2020-1-3. * Copyright (c) Kuba Szczodrzyński 2020-2-1.
*/ */
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.ERROR_NO_STUDENTS_IN_ACCOUNT import pl.szczodrzynski.edziennik.data.api.ERROR_NO_STUDENTS_IN_ACCOUNT
import pl.szczodrzynski.edziennik.data.api.VULCAN_API_ENDPOINT_STUDENT_LIST import pl.szczodrzynski.edziennik.data.api.VULCAN_API_ENDPOINT_STUDENT_LIST
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_UPDATE_SEMESTER
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
@ -66,6 +67,7 @@ class VulcanApiUpdateSemester(override val data: DataVulcan, val onSuccess: () -
dateYearEnd?.let { profile.dateYearEnd = it } dateYearEnd?.let { profile.dateYearEnd = it }
} }
data.setSyncNext(ENDPOINT_VULCAN_API_UPDATE_SEMESTER, if (data.studentSemesterNumber == 2) 7*DAY else 2*DAY)
onSuccess() onSuccess()
} }
} ?: onSuccess()} } ?: onSuccess()}

View File

@ -13,6 +13,7 @@ import io.github.wulkanowy.signer.android.getPrivateKeyFromCert
import pl.szczodrzynski.edziennik.currentTimeUnix import pl.szczodrzynski.edziennik.currentTimeUnix
import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiUpdateSemester
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.getJsonObject import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.getString import pl.szczodrzynski.edziennik.getString

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.MTIzNDU2Nzg5MDHOhFUjfn===.$param2".sha256() return "$param1.MTIzNDU2Nzg5MDdK88yzVk===.$param2".sha256()
} }
} }

View File

@ -120,11 +120,15 @@ interface TimetableDao {
@Query(""" @Query("""
SELECT SELECT
timetable.*, timetable.*,
subjects.subjectLongName AS subjectName,
teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName, teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName,
oldS.subjectLongName AS oldSubjectName,
oldT.teacherName ||" "|| oldT.teacherSurname AS oldTeacherName, oldT.teacherName ||" "|| oldT.teacherSurname AS oldTeacherName,
metadata.seen, metadata.notified, metadata.addedDate metadata.seen, metadata.notified, metadata.addedDate
FROM timetable FROM timetable
LEFT JOIN subjects USING(profileId, subjectId)
LEFT JOIN teachers USING(profileId, teacherId) LEFT JOIN teachers USING(profileId, teacherId)
LEFT JOIN subjects AS oldS ON timetable.profileId = oldS.profileId AND timetable.oldSubjectId = oldS.subjectId
LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId
LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId
WHERE timetable.type NOT IN (${Lesson.TYPE_NORMAL}, ${Lesson.TYPE_NO_LESSONS}, ${Lesson.TYPE_SHIFTED_SOURCE}) AND metadata.notified = 0 WHERE timetable.type NOT IN (${Lesson.TYPE_NORMAL}, ${Lesson.TYPE_NO_LESSONS}, ${Lesson.TYPE_SHIFTED_SOURCE}) AND metadata.notified = 0

View File

@ -21,7 +21,7 @@ class Migration56 : Migration(55, 56) {
profileId INTEGER NOT NULL, profileId INTEGER NOT NULL,
lessonRangeNumber INTEGER NOT NULL, lessonRangeNumber INTEGER NOT NULL,
lessonRangeStart TEXT NOT NULL, lessonRangeStart TEXT NOT NULL,
LessonRangeEnd TEXT NOT NULL, lessonRangeEnd TEXT NOT NULL,
PRIMARY KEY(profileId, lessonRangeNumber))""") PRIMARY KEY(profileId, lessonRangeNumber))""")
} }
} }

View File

@ -10,26 +10,25 @@ import androidx.sqlite.db.SupportSQLiteDatabase
class Migration76 : Migration(75, 76) { class Migration76 : Migration(75, 76) {
override fun migrate(database: SupportSQLiteDatabase) { override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE feedbackMessages RENAME TO _feedbackMessages;") database.execSQL("ALTER TABLE feedbackMessages RENAME TO _feedbackMessages;")
database.execSQL("CREATE TABLE feedbackMessages (\n" + database.execSQL("""CREATE TABLE feedbackMessages (
"\tmessageId INTEGER NOT NULL PRIMARY KEY,\n" + messageId INTEGER NOT NULL PRIMARY KEY,
"\treceived INTEGER NOT NULL,\n" + received INTEGER NOT NULL,
"\ttext TEXT NOT NULL,\n" + text TEXT NOT NULL,
"\tsenderName TEXT NOT NULL,\n" + senderName TEXT NOT NULL,
"\tdeviceId TEXT DEFAULT NULL,\n" + deviceId TEXT DEFAULT NULL,
"\tdeviceName TEXT DEFAULT NULL,\n" + deviceName TEXT DEFAULT NULL,
"\tdevId INTEGER DEFAULT NULL,\n" + devId INTEGER DEFAULT NULL,
"\tdevImage TEXT DEFAULT NULL,\n" + devImage TEXT DEFAULT NULL,
"\tsentTime INTEGER NOT NULL\n" + sentTime INTEGER NOT NULL);""")
");") database.execSQL("""INSERT INTO feedbackMessages (messageId, received, text, senderName, deviceId, deviceName, devId, devImage, sentTime)
database.execSQL("INSERT INTO feedbackMessages (messageId, received, text, senderName, deviceId, deviceName, devId, devImage, sentTime)\n" + SELECT messageId, received, text,
"SELECT messageId, received, text,\n" + CASE fromUser IS NOT NULL WHEN 1 THEN CASE fromUserName IS NULL WHEN 1 THEN "" ELSE fromUserName END ELSE "" END AS senderName,
"CASE fromUser IS NOT NULL WHEN 1 THEN CASE fromUserName IS NULL WHEN 1 THEN \"\" ELSE fromUserName END ELSE \"\" END AS senderName,\n" + fromUser AS deviceId,
"fromUser AS deviceId,\n" + NULL AS deviceName,
"NULL AS deviceName,\n" + CASE received AND fromUser IS NULL WHEN 1 THEN 100 ELSE NULL END AS devId,
"CASE received AND fromUser IS NULL WHEN 1 THEN 100 ELSE NULL END AS devId,\n" + NULL AS devImage,
"NULL AS devImage,\n" + sentTime
"sentTime\n" + FROM _feedbackMessages;""")
"FROM _feedbackMessages;")
database.execSQL("DROP TABLE _feedbackMessages;") database.execSQL("DROP TABLE _feedbackMessages;")
} }
} }

View File

@ -10,6 +10,7 @@ import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Environment import android.os.Environment
import android.util.Log import android.util.Log
import android.view.View
import android.view.View.MeasureSpec import android.view.View.MeasureSpec
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView import android.widget.TextView
@ -60,6 +61,7 @@ class GenerateBlockTimetableDialog(
private lateinit var b: DialogGenerateBlockTimetableBinding private lateinit var b: DialogGenerateBlockTimetableBinding
private var showProfileName: Boolean = false private var showProfileName: Boolean = false
private var showTeachersNames: Boolean = true
private var noColors: Boolean = false private var noColors: Boolean = false
init { run { init { run {
@ -78,6 +80,9 @@ class GenerateBlockTimetableDialog(
b.showProfileNameItem.onClick { b.showProfileNameCheckbox.trigger() } b.showProfileNameItem.onClick { b.showProfileNameCheckbox.trigger() }
b.showProfileNameCheckbox.setOnCheckedChangeListener { _, isChecked -> showProfileName = isChecked } b.showProfileNameCheckbox.setOnCheckedChangeListener { _, isChecked -> showProfileName = isChecked }
b.showTeachersNamesItem.onClick { b.showTeachersNamesCheckbox.trigger() }
b.showTeachersNamesCheckbox.setOnCheckedChangeListener { _, isChecked -> showTeachersNames = isChecked }
b.noColorsItem.onClick { b.noColorsCheckbox.trigger() } b.noColorsItem.onClick { b.noColorsCheckbox.trigger() }
b.noColorsCheckbox.setOnCheckedChangeListener { _, isChecked -> noColors = isChecked } b.noColorsCheckbox.setOnCheckedChangeListener { _, isChecked -> noColors = isChecked }
@ -221,6 +226,8 @@ class GenerateBlockTimetableDialog(
teacherName.text = lesson.displayTeacherName ?: "" teacherName.text = lesson.displayTeacherName ?: ""
teamName.text = lesson.displayTeamName ?: "" teamName.text = lesson.displayTeamName ?: ""
if (!showTeachersNames) teacherName.visibility = View.GONE
when (lesson.type) { when (lesson.type) {
Lesson.TYPE_NORMAL -> {} Lesson.TYPE_NORMAL -> {}
Lesson.TYPE_CANCELLED, Lesson.TYPE_SHIFTED_SOURCE -> { Lesson.TYPE_CANCELLED, Lesson.TYPE_SHIFTED_SOURCE -> {

View File

@ -22,14 +22,11 @@ import kotlinx.coroutines.*
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.events.FeedbackMessageEvent import pl.szczodrzynski.edziennik.data.api.events.FeedbackMessageEvent
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
import pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage import pl.szczodrzynski.edziennik.data.db.entity.FeedbackMessage
import pl.szczodrzynski.edziennik.databinding.FragmentFeedbackBinding import pl.szczodrzynski.edziennik.databinding.FragmentFeedbackBinding
import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.utils.Themes import pl.szczodrzynski.edziennik.utils.Themes
import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.edziennik.utils.Utils.openUrl import pl.szczodrzynski.edziennik.utils.Utils.openUrl
@ -82,7 +79,7 @@ class FeedbackFragment : Fragment(), CoroutineScope {
0 to User(0, "Ja", null) 0 to User(0, "Ja", null)
) )
private fun getUser(message: FeedbackMessage): User { private fun getUser(message: FeedbackMessage): User {
val userId = message.devId ?: if (message.received) 1 else 0 val userId = message.devId ?: if (message.received) -message.senderName.crc16() else 0
return users[userId] ?: run { return users[userId] ?: run {
User(userId, message.senderName, message.devImage).also { users[userId] = it } User(userId, message.senderName, message.devImage).also { users[userId] = it }
} }
@ -118,13 +115,11 @@ class FeedbackFragment : Fragment(), CoroutineScope {
} }
private suspend fun loadMessages(messageList: List<FeedbackMessage>? = null) { private suspend fun loadMessages(messageList: List<FeedbackMessage>? = null) {
/*if (messageList != null && messageList.isNotEmpty()) val messages = withContext(Dispatchers.Default) {
return*/
val messages = messageList ?: withContext(Dispatchers.Default) {
if (currentDeviceId == null) if (currentDeviceId == null)
app.db.feedbackMessageDao().allNow messageList ?: app.db.feedbackMessageDao().allNow
else else
app.db.feedbackMessageDao().getByDeviceIdNow(currentDeviceId!!) messageList?.filter { it.deviceId == currentDeviceId } ?: app.db.feedbackMessageDao().getByDeviceIdNow(currentDeviceId!!)
} }
if (messages.isNotEmpty()) { if (messages.isNotEmpty()) {
@ -172,14 +167,14 @@ class FeedbackFragment : Fragment(), CoroutineScope {
} }
if (isDev) { if (isDev) {
messages.firstOrNull { it.received }?.let { messages.firstOrNull { it.received && it.devId == null }?.let {
currentDeviceId = it.deviceId currentDeviceId = it.deviceId
b.targetDeviceDropDown.setText("${it.senderName} (${it.deviceId}) - ${it.deviceName}") b.targetDeviceDropDown.setText("${it.senderName} (${it.deviceId}) - ${it.deviceName}")
} }
// handle notification intent // handle notification intent
arguments?.getString("feedbackMessageDeviceId")?.let { deviceId -> arguments?.getString("feedbackMessageDeviceId")?.let { deviceId ->
currentDeviceId = deviceId messages.firstOrNull { it.received && it.deviceId == deviceId && it.devId == null }?.let {
messages.firstOrNull { it.received && it.deviceId == deviceId }?.let { currentDeviceId = deviceId
b.targetDeviceDropDown.setText("${it.senderName} (${it.deviceId}) - ${it.deviceName}") b.targetDeviceDropDown.setText("${it.senderName} (${it.deviceId}) - ${it.deviceName}")
} }
} }

View File

@ -34,6 +34,32 @@
android:text="@string/timetable_generate_show_profile_name" /> android:text="@string/timetable_generate_show_profile_name" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/showTeachersNamesItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal">
<CheckBox
android:id="@+id/showTeachersNamesCheckbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:checked="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/timetable_generate_show_teachers_names" />
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/noColorsItem" android:id="@+id/noColorsItem"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -1173,4 +1173,5 @@
<string name="dialog_grades_config_color_by_value">Wg wartości oceny</string> <string name="dialog_grades_config_color_by_value">Wg wartości oceny</string>
<string name="other">Inne</string> <string name="other">Inne</string>
<string name="menu_grades_config">Ustawienia ocen</string> <string name="menu_grades_config">Ustawienia ocen</string>
<string name="timetable_generate_show_teachers_names">Pokaż imiona i nazwiska nauczycieli</string>
</resources> </resources>

View File

@ -5,8 +5,8 @@ buildscript {
kotlin_version = '1.3.61' kotlin_version = '1.3.61'
release = [ release = [
versionName: "4.0-beta.6", versionName: "4.0-beta.7",
versionCode: 4000006 versionCode: 4000007
] ]
setup = [ setup = [