Compare commits

..

No commits in common. "v4.7.1" and "v4.7-rc.2" have entirely different histories.

28 changed files with 141 additions and 384 deletions

View file

@ -26,7 +26,7 @@ if __name__ == "__main__":
exit(-1)
with requests.get(
f"https://api.github.com/repos/{repo}/actions/runs?per_page=5&status=success"
f"https://api.github.com/repos/{repo}/actions/runs?per_page=1&status=success"
) as r:
data = json.loads(r.text)
runs = [run for run in data["workflow_runs"] if run["head_sha"] == sha]

View file

@ -21,8 +21,10 @@ if __name__ == "__main__":
print("::set-output name=changelogDir::" + dir)
(title, changelog) = get_changelog(project_dir, format="plain")
with open(dir + "whatsnew-pl-PL", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=changelogPlainFile::" + dir + "whatsnew-pl-PL")
# plain text changelog - Firebase App Distribution
with open(dir + "whatsnew-titled.txt", "w", encoding="utf-8") as f:
f.write(title)
f.write("\n")
@ -31,31 +33,16 @@ if __name__ == "__main__":
print("::set-output name=changelogTitle::" + title)
# plain text changelog, max 500 chars - Google Play
with open(dir + "whatsnew-pl-PL", "w", encoding="utf-8") as f:
changelog_lines = changelog.split("\n")
changelog = ""
for line in changelog_lines:
if len(changelog) + len(line) < 500:
changelog += "\n" + line
changelog = changelog.strip()
f.write(changelog)
print("::set-output name=changelogPlainFile::" + dir + "whatsnew-pl-PL")
# markdown changelog - Discord webhook
(_, changelog) = get_changelog(project_dir, format="markdown")
with open(dir + "whatsnew.md", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=changelogMarkdownFile::" + dir + "whatsnew.md")
# html changelog - version info in DB
(_, changelog) = get_changelog(project_dir, format="html")
with open(dir + "whatsnew.html", "w", encoding="utf-8") as f:
f.write(changelog)
print("::set-output name=changelogHtmlFile::" + dir + "whatsnew.html")
changelog = get_commit_log(project_dir, format="plain", max_lines=10)
with open(dir + "commit_log.txt", "w", encoding="utf-8") as f:
f.write(changelog)

View file

@ -46,7 +46,7 @@ jobs:
runs-on: self-hosted
needs:
- prepare
if: ${{ needs.prepare.outputs.hasNewChanges == 'true' }}
if: needs.prepare.outputs.hasNewChanges
outputs:
androidHome: ${{ env.ANDROID_HOME }}
androidSdkRoot: ${{ env.ANDROID_SDK_ROOT }}

View file

@ -113,11 +113,12 @@ jobs:
releaseFile: ${{ needs.sign.outputs.signedReleaseFile }}
releaseName: ${{ steps.changelog.outputs.appVersionName }}
track: ${{ secrets.PLAY_RELEASE_TRACK }}
userFraction: 1.0
whatsNewDirectory: ${{ steps.changelog.outputs.changelogDir }}
- name: Upload workflow artifact
uses: actions/upload-artifact@v2
if: always()
if: true
with:
name: ${{ steps.changelog.outputs.appVersionName }}
path: |

View file

@ -15,7 +15,6 @@
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@ -26,7 +25,6 @@
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@ -38,7 +36,6 @@
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
@ -49,7 +46,6 @@
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
@ -60,7 +56,6 @@
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@ -71,7 +66,6 @@
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@ -82,7 +76,6 @@
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
@ -94,7 +87,6 @@
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
@ -106,7 +98,6 @@
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>

View file

@ -32,9 +32,8 @@
-keepnames class pl.szczodrzynski.edziennik.ui.widgets.luckynumber.WidgetLuckyNumberProvider
-keepnames class androidx.appcompat.view.menu.MenuBuilder { setHeaderTitleInt(java.lang.CharSequence); }
-keepnames class androidx.appcompat.view.menu.MenuPopupHelper { showPopup(int, int, boolean, boolean); }
-keepclassmembernames class androidx.appcompat.view.menu.StandardMenuPopup { private *; }
-keepclassmembernames class androidx.appcompat.view.menu.MenuItemImpl { private *; }
-keepnames class androidx.appcompat.view.menu.MenuPopupHelper { showPopup(int, int, boolean, boolean); }
-keepclassmembernames class com.mikepenz.materialdrawer.widget.MiniDrawerSliderView { private *; }

View file

@ -1,7 +1,13 @@
<h3>Wersja 4.7.1, 2021-04-12</h3>
<h3>Wersja 4.7-rc.2, 2021-04-05</h3>
<ul>
<li>Poprawiono sprawdzanie dostępności e-dziennika.</li>
<li>Zmieniono datę w informacjach o aplikacji. @Luncenok</li>
<li><u>Szkolny.eu jest teraz open source!</u> Zapraszamy na stronę <a href="https://szkolny.eu/">https://szkolny.eu/</a> po więcej ważnych informacji.</li>
<li>Poprawiono wybieranie obrazków (tła nagłówka, tła aplikacji oraz profilu) z dowolnego źródła.</li>
<li>Zaktualizowano tłumaczenie na język angielski. @MarcinK50</li>
<li>Dodano ekran informacji o kompilacji w Ustawieniach.</li>
<li>Zaktualizowano ekran licencji open source.</li>
<li>Naprawiono zatrzymanie aplikacji na Androidzie 4.4 i starszych.</li>
<li>Naprawiono problemy z połączeniem internetowym na Androidzie 4.4 i starszych.</li>
<li>Zoptymalizowano wielkość aplikacji.</li>
</ul>
<br>
<br>

View file

@ -9,7 +9,7 @@
/*secret password - removed for source code publication*/
static toys AES_IV[16] = {
0xcc, 0x64, 0xdb, 0x3a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
0x25, 0x68, 0xd4, 0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);

View file

@ -6,7 +6,6 @@ package pl.szczodrzynski.edziennik.config
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import pl.szczodrzynski.edziennik.BuildConfig
import pl.szczodrzynski.edziennik.config.utils.get
import pl.szczodrzynski.edziennik.config.utils.getIntList
import pl.szczodrzynski.edziennik.config.utils.set
@ -124,19 +123,6 @@ class ConfigSync(private val config: Config) {
private var mRegisterAvailability: Map<String, RegisterAvailabilityStatus>? = null
var registerAvailability: Map<String, RegisterAvailabilityStatus>
get() {
val flavor = config.values.get("registerAvailabilityFlavor", null as String?)
if (BuildConfig.FLAVOR != flavor)
return mapOf()
mRegisterAvailability = mRegisterAvailability ?: config.values.get("registerAvailability", null as String?)?.let { it ->
gson.fromJson(it, object: TypeToken<Map<String, RegisterAvailabilityStatus>>(){}.type)
}
return mRegisterAvailability ?: mapOf()
}
set(value) {
config.setMap("registerAvailability", value)
config.set("registerAvailabilityFlavor", BuildConfig.FLAVOR)
mRegisterAvailability = value
}
get() { mRegisterAvailability = mRegisterAvailability ?: config.values.get("registerAvailability", null as String?)?.let { it -> gson.fromJson<Map<String, RegisterAvailabilityStatus>>(it, object: TypeToken<Map<String, RegisterAvailabilityStatus>>(){}.type) }; return mRegisterAvailability ?: mapOf() }
set(value) { config.setMap("registerAvailability", value); mRegisterAvailability = value }
}

View file

@ -15,7 +15,6 @@ class ApiCacheInterceptor(val app: App) : Interceptor {
val request = chain.request()
if (request.url().host() == "api.szkolny.eu"
&& Signing.appCertificate.md5() == app.config.apiInvalidCert
&& !app.buildManager.isSigned
) {
val response = ApiResponse<Unit>(
success = false,

View file

@ -46,6 +46,6 @@ object Signing {
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
return "$param1.MTIzNDU2Nzg5MDXHhAtZBW===.$param2".sha256()
return "$param1.MTIzNDU2Nzg5MD+7y77uUm===.$param2".sha256()
}
}

View file

@ -199,14 +199,10 @@ class EventDetailsDialog(
}
b.downloadButton.attachToastHint(R.string.hint_download_again)
BetterLink.attach(b.topic, onActionSelected = dialog::dismiss)
event.teacherName?.let { name ->
BetterLink.attach(
b.teacherName,
teachers = mapOf(event.teacherId to name),
onActionSelected = dialog::dismiss
)
b.topic.text = event.topic
BetterLink.attach(b.topic) {
dialog.dismiss()
}
if (event.homeworkBody == null && !event.addedManually && event.type == Event.TYPE_HOMEWORK) {
@ -224,7 +220,10 @@ class EventDetailsDialog(
b.bodyTitle.isVisible = true
b.bodyProgressBar.isVisible = false
b.body.isVisible = true
BetterLink.attach(b.body, onActionSelected = dialog::dismiss)
b.body.text = event.homeworkBody
BetterLink.attach(b.body) {
dialog.dismiss()
}
}
if (event.attachmentIds.isNullOrEmpty() || event.attachmentNames.isNullOrEmpty()) {

View file

@ -14,7 +14,6 @@ import pl.szczodrzynski.edziennik.databinding.DialogGradeDetailsBinding
import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.setTintColor
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter
import pl.szczodrzynski.edziennik.utils.BetterLink
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import kotlin.coroutines.CoroutineContext
@ -69,14 +68,6 @@ class GradeDetailsDialog(
GradesConfigDialog(activity, reloadOnDismiss = true)
}
grade.teacherName?.let { name ->
BetterLink.attach(
b.teacherName,
teachers = mapOf(grade.teacherId to name),
onActionSelected = dialog::dismiss
)
}
launch {
val historyList = withContext(Dispatchers.Default) {
app.db.gradeDao().getByParentIdNow(App.profileId, grade.id)

View file

@ -25,7 +25,6 @@ import pl.szczodrzynski.edziennik.ui.dialogs.event.EventDetailsDialog
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListAdapter
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment
import pl.szczodrzynski.edziennik.utils.BetterLink
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Week
@ -217,19 +216,5 @@ class LessonDetailsDialog(
b.eventsNoData.visibility = View.VISIBLE
}
})
lesson.displayTeacherName?.let { name ->
lesson.displayTeacherId ?: return@let
BetterLink.attach(
b.teacherNameView,
teachers = mapOf(lesson.displayTeacherId!! to name),
onActionSelected = dialog::dismiss
)
BetterLink.attach(
b.oldTeacherNameView,
teachers = mapOf(lesson.displayTeacherId!! to name),
onActionSelected = dialog::dismiss
)
}
}
}

View file

@ -16,7 +16,6 @@ import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.full.AttendanceFull
import pl.szczodrzynski.edziennik.databinding.AttendanceDetailsDialogBinding
import pl.szczodrzynski.edziennik.setTintColor
import pl.szczodrzynski.edziennik.utils.BetterLink
import kotlin.coroutines.CoroutineContext
class AttendanceDetailsDialog(
@ -61,13 +60,5 @@ class AttendanceDetailsDialog(
b.attendanceName.background.setTintColor(attendanceColor)
b.attendanceIsCounted.setText(if (attendance.isCounted) R.string.yes else R.string.no)
attendance.teacherName?.let { name ->
BetterLink.attach(
b.teacherName,
teachers = mapOf(attendance.teacherId to name),
onActionSelected = dialog::dismiss
)
}
}}
}

View file

@ -21,7 +21,6 @@ import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_MOBIDZIENNIK
import pl.szczodrzynski.edziennik.data.db.entity.Notice
import pl.szczodrzynski.edziennik.data.db.full.NoticeFull
import pl.szczodrzynski.edziennik.utils.BetterLink
import pl.szczodrzynski.edziennik.utils.Utils.bs
import pl.szczodrzynski.edziennik.utils.models.Date
@ -84,14 +83,6 @@ class NoticesAdapter//getting the context and product list with constructor
} else {
holder.noticesItemReason.background = null
}
BetterLink.attach(holder.noticesItemReason)
notice.teacherName?.let { name ->
BetterLink.attach(holder.noticesItemTeacherName, teachers = mapOf(
notice.teacherId to name
))
}
}
override fun getItemCount(): Int {

View file

@ -33,7 +33,6 @@ import pl.szczodrzynski.edziennik.ui.dialogs.RegisterUnavailableDialog
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackActivity
import pl.szczodrzynski.edziennik.utils.BetterLinkMovementMethod
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import pl.szczodrzynski.edziennik.utils.models.Date
import kotlin.coroutines.CoroutineContext
class LoginChooserFragment : Fragment(), CoroutineScope {
@ -66,15 +65,6 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (!isAdded) return
b.versionText.setText(
R.string.login_chooser_version_format,
app.buildManager.versionName,
Date.fromMillis(app.buildManager.buildTimestamp).stringY_m_d
)
b.versionText.onClick {
app.buildManager.showVersionDialog(activity)
}
val adapter = LoginChooserAdapter(activity, this::onLoginModeClicked)
LoginInfo.chooserList = LoginInfo.chooserList

View file

@ -345,7 +345,6 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
b.recipients.setAdapter(adapter)
handleReplyMessage()
handleMailToIntent()
}}
private fun handleReplyMessage() { launch {
@ -403,22 +402,6 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
}
}}
private fun handleMailToIntent() {
val teacherId = arguments?.getLong("messageRecipientId")
if (teacherId == 0L)
return
val chipList = mutableListOf<ChipInfo>()
teachers.firstOrNull { it.id == teacherId }?.let { teacher ->
teacher.image = getProfileImage(48, 24, 16, 12, 1, teacher.fullName)
chipList += ChipInfo(teacher.fullName, teacher)
}
b.recipients.addTextWithChips(chipList)
val subject = arguments?.getString("messageSubject")
b.subject.setText(subject ?: return)
}
private fun sendMessage() {
b.recipientsLayout.error = null
b.subjectLayout.error = null

View file

@ -7,8 +7,6 @@
package pl.szczodrzynski.edziennik.utils
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.text.Spannable
import android.text.SpannableString
@ -21,268 +19,141 @@ import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.view.menu.MenuBuilder
import androidx.appcompat.view.menu.MenuPopupHelper
import androidx.core.widget.addTextChangedListener
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.Intent
import pl.szczodrzynski.edziennik.copyToClipboard
import pl.szczodrzynski.edziennik.data.api.Regexes
import pl.szczodrzynski.edziennik.get
import pl.szczodrzynski.edziennik.getTextPosition
import pl.szczodrzynski.edziennik.utils.models.Date
@SuppressLint("RestrictedApi")
object BetterLink {
/**
* Used in conjunction with the item's ID to execute the
* [attach]'s onActionSelected listener when the item is
* clicked.
*/
private const val FLAG_ACTION = 0x8000
@SuppressLint("RestrictedApi")
fun attach(textView: TextView, onActionSelected: (() -> Unit)? = null) {
textView.autoLinkMask = Linkify.WEB_URLS or Linkify.EMAIL_ADDRESSES
BetterLinkMovementMethod.linkify(textView.autoLinkMask, textView).setOnLinkClickListener { v, span: BetterLinkMovementMethod.ClickableSpanWithText ->
val url = span.text()
val c = v.context
private fun MenuBuilder.setTitle(title: CharSequence): MenuBuilder {
this::class.java.getDeclaredMethod("setHeaderTitleInt", CharSequence::class.java).let {
it.isAccessible = true
it.invoke(this, title)
}
return this
}
val s = v.text as Spanned
val start = s.getSpanStart(span.span())
val end = s.getSpanEnd(span.span())
private fun MenuItem.addListener(listener: (item: MenuItem) -> Boolean): MenuItem {
this::class.java.getDeclaredField("mClickListener").let {
it.isAccessible = true
val oldListener = it.get(this) as? MenuItem.OnMenuItemClickListener
it.set(this, object : MenuItem.OnMenuItemClickListener {
override fun onMenuItemClick(item: MenuItem): Boolean {
oldListener?.onMenuItemClick(item)
return listener(item)
val parent = v.rootView.findViewById<ViewGroup>(android.R.id.content)
val parentLocation = intArrayOf(0, 0)
parent.getLocationOnScreen(parentLocation)
val rect = textView.getTextPosition(start..end)
val view = View(c)
view.layoutParams = ViewGroup.LayoutParams(rect.width(), rect.height())
view.setBackgroundColor(Color.TRANSPARENT)
parent.addView(view)
view.x = rect.left.toFloat() - parentLocation[0]
view.y = rect.top.toFloat() - parentLocation[1]
val menu = MenuBuilder(c)
val helper = MenuPopupHelper(c, menu, view)
val popup = helper.popup
var menuTitle = url.substringAfter(":")
var date: Date? = null
var urlItem: MenuItem? = null
var createEventItem: MenuItem? = null
//var goToTimetableItem: MenuItem? = null // TODO 2020-03-19: implement this
var mailItem: MenuItem? = null
var copyItem: MenuItem? = null
when {
url.startsWith("mailto:") -> {
mailItem = menu.add(1, 20, 2, "Napisz e-mail")
}
})
}
return this
}
url.startsWith("dateYmd:") -> {
createEventItem = menu.add(1, 10, 2, "Utwórz wydarzenie")
//goToTimetableItem = menu.add(1, 11, 3, "Idź do planu lekcji")
date = parseDateYmd(menuTitle)
}
url.startsWith("dateDmy:") -> {
createEventItem = menu.add(1, 10, 2, "Utwórz wydarzenie")
//goToTimetableItem = menu.add(1, 11, 3, "Idź do planu lekcji")
date = parseDateDmy(menuTitle)
}
url.startsWith("dateAbs:") -> {
createEventItem = menu.add(1, 10, 2, "Utwórz wydarzenie")
//goToTimetableItem = menu.add(1, 11, 3, "Idź do planu lekcji")
date = parseDateAbs(menuTitle)
}
url.startsWith("dateRel:") -> {
createEventItem = menu.add(1, 10, 2, "Utwórz wydarzenie")
//goToTimetableItem = menu.add(1, 11, 3, "Idź do planu lekcji")
date = parseDateRel(menuTitle)
}
else -> {
urlItem = menu.add(1, 1, 2, "Otwórz w przeglądarce")
menuTitle = url
}
}
copyItem = menu.add(1, 1000, 1000, "Kopiuj tekst")
private fun createUrlItems(menu: MenuBuilder, context: Context, url: String) {
menu.setTitle(url)
menu.add(
1,
2,
2,
"Otwórz w przeglądarce"
).setOnMenuItemClickListener {
Utils.openUrl(context, url)
true
}
}
helper.setOnDismissListener { parent.removeView(view) }
private fun createMailtoItems(menu: MenuBuilder, context: Context, url: String) {
menu.add(
1,
3,
3,
"Napisz e-mail"
).setOnMenuItemClickListener {
Utils.openUrl(context, url)
true
}
}
private fun createDateItems(menu: MenuBuilder, context: Context, date: Date?) {
date ?: return
menu.setTitle(date.formattedString)
menu.add(
1,
4 or FLAG_ACTION,
4,
"Utwórz wydarzenie"
).setOnMenuItemClickListener {
val intent = Intent(
Intent.ACTION_MAIN,
"action" to "createManualEvent",
"eventDate" to date.stringY_m_d
)
context.sendBroadcast(intent)
true
}
}
private fun createTeacherItems(menu: MenuBuilder, context: Context, teacherId: Long, fullName: String) {
menu.setTitle(fullName)
menu.add(
1,
5 or FLAG_ACTION,
5,
"Napisz wiadomość"
).setOnMenuItemClickListener {
val intent = Intent(
Intent.ACTION_MAIN,
"fragmentId" to MainActivity.TARGET_MESSAGES_COMPOSE,
"messageRecipientId" to teacherId
)
context.sendBroadcast(intent)
true
}
}
private fun onClickListener(
view: TextView,
span: BetterLinkMovementMethod.ClickableSpanWithText,
onActionSelected: (() -> Unit)?
): Boolean {
val context = view.context
val spanned = view.text as Spanned
val start = spanned.getSpanStart(span.span())
val end = spanned.getSpanEnd(span.span())
val parent = view.rootView.findViewById<ViewGroup>(android.R.id.content)
val parentLocation = intArrayOf(0, 0)
parent.getLocationOnScreen(parentLocation)
val rect = view.getTextPosition(start..end)
val popupView = View(context)
popupView.layoutParams = ViewGroup.LayoutParams(rect.width(), rect.height())
popupView.setBackgroundColor(Color.TRANSPARENT)
parent.addView(popupView)
popupView.x = rect.left.toFloat() - parentLocation[0]
popupView.y = rect.top.toFloat() - parentLocation[1]
val menu = MenuBuilder(context)
val helper = MenuPopupHelper(context, menu, popupView)
val popup = helper.popup
val spanUrl = span.text()
val spanParameter = spanUrl.substringAfter(":")
val spanText = spanned.substring(start, end)
//goToTimetableItem = menu.add(1, 11, 3, "Idź do planu lekcji")
// create appropriate items for spans
when {
spanUrl.startsWith("mailto:") -> createMailtoItems(menu, context, spanUrl)
spanUrl.startsWith("dateYmd:") -> createDateItems(menu, context, parseDateYmd(spanParameter))
spanUrl.startsWith("dateDmy:") -> createDateItems(menu, context, parseDateDmy(spanParameter))
spanUrl.startsWith("dateAbs:") -> createDateItems(menu, context, parseDateAbs(spanParameter))
spanUrl.startsWith("dateRel:") -> createDateItems(menu, context, parseDateRel(spanParameter))
spanUrl.startsWith("teacher:") -> createTeacherItems(
menu,
context,
teacherId = spanParameter.toLongOrNull() ?: -1,
fullName = spanText
)
else -> createUrlItems(menu, context, spanUrl)
}
menu.add(1, 1000, 1000, "Kopiuj tekst").setOnMenuItemClickListener {
spanParameter.copyToClipboard(context)
true
}
helper.setOnDismissListener { parent.removeView(popupView) }
menu.visibleItems.forEach { item ->
if ((item.itemId and FLAG_ACTION) != FLAG_ACTION)
return@forEach
item.addListener {
urlItem?.setOnMenuItemClickListener { Utils.openUrl(c, url); true }
mailItem?.setOnMenuItemClickListener { Utils.openUrl(c, url); true }
copyItem?.setOnMenuItemClickListener { menuTitle.copyToClipboard(c); true }
createEventItem?.setOnMenuItemClickListener {
onActionSelected?.invoke()
val intent = Intent(
android.content.Intent.ACTION_MAIN,
"action" to "createManualEvent",
"eventDate" to date?.stringY_m_d
)
c.sendBroadcast(intent)
true
}
}
popup::class.java.getDeclaredField("mShowTitle").let {
it.isAccessible = true
it.set(popup, true)
}
helper::class.java.getDeclaredMethod(
"showPopup",
Int::class.java,
Int::class.java,
Boolean::class.java,
Boolean::class.java
).let {
it.isAccessible = true
it.invoke(helper, 0, 0, false, true)
}
return true
}
fun attach(
textView: TextView,
teachers: Map<Long, String>? = null,
onActionSelected: (() -> Unit)? = null
) {
textView.autoLinkMask = Linkify.WEB_URLS or Linkify.EMAIL_ADDRESSES
BetterLinkMovementMethod
.linkify(textView.autoLinkMask, textView)
.setOnLinkClickListener { view, span ->
onClickListener(view, span, onActionSelected)
menu::class.java.getDeclaredMethod("setHeaderTitleInt", CharSequence::class.java).let {
it.isAccessible = true
it.invoke(menu, menuTitle)
}
textView.addTextChangedListener {
attachSpan(textView, teachers)
popup::class.java.getDeclaredField("mShowTitle").let {
it.isAccessible = true
it.set(popup, true)
}
helper::class.java.getDeclaredMethod("showPopup", Int::class.java, Int::class.java, Boolean::class.java, Boolean::class.java).let {
it.isAccessible = true
it.invoke(helper, 0, 0, false, true)
}
true
}
attachSpan(textView, teachers)
}
private fun attachSpan(
textView: TextView,
teachers: Map<Long, String>? = null
) {
val spanned = textView.text as? Spannable ?: SpannableString(textView.text)
teachers?.forEach { (id, fullName) ->
val index = textView.text.indexOf(fullName)
if (index == -1)
return@forEach
val span = URLSpan("teacher:$id")
spanned.setSpan(
span,
index,
index + fullName.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
val spanned = textView.text as? Spannable ?: {
SpannableString(textView.text)
}()
Regexes.LINKIFY_DATE_YMD.findAll(textView.text).forEach { match ->
val span = URLSpan("dateYmd:" + match.value)
spanned.setSpan(
span,
match.range.first,
match.range.last + 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
spanned.setSpan(span, match.range.first, match.range.last + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
Regexes.LINKIFY_DATE_DMY.findAll(textView.text).forEach { match ->
val span = URLSpan("dateDmy:" + match.value)
spanned.setSpan(
span,
match.range.first,
match.range.last + 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
spanned.setSpan(span, match.range.first, match.range.last + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
Regexes.LINKIFY_DATE_ABSOLUTE.findAll(textView.text).forEach { match ->
val span = URLSpan("dateAbs:" + match.value)
spanned.setSpan(
span,
match.range.first,
match.range.last + 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
spanned.setSpan(span, match.range.first, match.range.last + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
Regexes.LINKIFY_DATE_RELATIVE.findAll(textView.text).forEach { match ->
val span = URLSpan("dateRel:" + match.value)
spanned.setSpan(
span,
match.range.first,
match.range.last + 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
spanned.setSpan(span, match.range.first, match.range.last + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
//Linkify.addLinks(textView, LINKIFY_DATE_ABSOLUTE.toPattern(), "dateAbs:")
//Linkify.addLinks(textView, LINKIFY_DATE_RELATIVE.toPattern(), "dateRel:")
}
private val monthNames =
listOf("sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paź", "lis", "gru")
private val monthNames = listOf("sty", "lut", "mar", "kwi", "maj", "cze", "lip", "sie", "wrz", "paź", "lis", "gru")
private fun parseDateYmd(text: String): Date? {
return Regexes.LINKIFY_DATE_YMD.find(text)?.let {
@ -292,7 +163,6 @@ object BetterLink {
Date(year, month, day)
}
}
private fun parseDateDmy(text: String): Date? {
return Regexes.LINKIFY_DATE_DMY.find(text)?.let {
val day = it[1].toIntOrNull() ?: 1
@ -324,7 +194,7 @@ object BetterLink {
else -> 1
}
date.stepForward(0, 0, amount * unitInDays)
date.stepForward(0, 0, amount*unitInDays)
}
}
}

View file

@ -94,7 +94,6 @@
android:textAppearance="@style/NavView.TextView.Helper" />
<TextView
android:id="@+id/teacherName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"

View file

@ -112,7 +112,6 @@
android:text="@string/dialog_event_details_teacher"
android:visibility="@{event.teacherName != null ? View.VISIBLE : View.GONE}"/>
<TextView
android:id="@+id/teacherName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{event.teacherName}"

View file

@ -121,7 +121,6 @@
android:textAppearance="@style/NavView.TextView.Helper" />
<TextView
android:id="@+id/teacherName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"

View file

@ -176,7 +176,6 @@
android:textAppearance="@style/NavView.TextView.Helper"
android:text="@string/dialog_lesson_details_teacher" />
<TextView
android:id="@+id/oldTeacherNameView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Helper"
@ -187,7 +186,6 @@
app:strikeThrough="@{true}"
tools:text="Janósz Kowalski" />
<TextView
android:id="@+id/teacherNameView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{teacherName}"

View file

@ -72,16 +72,10 @@
android:text="@string/cancel"
android:textAllCaps="false" />
<TextView
android:id="@+id/versionText"
<Space
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="?selectableItemBackgroundBorderless"
android:gravity="center"
android:textAppearance="@style/NavView.TextView.Small"
android:textSize="12sp"
tools:text="Szkolny.eu v4.7-rc.2\n2021-04-06" />
android:layout_height="0dp"
android:layout_weight="1" />
<com.google.android.material.button.MaterialButton
android:id="@+id/helpButton"

View file

@ -856,7 +856,7 @@
<string name="settings_about_licenses_text">Open-Source-Lizenzen</string>
<string name="settings_about_privacy_policy_text">Datenschutzrichtlinie</string>
<string name="settings_card_register_title">E-Klassenbuch</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nSeptember 2018 - April 2021</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nSeptember 2018 - Februar 2021</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_version_text">Version</string>

View file

@ -858,7 +858,7 @@
<string name="settings_about_licenses_text">Open-source licenses</string>
<string name="settings_about_privacy_policy_text">Privacy policy</string>
<string name="settings_card_register_title">E-register</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nSeptember 2018 - April 2021</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nSeptember 2018 - February 2021</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_version_text">Version</string>
@ -1333,7 +1333,7 @@
<string name="attendance_config_use_symbols_hint">Visible when the list is expanded</string>
<string name="attendance_config_show_presence_in_month">Display attendance in months view</string>
<string name="attendance_percentage_format">%.2f%%</string>
<string name="attendance_period_summary_format">Attendance during this period: %.2f%%</string>
<string name="attendance_period_summary_format">Attendance during this period: %.2%%</string>
<string name="settings_add_student_subtext">Log in child/parent account in app</string>
<string name="login_mode_edudziennik_web_guide">Enter the e-mail address and password that you use to log in to the browser on the EduDziennik website.</string>
<string name="profile_year_not_started_format">Probably the school year for this student has not yet started (will start %s). Please try to sync later.</string>

View file

@ -921,7 +921,7 @@
<string name="settings_about_licenses_text">Licencje open-source</string>
<string name="settings_about_privacy_policy_text">Polityka prywatności</string>
<string name="settings_card_register_title">E-dziennik</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nwrzesień 2018 - kwiecień 2021</string>
<string name="settings_about_title_subtext">© Kuba Szczodrzyński &amp;&amp; Kacper Ziubryniewicz\nwrzesień 2018 - luty 2021</string>
<string name="settings_about_update_subtext">Kliknij, aby sprawdzić aktualizacje</string>
<string name="settings_about_update_text">Aktualizacja</string>
<string name="settings_about_version_text">Wersja</string>
@ -1424,5 +1424,4 @@
<string name="build_date">Data kompilacji</string>
<string name="permissions_generate_timetable">Aby móc zapisać wygenerowany plan lekcji musisz przyznać uprawnienia dostępu do pamięci urządzenia.\n\nKliknij OK, aby przyznać uprawnienia.</string>
<string name="privacy_policy_dialog_html"><![CDATA[Korzystając z aplikacji potwierdzasz <a href="https://szkolny.eu/privacy-policy">przeczytanie Polityki prywatności</a> i akceptujesz jej postanowienia.<br /><br />Autorzy aplikacji nie biorą odpowiedzialności za korzystanie z aplikacji Szkolny.eu.]]></string>
<string name="login_chooser_version_format">Szkolny.eu v%s\n%s</string>
</resources>

View file

@ -5,8 +5,8 @@ buildscript {
kotlin_version = '1.4.31'
release = [
versionName: "4.7.1",
versionCode: 4070199
versionName: "4.7-rc.2",
versionCode: 4070020
]
setup = [