Pith - wedge_android
wedge_android/app/src/main/java/com/vgmlr/wedge/WedgeWidgetService.kt [6.1 kb]
Modified: 00:00:27 153 026 (19 Aug 026)
5 Days Ago
package com.vgmlr.wedge

import android.content.Context
import android.content.Intent
import android.graphics.Color as AndroidColor
import android.graphics.Typeface
import android.os.Build
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.BackgroundColorSpan
import android.text.style.ForegroundColorSpan
import android.text.style.StrikethroughSpan
import android.text.style.StyleSpan
import android.text.style.UnderlineSpan
import android.util.TypedValue
import android.widget.RemoteViews
import android.widget.RemoteViewsService
import androidx.core.graphics.toColorInt
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking

class WedgeWidgetService : RemoteViewsService() {
    override fun onGetViewFactory(intent: Intent): RemoteViewsFactory {
        return WedgeWidgetFactory(applicationContext)
    }
}

class WedgeWidgetFactory(private val context: Context) : RemoteViewsService.RemoteViewsFactory {
    private var noteContent: String = ""
    private var textColor: String = WedgeConfig.WIDGET_TEXT_COLOR_DEFAULT
    private var fontSize: Float = WedgeConfig.WIDGET_FONT_SIZE_DEFAULT
    private var lineHeight: Float = WedgeConfig.LINE_HEIGHT_DEFAULT
    private var boldColor: String = WedgeConfig.BOLD_COLOR_DEFAULT
    private var widgetNextTimeBg: String = WedgeConfig.WIDGET_CALENDAR_COLOR_DEFAULT
    private var headerFormat: String = WedgeConfig.HEADER_FORMAT_DEFAULT

    override fun onCreate() {}

    override fun onDataSetChanged() {
        runBlocking {
            val db = AppDatabase.getInstance(context)
            val prefs = PreferenceManager(context)
            noteContent = db.noteDao().getNoteSync()?.content ?: ""
            textColor = prefs.widgetTextColor.first()
            fontSize = prefs.widgetFontSize.first()
            lineHeight = prefs.lineHeight.first()
            boldColor = prefs.widgetBoldColor.first()
            widgetNextTimeBg = prefs.widgetNextTimeBg.first()
            headerFormat = prefs.headerFormat.first()
        }
    }

    override fun onDestroy() {}
    override fun getCount(): Int = 1
    override fun getLoadingView(): RemoteViews? = null
    override fun getViewTypeCount(): Int = 1
    override fun getItemId(position: Int): Long = position.toLong()
    override fun hasStableIds(): Boolean = true

    override fun getViewAt(position: Int): RemoteViews {
        onDataSetChanged()
        val views = RemoteViews(context.packageName, R.layout.widget_item)

        val spannable = SpannableStringBuilder(noteContent)
        WedgeRegex.BOLD_LINE.findAll(noteContent).forEach { match ->
            spannable.setSpan(StyleSpan(Typeface.BOLD), match.range.first, match.range.last + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
            try {
                spannable.setSpan(ForegroundColorSpan(boldColor.toColorInt()), match.range.first, match.range.last + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
            } catch (_: Exception) {}
        }

        WedgeRegex.ITALIC_LINE.findAll(noteContent).forEach { match ->
            spannable.setSpan(StyleSpan(Typeface.ITALIC), match.range.first, match.range.last + 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
        }

        WedgeRegex.UNDERLINE_LINE.findAll(noteContent).forEach { match ->
            val contentGroup = match.groups[1]
            if (contentGroup != null) {
                try {
                    spannable.setSpan(
                        UnderlineSpan(),
                        contentGroup.range.first,
                        contentGroup.range.last + 1,
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                    )
                } catch (_: Exception) {}
            }
        }

        val nextTimeOffset = WedgeEditorEngine.findNextTimeHighlight(noteContent, headerFormat)
        if (nextTimeOffset != null && nextTimeOffset >= 0 && nextTimeOffset < noteContent.length) {
            val endLine = noteContent.indexOf('\n', nextTimeOffset)
            val endOffset = if (endLine == -1) noteContent.length else endLine
            try {
                spannable.setSpan(
                    BackgroundColorSpan(widgetNextTimeBg.toColorInt()),
                    nextTimeOffset,
                    endOffset,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                )
            } catch (_: Exception) {}
        }

        WedgeRegex.STRIKE_LINE.findAll(noteContent).forEach { match ->
            val contentGroup = match.groups[1]
            if (contentGroup != null) {
                try {
                    spannable.setSpan(
                        StrikethroughSpan(),
                        contentGroup.range.first,
                        contentGroup.range.last + 1,
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                    )
                } catch (_: Exception) {}
            }
        }

        WedgeRegex.COMMENT_LINE.findAll(noteContent).forEach { match ->
            try {
                val faded = (textColor.toColorInt() and 0x00FFFFFF) or (0x99 shl 24)
                spannable.setSpan(
                    ForegroundColorSpan(faded),
                    match.range.first,
                    match.range.last + 1,
                    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
                )
            } catch (_: Exception) {}
        }
        
        views.setTextViewText(R.id.item_text, spannable)

        views.setOnClickFillInIntent(R.id.item_text, Intent())

        try {
            views.setTextColor(R.id.item_text, textColor.toColorInt())
        } catch (_: Exception) {
            views.setTextColor(R.id.item_text, AndroidColor.WHITE)
        }

        views.setTextViewTextSize(R.id.item_text, TypedValue.COMPLEX_UNIT_SP, fontSize)

        if (Build.VERSION.SDK_INT >= 31) {
            try {
                val method = RemoteViews::class.java.getMethod(
                    "setLineSpacing",
                    Int::class.javaPrimitiveType,
                    Float::class.javaPrimitiveType,
                    Float::class.javaPrimitiveType
                )
                method.invoke(views, R.id.item_text, 0f, lineHeight)
            } catch (_: Exception) {}
        }

        return views
    }
}
Updates
Kerf - Android 157.026
Kiln - Android 157.026
Wedge - Android 156.026
Whittle - Linux 155.026
Grit - Firefox/Chrome 154.026

Menu
Calendar
Project Tin (024/029)
Miter
RSS Feed
User Avatar
@vgmlr
=SUM(parts)
0.00312
256,991 (+245)