aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2021-04-17 18:59:06 -0700
committerAllan Wang <me@allanwang.ca>2021-04-17 18:59:06 -0700
commite1ae3536102a5bb83a3c73c3731eb4af56b96914 (patch)
treec28d7a68359bd4c939cd311768c12454117bb921
parent7a2026fb3f0342bf42824cb1b7d53f27730e8b01 (diff)
downloadfrost-e1ae3536102a5bb83a3c73c3731eb4af56b96914.tar.gz
frost-e1ae3536102a5bb83a3c73c3731eb4af56b96914.tar.bz2
frost-e1ae3536102a5bb83a3c73c3731eb4af56b96914.zip
Inject activity themer
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt7
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt3
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt9
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt18
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt3
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt3
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt7
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt54
12 files changed, 83 insertions, 53 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt
index 5b2544c9..36e44936 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt
@@ -24,7 +24,7 @@ import com.pitchedapps.frost.contracts.VideoViewHolder
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
-import com.pitchedapps.frost.utils.setFrostTheme
+import com.pitchedapps.frost.utils.ActivityThemer
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@@ -43,6 +43,9 @@ abstract class BaseActivity : KauBaseActivity() {
@Inject
lateinit var themeProvider: ThemeProvider
+ @Inject
+ lateinit var activityThemer: ActivityThemer
+
/**
* Inherited consumer to customize back press
*/
@@ -57,7 +60,7 @@ abstract class BaseActivity : KauBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- if (this !is WebOverlayActivityBase) setFrostTheme(themeProvider)
+ if (this !is WebOverlayActivityBase) activityThemer.setFrostTheme()
}
override fun onStop() {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt
index 51f4732a..19e54f68 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt
@@ -122,7 +122,6 @@ import com.pitchedapps.frost.utils.frostNavigationBar
import com.pitchedapps.frost.utils.launchLogin
import com.pitchedapps.frost.utils.launchNewTask
import com.pitchedapps.frost.utils.launchWebOverlay
-import com.pitchedapps.frost.utils.setFrostColors
import com.pitchedapps.frost.utils.urlEncode
import com.pitchedapps.frost.views.BadgedIcon
import com.pitchedapps.frost.views.FrostVideoViewer
@@ -219,7 +218,7 @@ abstract class BaseMainActivity :
}
drawerWrapperBinding.mainContainer.addView(contentBinding.root)
with(contentBinding) {
- setFrostColors {
+ activityThemer.setFrostColors {
toolbar(toolbar)
themeWindow = false
header(appbar)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt
index 0d762241..4b5180d7 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt
@@ -31,19 +31,21 @@ import com.pitchedapps.frost.databinding.ActivityDebugBinding
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.injectors.JsActions
import com.pitchedapps.frost.injectors.ThemeProvider
+import com.pitchedapps.frost.utils.ActivityThemer
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.createFreshDir
-import com.pitchedapps.frost.utils.setFrostColors
+import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineExceptionHandler
import org.koin.android.ext.android.inject
-import org.koin.core.component.inject
import java.io.File
+import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
/**
* Created by Allan Wang on 05/01/18.
*/
+@AndroidEntryPoint
class DebugActivity : KauBaseActivity() {
companion object {
@@ -53,6 +55,9 @@ class DebugActivity : KauBaseActivity() {
fun baseDir(context: Context) = File(context.externalCacheDir, "offline_debug")
}
+ @Inject
+ lateinit var activityThemer: ActivityThemer
+
private val themeProvider: ThemeProvider by inject()
lateinit var binding: ActivityDebugBinding
@@ -72,7 +77,7 @@ class DebugActivity : KauBaseActivity() {
}
setTitle(R.string.debug_frost)
- setFrostColors {
+ activityThemer.setFrostColors {
toolbar(toolbar)
}
debugWebview.loadUrl(FbItem.FEED.url)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
index c85a7472..bcb43299 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
@@ -61,12 +61,12 @@ import com.pitchedapps.frost.services.LocalService
import com.pitchedapps.frost.utils.ARG_COOKIE
import com.pitchedapps.frost.utils.ARG_IMAGE_URL
import com.pitchedapps.frost.utils.ARG_TEXT
+import com.pitchedapps.frost.utils.ActivityThemer
import com.pitchedapps.frost.utils.frostDownload
import com.pitchedapps.frost.utils.frostSnackbar
import com.pitchedapps.frost.utils.frostUriFromFile
import com.pitchedapps.frost.utils.isIndirectImageUrl
import com.pitchedapps.frost.utils.logFrostEvent
-import com.pitchedapps.frost.utils.setFrostColors
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
@@ -74,10 +74,10 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.inject
-import org.koin.core.component.inject
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
+import javax.inject.Inject
import kotlin.math.abs
import kotlin.math.max
@@ -86,6 +86,9 @@ import kotlin.math.max
*/
class ImageActivity : KauBaseActivity() {
+ @Inject
+ lateinit var activityThemer: ActivityThemer
+
private val prefs: Prefs by inject()
private val themeProvider: ThemeProvider by inject()
@@ -224,7 +227,7 @@ class ImageActivity : KauBaseActivity() {
loadError(e)
}
})
- setFrostColors {
+ activityThemer.setFrostColors {
themeWindow = false
}
dragHelper = ViewDragHelper.create(imageDrag, ViewDragCallback()).apply {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt
index be31208b..8fd45ab8 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt
@@ -48,14 +48,16 @@ import com.pitchedapps.frost.intro.IntroFragmentWelcome
import com.pitchedapps.frost.intro.IntroTabContextFragment
import com.pitchedapps.frost.intro.IntroTabTouchFragment
import com.pitchedapps.frost.prefs.Prefs
+import com.pitchedapps.frost.utils.ActivityThemer
import com.pitchedapps.frost.utils.cookies
import com.pitchedapps.frost.utils.launchNewTask
import com.pitchedapps.frost.utils.loadAssets
-import com.pitchedapps.frost.utils.setFrostTheme
import com.pitchedapps.frost.widgets.NotificationWidget
+import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
+import javax.inject.Inject
/**
* Created by Allan Wang on 2017-07-25.
@@ -63,6 +65,7 @@ import org.koin.android.ext.android.inject
* A beautiful intro activity
* Phone showcases are drawn via layers
*/
+@AndroidEntryPoint
class IntroActivity :
KauBaseActivity(),
ViewPager.PageTransformer,
@@ -70,6 +73,10 @@ class IntroActivity :
private val prefs: Prefs by inject()
private val themeProvider: ThemeProvider by inject()
+
+ @Inject
+ lateinit var activityThemer: ActivityThemer
+
lateinit var binding: ActivityIntroBinding
private var barHasNext = true
@@ -116,7 +123,7 @@ class IntroActivity :
indicator.invalidate()
}
fragments.forEach { it.themeFragment() }
- setFrostTheme(themeProvider, true)
+ activityThemer.setFrostTheme(forceTransparent = true)
}
/**
@@ -159,7 +166,12 @@ class IntroActivity :
if (f != null)
ValueAnimator.ofFloat(0f, 1f).apply {
addUpdateListener {
- f.setTint(themeProvider.textColor.blendWith(Color.WHITE, it.animatedValue as Float))
+ f.setTint(
+ themeProvider.textColor.blendWith(
+ Color.WHITE,
+ it.animatedValue as Float
+ )
+ )
}
duration = 600
start()
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt
index 33913cc3..72d17eb7 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt
@@ -45,7 +45,6 @@ import com.pitchedapps.frost.utils.frostEvent
import com.pitchedapps.frost.utils.frostJsoup
import com.pitchedapps.frost.utils.launchNewTask
import com.pitchedapps.frost.utils.logFrostEvent
-import com.pitchedapps.frost.utils.setFrostColors
import com.pitchedapps.frost.utils.uniqueOnly
import com.pitchedapps.frost.web.LoginWebView
import kotlinx.coroutines.Dispatchers
@@ -80,7 +79,7 @@ class LoginActivity : BaseActivity() {
setContentView(R.layout.activity_login)
setSupportActionBar(toolbar)
setTitle(R.string.kau_login)
- setFrostColors {
+ activityThemer.setFrostColors {
toolbar(toolbar)
}
profileLoader = GlideApp.with(profile)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt
index 33215c7e..f2e00aae 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt
@@ -29,7 +29,6 @@ import com.mikepenz.fastadapter.listeners.ClickEventHook
import com.pitchedapps.frost.R
import com.pitchedapps.frost.utils.cookies
import com.pitchedapps.frost.utils.launchNewTask
-import com.pitchedapps.frost.utils.setFrostColors
import com.pitchedapps.frost.views.AccountItem
import kotlinx.coroutines.launch
@@ -67,7 +66,7 @@ class SelectorActivity : BaseActivity() {
}
}
})
- setFrostColors {
+ activityThemer.setFrostColors {
text(text)
background(container)
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
index 6bdbb68d..bce3aa48 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
@@ -49,6 +49,7 @@ import com.pitchedapps.frost.settings.getFeedPrefs
import com.pitchedapps.frost.settings.getNotificationPrefs
import com.pitchedapps.frost.settings.getSecurityPrefs
import com.pitchedapps.frost.settings.sendDebug
+import com.pitchedapps.frost.utils.ActivityThemer
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.REQUEST_REFRESH
import com.pitchedapps.frost.utils.REQUEST_RESTART
@@ -57,7 +58,6 @@ import com.pitchedapps.frost.utils.frostChangelog
import com.pitchedapps.frost.utils.frostNavigationBar
import com.pitchedapps.frost.utils.launchNewTask
import com.pitchedapps.frost.utils.loadAssets
-import com.pitchedapps.frost.utils.setFrostTheme
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
@@ -81,6 +81,9 @@ class SettingsActivity : KPrefActivity() {
@Inject
lateinit var notifDao: NotificationDao
+ @Inject
+ lateinit var activityThemer: ActivityThemer
+
private var resultFlag = Activity.RESULT_CANCELED
companion object {
@@ -230,7 +233,7 @@ class SettingsActivity : KPrefActivity() {
@SuppressLint("MissingSuperCall")
override fun onCreate(savedInstanceState: Bundle?) {
- setFrostTheme(themeProvider, true)
+ activityThemer.setFrostTheme(forceTransparent = true)
super.onCreate(savedInstanceState)
animate = prefs.animate
themeExterior(false)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt
index 4c85a084..adf543df 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt
@@ -42,18 +42,20 @@ import com.pitchedapps.frost.db.saveTabs
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.iitems.TabIItem
import com.pitchedapps.frost.utils.L
-import com.pitchedapps.frost.utils.setFrostColors
+import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
-import org.koin.android.ext.android.inject
import java.util.Collections
+import javax.inject.Inject
/**
* Created by Allan Wang on 26/11/17.
*/
+@AndroidEntryPoint
class TabCustomizerActivity : BaseActivity() {
- private val genericDao: GenericDao by inject()
+ @Inject
+ lateinit var genericDao: GenericDao
private val adapter = FastItemAdapter<TabIItem>()
@@ -107,7 +109,7 @@ class TabCustomizerActivity : BaseActivity() {
fabCancel.setIcon(GoogleMaterial.Icon.gmd_close, themeProvider.iconColor)
fabCancel.backgroundTintList = ColorStateList.valueOf(themeProvider.accentColor)
fabCancel.setOnClickListener { finish() }
- setFrostColors {
+ activityThemer.setFrostColors {
themeWindow = true
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt
index 6642eb7d..3ae3aef0 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt
@@ -67,7 +67,6 @@ import com.pitchedapps.frost.utils.ARG_USER_ID
import com.pitchedapps.frost.utils.BiometricUtils
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.frostSnackbar
-import com.pitchedapps.frost.utils.setFrostColors
import com.pitchedapps.frost.views.FrostContentWeb
import com.pitchedapps.frost.views.FrostVideoViewer
import com.pitchedapps.frost.views.FrostWebView
@@ -205,10 +204,11 @@ abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT
setSupportActionBar(toolbar)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
- toolbar.navigationIcon = GoogleMaterial.Icon.gmd_close.toDrawable(this, 16, themeProvider.iconColor)
+ toolbar.navigationIcon =
+ GoogleMaterial.Icon.gmd_close.toDrawable(this, 16, themeProvider.iconColor)
toolbar.setNavigationOnClickListener { finishSlideOut() }
- setFrostColors {
+ activityThemer.setFrostColors {
toolbar(toolbar)
themeWindow = false
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
index bfa59a4f..e99d7a2c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
@@ -33,7 +33,6 @@ import com.pitchedapps.frost.utils.frostEvent
import com.pitchedapps.frost.utils.frostNavigationBar
import com.pitchedapps.frost.utils.frostSnackbar
import com.pitchedapps.frost.utils.launchTabCustomizerActivity
-import com.pitchedapps.frost.utils.setFrostTheme
import com.pitchedapps.frost.views.KPrefTextSeekbar
/**
@@ -55,7 +54,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
item.pref = index
shouldRestartMain()
reload()
- setFrostTheme(themeProvider, true)
+ activityThemer.setFrostTheme(forceTransparent = true)
themeExterior()
invalidateOptionsMenu()
frostEvent("Theme", "Count" to Theme(index).name)
@@ -110,7 +109,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
prefs.customBackgroundColor = it
bgCanvas.ripple(it, duration = 500L)
invalidateCustomTheme()
- setFrostTheme(themeProvider, true)
+ activityThemer.setFrostTheme(forceTransparent = true)
shouldRestartMain()
}
) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
index ccc04145..73572a44 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
@@ -72,20 +72,20 @@ import com.pitchedapps.frost.facebook.formattedFbUrl
import com.pitchedapps.frost.injectors.JsAssets
import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
+import dagger.hilt.android.scopes.ActivityScoped
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import org.apache.commons.text.StringEscapeUtils
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
-import org.koin.core.component.KoinComponent
-import org.koin.core.component.inject
import java.io.File
import java.io.IOException
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import java.util.ArrayList
import java.util.Locale
+import javax.inject.Inject
/**
* Created by Allan Wang on 2017-06-03.
@@ -184,25 +184,37 @@ fun WebOverlayActivity.url(): String {
return intent.getStringExtra(ARG_URL) ?: FbItem.FEED.url
}
-fun Activity.setFrostTheme(themeProvider: ThemeProvider, forceTransparent: Boolean = false) {
- val isTransparent =
- forceTransparent || (Color.alpha(themeProvider.bgColor) != 255) || (
- Color.alpha(
- themeProvider.headerColor
- ) != 255
- )
- if (themeProvider.bgColor.isColorDark) {
- setTheme(if (isTransparent) R.style.FrostTheme_Transparent else R.style.FrostTheme)
- } else {
- setTheme(if (isTransparent) R.style.FrostTheme_Light_Transparent else R.style.FrostTheme_Light)
+@ActivityScoped
+class ActivityThemer @Inject constructor(
+ private val activity: Activity,
+ private val prefs: Prefs,
+ private val themeProvider: ThemeProvider
+) {
+ fun setFrostTheme(forceTransparent: Boolean = false) {
+ val isTransparent =
+ forceTransparent || (Color.alpha(themeProvider.bgColor) != 255) || (
+ Color.alpha(
+ themeProvider.headerColor
+ ) != 255
+ )
+ if (themeProvider.bgColor.isColorDark) {
+ activity.setTheme(if (isTransparent) R.style.FrostTheme_Transparent else R.style.FrostTheme)
+ } else {
+ activity.setTheme(if (isTransparent) R.style.FrostTheme_Light_Transparent else R.style.FrostTheme_Light)
+ }
}
-}
-
-class ActivityThemeUtils : KoinComponent {
- private val prefs: Prefs by inject()
- private val themeProvider: ThemeProvider by inject()
+ fun setFrostColors(builder: ActivityThemeUtils.() -> Unit) {
+ val themer = ActivityThemeUtils(prefs = prefs, themeProvider = themeProvider)
+ themer.builder()
+ themer.theme(activity)
+ }
+}
+class ActivityThemeUtils(
+ private val prefs: Prefs,
+ private val themeProvider: ThemeProvider
+) {
private var toolbar: Toolbar? = null
var themeWindow = true
private var texts = mutableListOf<TextView>()
@@ -240,12 +252,6 @@ class ActivityThemeUtils : KoinComponent {
}
}
-inline fun Activity.setFrostColors(builder: ActivityThemeUtils.() -> Unit) {
- val themer = ActivityThemeUtils()
- themer.builder()
- themer.theme(this)
-}
-
fun frostEvent(name: String, vararg events: Pair<String, Any>) {
// todo bind
L.v { "Event: $name ${events.joinToString(", ")}" }