mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-01-18 12:56:45 -06:00
[UI] Add text styling to manual events. (#96)
* [UI] Move text styling outside of messages module. * [UI] Add text styling to event manual dialog. * [UI/Events] Implement showing HTML-formatted content. * [UI] Fix searching in styled event topic. Create HtmlMode enum. * [UI] Add HTML Simple mode to text styling manager. Fix CharSequence replacing. * [Events] Disable self-shared event notifications. * [UI] Fix simple HTML mode format. Fix HTML in notifications. * [HTML] Replace usages of Html and HtmlCompat with BetterHtml. * [Events] Fix editing self-added events from other devices. * [Events] Implement receiving and fix showing HTML-formatted events. * [UI/Events] Add observing changes in event details dialog. * [Firebase] Disable self-shared event notifications.
This commit is contained in:
parent
7e0f69d95d
commit
74b766f18a
@ -1007,8 +1007,29 @@ inline fun <T> LongSparseArray<T>.filter(predicate: (T) -> Boolean): List<T> {
|
|||||||
return destination
|
return destination
|
||||||
}
|
}
|
||||||
|
|
||||||
fun CharSequence.replace(oldValue: String, newValue: CharSequence, ignoreCase: Boolean = false): CharSequence =
|
fun CharSequence.replaceSpanned(oldValue: String, newValue: CharSequence, ignoreCase: Boolean = false): CharSequence {
|
||||||
splitToSequence(oldValue, ignoreCase = ignoreCase).toList().concat(newValue)
|
var seq = this
|
||||||
|
var index = seq.indexOf(oldValue, ignoreCase = ignoreCase)
|
||||||
|
while (index != -1) {
|
||||||
|
val sb = SpannableStringBuilder()
|
||||||
|
sb.appendRange(seq, 0, index)
|
||||||
|
sb.append(newValue)
|
||||||
|
sb.appendRange(seq, index + oldValue.length, seq.length)
|
||||||
|
seq = sb
|
||||||
|
index = seq.indexOf(oldValue, startIndex = index + 1, ignoreCase = ignoreCase)
|
||||||
|
}
|
||||||
|
return seq
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SpannableStringBuilder.replaceSpan(spanClass: Class<*>, prefix: CharSequence, suffix: CharSequence): SpannableStringBuilder {
|
||||||
|
getSpans(0, length, spanClass).forEach {
|
||||||
|
val spanStart = getSpanStart(it)
|
||||||
|
insert(spanStart, prefix)
|
||||||
|
val spanEnd = getSpanEnd(it)
|
||||||
|
insert(spanEnd, suffix)
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
fun Int.toColorStateList(): ColorStateList {
|
fun Int.toColorStateList(): ColorStateList {
|
||||||
val states = arrayOf(
|
val states = arrayOf(
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||||
|
|
||||||
import android.text.Html
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||||
@ -9,6 +8,7 @@ import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
|
|||||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||||
import pl.szczodrzynski.edziennik.get
|
import pl.szczodrzynski.edziennik.get
|
||||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
|
|
||||||
class EdudziennikWebGetHomework(
|
class EdudziennikWebGetHomework(
|
||||||
override val data: DataEdudziennik,
|
override val data: DataEdudziennik,
|
||||||
@ -26,7 +26,8 @@ class EdudziennikWebGetHomework(
|
|||||||
webGet(TAG, "Homework/$id") { text ->
|
webGet(TAG, "Homework/$id") { text ->
|
||||||
val description = Regexes.EDUDZIENNIK_HOMEWORK_DESCRIPTION.find(text)?.get(1)?.trim()
|
val description = Regexes.EDUDZIENNIK_HOMEWORK_DESCRIPTION.find(text)?.get(1)?.trim()
|
||||||
|
|
||||||
if (description != null) event.topic = Html.fromHtml(description).toString()
|
if (description != null)
|
||||||
|
event.topic = BetterHtml.fromHtml(context = null, description).toString()
|
||||||
|
|
||||||
event.homeworkBody = ""
|
event.homeworkBody = ""
|
||||||
event.isDownloaded = true
|
event.isDownloaded = true
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia
|
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia
|
||||||
|
|
||||||
import android.text.Html
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
|
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
|
|
||||||
class LibrusSynergiaGetHomework(override val data: DataLibrus,
|
class LibrusSynergiaGetHomework(override val data: DataLibrus,
|
||||||
val event: EventFull,
|
val event: EventFull,
|
||||||
@ -23,7 +23,10 @@ class LibrusSynergiaGetHomework(override val data: DataLibrus,
|
|||||||
val table = doc.select("table.decorated tbody > tr")
|
val table = doc.select("table.decorated tbody > tr")
|
||||||
|
|
||||||
event.topic = table[1].select("td")[1].text()
|
event.topic = table[1].select("td")[1].text()
|
||||||
event.homeworkBody = Html.fromHtml(table[5].select("td")[1].html()).toString()
|
event.homeworkBody = BetterHtml.fromHtml(
|
||||||
|
context = null,
|
||||||
|
html = table[5].select("td")[1].html(),
|
||||||
|
).toString()
|
||||||
event.isDownloaded = true
|
event.isDownloaded = true
|
||||||
|
|
||||||
event.attachmentIds = mutableListOf()
|
event.attachmentIds = mutableListOf()
|
||||||
|
@ -4,12 +4,12 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.api
|
package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.api
|
||||||
|
|
||||||
import android.text.Html
|
|
||||||
import androidx.core.util.contains
|
import androidx.core.util.contains
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik
|
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
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
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ class MobidziennikApiHomework(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
val id = cols[0].toLong()
|
val id = cols[0].toLong()
|
||||||
val teacherId = cols[7].toLong()
|
val teacherId = cols[7].toLong()
|
||||||
val subjectId = cols[6].toLong()
|
val subjectId = cols[6].toLong()
|
||||||
val topic = Html.fromHtml(cols[1])?.toString()?.trim() ?: ""
|
val topic = BetterHtml.fromHtml(context = null, cols[1]).toString().trim()
|
||||||
val eventDate = Date.fromYmd(cols[2])
|
val eventDate = Date.fromYmd(cols[2])
|
||||||
val startTime = Time.fromYmdHm(cols[3])
|
val startTime = Time.fromYmdHm(cols[3])
|
||||||
|
|
||||||
|
@ -245,7 +245,10 @@ class SzkolnyApi(val app: App) : CoroutineScope {
|
|||||||
seen = profile.empty
|
seen = profile.empty
|
||||||
notified = profile.empty
|
notified = profile.empty
|
||||||
|
|
||||||
if (profile.userCode == event.sharedBy) sharedBy = "self"
|
if (profile.userCode == event.sharedBy) {
|
||||||
|
sharedBy = "self"
|
||||||
|
addedManually = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,80 +69,90 @@ class Notifications(val app: App, val notifications: MutableList<Notification>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun eventNotifications() {
|
private fun eventNotifications() {
|
||||||
for (event in app.db.eventDao().getNotNotifiedNow().filter { it.date >= today }) {
|
app.db.eventDao().getNotNotifiedNow().filter {
|
||||||
|
it.date >= today
|
||||||
|
}.forEach { event ->
|
||||||
val text = if (event.isHomework)
|
val text = if (event.isHomework)
|
||||||
app.getString(
|
app.getString(
|
||||||
if (event.subjectLongName.isNullOrEmpty())
|
if (event.subjectLongName.isNullOrEmpty())
|
||||||
R.string.notification_homework_no_subject_format
|
R.string.notification_homework_no_subject_format
|
||||||
else
|
else
|
||||||
R.string.notification_homework_format,
|
R.string.notification_homework_format,
|
||||||
event.subjectLongName,
|
event.subjectLongName,
|
||||||
event.date.formattedString
|
event.date.formattedString
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
app.getString(
|
app.getString(
|
||||||
if (event.subjectLongName.isNullOrEmpty())
|
if (event.subjectLongName.isNullOrEmpty())
|
||||||
R.string.notification_event_no_subject_format
|
R.string.notification_event_no_subject_format
|
||||||
else
|
else
|
||||||
R.string.notification_event_format,
|
R.string.notification_event_format,
|
||||||
event.typeName ?: "wydarzenie",
|
event.typeName ?: "wydarzenie",
|
||||||
event.date.formattedString,
|
event.date.formattedString,
|
||||||
event.subjectLongName
|
event.subjectLongName
|
||||||
)
|
)
|
||||||
val textLong = app.getString(
|
val textLong = app.getString(
|
||||||
R.string.notification_event_long_format,
|
R.string.notification_event_long_format,
|
||||||
event.typeName ?: "-",
|
event.typeName ?: "-",
|
||||||
event.subjectLongName ?: "-",
|
event.subjectLongName ?: "-",
|
||||||
event.date.formattedString,
|
event.date.formattedString,
|
||||||
Week.getFullDayName(event.date.weekDay),
|
Week.getFullDayName(event.date.weekDay),
|
||||||
event.time?.stringHM ?: app.getString(R.string.event_all_day),
|
event.time?.stringHM ?: app.getString(R.string.event_all_day),
|
||||||
event.topic.take(200)
|
event.topic.take(200)
|
||||||
)
|
)
|
||||||
val type = if (event.isHomework) Notification.TYPE_NEW_HOMEWORK else Notification.TYPE_NEW_EVENT
|
val type = if (event.isHomework)
|
||||||
|
Notification.TYPE_NEW_HOMEWORK
|
||||||
|
else
|
||||||
|
Notification.TYPE_NEW_EVENT
|
||||||
notifications += Notification(
|
notifications += 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),
|
||||||
text = text,
|
text = text,
|
||||||
textLong = textLong,
|
textLong = textLong,
|
||||||
type = type,
|
type = type,
|
||||||
profileId = event.profileId,
|
profileId = event.profileId,
|
||||||
profileName = profiles.singleOrNull { it.id == event.profileId }?.name,
|
profileName = profiles.singleOrNull { it.id == event.profileId }?.name,
|
||||||
viewId = if (event.isHomework) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA,
|
viewId = if (event.isHomework) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA,
|
||||||
addedDate = event.addedDate
|
addedDate = event.addedDate
|
||||||
).addExtra("eventId", event.id).addExtra("eventDate", event.date.value.toLong())
|
).addExtra("eventId", event.id).addExtra("eventDate", event.date.value.toLong())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sharedEventNotifications() {
|
fun sharedEventNotifications() {
|
||||||
for (event in app.db.eventDao().getNotNotifiedNow().filter { it.date >= today && it.sharedBy != null }) {
|
app.db.eventDao().getNotNotifiedNow().filter {
|
||||||
|
it.date >= today && it.sharedBy != null && it.sharedBy != "self"
|
||||||
|
}.forEach { event ->
|
||||||
val text = app.getString(
|
val text = app.getString(
|
||||||
R.string.notification_shared_event_format,
|
R.string.notification_shared_event_format,
|
||||||
event.sharedByName,
|
event.sharedByName,
|
||||||
event.typeName ?: "wydarzenie",
|
event.typeName ?: "wydarzenie",
|
||||||
event.date.formattedString,
|
event.date.formattedString,
|
||||||
event.topic
|
event.topicHtml
|
||||||
)
|
)
|
||||||
val textLong = app.getString(
|
val textLong = app.getString(
|
||||||
R.string.notification_shared_event_long_format,
|
R.string.notification_shared_event_long_format,
|
||||||
event.sharedByName,
|
event.sharedByName,
|
||||||
event.typeName ?: "-",
|
event.typeName ?: "-",
|
||||||
event.subjectLongName ?: "-",
|
event.subjectLongName ?: "-",
|
||||||
event.date.formattedString,
|
event.date.formattedString,
|
||||||
Week.getFullDayName(event.date.weekDay),
|
Week.getFullDayName(event.date.weekDay),
|
||||||
event.time?.stringHM ?: app.getString(R.string.event_all_day),
|
event.time?.stringHM ?: app.getString(R.string.event_all_day),
|
||||||
event.topic.take(200)
|
event.topicHtml.take(200)
|
||||||
)
|
)
|
||||||
val type = if (event.isHomework) Notification.TYPE_NEW_HOMEWORK else Notification.TYPE_NEW_EVENT
|
val type = if (event.isHomework)
|
||||||
|
Notification.TYPE_NEW_HOMEWORK
|
||||||
|
else
|
||||||
|
Notification.TYPE_NEW_EVENT
|
||||||
notifications += Notification(
|
notifications += 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),
|
||||||
text = text,
|
text = text,
|
||||||
textLong = textLong,
|
textLong = textLong,
|
||||||
type = type,
|
type = type,
|
||||||
profileId = event.profileId,
|
profileId = event.profileId,
|
||||||
profileName = profiles.singleOrNull { it.id == event.profileId }?.name,
|
profileName = profiles.singleOrNull { it.id == event.profileId }?.name,
|
||||||
viewId = if (event.isHomework) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA,
|
viewId = if (event.isHomework) MainActivity.DRAWER_ITEM_HOMEWORK else MainActivity.DRAWER_ITEM_AGENDA,
|
||||||
addedDate = event.addedDate
|
addedDate = event.addedDate
|
||||||
).addExtra("eventId", event.id).addExtra("eventDate", event.date.value.toLong())
|
).addExtra("eventId", event.id).addExtra("eventDate", event.date.value.toLong())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,10 @@ abstract class EventDao : BaseDao<Event, EventFull> {
|
|||||||
fun getAllByDateNow(profileId: Int, date: Date) =
|
fun getAllByDateNow(profileId: Int, date: Date) =
|
||||||
getRawNow("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId AND eventDate = '${date.stringY_m_d}' $ORDER_BY")
|
getRawNow("$QUERY WHERE $NOT_BLACKLISTED AND events.profileId = $profileId AND eventDate = '${date.stringY_m_d}' $ORDER_BY")
|
||||||
|
|
||||||
|
// GET ONE - LIVE DATA
|
||||||
|
fun getById(profileId: Int, id: Long) =
|
||||||
|
getOne("$QUERY WHERE events.profileId = $profileId AND eventId = $id")
|
||||||
|
|
||||||
// GET ONE - NOW
|
// GET ONE - NOW
|
||||||
fun getByIdNow(profileId: Int, id: Long) =
|
fun getByIdNow(profileId: Int, id: Long) =
|
||||||
getOneNow("$QUERY WHERE events.profileId = $profileId AND eventId = $id")
|
getOneNow("$QUERY WHERE events.profileId = $profileId AND eventId = $id")
|
||||||
|
@ -75,6 +75,7 @@ open class Event(
|
|||||||
|
|
||||||
@ColumnInfo(name = "eventAddedManually")
|
@ColumnInfo(name = "eventAddedManually")
|
||||||
var addedManually: Boolean = false
|
var addedManually: Boolean = false
|
||||||
|
get() = field || sharedBy == "self"
|
||||||
@ColumnInfo(name = "eventSharedBy")
|
@ColumnInfo(name = "eventSharedBy")
|
||||||
var sharedBy: String? = null
|
var sharedBy: String? = null
|
||||||
@ColumnInfo(name = "eventSharedByName")
|
@ColumnInfo(name = "eventSharedByName")
|
||||||
|
@ -7,6 +7,7 @@ import androidx.room.Ignore
|
|||||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.search.Searchable
|
import pl.szczodrzynski.edziennik.ui.modules.search.Searchable
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
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
|
||||||
|
|
||||||
@ -48,6 +49,20 @@ class EventFull(
|
|||||||
var teamName: String? = null
|
var teamName: String? = null
|
||||||
var teamCode: String? = null
|
var teamCode: String? = null
|
||||||
|
|
||||||
|
@delegate:Ignore
|
||||||
|
@delegate:Transient
|
||||||
|
val topicHtml by lazy {
|
||||||
|
BetterHtml.fromHtml(context = null, topic, nl2br = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@delegate:Ignore
|
||||||
|
@delegate:Transient
|
||||||
|
val bodyHtml by lazy {
|
||||||
|
homeworkBody?.let {
|
||||||
|
BetterHtml.fromHtml(context = null, it, nl2br = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Ignore
|
@Ignore
|
||||||
@Transient
|
@Transient
|
||||||
override var searchPriority = 0
|
override var searchPriority = 0
|
||||||
@ -60,7 +75,7 @@ class EventFull(
|
|||||||
@delegate:Transient
|
@delegate:Transient
|
||||||
override val searchKeywords by lazy {
|
override val searchKeywords by lazy {
|
||||||
listOf(
|
listOf(
|
||||||
listOf(topic, homeworkBody),
|
listOf(topicHtml.toString(), bodyHtml?.toString()),
|
||||||
attachmentNames,
|
attachmentNames,
|
||||||
listOf(subjectLongName),
|
listOf(subjectLongName),
|
||||||
listOf(teacherName),
|
listOf(teacherName),
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
*/
|
*/
|
||||||
package pl.szczodrzynski.edziennik.data.db.full
|
package pl.szczodrzynski.edziennik.data.db.full
|
||||||
|
|
||||||
import androidx.core.text.HtmlCompat
|
|
||||||
import androidx.room.Ignore
|
import androidx.room.Ignore
|
||||||
import androidx.room.Relation
|
import androidx.room.Relation
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
|
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.search.Searchable
|
import pl.szczodrzynski.edziennik.ui.modules.search.Searchable
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
|
|
||||||
class MessageFull(
|
class MessageFull(
|
||||||
profileId: Int, id: Long, type: Int,
|
profileId: Int, id: Long, type: Int,
|
||||||
@ -33,11 +33,10 @@ class MessageFull(
|
|||||||
@delegate:Transient
|
@delegate:Transient
|
||||||
val bodyHtml by lazy {
|
val bodyHtml by lazy {
|
||||||
body?.let {
|
body?.let {
|
||||||
HtmlCompat.fromHtml(it, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
BetterHtml.fromHtml(context = null, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Ignore
|
@Ignore
|
||||||
@Transient
|
@Transient
|
||||||
override var searchPriority = 0
|
override var searchPriority = 0
|
||||||
|
@ -122,7 +122,7 @@ class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message:
|
|||||||
id = json.getLong("id") ?: return,
|
id = json.getLong("id") ?: return,
|
||||||
date = json.getInt("eventDate")?.let { Date.fromValue(it) } ?: return,
|
date = json.getInt("eventDate")?.let { Date.fromValue(it) } ?: return,
|
||||||
time = json.getInt("startTime")?.let { Time.fromValue(it) },
|
time = json.getInt("startTime")?.let { Time.fromValue(it) },
|
||||||
topic = json.getString("topic") ?: "",
|
topic = json.getString("topicHtml") ?: json.getString("topic") ?: "",
|
||||||
color = json.getInt("color"),
|
color = json.getInt("color"),
|
||||||
type = json.getLong("type") ?: 0,
|
type = json.getLong("type") ?: 0,
|
||||||
teacherId = json.getLong("teacherId") ?: -1,
|
teacherId = json.getLong("teacherId") ?: -1,
|
||||||
@ -135,7 +135,10 @@ class SzkolnyAppFirebase(val app: App, val profiles: List<Profile>, val message:
|
|||||||
|
|
||||||
event.sharedBy = json.getString("sharedBy")
|
event.sharedBy = json.getString("sharedBy")
|
||||||
event.sharedByName = json.getString("sharedByName")
|
event.sharedByName = json.getString("sharedByName")
|
||||||
if (profile.userCode == event.sharedBy) event.sharedBy = "self"
|
if (profile.userCode == event.sharedBy) {
|
||||||
|
event.sharedBy = "self"
|
||||||
|
event.addedManually = true
|
||||||
|
}
|
||||||
|
|
||||||
val metadata = Metadata(
|
val metadata = Metadata(
|
||||||
event.profileId,
|
event.profileId,
|
||||||
@ -148,7 +151,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)) {
|
if (!notificationFilter.contains(type) && event.sharedBy != "self") {
|
||||||
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),
|
||||||
|
@ -9,7 +9,6 @@ import android.app.NotificationManager
|
|||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.text.Html
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.work.*
|
import androidx.work.*
|
||||||
@ -20,6 +19,7 @@ import pl.szczodrzynski.edziennik.R
|
|||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ class UpdateWorker(val context: Context, val params: WorkerParameters) : Worker(
|
|||||||
.setStyle(NotificationCompat.BigTextStyle()
|
.setStyle(NotificationCompat.BigTextStyle()
|
||||||
.bigText(listOf(
|
.bigText(listOf(
|
||||||
app.getString(R.string.notification_updates_text, update.versionName),
|
app.getString(R.string.notification_updates_text, update.versionName),
|
||||||
update.releaseNotes?.let { Html.fromHtml(it) }
|
update.releaseNotes?.let { BetterHtml.fromHtml(context = null, it) }
|
||||||
).concat("\n")))
|
).concat("\n")))
|
||||||
.setColor(0xff2196f3.toInt())
|
.setColor(0xff2196f3.toInt())
|
||||||
.setLights(0xFF00FFFF.toInt(), 2000, 2000)
|
.setLights(0xFF00FFFF.toInt(), 2000, 2000)
|
||||||
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2021-10-11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.dialogs
|
||||||
|
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.text.Editable
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.databinding.StyledTextDialogBinding
|
||||||
|
import pl.szczodrzynski.edziennik.utils.DefaultTextStyles
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Themes
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.HtmlMode.SIMPLE
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.StylingConfig
|
||||||
|
|
||||||
|
class StyledTextDialog(
|
||||||
|
val activity: AppCompatActivity,
|
||||||
|
val initialText: Editable?,
|
||||||
|
val onSuccess: (text: Editable) -> Unit,
|
||||||
|
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||||
|
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "StyledTextDialog"
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var app: App
|
||||||
|
private lateinit var b: StyledTextDialogBinding
|
||||||
|
private lateinit var dialog: AlertDialog
|
||||||
|
private lateinit var config: StylingConfig
|
||||||
|
|
||||||
|
private val manager
|
||||||
|
get() = app.textStylingManager
|
||||||
|
|
||||||
|
init {
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun show() {
|
||||||
|
if (activity.isFinishing)
|
||||||
|
return
|
||||||
|
onShowListener?.invoke(TAG)
|
||||||
|
app = activity.applicationContext as App
|
||||||
|
b = StyledTextDialogBinding.inflate(activity.layoutInflater)
|
||||||
|
|
||||||
|
dialog = MaterialAlertDialogBuilder(activity)
|
||||||
|
.setTitle(R.string.styled_text_dialog_title)
|
||||||
|
.setView(b.root)
|
||||||
|
.setPositiveButton(R.string.save) { _, _ ->
|
||||||
|
onSuccess(b.editText.text ?: SpannableStringBuilder(""))
|
||||||
|
}
|
||||||
|
.setNeutralButton(R.string.cancel, null)
|
||||||
|
.setOnDismissListener {
|
||||||
|
onDismissListener?.invoke(TAG)
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
|
||||||
|
config = StylingConfig(
|
||||||
|
editText = b.editText,
|
||||||
|
fontStyleGroup = b.fontStyle.styles,
|
||||||
|
fontStyleClear = b.fontStyle.clear,
|
||||||
|
styles = DefaultTextStyles.getAsList(b.fontStyle),
|
||||||
|
textHtml = if (App.devMode) b.htmlText else null,
|
||||||
|
htmlMode = SIMPLE,
|
||||||
|
)
|
||||||
|
|
||||||
|
manager.attach(config)
|
||||||
|
|
||||||
|
b.editText.text = initialText
|
||||||
|
|
||||||
|
// this is awful
|
||||||
|
if (Themes.isDark) {
|
||||||
|
val colorStateList = ColorStateList.valueOf(0x40ffffff)
|
||||||
|
b.fontStyle.bold.strokeColor = colorStateList
|
||||||
|
b.fontStyle.italic.strokeColor = colorStateList
|
||||||
|
b.fontStyle.underline.strokeColor = colorStateList
|
||||||
|
b.fontStyle.strike.strokeColor = colorStateList
|
||||||
|
b.fontStyle.subscript.strokeColor = colorStateList
|
||||||
|
b.fontStyle.superscript.strokeColor = colorStateList
|
||||||
|
b.fontStyle.clear.strokeColor = colorStateList
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.ui.dialogs
|
package pl.szczodrzynski.edziennik.ui.dialogs
|
||||||
|
|
||||||
import android.text.Html
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
@ -14,6 +13,7 @@ import kotlinx.coroutines.Job
|
|||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||||
import pl.szczodrzynski.edziennik.sync.UpdateDownloaderService
|
import pl.szczodrzynski.edziennik.sync.UpdateDownloaderService
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class UpdateAvailableDialog(
|
class UpdateAvailableDialog(
|
||||||
@ -48,7 +48,7 @@ class UpdateAvailableDialog(
|
|||||||
R.string.update_available_format,
|
R.string.update_available_format,
|
||||||
BuildConfig.VERSION_NAME,
|
BuildConfig.VERSION_NAME,
|
||||||
update.versionName,
|
update.versionName,
|
||||||
update.releaseNotes?.let { Html.fromHtml(it) } ?: "---"
|
update.releaseNotes?.let { BetterHtml.fromHtml(activity, it) } ?: "---"
|
||||||
)
|
)
|
||||||
.setPositiveButton(R.string.update_available_button) { dialog, _ ->
|
.setPositiveButton(R.string.update_available_button) { dialog, _ ->
|
||||||
activity.startService(Intent(app, UpdateDownloaderService::class.java))
|
activity.startService(Intent(app, UpdateDownloaderService::class.java))
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package pl.szczodrzynski.edziennik.ui.dialogs.changelog
|
package pl.szczodrzynski.edziennik.ui.dialogs.changelog
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.text.Html
|
|
||||||
import android.widget.ScrollView
|
import android.widget.ScrollView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
@ -18,6 +17,7 @@ import pl.szczodrzynski.edziennik.App
|
|||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.dp
|
import pl.szczodrzynski.edziennik.dp
|
||||||
import pl.szczodrzynski.edziennik.utils.BetterLinkMovementMethod
|
import pl.szczodrzynski.edziennik.utils.BetterLinkMovementMethod
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class ChangelogDialog(
|
class ChangelogDialog(
|
||||||
@ -52,12 +52,11 @@ class ChangelogDialog(
|
|||||||
text = text.replace("""\[(.+?)]\(@([A-z0-9-]+)\)""".toRegex(), "<a href=\"$commitsUrlPrefix$2\">$1</a>")
|
text = text.replace("""\[(.+?)]\(@([A-z0-9-]+)\)""".toRegex(), "<a href=\"$commitsUrlPrefix$2\">$1</a>")
|
||||||
text = text.replace("""\s@([A-z0-9-]+)""".toRegex(), " <a href=\"$commitsUrlPrefix$1\">@$1</a>")
|
text = text.replace("""\s@([A-z0-9-]+)""".toRegex(), " <a href=\"$commitsUrlPrefix$1\">@$1</a>")
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
val html = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||||
textView.text = Html.fromHtml(text)
|
text
|
||||||
}
|
else
|
||||||
else {
|
text.replace("<li>", "<br><li> - ")
|
||||||
textView.text = Html.fromHtml(text.replace("<li>", "<br><li> - "))
|
textView.text = BetterHtml.fromHtml(activity, html)
|
||||||
}
|
|
||||||
|
|
||||||
textView.movementMethod = BetterLinkMovementMethod.getInstance()
|
textView.movementMethod = BetterLinkMovementMethod.getInstance()
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.ui.dialogs.sync
|
package pl.szczodrzynski.edziennik.ui.dialogs.sync
|
||||||
|
|
||||||
import android.text.Html
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
@ -14,6 +13,7 @@ import pl.szczodrzynski.edziennik.R
|
|||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||||
import pl.szczodrzynski.edziennik.data.api.task.AppSync
|
import pl.szczodrzynski.edziennik.data.api.task.AppSync
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class RegistrationConfigDialog(
|
class RegistrationConfigDialog(
|
||||||
@ -61,7 +61,7 @@ class RegistrationConfigDialog(
|
|||||||
onShowListener?.invoke(TAG + "Enable")
|
onShowListener?.invoke(TAG + "Enable")
|
||||||
dialog = MaterialAlertDialogBuilder(activity)
|
dialog = MaterialAlertDialogBuilder(activity)
|
||||||
.setTitle(R.string.registration_config_title)
|
.setTitle(R.string.registration_config_title)
|
||||||
.setMessage(Html.fromHtml(app.getString(R.string.registration_config_enable_text)))
|
.setMessage(BetterHtml.fromHtml(activity, R.string.registration_config_enable_text))
|
||||||
.setPositiveButton(R.string.i_agree) { _, _ ->
|
.setPositiveButton(R.string.i_agree) { _, _ ->
|
||||||
enableRegistration()
|
enableRegistration()
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ class RegistrationConfigDialog(
|
|||||||
onShowListener?.invoke(TAG + "Disable")
|
onShowListener?.invoke(TAG + "Disable")
|
||||||
dialog = MaterialAlertDialogBuilder(activity)
|
dialog = MaterialAlertDialogBuilder(activity)
|
||||||
.setTitle(R.string.registration_config_title)
|
.setTitle(R.string.registration_config_title)
|
||||||
.setMessage(Html.fromHtml(app.getString(R.string.registration_config_disable_text)))
|
.setMessage(R.string.registration_config_disable_text)
|
||||||
.setPositiveButton(R.string.ok) { _, _ ->
|
.setPositiveButton(R.string.ok) { _, _ ->
|
||||||
disableRegistration()
|
disableRegistration()
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Html
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
@ -22,6 +21,7 @@ import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
|||||||
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ErrorReportRequest
|
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ErrorReportRequest
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
import pl.szczodrzynski.edziennik.utils.Themes.appTheme
|
import pl.szczodrzynski.edziennik.utils.Themes.appTheme
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -90,7 +90,7 @@ class CrashActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
moreInfoButton.setOnClickListener {
|
moreInfoButton.setOnClickListener {
|
||||||
MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialogMonospace)
|
MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialogMonospace)
|
||||||
.setTitle(R.string.crash_details)
|
.setTitle(R.string.crash_details)
|
||||||
.setMessage(Html.fromHtml(getErrorString(intent, false)))
|
.setMessage(BetterHtml.fromHtml(context = null, getErrorString(intent, false)))
|
||||||
.setPositiveButton(R.string.close, null)
|
.setPositiveButton(R.string.close, null)
|
||||||
.setNeutralButton(R.string.copy_to_clipboard) { _, _ -> copyErrorToClipboard() }
|
.setNeutralButton(R.string.copy_to_clipboard) { _, _ -> copyErrorToClipboard() }
|
||||||
.show()
|
.show()
|
||||||
|
@ -31,6 +31,7 @@ import kotlin.coroutines.CoroutineContext
|
|||||||
|
|
||||||
class EventDetailsDialog(
|
class EventDetailsDialog(
|
||||||
val activity: AppCompatActivity,
|
val activity: AppCompatActivity,
|
||||||
|
// this event is observed for changes
|
||||||
var event: EventFull,
|
var event: EventFull,
|
||||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||||
@ -85,7 +86,11 @@ class EventDetailsDialog(
|
|||||||
showRemoveEventDialog()
|
showRemoveEventDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
update()
|
// watch the event for changes
|
||||||
|
app.db.eventDao().getById(event.profileId, event.id).observe(activity) {
|
||||||
|
event = it ?: return@observe
|
||||||
|
update()
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
private fun update() {
|
private fun update() {
|
||||||
@ -93,6 +98,9 @@ class EventDetailsDialog(
|
|||||||
b.eventShared = eventShared
|
b.eventShared = eventShared
|
||||||
b.eventOwn = eventOwn
|
b.eventOwn = eventOwn
|
||||||
|
|
||||||
|
b.topic.text = event.topicHtml
|
||||||
|
b.body.text = event.bodyHtml
|
||||||
|
|
||||||
if (!event.seen) {
|
if (!event.seen) {
|
||||||
manager.markAsSeen(event)
|
manager.markAsSeen(event)
|
||||||
}
|
}
|
||||||
@ -170,8 +178,9 @@ class EventDetailsDialog(
|
|||||||
dialog.dismiss()
|
dialog.dismiss()
|
||||||
return@EventManualDialog
|
return@EventManualDialog
|
||||||
}
|
}
|
||||||
event = it
|
// this should not be needed as the event is observed by the ID
|
||||||
update()
|
// event = it
|
||||||
|
// update()
|
||||||
},
|
},
|
||||||
onShowListener = onShowListener,
|
onShowListener = onShowListener,
|
||||||
onDismissListener = onDismissListener
|
onDismissListener = onDismissListener
|
||||||
@ -350,7 +359,7 @@ class EventDetailsDialog(
|
|||||||
val intent = Intent(Intent.ACTION_EDIT).apply {
|
val intent = Intent(Intent.ACTION_EDIT).apply {
|
||||||
data = Events.CONTENT_URI
|
data = Events.CONTENT_URI
|
||||||
putExtra(Events.TITLE, title)
|
putExtra(Events.TITLE, title)
|
||||||
putExtra(Events.DESCRIPTION, event.topic)
|
putExtra(Events.DESCRIPTION, event.topicHtml.toString())
|
||||||
|
|
||||||
if (event.time == null) {
|
if (event.time == null) {
|
||||||
putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, true)
|
putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, true)
|
||||||
|
@ -13,6 +13,9 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.jaredrummler.android.colorpicker.ColorPickerDialog
|
import com.jaredrummler.android.colorpicker.ColorPickerDialog
|
||||||
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
|
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
|
||||||
|
import com.mikepenz.iconics.IconicsDrawable
|
||||||
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||||
|
import com.mikepenz.iconics.utils.sizeDp
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import org.greenrobot.eventbus.Subscribe
|
import org.greenrobot.eventbus.Subscribe
|
||||||
@ -27,9 +30,13 @@ import pl.szczodrzynski.edziennik.data.db.entity.*
|
|||||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
|
import pl.szczodrzynski.edziennik.data.db.full.LessonFull
|
||||||
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
|
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
|
||||||
|
import pl.szczodrzynski.edziennik.ui.dialogs.StyledTextDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationConfigDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegistrationConfigDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.views.TimeDropdown.Companion.DISPLAY_LESSONS
|
import pl.szczodrzynski.edziennik.ui.modules.views.TimeDropdown.Companion.DISPLAY_LESSONS
|
||||||
import pl.szczodrzynski.edziennik.utils.Anim
|
import pl.szczodrzynski.edziennik.utils.Anim
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.HtmlMode.SIMPLE
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.StylingConfigBase
|
||||||
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
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
@ -59,6 +66,10 @@ class EventManualDialog(
|
|||||||
private lateinit var b: DialogEventManualV2Binding
|
private lateinit var b: DialogEventManualV2Binding
|
||||||
private lateinit var dialog: AlertDialog
|
private lateinit var dialog: AlertDialog
|
||||||
private lateinit var profile: Profile
|
private lateinit var profile: Profile
|
||||||
|
private lateinit var stylingConfig: StylingConfigBase
|
||||||
|
|
||||||
|
private val textStylingManager
|
||||||
|
get() = app.textStylingManager
|
||||||
|
|
||||||
private var customColor: Int? = null
|
private var customColor: Int? = null
|
||||||
private val editingShared = editingEvent?.sharedBy != null
|
private val editingShared = editingEvent?.sharedBy != null
|
||||||
@ -128,6 +139,23 @@ class EventManualDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.topicLayout.endIconDrawable = IconicsDrawable(activity, CommunityMaterial.Icon3.cmd_open_in_new).apply {
|
||||||
|
sizeDp = 24
|
||||||
|
}
|
||||||
|
b.topicLayout.setEndIconOnClickListener {
|
||||||
|
StyledTextDialog(
|
||||||
|
activity,
|
||||||
|
initialText = b.topic.text,
|
||||||
|
onSuccess = {
|
||||||
|
b.topic.text = it
|
||||||
|
},
|
||||||
|
onShowListener,
|
||||||
|
onDismissListener
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
stylingConfig = StylingConfigBase(editText = b.topic, htmlMode = SIMPLE)
|
||||||
|
|
||||||
updateShareText()
|
updateShareText()
|
||||||
b.shareSwitch.onChange { _, isChecked ->
|
b.shareSwitch.onChange { _, isChecked ->
|
||||||
updateShareText(isChecked)
|
updateShareText(isChecked)
|
||||||
@ -332,7 +360,7 @@ class EventManualDialog(
|
|||||||
|
|
||||||
// copy data from event being edited
|
// copy data from event being edited
|
||||||
editingEvent?.let {
|
editingEvent?.let {
|
||||||
b.topic.setText(it.topic)
|
b.topic.setText(BetterHtml.fromHtml(activity, it.topic, nl2br = true))
|
||||||
if (it.color != -1)
|
if (it.color != -1)
|
||||||
customColor = it.color
|
customColor = it.color
|
||||||
}
|
}
|
||||||
@ -458,12 +486,13 @@ class EventManualDialog(
|
|||||||
|
|
||||||
val id = System.currentTimeMillis()
|
val id = System.currentTimeMillis()
|
||||||
|
|
||||||
|
val topicHtml = textStylingManager.getHtmlText(stylingConfig)
|
||||||
val eventObject = Event(
|
val eventObject = Event(
|
||||||
profileId = profileId,
|
profileId = profileId,
|
||||||
id = editingEvent?.id ?: id,
|
id = editingEvent?.id ?: id,
|
||||||
date = date,
|
date = date,
|
||||||
time = startTime,
|
time = startTime,
|
||||||
topic = topic,
|
topic = topicHtml,
|
||||||
color = customColor,
|
color = customColor,
|
||||||
type = type?.id ?: Event.TYPE_DEFAULT,
|
type = type?.id ?: Event.TYPE_DEFAULT,
|
||||||
teacherId = teacher?.id ?: -1,
|
teacherId = teacher?.id ?: -1,
|
||||||
|
@ -9,7 +9,6 @@ import android.view.ViewGroup
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.mikepenz.iconics.utils.buildIconics
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||||
import pl.szczodrzynski.edziennik.databinding.EventListItemBinding
|
import pl.szczodrzynski.edziennik.databinding.EventListItemBinding
|
||||||
@ -99,15 +98,13 @@ class EventViewHolder(
|
|||||||
/* 3$ */
|
/* 3$ */
|
||||||
item.teamName?.let { bullet + it } ?: "",
|
item.teamName?.let { bullet + it } ?: "",
|
||||||
)
|
)
|
||||||
|
// workaround for the span data lost during setText above
|
||||||
val addedBySpanned = adapter.highlightSearchText(
|
val addedBySpanned = adapter.highlightSearchText(
|
||||||
item = item,
|
item = item,
|
||||||
text = addedBy,
|
text = addedBy,
|
||||||
color = colorHighlight
|
color = colorHighlight
|
||||||
)
|
)
|
||||||
b.addedBy.text = b.addedBy.text.replace(addedBy, addedBySpanned)
|
b.addedBy.text = b.addedBy.text.replaceSpanned(addedBy, addedBySpanned)
|
||||||
// for now, as CharSequence.replace() converts the original sequence to string,
|
|
||||||
// so the Iconics span data is lost and the share icon set above does not display
|
|
||||||
b.addedBy.buildIconics()
|
|
||||||
|
|
||||||
b.attachmentIcon.isVisible = item.hasAttachments
|
b.attachmentIcon.isVisible = item.hasAttachments
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ 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
|
||||||
@ -25,6 +24,7 @@ import pl.szczodrzynski.edziennik.ui.dialogs.UpdateAvailableDialog
|
|||||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCard
|
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCard
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardAdapter
|
import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardAdapter
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
|
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class HomeAvailabilityCard(
|
class HomeAvailabilityCard(
|
||||||
@ -61,8 +61,8 @@ class HomeAvailabilityCard(
|
|||||||
|
|
||||||
// show "register unavailable" only when disabled
|
// show "register unavailable" only when disabled
|
||||||
if (status?.userMessage != null) {
|
if (status?.userMessage != null) {
|
||||||
b.homeAvailabilityTitle.text = HtmlCompat.fromHtml(status.userMessage.title, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
b.homeAvailabilityTitle.text = BetterHtml.fromHtml(activity, status.userMessage.title)
|
||||||
b.homeAvailabilityText.text = HtmlCompat.fromHtml(status.userMessage.contentShort, HtmlCompat.FROM_HTML_MODE_LEGACY)
|
b.homeAvailabilityText.text = BetterHtml.fromHtml(activity, status.userMessage.contentShort)
|
||||||
b.homeAvailabilityUpdate.isVisible = false
|
b.homeAvailabilityUpdate.isVisible = false
|
||||||
b.homeAvailabilityIcon.setImageResource(R.drawable.ic_sync)
|
b.homeAvailabilityIcon.setImageResource(R.drawable.ic_sync)
|
||||||
if (status.userMessage.icon != null)
|
if (status.userMessage.icon != null)
|
||||||
|
@ -10,7 +10,6 @@ import android.app.Activity
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Html
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -31,6 +30,7 @@ import pl.szczodrzynski.edziennik.ui.dialogs.RegisterUnavailableDialog
|
|||||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackActivity
|
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackActivity
|
||||||
import pl.szczodrzynski.edziennik.utils.BetterLinkMovementMethod
|
import pl.szczodrzynski.edziennik.utils.BetterLinkMovementMethod
|
||||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
|
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
@ -218,7 +218,7 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
|
|||||||
if (!app.config.privacyPolicyAccepted) {
|
if (!app.config.privacyPolicyAccepted) {
|
||||||
MaterialAlertDialogBuilder(activity)
|
MaterialAlertDialogBuilder(activity)
|
||||||
.setTitle(R.string.privacy_policy)
|
.setTitle(R.string.privacy_policy)
|
||||||
.setMessage(Html.fromHtml(activity.getString(R.string.privacy_policy_dialog_html)))
|
.setMessage(BetterHtml.fromHtml(activity, R.string.privacy_policy_dialog_html))
|
||||||
.setPositiveButton(R.string.i_agree) { _, _ ->
|
.setPositiveButton(R.string.i_agree) { _, _ ->
|
||||||
app.config.privacyPolicyAccepted = true
|
app.config.privacyPolicyAccepted = true
|
||||||
onLoginModeClicked(loginType, loginMode)
|
onLoginModeClicked(loginType, loginMode)
|
||||||
|
@ -38,15 +38,17 @@ import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
|||||||
import pl.szczodrzynski.edziennik.databinding.MessagesComposeFragmentBinding
|
import pl.szczodrzynski.edziennik.databinding.MessagesComposeFragmentBinding
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.MessagesConfigDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.MessagesConfigDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.messages.list.MessagesFragment
|
import pl.szczodrzynski.edziennik.ui.modules.messages.list.MessagesFragment
|
||||||
|
import pl.szczodrzynski.edziennik.utils.DefaultTextStyles
|
||||||
import pl.szczodrzynski.edziennik.utils.Themes
|
import pl.szczodrzynski.edziennik.utils.Themes
|
||||||
import pl.szczodrzynski.edziennik.utils.managers.MessageManager.UIConfig
|
import pl.szczodrzynski.edziennik.utils.managers.MessageManager.UIConfig
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.HtmlMode.COMPATIBLE
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.HtmlMode.ORIGINAL
|
||||||
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.StylingConfig
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.StylingConfig
|
||||||
import pl.szczodrzynski.edziennik.utils.span.*
|
import pl.szczodrzynski.edziennik.utils.span.*
|
||||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
|
||||||
class MessagesComposeFragment : Fragment(), CoroutineScope {
|
class MessagesComposeFragment : Fragment(), CoroutineScope {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "MessagesComposeFragment"
|
private const val TAG = "MessagesComposeFragment"
|
||||||
@ -103,6 +105,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
|
|||||||
b.breakpoints.visibility = if (App.devMode) View.VISIBLE else View.GONE
|
b.breakpoints.visibility = if (App.devMode) View.VISIBLE else View.GONE
|
||||||
b.breakpoints.setOnClickListener {
|
b.breakpoints.setOnClickListener {
|
||||||
b.breakpoints.isEnabled = true
|
b.breakpoints.isEnabled = true
|
||||||
|
@SuppressLint("SetTextI18n")
|
||||||
b.breakpoints.text = "Breakpoints!"
|
b.breakpoints.text = "Breakpoints!"
|
||||||
// do your job
|
// do your job
|
||||||
}
|
}
|
||||||
@ -232,45 +235,7 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
|
|||||||
b.subjectLayout.isEnabled = false
|
b.subjectLayout.isEnabled = false
|
||||||
b.textLayout.isEnabled = false
|
b.textLayout.isEnabled = false
|
||||||
|
|
||||||
val styles = listOf(
|
val styles = DefaultTextStyles.getAsList(b.fontStyle)
|
||||||
StylingConfig.Style(
|
|
||||||
button = b.fontStyleBold,
|
|
||||||
spanClass = BoldSpan::class.java,
|
|
||||||
icon = CommunityMaterial.Icon2.cmd_format_bold,
|
|
||||||
hint = R.string.hint_style_bold,
|
|
||||||
),
|
|
||||||
StylingConfig.Style(
|
|
||||||
button = b.fontStyleItalic,
|
|
||||||
spanClass = ItalicSpan::class.java,
|
|
||||||
icon = CommunityMaterial.Icon2.cmd_format_italic,
|
|
||||||
hint = R.string.hint_style_italic,
|
|
||||||
),
|
|
||||||
StylingConfig.Style(
|
|
||||||
button = b.fontStyleUnderline,
|
|
||||||
// a custom span is used to prevent issues with keyboards which underline words
|
|
||||||
spanClass = UnderlineCustomSpan::class.java,
|
|
||||||
icon = CommunityMaterial.Icon2.cmd_format_underline,
|
|
||||||
hint = R.string.hint_style_underline,
|
|
||||||
),
|
|
||||||
StylingConfig.Style(
|
|
||||||
button = b.fontStyleStrike,
|
|
||||||
spanClass = StrikethroughSpan::class.java,
|
|
||||||
icon = CommunityMaterial.Icon2.cmd_format_strikethrough,
|
|
||||||
hint = R.string.hint_style_strike,
|
|
||||||
),
|
|
||||||
StylingConfig.Style(
|
|
||||||
button = b.fontStyleSubscript,
|
|
||||||
spanClass = SubscriptSizeSpan::class.java,
|
|
||||||
icon = CommunityMaterial.Icon2.cmd_format_subscript,
|
|
||||||
hint = R.string.hint_style_subscript,
|
|
||||||
),
|
|
||||||
StylingConfig.Style(
|
|
||||||
button = b.fontStyleSuperscript,
|
|
||||||
spanClass = SuperscriptSizeSpan::class.java,
|
|
||||||
icon = CommunityMaterial.Icon2.cmd_format_superscript,
|
|
||||||
hint = R.string.hint_style_superscript,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
uiConfig = UIConfig(
|
uiConfig = UIConfig(
|
||||||
context = activity,
|
context = activity,
|
||||||
@ -285,28 +250,24 @@ class MessagesComposeFragment : Fragment(), CoroutineScope {
|
|||||||
)
|
)
|
||||||
stylingConfig = StylingConfig(
|
stylingConfig = StylingConfig(
|
||||||
editText = b.text,
|
editText = b.text,
|
||||||
fontStyleGroup = b.fontStyle,
|
fontStyleGroup = b.fontStyle.styles,
|
||||||
fontStyleClear = b.fontStyleClear,
|
fontStyleClear = b.fontStyle.clear,
|
||||||
styles = styles,
|
styles = styles,
|
||||||
textHtml = if (App.devMode) b.textHtml else null,
|
textHtml = if (App.devMode) b.textHtml else null,
|
||||||
htmlCompatibleMode = app.profile.loginStoreType == LOGIN_TYPE_MOBIDZIENNIK,
|
htmlMode = when (app.profile.loginStoreType) {
|
||||||
|
LOGIN_TYPE_MOBIDZIENNIK -> COMPATIBLE
|
||||||
|
else -> ORIGINAL
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
b.fontStyleLayout.isVisible = enableTextStyling
|
b.fontStyle.root.isVisible = enableTextStyling
|
||||||
if (enableTextStyling) {
|
if (enableTextStyling) {
|
||||||
textStylingManager.attach(stylingConfig)
|
textStylingManager.attach(stylingConfig)
|
||||||
b.fontStyle.addOnButtonCheckedListener { _, _, _ ->
|
b.fontStyle.styles.addOnButtonCheckedListener { _, _, _ ->
|
||||||
changedBody = true
|
changedBody = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (App.devMode) {
|
|
||||||
b.textHtml.isVisible = true
|
|
||||||
b.text.addTextChangedListener {
|
|
||||||
b.textHtml.text = getMessageBody()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
activity.navView.bottomBar.apply {
|
activity.navView.bottomBar.apply {
|
||||||
fabEnable = true
|
fabEnable = true
|
||||||
fabExtendedText = getString(R.string.messages_compose_send)
|
fabExtendedText = getString(R.string.messages_compose_send)
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package pl.szczodrzynski.edziennik.ui.modules.messages.single
|
package pl.szczodrzynski.edziennik.ui.modules.messages.single
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.Html
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -32,6 +31,7 @@ import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesUtils
|
|||||||
import pl.szczodrzynski.edziennik.ui.modules.messages.list.MessagesFragment
|
import pl.szczodrzynski.edziennik.ui.modules.messages.list.MessagesFragment
|
||||||
import pl.szczodrzynski.edziennik.utils.Anim
|
import pl.szczodrzynski.edziennik.utils.Anim
|
||||||
import pl.szczodrzynski.edziennik.utils.BetterLink
|
import pl.szczodrzynski.edziennik.utils.BetterLink
|
||||||
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
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
|
||||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||||
@ -255,7 +255,7 @@ class MessageFragment : Fragment(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
messageRecipients.append("</ul>")
|
messageRecipients.append("</ul>")
|
||||||
b.recipients.text = Html.fromHtml(messageRecipients.toString())
|
b.recipients.text = BetterHtml.fromHtml(activity, messageRecipients)
|
||||||
|
|
||||||
showAttachments()
|
showAttachments()
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.ui.widgets.timetable;
|
package pl.szczodrzynski.edziennik.ui.widgets.timetable;
|
||||||
|
|
||||||
|
import static android.util.TypedValue.COMPLEX_UNIT_SP;
|
||||||
|
|
||||||
import android.appwidget.AppWidgetManager;
|
import android.appwidget.AppWidgetManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -16,7 +18,6 @@ import android.graphics.Paint;
|
|||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.PorterDuffColorFilter;
|
import android.graphics.PorterDuffColorFilter;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.text.Html;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
@ -32,14 +33,13 @@ import com.mikepenz.iconics.utils.IconicsDrawableExtensionsKt;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
|
import pl.szczodrzynski.edziennik.ExtensionsKt;
|
||||||
import pl.szczodrzynski.edziennik.R;
|
import pl.szczodrzynski.edziennik.R;
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||||
import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel;
|
import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel;
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Week;
|
import pl.szczodrzynski.edziennik.utils.models.Week;
|
||||||
|
|
||||||
import static android.util.TypedValue.COMPLEX_UNIT_SP;
|
|
||||||
|
|
||||||
public class WidgetTimetableFactory implements RemoteViewsService.RemoteViewsFactory {
|
public class WidgetTimetableFactory implements RemoteViewsService.RemoteViewsFactory {
|
||||||
|
|
||||||
private static final String TAG = "WidgetTimetableProvider";
|
private static final String TAG = "WidgetTimetableProvider";
|
||||||
@ -309,17 +309,17 @@ public class WidgetTimetableFactory implements RemoteViewsService.RemoteViewsFac
|
|||||||
|
|
||||||
views.setViewVisibility(R.id.widgetTimetableOldSubjectName, View.GONE);
|
views.setViewVisibility(R.id.widgetTimetableOldSubjectName, View.GONE);
|
||||||
if (lesson.lessonChange) {
|
if (lesson.lessonChange) {
|
||||||
views.setTextViewText(R.id.widgetTimetableSubjectName, Html.fromHtml("<i>"+lesson.subjectName+"</i>"));
|
views.setTextViewText(R.id.widgetTimetableSubjectName, ExtensionsKt.asItalicSpannable(lesson.subjectName));
|
||||||
if (lesson.lessonChangeNoClassroom) {
|
if (lesson.lessonChangeNoClassroom) {
|
||||||
views.setTextViewText(R.id.widgetTimetableClassroomName, Html.fromHtml("<del>"+lesson.classroomName+"</del>"));
|
views.setTextViewText(R.id.widgetTimetableClassroomName, ExtensionsKt.asStrikethroughSpannable(lesson.classroomName));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
views.setTextViewText(R.id.widgetTimetableClassroomName, Html.fromHtml("<i>" + lesson.classroomName + "</i>"));
|
views.setTextViewText(R.id.widgetTimetableClassroomName, ExtensionsKt.asItalicSpannable(lesson.classroomName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (lesson.lessonCancelled) {
|
else if (lesson.lessonCancelled) {
|
||||||
views.setTextViewText(R.id.widgetTimetableSubjectName, Html.fromHtml("<del>"+lesson.subjectName+"</del>"));
|
views.setTextViewText(R.id.widgetTimetableSubjectName, ExtensionsKt.asStrikethroughSpannable(lesson.subjectName));
|
||||||
views.setTextViewText(R.id.widgetTimetableClassroomName, Html.fromHtml("<del>"+lesson.classroomName+"</del>"));
|
views.setTextViewText(R.id.widgetTimetableClassroomName, ExtensionsKt.asStrikethroughSpannable(lesson.classroomName));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
views.setTextViewText(R.id.widgetTimetableSubjectName, lesson.subjectName);
|
views.setTextViewText(R.id.widgetTimetableSubjectName, lesson.subjectName);
|
||||||
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2021-10-11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.utils
|
||||||
|
|
||||||
|
import android.text.style.StrikethroughSpan
|
||||||
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.databinding.StyledTextButtonsBinding
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.StylingConfig
|
||||||
|
import pl.szczodrzynski.edziennik.utils.span.*
|
||||||
|
|
||||||
|
object DefaultTextStyles {
|
||||||
|
|
||||||
|
fun getAsList(b: StyledTextButtonsBinding) = listOf(
|
||||||
|
StylingConfig.Style(
|
||||||
|
button = b.bold,
|
||||||
|
spanClass = BoldSpan::class.java,
|
||||||
|
icon = CommunityMaterial.Icon2.cmd_format_bold,
|
||||||
|
hint = R.string.hint_style_bold,
|
||||||
|
),
|
||||||
|
StylingConfig.Style(
|
||||||
|
button = b.italic,
|
||||||
|
spanClass = ItalicSpan::class.java,
|
||||||
|
icon = CommunityMaterial.Icon2.cmd_format_italic,
|
||||||
|
hint = R.string.hint_style_italic,
|
||||||
|
),
|
||||||
|
StylingConfig.Style(
|
||||||
|
button = b.underline,
|
||||||
|
// a custom span is used to prevent issues with keyboards which underline words
|
||||||
|
spanClass = UnderlineCustomSpan::class.java,
|
||||||
|
icon = CommunityMaterial.Icon2.cmd_format_underline,
|
||||||
|
hint = R.string.hint_style_underline,
|
||||||
|
),
|
||||||
|
StylingConfig.Style(
|
||||||
|
button = b.strike,
|
||||||
|
spanClass = StrikethroughSpan::class.java,
|
||||||
|
icon = CommunityMaterial.Icon2.cmd_format_strikethrough,
|
||||||
|
hint = R.string.hint_style_strike,
|
||||||
|
),
|
||||||
|
StylingConfig.Style(
|
||||||
|
button = b.subscript,
|
||||||
|
spanClass = SubscriptSizeSpan::class.java,
|
||||||
|
icon = CommunityMaterial.Icon2.cmd_format_subscript,
|
||||||
|
hint = R.string.hint_style_subscript,
|
||||||
|
),
|
||||||
|
StylingConfig.Style(
|
||||||
|
button = b.superscript,
|
||||||
|
spanClass = SuperscriptSizeSpan::class.java,
|
||||||
|
icon = CommunityMaterial.Icon2.cmd_format_superscript,
|
||||||
|
hint = R.string.hint_style_superscript,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
@ -32,8 +32,14 @@ object BetterHtml {
|
|||||||
SuperscriptSizeSpan::class.java,
|
SuperscriptSizeSpan::class.java,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun fromHtml(context: Context, stringRes: Int) = fromHtml(
|
||||||
|
context,
|
||||||
|
context.getString(stringRes),
|
||||||
|
nl2br = true,
|
||||||
|
)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun fromHtml(context: Context, html: String): Spanned {
|
fun fromHtml(context: Context?, html: CharSequence, nl2br: Boolean = false): Spanned {
|
||||||
val hexPattern = "(#[a-fA-F0-9]{6})"
|
val hexPattern = "(#[a-fA-F0-9]{6})"
|
||||||
val colorRegex = "(?:color=\"$hexPattern\")|(?:style=\"color: ?${hexPattern})"
|
val colorRegex = "(?:color=\"$hexPattern\")|(?:style=\"color: ?${hexPattern})"
|
||||||
.toRegex(RegexOption.IGNORE_CASE)
|
.toRegex(RegexOption.IGNORE_CASE)
|
||||||
@ -42,29 +48,35 @@ object BetterHtml {
|
|||||||
.replace("\\[META:[A-z0-9]+;[0-9-]+]".toRegex(), "")
|
.replace("\\[META:[A-z0-9]+;[0-9-]+]".toRegex(), "")
|
||||||
.replace("background-color: ?$hexPattern;".toRegex(), "")
|
.replace("background-color: ?$hexPattern;".toRegex(), "")
|
||||||
|
|
||||||
val colorBackground = android.R.attr.colorBackground.resolveAttr(context)
|
if (nl2br) {
|
||||||
val textColorPrimary = android.R.attr.textColorPrimary.resolveAttr(context) and 0xffffff
|
text = text.replace("\n", "<br>")
|
||||||
|
}
|
||||||
|
|
||||||
colorRegex.findAll(text).forEach { result ->
|
if (context != null) {
|
||||||
val group = result.groups.drop(1).firstOrNull { it != null } ?: return@forEach
|
val colorBackground = android.R.attr.colorBackground.resolveAttr(context)
|
||||||
|
val textColorPrimary = android.R.attr.textColorPrimary.resolveAttr(context) and 0xffffff
|
||||||
|
|
||||||
val color = Color.parseColor(group.value)
|
colorRegex.findAll(text).forEach { result ->
|
||||||
var newColor = 0xff000000.toInt() or color
|
val group = result.groups.drop(1).firstOrNull { it != null } ?: return@forEach
|
||||||
|
|
||||||
var blendAmount = 1
|
val color = Color.parseColor(group.value)
|
||||||
var numIterations = 0
|
var newColor = 0xff000000.toInt() or color
|
||||||
|
|
||||||
while (numIterations < 100 && ColorUtils.calculateContrast(
|
var blendAmount = 1
|
||||||
colorBackground,
|
var numIterations = 0
|
||||||
newColor
|
|
||||||
) < 4.5f
|
while (numIterations < 100 && ColorUtils.calculateContrast(
|
||||||
) {
|
colorBackground,
|
||||||
blendAmount += 2
|
newColor
|
||||||
newColor = blendColors(color, blendAmount shl 24 or textColorPrimary)
|
) < 4.5f
|
||||||
numIterations++
|
) {
|
||||||
|
blendAmount += 2
|
||||||
|
newColor = blendColors(color, blendAmount shl 24 or textColorPrimary)
|
||||||
|
numIterations++
|
||||||
|
}
|
||||||
|
|
||||||
|
text = text.replaceRange(group.range, "#" + (newColor and 0xffffff).toString(16))
|
||||||
}
|
}
|
||||||
|
|
||||||
text = text.replaceRange(group.range, "#" + (newColor and 0xffffff).toString(16))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*val olRegex = """<ol>(.+?)</\s*?ol>"""
|
/*val olRegex = """<ol>(.+?)</\s*?ol>"""
|
||||||
|
@ -45,16 +45,13 @@ class EventManager(val app: App) : CoroutineScope {
|
|||||||
showType: Boolean = true,
|
showType: Boolean = true,
|
||||||
doneIconColor: Int? = null
|
doneIconColor: Int? = null
|
||||||
) {
|
) {
|
||||||
var eventTopic = if (showType)
|
val topicSpan = event.topicHtml
|
||||||
"${event.typeName ?: "wydarzenie"} - ${event.topic}"
|
|
||||||
else
|
|
||||||
event.topic
|
|
||||||
|
|
||||||
if (event.addedManually) {
|
title.text = listOfNotNull(
|
||||||
eventTopic = "{cmd-clipboard-edit-outline} $eventTopic"
|
if (event.addedManually) "{cmd-clipboard-edit-outline} " else null,
|
||||||
}
|
if (showType) "${event.typeName ?: "wydarzenie"} - " else null,
|
||||||
|
topicSpan,
|
||||||
title.text = eventTopic
|
).concat()
|
||||||
|
|
||||||
title.setCompoundDrawables(
|
title.setCompoundDrawables(
|
||||||
null,
|
null,
|
||||||
|
@ -25,6 +25,7 @@ import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
|||||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesUtils
|
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesUtils
|
||||||
import pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
import pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
||||||
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.HtmlMode.ORIGINAL
|
||||||
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.StylingConfig
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.StylingConfig
|
||||||
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
|
||||||
@ -148,7 +149,7 @@ class MessageManager(private val app: App) {
|
|||||||
suspend fun saveAsDraft(config: UIConfig, stylingConfig: StylingConfig, profileId: Int, messageId: Long?) {
|
suspend fun saveAsDraft(config: UIConfig, stylingConfig: StylingConfig, profileId: Int, messageId: Long?) {
|
||||||
val teachers = config.recipients.allChips.mapNotNull { it.data as? Teacher }
|
val teachers = config.recipients.allChips.mapNotNull { it.data as? Teacher }
|
||||||
val subject = config.subject.text?.toString() ?: ""
|
val subject = config.subject.text?.toString() ?: ""
|
||||||
val body = textStylingManager.getHtmlText(stylingConfig, enableHtmlCompatible = false)
|
val body = textStylingManager.getHtmlText(stylingConfig, htmlMode = ORIGINAL)
|
||||||
|
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
if (messageId != null) {
|
if (messageId != null) {
|
||||||
|
@ -6,18 +6,25 @@ package pl.szczodrzynski.edziennik.utils.managers
|
|||||||
|
|
||||||
import android.text.SpannableStringBuilder
|
import android.text.SpannableStringBuilder
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
|
import android.text.style.StrikethroughSpan
|
||||||
|
import android.text.style.SubscriptSpan
|
||||||
|
import android.text.style.SuperscriptSpan
|
||||||
|
import android.text.style.UnderlineSpan
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.widget.addTextChangedListener
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
import com.google.android.material.button.MaterialButtonToggleGroup
|
import com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
import com.mikepenz.iconics.typeface.IIcon
|
import com.mikepenz.iconics.typeface.IIcon
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.attachToastHint
|
|
||||||
import pl.szczodrzynski.edziennik.hasSet
|
|
||||||
import pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
import pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
||||||
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.TextStylingManager.HtmlMode.*
|
||||||
|
import pl.szczodrzynski.edziennik.utils.span.BoldSpan
|
||||||
|
import pl.szczodrzynski.edziennik.utils.span.ItalicSpan
|
||||||
|
|
||||||
class TextStylingManager(private val app: App) {
|
class TextStylingManager(private val app: App) {
|
||||||
companion object {
|
companion object {
|
||||||
@ -28,14 +35,45 @@ class TextStylingManager(private val app: App) {
|
|||||||
"((?:<br>)+)</p>".toRegex()
|
"((?:<br>)+)</p>".toRegex()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class StylingConfig(
|
enum class HtmlMode {
|
||||||
|
/**
|
||||||
|
* The default mode, suitable for fromHtml conversion.
|
||||||
|
*/
|
||||||
|
ORIGINAL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A more browser-compatible mode.
|
||||||
|
*/
|
||||||
|
COMPATIBLE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple, paragraph-stripped mode with \n instead of <br>.
|
||||||
|
* The converted text has no HTML tags when no spans in source.
|
||||||
|
*/
|
||||||
|
SIMPLE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Markdown-compatible text mode.
|
||||||
|
*/
|
||||||
|
MARKDOWN,
|
||||||
|
}
|
||||||
|
|
||||||
|
open class StylingConfigBase(
|
||||||
val editText: TextInputKeyboardEdit,
|
val editText: TextInputKeyboardEdit,
|
||||||
|
val htmlMode: HtmlMode = ORIGINAL,
|
||||||
|
) {
|
||||||
|
var watchStyleChecked = true
|
||||||
|
var watchSelectionChanged = true
|
||||||
|
}
|
||||||
|
|
||||||
|
class StylingConfig(
|
||||||
|
editText: TextInputKeyboardEdit,
|
||||||
val fontStyleGroup: MaterialButtonToggleGroup,
|
val fontStyleGroup: MaterialButtonToggleGroup,
|
||||||
val fontStyleClear: Button,
|
val fontStyleClear: Button,
|
||||||
val styles: List<Style>,
|
val styles: List<Style>,
|
||||||
val textHtml: TextView? = null,
|
val textHtml: TextView? = null,
|
||||||
val htmlCompatibleMode: Boolean = false,
|
htmlMode: HtmlMode = ORIGINAL,
|
||||||
) {
|
) : StylingConfigBase(editText, htmlMode) {
|
||||||
data class Style(
|
data class Style(
|
||||||
val button: MaterialButton,
|
val button: MaterialButton,
|
||||||
val spanClass: Class<*>,
|
val spanClass: Class<*>,
|
||||||
@ -45,9 +83,6 @@ class TextStylingManager(private val app: App) {
|
|||||||
) {
|
) {
|
||||||
fun newInstance(): Any = spanClass.newInstance()
|
fun newInstance(): Any = spanClass.newInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
var watchStyleChecked = true
|
|
||||||
var watchSelectionChanged = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun attach(config: StylingConfig) {
|
fun attach(config: StylingConfig) {
|
||||||
@ -76,6 +111,14 @@ class TextStylingManager(private val app: App) {
|
|||||||
onSelectionChanged(config, selectionStart, selectionEnd)
|
onSelectionChanged(config, selectionStart, selectionEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.textHtml != null) {
|
||||||
|
config.editText.addTextChangedListener {
|
||||||
|
config.textHtml.text = getHtmlText(config)
|
||||||
|
}
|
||||||
|
config.textHtml.isVisible = true
|
||||||
|
config.textHtml.text = getHtmlText(config)
|
||||||
|
}
|
||||||
|
|
||||||
/*b.fontStyleBold.shapeAppearanceModel = b.fontStyleBold.shapeAppearanceModel
|
/*b.fontStyleBold.shapeAppearanceModel = b.fontStyleBold.shapeAppearanceModel
|
||||||
.toBuilder()
|
.toBuilder()
|
||||||
.setBottomLeftCornerSize(0f)
|
.setBottomLeftCornerSize(0f)
|
||||||
@ -91,15 +134,14 @@ class TextStylingManager(private val app: App) {
|
|||||||
.build()*/
|
.build()*/
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getHtmlText(config: StylingConfig, enableHtmlCompatible: Boolean = true): String {
|
fun getHtmlText(config: StylingConfigBase, htmlMode: HtmlMode = config.htmlMode): String {
|
||||||
val text = config.editText.text?.trimEnd() ?: return ""
|
val text = config.editText.text?.trimEnd() ?: return ""
|
||||||
val spanned = SpannableStringBuilder(text)
|
val spanned = SpannableStringBuilder(text)
|
||||||
|
|
||||||
val htmlCompatibleMode = config.htmlCompatibleMode && enableHtmlCompatible
|
val toHtmlFlag = when (htmlMode) {
|
||||||
val toHtmlFlag = if (htmlCompatibleMode)
|
COMPATIBLE -> HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL
|
||||||
HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL
|
else -> HtmlCompat.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE
|
||||||
else
|
}
|
||||||
HtmlCompat.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE
|
|
||||||
|
|
||||||
// apparently setting the spans to a different Spannable calls the original EditText's
|
// apparently setting the spans to a different Spannable calls the original EditText's
|
||||||
// onSelectionChanged with selectionStart=-1, which in effect unchecks the format toggles
|
// onSelectionChanged with selectionStart=-1, which in effect unchecks the format toggles
|
||||||
@ -113,24 +155,41 @@ class TextStylingManager(private val app: App) {
|
|||||||
if (spanStart == spanEnd && it::class.java in BetterHtml.customSpanClasses)
|
if (spanStart == spanEnd && it::class.java in BetterHtml.customSpanClasses)
|
||||||
spanned.removeSpan(it)
|
spanned.removeSpan(it)
|
||||||
}
|
}
|
||||||
var textHtml = HtmlCompat.toHtml(spanned, toHtmlFlag)
|
|
||||||
.replace("\n", "")
|
var textHtml = when (htmlMode) {
|
||||||
.replace(" dir=\"ltr\"", "")
|
SIMPLE -> spanned
|
||||||
.replace("</b><b>", "")
|
.replaceSpan(BoldSpan::class.java, "<b>", "</b>")
|
||||||
.replace("</i><i>", "")
|
.replaceSpan(ItalicSpan::class.java, "<i>", "</i>")
|
||||||
.replace("</u><u>", "")
|
.replaceSpan(UnderlineSpan::class.java, "<u>", "</u>")
|
||||||
.replace("</sub><sub>", "")
|
.replaceSpan(StrikethroughSpan::class.java, "<s>", "</s>")
|
||||||
.replace("</sup><sup>", "")
|
.replaceSpan(SubscriptSpan::class.java, "<sub>", "</sub>")
|
||||||
.replace("p style=\"margin-top:0; margin-bottom:0;\"", "p")
|
.replaceSpan(SuperscriptSpan::class.java, "<sup>", "</sup>")
|
||||||
.replace("<br></p>", "</p><br>")
|
.toString()
|
||||||
// replace multiple newlines so they convert fromHtml correctly
|
MARKDOWN -> spanned
|
||||||
// this should not be breaking with htmlCompatibleMode == true,
|
.replaceSpan(BoldSpan::class.java, "**", "**")
|
||||||
// as line breaks cannot occur inside paragraphs with these flags
|
.replaceSpan(ItalicSpan::class.java, "_", "_")
|
||||||
.replace(paragraphBrRegex, "</p>$1")
|
.replaceSpan(UnderlineSpan::class.java, "__", "__")
|
||||||
|
.replaceSpan(StrikethroughSpan::class.java, "~~", "~~")
|
||||||
|
.toString()
|
||||||
|
else -> HtmlCompat.toHtml(spanned, toHtmlFlag)
|
||||||
|
.replace("\n", "")
|
||||||
|
.replace(" dir=\"ltr\"", "")
|
||||||
|
.replace("</b><b>", "")
|
||||||
|
.replace("</i><i>", "")
|
||||||
|
.replace("</u><u>", "")
|
||||||
|
.replace("</sub><sub>", "")
|
||||||
|
.replace("</sup><sup>", "")
|
||||||
|
.replace("p style=\"margin-top:0; margin-bottom:0;\"", "p")
|
||||||
|
.replace("<br></p>", "</p><br>")
|
||||||
|
// replace multiple newlines so they convert fromHtml correctly
|
||||||
|
// this should not be breaking with htmlCompatibleMode == true,
|
||||||
|
// as line breaks cannot occur inside paragraphs with these flags
|
||||||
|
.replace(paragraphBrRegex, "</p>$1")
|
||||||
|
}
|
||||||
|
|
||||||
config.watchSelectionChanged = true
|
config.watchSelectionChanged = true
|
||||||
|
|
||||||
if (htmlCompatibleMode) {
|
if (htmlMode == COMPATIBLE) {
|
||||||
textHtml = textHtml
|
textHtml = textHtml
|
||||||
.replace("<br>", "<p> </p>")
|
.replace("<br>", "<p> </p>")
|
||||||
.replace("<b>", "<strong>")
|
.replace("<b>", "<strong>")
|
||||||
@ -147,7 +206,7 @@ class TextStylingManager(private val app: App) {
|
|||||||
private fun onStyleChecked(
|
private fun onStyleChecked(
|
||||||
config: StylingConfig,
|
config: StylingConfig,
|
||||||
style: StylingConfig.Style,
|
style: StylingConfig.Style,
|
||||||
isChecked: Boolean
|
isChecked: Boolean,
|
||||||
) {
|
) {
|
||||||
if (!config.watchStyleChecked)
|
if (!config.watchStyleChecked)
|
||||||
return
|
return
|
||||||
|
@ -164,7 +164,6 @@
|
|||||||
android:id="@+id/topic"
|
android:id="@+id/topic"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@{event.topic}"
|
|
||||||
android:textAppearance="@style/NavView.TextView.Medium"
|
android:textAppearance="@style/NavView.TextView.Medium"
|
||||||
android:textIsSelectable="true"
|
android:textIsSelectable="true"
|
||||||
tools:text="Rozdział II: Panowanie Piastów i Jagiellonów.Przeniesiony z 11 grudnia." />
|
tools:text="Rozdział II: Panowanie Piastów i Jagiellonów.Przeniesiony z 11 grudnia." />
|
||||||
@ -190,7 +189,6 @@
|
|||||||
android:id="@+id/body"
|
android:id="@+id/body"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@{event.homeworkBody}"
|
|
||||||
android:textAppearance="@style/NavView.TextView.Medium"
|
android:textAppearance="@style/NavView.TextView.Medium"
|
||||||
android:textIsSelectable="true"
|
android:textIsSelectable="true"
|
||||||
tools:text="Rozdział II: Panowanie Piastów i Jagiellonów.Przeniesiony z 11 grudnia." />
|
tools:text="Rozdział II: Panowanie Piastów i Jagiellonów.Przeniesiony z 11 grudnia." />
|
||||||
|
@ -118,11 +118,14 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/topicLayout"
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
||||||
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:hint="@string/dialog_event_manual_topic">
|
android:hint="@string/dialog_event_manual_topic"
|
||||||
|
app:endIconMode="custom"
|
||||||
|
tools:endIconDrawable="@android:drawable/ic_menu_crop">
|
||||||
|
|
||||||
<pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
<pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
||||||
android:id="@+id/topic"
|
android:id="@+id/topic"
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<data>
|
<data>
|
||||||
<import type="android.view.View" />
|
<import type="android.view.View" />
|
||||||
<import type="androidx.core.text.HtmlCompat" />
|
<import type="pl.szczodrzynski.edziennik.utils.html.BetterHtml" />
|
||||||
<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" />
|
||||||
@ -43,7 +43,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="@{HtmlCompat.fromHtml(message.title, HtmlCompat.FROM_HTML_MODE_LEGACY)}"
|
android:text="@{BetterHtml.fromHtml(context, message.title, false)}"
|
||||||
android:textAppearance="@style/NavView.TextView.Title"
|
android:textAppearance="@style/NavView.TextView.Title"
|
||||||
tools:text="Dziennik nie działa" />
|
tools:text="Dziennik nie działa" />
|
||||||
|
|
||||||
@ -52,7 +52,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="@{HtmlCompat.fromHtml(message.contentLong, HtmlCompat.FROM_HTML_MODE_LEGACY)}"
|
android:text="@{BetterHtml.fromHtml(context, message.contentLong, false)}"
|
||||||
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
|
||||||
|
@ -95,7 +95,7 @@
|
|||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<com.mikepenz.iconics.view.IconicsTextView
|
||||||
android:id="@+id/addedBy"
|
android:id="@+id/addedBy"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -2,202 +2,106 @@
|
|||||||
<!--
|
<!--
|
||||||
~ Copyright (c) Kuba Szczodrzyński 2019-12-22.
|
~ Copyright (c) Kuba Szczodrzyński 2019-12-22.
|
||||||
-->
|
-->
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<data>
|
<LinearLayout
|
||||||
|
|
||||||
<import type="com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial" />
|
|
||||||
</data>
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
<LinearLayout
|
android:paddingBottom="40dp"><!-- half of the FAB's size -->
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/recipientsLayout"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
app:boxBackgroundColor="@android:color/transparent"
|
||||||
android:paddingBottom="40dp"><!-- half of the FAB's size -->
|
app:boxBackgroundMode="filled"
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
app:endIconDrawable="@drawable/dropdown_arrow"
|
||||||
android:id="@+id/recipientsLayout"
|
app:endIconMode="custom">
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense"
|
|
||||||
|
<com.hootsuite.nachos.NachoTextView
|
||||||
|
android:id="@+id/recipients"
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputEditText.FilledBox.Dense"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:boxBackgroundColor="@android:color/transparent"
|
android:focusable="true"
|
||||||
app:boxBackgroundMode="filled"
|
android:focusableInTouchMode="true"
|
||||||
app:endIconDrawable="@drawable/dropdown_arrow"
|
android:focusedByDefault="true"
|
||||||
app:endIconMode="custom">
|
android:hint="@string/messages_compose_to_hint" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<com.hootsuite.nachos.NachoTextView
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/recipients"
|
android:id="@+id/subjectLayout"
|
||||||
style="@style/Widget.MaterialComponents.TextInputEditText.FilledBox.Dense"
|
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:focusable="true"
|
app:boxBackgroundColor="@android:color/transparent"
|
||||||
android:focusableInTouchMode="true"
|
app:boxBackgroundMode="filled"
|
||||||
android:focusedByDefault="true"
|
app:counterEnabled="true"
|
||||||
android:hint="@string/messages_compose_to_hint" />
|
tools:counterMaxLength="180">
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
||||||
android:id="@+id/subjectLayout"
|
android:id="@+id/subject"
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox"
|
style="@style/Widget.MaterialComponents.TextInputEditText.FilledBox"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:boxBackgroundColor="@android:color/transparent"
|
android:focusable="true"
|
||||||
app:boxBackgroundMode="filled"
|
android:focusableInTouchMode="true"
|
||||||
app:counterEnabled="true"
|
android:hint="@string/messages_compose_subject_hint"
|
||||||
tools:counterMaxLength="180">
|
android:inputType="textCapSentences|textAutoCorrect|textShortMessage|textAutoComplete|textEmailSubject"
|
||||||
|
android:singleLine="true"
|
||||||
|
tools:text="kachoomba" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/subject"
|
android:id="@+id/textLayout"
|
||||||
style="@style/Widget.MaterialComponents.TextInputEditText.FilledBox"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
app:boxBackgroundColor="@android:color/transparent"
|
||||||
android:focusable="true"
|
app:boxBackgroundMode="filled"
|
||||||
android:focusableInTouchMode="true"
|
app:counterEnabled="true"
|
||||||
android:hint="@string/messages_compose_subject_hint"
|
tools:counterMaxLength="1983">
|
||||||
android:inputType="textCapSentences|textAutoCorrect|textShortMessage|textAutoComplete|textEmailSubject"
|
|
||||||
android:singleLine="true"
|
|
||||||
tools:text="kachoomba" />
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
||||||
android:id="@+id/textLayout"
|
android:id="@+id/text"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:boxBackgroundColor="@android:color/transparent"
|
android:ems="10"
|
||||||
app:boxBackgroundMode="filled"
|
android:focusable="true"
|
||||||
app:counterEnabled="true"
|
android:focusableInTouchMode="true"
|
||||||
tools:counterMaxLength="1983">
|
android:gravity="start|top"
|
||||||
|
android:hint="@string/messages_compose_text_hint"
|
||||||
|
android:inputType="textMultiLine|textAutoCorrect|textLongMessage|textAutoComplete|textCapSentences"
|
||||||
|
android:minLines="3"
|
||||||
|
tools:text="Witam,\n\nchciałem przekazać bardzo ważną wiadomość.\nJest to cytat znanej osoby.\n\n"To jest tak, ale nie. Pamiętaj żeby oczywiście"\n\nCytat ma bardzo duże przesłanie i ogromny wpływ na dzisiejszą kulturę i rozwój współczesnej cywilizacji.\n\nJako zadanie domowe, należy wypisać 5 pierwszych liczb pierwszych. Uzasadnij decyzję, odwołując się do cytatu i 3 innych przykładów z literatury lub filmu.\n\nPozdrawiam,\nJa." />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
<include
|
||||||
android:id="@+id/text"
|
android:id="@+id/fontStyle"
|
||||||
android:layout_width="match_parent"
|
layout="@layout/styled_text_buttons" />
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ems="10"
|
|
||||||
android:focusable="true"
|
|
||||||
android:focusableInTouchMode="true"
|
|
||||||
android:gravity="start|top"
|
|
||||||
android:hint="@string/messages_compose_text_hint"
|
|
||||||
android:inputType="textMultiLine|textAutoCorrect|textLongMessage|textAutoComplete|textCapSentences"
|
|
||||||
android:minLines="3"
|
|
||||||
tools:text="Witam,\n\nchciałem przekazać bardzo ważną wiadomość.\nJest to cytat znanej osoby.\n\n"To jest tak, ale nie. Pamiętaj żeby oczywiście"\n\nCytat ma bardzo duże przesłanie i ogromny wpływ na dzisiejszą kulturę i rozwój współczesnej cywilizacji.\n\nJako zadanie domowe, należy wypisać 5 pierwszych liczb pierwszych. Uzasadnij decyzję, odwołując się do cytatu i 3 innych przykładów z literatury lub filmu.\n\nPozdrawiam,\nJa." />
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<Button
|
||||||
android:id="@+id/fontStyleLayout"
|
android:id="@+id/breakpoints"
|
||||||
android:layout_width="wrap_content"
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical">
|
android:layout_marginHorizontal="8dp"
|
||||||
|
android:text="Breakpoints!"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButtonToggleGroup
|
<TextView
|
||||||
android:id="@+id/fontStyle"
|
android:id="@+id/textHtml"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="8dp">
|
android:layout_margin="8dp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
<com.google.android.material.button.MaterialButton
|
android:visibility="gone"
|
||||||
android:id="@+id/fontStyleBold"
|
tools:text="<p>Witam,</p>To jest bardzo długi tekst żeby sprawdzić ok działa"
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
tools:visibility="visible" />
|
||||||
android:layout_width="wrap_content"
|
</LinearLayout>
|
||||||
android:layout_height="wrap_content"
|
</ScrollView>
|
||||||
android:fontFamily="@font/community_material_font_v5_8_55"
|
|
||||||
android:minWidth="48dp"
|
|
||||||
android:textSize="20sp"
|
|
||||||
app:iconPadding="0dp"
|
|
||||||
tools:text="\uf674" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fontStyleItalic"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="@font/community_material_font_v5_8_55"
|
|
||||||
android:minWidth="48dp"
|
|
||||||
android:textSize="20sp"
|
|
||||||
app:iconPadding="0dp"
|
|
||||||
tools:text="\uf691" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fontStyleUnderline"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="@font/community_material_font_v5_8_55"
|
|
||||||
android:minWidth="48dp"
|
|
||||||
android:textSize="20sp"
|
|
||||||
app:iconPadding="0dp"
|
|
||||||
tools:text="\uf6c5" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fontStyleStrike"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="@font/community_material_font_v5_8_55"
|
|
||||||
android:minWidth="48dp"
|
|
||||||
android:textSize="20sp"
|
|
||||||
app:iconPadding="0dp"
|
|
||||||
tools:text="\uf6b1" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fontStyleSubscript"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="@font/community_material_font_v5_8_55"
|
|
||||||
android:minWidth="48dp"
|
|
||||||
android:textSize="20sp"
|
|
||||||
app:iconPadding="0dp"
|
|
||||||
tools:text="\uf6b2" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fontStyleSuperscript"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:fontFamily="@font/community_material_font_v5_8_55"
|
|
||||||
android:minWidth="48dp"
|
|
||||||
android:textSize="20sp"
|
|
||||||
app:iconPadding="0dp"
|
|
||||||
tools:text="\uf6b3" />
|
|
||||||
</com.google.android.material.button.MaterialButtonToggleGroup>
|
|
||||||
|
|
||||||
<!-- TODO 2021-10-05: stack the group and button on top -->
|
|
||||||
<!-- android:layout_marginTop="-13dp" -->
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/fontStyleClear"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="8dp"
|
|
||||||
android:text="@string/messages_compose_style_clear" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/breakpoints"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="8dp"
|
|
||||||
android:text="Breakpoints!"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textHtml"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="8dp"
|
|
||||||
android:fontFamily="monospace"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:text="<p>Witam,</p>To jest bardzo długi tekst żeby sprawdzić ok działa"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
</layout>
|
|
||||||
|
99
app/src/main/res/layout/styled_text_buttons.xml
Normal file
99
app/src/main/res/layout/styled_text_buttons.xml
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (c) Kuba Szczodrzyński 2021-10-11.
|
||||||
|
-->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
|
android:id="@+id/styles"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="8dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/bold"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/community_material_font_v5_8_55"
|
||||||
|
android:minWidth="48dp"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:iconPadding="0dp"
|
||||||
|
tools:text="\uf674" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/italic"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/community_material_font_v5_8_55"
|
||||||
|
android:minWidth="48dp"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:iconPadding="0dp"
|
||||||
|
tools:text="\uf691" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/underline"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/community_material_font_v5_8_55"
|
||||||
|
android:minWidth="48dp"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:iconPadding="0dp"
|
||||||
|
tools:text="\uf6c5" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/strike"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/community_material_font_v5_8_55"
|
||||||
|
android:minWidth="48dp"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:iconPadding="0dp"
|
||||||
|
tools:text="\uf6b1" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/subscript"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/community_material_font_v5_8_55"
|
||||||
|
android:minWidth="48dp"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:iconPadding="0dp"
|
||||||
|
tools:text="\uf6b2" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/superscript"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/community_material_font_v5_8_55"
|
||||||
|
android:minWidth="48dp"
|
||||||
|
android:textSize="20sp"
|
||||||
|
app:iconPadding="0dp"
|
||||||
|
tools:text="\uf6b3" />
|
||||||
|
</com.google.android.material.button.MaterialButtonToggleGroup>
|
||||||
|
</HorizontalScrollView>
|
||||||
|
<!-- TODO 2021-10-05: stack the group and button on top -->
|
||||||
|
<!-- android:layout_marginTop="-13dp" -->
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/clear"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="8dp"
|
||||||
|
android:text="@string/styled_text_clear_button" />
|
||||||
|
</LinearLayout>
|
46
app/src/main/res/layout/styled_text_dialog.xml
Normal file
46
app/src/main/res/layout/styled_text_dialog.xml
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (c) Kuba Szczodrzyński 2021-10-11.
|
||||||
|
-->
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="24dp">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="250dp"
|
||||||
|
app:counterEnabled="true">
|
||||||
|
|
||||||
|
<pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
||||||
|
android:id="@+id/editText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="top"
|
||||||
|
android:inputType="textMultiLine|textAutoCorrect|textLongMessage|textAutoComplete|textCapSentences"
|
||||||
|
android:minLines="10"
|
||||||
|
tools:text="Witam,\n\nchciałem przekazać bardzo ważną wiadomość.\nJest to cytat znanej osoby.\n\n"To jest tak, ale nie. Pamiętaj żeby oczywiście"\n\nCytat ma bardzo duże przesłanie i ogromny wpływ na dzisiejszą kulturę i rozwój współczesnej cywilizacji.\n\nJako zadanie domowe, należy wypisać 5 pierwszych liczb pierwszych. Uzasadnij decyzję, odwołując się do cytatu i 3 innych przykładów z literatury lub filmu.\n\nPozdrawiam,\nJa." />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/fontStyle"
|
||||||
|
layout="@layout/styled_text_buttons" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/htmlText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:visibility="gone" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
@ -1470,7 +1470,7 @@
|
|||||||
<string name="hint_style_strike">Przekreślenie</string>
|
<string name="hint_style_strike">Przekreślenie</string>
|
||||||
<string name="hint_style_subscript">Indeks dolny</string>
|
<string name="hint_style_subscript">Indeks dolny</string>
|
||||||
<string name="hint_style_superscript">Indeks górny</string>
|
<string name="hint_style_superscript">Indeks górny</string>
|
||||||
<string name="messages_compose_style_clear">Wyczyść format</string>
|
<string name="styled_text_clear_button">Wyczyść format</string>
|
||||||
<string name="hint_message_star">Oznacz gwiazdką</string>
|
<string name="hint_message_star">Oznacz gwiazdką</string>
|
||||||
<string name="message_forward">Przekaż dalej</string>
|
<string name="message_forward">Przekaż dalej</string>
|
||||||
<string name="message_delete">Usuń</string>
|
<string name="message_delete">Usuń</string>
|
||||||
@ -1491,4 +1491,5 @@
|
|||||||
<string name="messages_compose_discard_draft_text">Czy chcesz odrzucić zapisaną wersję wiadomości? Spowoduje to również anulowanie wprowadzonych zmian i usunięcie wiadomości.</string>
|
<string name="messages_compose_discard_draft_text">Czy chcesz odrzucić zapisaną wersję wiadomości? Spowoduje to również anulowanie wprowadzonych zmian i usunięcie wiadomości.</string>
|
||||||
<string name="login_mobidziennik_server_prefix">https://</string>
|
<string name="login_mobidziennik_server_prefix">https://</string>
|
||||||
<string name="login_mobidziennik_server_suffix">.mobidziennik.pl/</string>
|
<string name="login_mobidziennik_server_suffix">.mobidziennik.pl/</string>
|
||||||
|
<string name="styled_text_dialog_title">Edytuj tekst</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user