diff --git a/README.md b/README.md
index 0b2dbff..d0328ee 100644
--- a/README.md
+++ b/README.md
@@ -57,15 +57,15 @@ Then add the following dependencies in your app `build.gradle` or `build.gradle.
**Groovy**
```groovy
-def sentinelVersion = "1.3.3"
+def sentinelVersion = "1.4.0"
debugImplementation "com.infinum.sentinel:sentinel:$sentinelVersion"
-releaseImplementation "com.infinum.sentinel:sentinel-noop:$sentinelVersion"
+releaseImplementation "com.infinum.sentinel:sentinel-no-op:$sentinelVersion"
```
**KotlinDSL**
```kotlin
-val sentinelVersion = "1.3.3"
+val sentinelVersion = "1.4.0"
debugImplementation("com.infinum.sentinel:sentinel:$sentinelVersion")
releaseImplementation("com.infinum.sentinel:sentinel-no-op:$sentinelVersion")
```
diff --git a/config.gradle b/config.gradle
index f1557fe..dfb8f51 100644
--- a/config.gradle
+++ b/config.gradle
@@ -1,7 +1,7 @@
ext {
def major = 1
- def minor = 3
- def patch = 3
+ def minor = 4
+ def patch = 0
buildConfig = [
"minSdk" : 21,
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 1dadde7..0ab73b9 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,5 +1,5 @@
[versions]
-sentinel = "1.3.3"
+sentinel = "1.4.0"
gradle = "8.3.2"
kotlin = "1.9.22"
coroutines = "1.8.0"
diff --git a/sentinel/src/main/AndroidManifest.xml b/sentinel/src/main/AndroidManifest.xml
index 5d3da56..61a5144 100644
--- a/sentinel/src/main/AndroidManifest.xml
+++ b/sentinel/src/main/AndroidManifest.xml
@@ -3,12 +3,17 @@
+
+
-
-
-
-
diff --git a/sentinel/src/main/kotlin/com/infinum/sentinel/data/models/raw/PreferencesData.kt b/sentinel/src/main/kotlin/com/infinum/sentinel/data/models/raw/PreferencesData.kt
index 627390d..16ac160 100644
--- a/sentinel/src/main/kotlin/com/infinum/sentinel/data/models/raw/PreferencesData.kt
+++ b/sentinel/src/main/kotlin/com/infinum/sentinel/data/models/raw/PreferencesData.kt
@@ -2,5 +2,7 @@ package com.infinum.sentinel.data.models.raw
internal data class PreferencesData(
val name: String,
- val values: List>
+ val values: List>,
+ val isSortedAscending: Boolean = false,
+ val isExpanded: Boolean = true,
)
diff --git a/sentinel/src/main/kotlin/com/infinum/sentinel/data/sources/raw/collectors/PreferencesCollector.kt b/sentinel/src/main/kotlin/com/infinum/sentinel/data/sources/raw/collectors/PreferencesCollector.kt
index 882f71c..b9660d7 100644
--- a/sentinel/src/main/kotlin/com/infinum/sentinel/data/sources/raw/collectors/PreferencesCollector.kt
+++ b/sentinel/src/main/kotlin/com/infinum/sentinel/data/sources/raw/collectors/PreferencesCollector.kt
@@ -29,6 +29,8 @@ internal class PreferencesCollector(
prefsDirectory.list().orEmpty().toList().map { it.removeSuffix(PREFS_SUFFIX) }
} else {
listOf()
+ }.sortedBy { name ->
+ name
}.map { name ->
val allPrefs = getSharedPreferences(name, MODE_PRIVATE).all
val tuples = allPrefs.keys.toSet().mapNotNull {
diff --git a/sentinel/src/main/kotlin/com/infinum/sentinel/di/LibraryComponents.kt b/sentinel/src/main/kotlin/com/infinum/sentinel/di/LibraryComponents.kt
index 72d71cb..68800d7 100644
--- a/sentinel/src/main/kotlin/com/infinum/sentinel/di/LibraryComponents.kt
+++ b/sentinel/src/main/kotlin/com/infinum/sentinel/di/LibraryComponents.kt
@@ -42,6 +42,7 @@ internal object LibraryComponents {
tools.filterIsInstance().firstOrNull()?.userCertificates.orEmpty(),
onTriggered
)
+ WorkManagerInitializer.init(domainComponent)
domainComponent.setup()
}
diff --git a/sentinel/src/main/kotlin/com/infinum/sentinel/di/WorkManagerInitializer.kt b/sentinel/src/main/kotlin/com/infinum/sentinel/di/WorkManagerInitializer.kt
new file mode 100644
index 0000000..49f278c
--- /dev/null
+++ b/sentinel/src/main/kotlin/com/infinum/sentinel/di/WorkManagerInitializer.kt
@@ -0,0 +1,14 @@
+package com.infinum.sentinel.di
+
+import com.infinum.sentinel.di.component.DomainComponent
+import com.infinum.sentinel.ui.certificates.observer.CertificateCheckWorker
+import com.infinum.sentinel.ui.certificates.observer.DelegateWorker
+import com.infinum.sentinel.ui.certificates.observer.SentinelWorkerFactory
+
+internal object WorkManagerInitializer {
+
+ fun init(domainComponent: DomainComponent) {
+ DelegateWorker.workerFactories[CertificateCheckWorker.NAME] =
+ SentinelWorkerFactory(domainComponent.collectors, domainComponent.notificationFactory)
+ }
+}
diff --git a/sentinel/src/main/kotlin/com/infinum/sentinel/di/component/DomainComponent.kt b/sentinel/src/main/kotlin/com/infinum/sentinel/di/component/DomainComponent.kt
index 2301cae..f994549 100644
--- a/sentinel/src/main/kotlin/com/infinum/sentinel/di/component/DomainComponent.kt
+++ b/sentinel/src/main/kotlin/com/infinum/sentinel/di/component/DomainComponent.kt
@@ -50,7 +50,6 @@ import com.infinum.sentinel.ui.bundles.callbacks.BundleMonitorNotificationCallba
import com.infinum.sentinel.ui.bundles.details.BundleDetailsActivity
import com.infinum.sentinel.ui.certificates.observer.CertificatesObserver
import com.infinum.sentinel.ui.certificates.observer.SentinelWorkManager
-import com.infinum.sentinel.ui.certificates.observer.SentinelWorkerFactory
import com.infinum.sentinel.ui.crash.anr.SentinelAnrObserver
import com.infinum.sentinel.ui.crash.anr.SentinelAnrObserverRunnable
import com.infinum.sentinel.ui.crash.anr.SentinelUiAnrObserver
@@ -91,8 +90,6 @@ internal abstract class DomainComponent(
abstract val sentinelAnrObserver: SentinelAnrObserver
- abstract val sentinelWorkerFactory: SentinelWorkerFactory
-
abstract val sentinelWorkManager: SentinelWorkManager
abstract val sentinelAnrObserverRunnable: SentinelAnrObserverRunnable
@@ -157,15 +154,10 @@ internal abstract class DomainComponent(
fun sentinelAnrObserverRunnable(dao: CrashesDao): SentinelAnrObserverRunnable =
SentinelAnrObserverRunnable(context, notificationFactory, dao)
- @Provides
- @DomainScope
- fun sentinelWorkerFactory(): SentinelWorkerFactory =
- SentinelWorkerFactory(collectors, notificationFactory)
-
@Provides
@DomainScope
fun sentinelWorkManager(): SentinelWorkManager =
- SentinelWorkManager(context, sentinelWorkerFactory)
+ SentinelWorkManager(context)
@Provides
@DomainScope
diff --git a/sentinel/src/main/kotlin/com/infinum/sentinel/ui/certificates/observer/DelegateWorker.kt b/sentinel/src/main/kotlin/com/infinum/sentinel/ui/certificates/observer/DelegateWorker.kt
new file mode 100644
index 0000000..318599d
--- /dev/null
+++ b/sentinel/src/main/kotlin/com/infinum/sentinel/ui/certificates/observer/DelegateWorker.kt
@@ -0,0 +1,54 @@
+package com.infinum.sentinel.ui.certificates.observer
+
+import android.content.Context
+import androidx.annotation.UiThread
+import androidx.work.ListenableWorker
+import androidx.work.WorkerFactory
+import androidx.work.WorkerParameters
+import com.google.common.util.concurrent.ListenableFuture
+import com.infinum.sentinel.ui.shared.Constants.Keys.WORKER_CLASS_NAME
+import com.infinum.sentinel.ui.shared.Constants.Keys.WORKER_ID
+
+/**
+ * A worker to delegate work requests from within the library to workers
+ * that require factories with custom dependencies.
+ */
+internal class DelegateWorker(
+ appContext: Context,
+ parameters: WorkerParameters,
+) : ListenableWorker(appContext, parameters) {
+
+ private val workerClassName =
+ parameters.inputData.getString(WORKER_CLASS_NAME) ?: ""
+ private val workerId = parameters.inputData.getString(WORKER_ID)
+ private val delegateWorkerFactory = workerFactories[workerId]
+ private val delegatedWorker = delegateWorkerFactory?.createWorker(appContext, workerClassName, parameters)
+
+ override fun startWork(): ListenableFuture {
+ return if (delegatedWorker != null) {
+ delegatedWorker.startWork()
+ } else {
+ val errorMessage = "No delegateWorker available for $workerId" +
+ " with workerClassName of $workerClassName. Is the " +
+ "DelegateWorker.workerFactories populated correctly?"
+ throw IllegalStateException(errorMessage)
+ }
+ }
+
+ companion object {
+ const val DELEGATE_WORKER_ID = "com.infinum.sentinel.ui.certificates.observer.CertificateCheckWorker"
+
+ val workerFactories = object : AbstractMutableMap() {
+
+ private val backingWorkerMap = mutableMapOf()
+
+ @UiThread
+ override fun put(key: String, value: WorkerFactory): WorkerFactory? {
+ return backingWorkerMap.put(key, value)
+ }
+
+ override val entries: MutableSet>
+ get() = backingWorkerMap.entries
+ }
+ }
+}
diff --git a/sentinel/src/main/kotlin/com/infinum/sentinel/ui/certificates/observer/SentinelWorkManager.kt b/sentinel/src/main/kotlin/com/infinum/sentinel/ui/certificates/observer/SentinelWorkManager.kt
index 944d7b3..6d3103e 100644
--- a/sentinel/src/main/kotlin/com/infinum/sentinel/ui/certificates/observer/SentinelWorkManager.kt
+++ b/sentinel/src/main/kotlin/com/infinum/sentinel/ui/certificates/observer/SentinelWorkManager.kt
@@ -4,14 +4,12 @@ import android.content.Context
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.lifecycle.asFlow
-import androidx.work.Configuration
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.NetworkType
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkInfo
import androidx.work.WorkManager
-import androidx.work.WorkerFactory
import androidx.work.workDataOf
import com.infinum.sentinel.BuildConfig
import com.infinum.sentinel.data.models.local.CertificateMonitorEntity
@@ -19,6 +17,8 @@ import com.infinum.sentinel.ui.shared.Constants.Keys.EXPIRE_IN_AMOUNT
import com.infinum.sentinel.ui.shared.Constants.Keys.EXPIRE_IN_UNIT
import com.infinum.sentinel.ui.shared.Constants.Keys.NOTIFY_INVALID_NOW
import com.infinum.sentinel.ui.shared.Constants.Keys.NOTIFY_TO_EXPIRE
+import com.infinum.sentinel.ui.shared.Constants.Keys.WORKER_CLASS_NAME
+import com.infinum.sentinel.ui.shared.Constants.Keys.WORKER_ID
import java.time.Duration
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf
@@ -28,7 +28,6 @@ import me.tatarka.inject.annotations.Inject
@Inject
internal class SentinelWorkManager(
private val context: Context,
- private val workerFactory: WorkerFactory
) {
companion object {
@@ -36,36 +35,27 @@ internal class SentinelWorkManager(
private const val RELEASE_INTERVAL = 1440L
}
- init {
- WorkManager.initialize(
- context,
- Configuration.Builder()
- .setMinimumLoggingLevel(android.util.Log.INFO)
- .setWorkerFactory(workerFactory)
- .build()
- )
- }
-
@RequiresApi(Build.VERSION_CODES.O)
- fun startCertificatesCheck(entity: CertificateMonitorEntity) =
+ fun startCertificatesCheck(entity: CertificateMonitorEntity) {
+
+ val delegatedWorkData = workDataOf(
+ WORKER_CLASS_NAME to CertificateCheckWorker::class.qualifiedName,
+ WORKER_ID to CertificateCheckWorker.NAME,
+ NOTIFY_INVALID_NOW to entity.notifyInvalidNow,
+ NOTIFY_TO_EXPIRE to entity.notifyToExpire,
+ EXPIRE_IN_AMOUNT to entity.expireInAmount,
+ EXPIRE_IN_UNIT to entity.expireInUnit.name
+ )
WorkManager.getInstance(context)
.enqueueUniquePeriodicWork(
- CertificateCheckWorker.NAME,
+ DelegateWorker.DELEGATE_WORKER_ID,
ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE,
- PeriodicWorkRequestBuilder(
+ PeriodicWorkRequestBuilder(
when (BuildConfig.DEBUG) {
true -> Duration.ofMinutes(DEBUG_INTERVAL)
false -> Duration.ofMinutes(RELEASE_INTERVAL)
}
- )
- .setInputData(
- workDataOf(
- NOTIFY_INVALID_NOW to entity.notifyInvalidNow,
- NOTIFY_TO_EXPIRE to entity.notifyToExpire,
- EXPIRE_IN_AMOUNT to entity.expireInAmount,
- EXPIRE_IN_UNIT to entity.expireInUnit.name
- )
- )
+ ).setInputData(delegatedWorkData)
.setConstraints(
Constraints.Builder()
.setRequiredNetworkType(NetworkType.NOT_REQUIRED)
@@ -80,6 +70,7 @@ internal class SentinelWorkManager(
)
.build()
)
+ }
fun certificatesCheckState(): Flow =
WorkManager.getInstance(context)
diff --git a/sentinel/src/main/kotlin/com/infinum/sentinel/ui/main/preferences/PreferencesFragment.kt b/sentinel/src/main/kotlin/com/infinum/sentinel/ui/main/preferences/PreferencesFragment.kt
index 8ec5464..d1337e5 100644
--- a/sentinel/src/main/kotlin/com/infinum/sentinel/ui/main/preferences/PreferencesFragment.kt
+++ b/sentinel/src/main/kotlin/com/infinum/sentinel/ui/main/preferences/PreferencesFragment.kt
@@ -64,32 +64,51 @@ internal class PreferencesFragment :
}
}
- @Suppress("UNCHECKED_CAST")
private fun createItemView(data: PreferencesData): View =
SentinelViewItemPreferenceBinding.inflate(layoutInflater, binding.contentLayout, false)
.apply {
nameView.text = data.name
- data.values.forEach { tuple ->
- prefsLayout.addView(
- SentinelViewItemTextBinding.inflate(layoutInflater, prefsLayout, false)
- .apply {
- labelView.isAllCaps = false
- labelView.text = tuple.second
- valueView.text = tuple.third.toString()
- root.setOnClickListener { _ ->
- viewModel.cache(
- data.name,
- tuple
- )
- }
- root.setOnLongClickListener {
- it.context.copyToClipboard(
- key = tuple.second,
- value = tuple.third.toString()
- )
- }
- }.root
- )
+ sortImageView.setOnClickListener {
+ viewModel.onSortClicked(data)
+ }
+ hideExpandImageView.setOnClickListener {
+ viewModel.onHideExpandClicked(data)
+ }
+
+ if (data.isExpanded) {
+ prefsLayout.visibility = View.VISIBLE
+ sortImageView.visibility = View.VISIBLE
+ hideExpandImageView.setImageResource(R.drawable.sentinel_ic_minus)
+ showPreferenceData(data)
+ } else {
+ prefsLayout.visibility = View.GONE
+ sortImageView.visibility = View.GONE
+ hideExpandImageView.setImageResource(R.drawable.sentinel_ic_plus)
}
}.root
+
+ private fun SentinelViewItemPreferenceBinding.showPreferenceData(data: PreferencesData) {
+ data.values.forEach { (preferenceType, label, value) ->
+ prefsLayout.addView(
+ SentinelViewItemTextBinding.inflate(layoutInflater, prefsLayout, false)
+ .apply {
+ labelView.isAllCaps = false
+ labelView.text = label
+ valueView.text = value.toString()
+ root.setOnClickListener { _ ->
+ viewModel.cache(
+ name = data.name,
+ tuple = Triple(preferenceType, label, value)
+ )
+ }
+ root.setOnLongClickListener {
+ it.context.copyToClipboard(
+ key = label,
+ value = value.toString()
+ )
+ }
+ }.root
+ )
+ }
+ }
}
diff --git a/sentinel/src/main/kotlin/com/infinum/sentinel/ui/main/preferences/PreferencesViewModel.kt b/sentinel/src/main/kotlin/com/infinum/sentinel/ui/main/preferences/PreferencesViewModel.kt
index 0299b8c..b81e27e 100644
--- a/sentinel/src/main/kotlin/com/infinum/sentinel/ui/main/preferences/PreferencesViewModel.kt
+++ b/sentinel/src/main/kotlin/com/infinum/sentinel/ui/main/preferences/PreferencesViewModel.kt
@@ -1,6 +1,7 @@
package com.infinum.sentinel.ui.main.preferences
import com.infinum.sentinel.data.models.raw.PreferenceType
+import com.infinum.sentinel.data.models.raw.PreferencesData
import com.infinum.sentinel.domain.Factories
import com.infinum.sentinel.domain.Repositories
import com.infinum.sentinel.domain.preference.models.PreferenceParameters
@@ -38,4 +39,40 @@ internal class PreferencesViewModel(
}
emitEvent(PreferencesEvent.Cached())
}
+
+ fun onSortClicked(data: PreferencesData) {
+ val currentValues = (stateFlow.value as? PreferencesState.Data)?.value.orEmpty()
+ val sortedData = if (data.isSortedAscending) {
+ data.values.sortedByDescending { it.second }
+ } else {
+ data.values.sortedBy { it.second }
+ }
+ val changedValues = currentValues.map { preferencesData ->
+ if (preferencesData.name == data.name) {
+ preferencesData.copy(
+ values = sortedData,
+ isSortedAscending = !preferencesData.isSortedAscending
+ )
+ } else {
+ preferencesData
+ }
+ }
+ setState(PreferencesState.Data(value = changedValues))
+ }
+
+ fun onHideExpandClicked(data: PreferencesData) {
+ (stateFlow.value as? PreferencesState.Data)?.let { state ->
+ val currentValues = state.value
+ val changedValues = currentValues.map { preferencesData ->
+ if (preferencesData.name == data.name) {
+ preferencesData.copy(
+ isExpanded = !preferencesData.isExpanded
+ )
+ } else {
+ preferencesData
+ }
+ }
+ setState(PreferencesState.Data(value = changedValues))
+ }
+ }
}
diff --git a/sentinel/src/main/kotlin/com/infinum/sentinel/ui/shared/Constants.kt b/sentinel/src/main/kotlin/com/infinum/sentinel/ui/shared/Constants.kt
index 3e4004f..5ae33f0 100644
--- a/sentinel/src/main/kotlin/com/infinum/sentinel/ui/shared/Constants.kt
+++ b/sentinel/src/main/kotlin/com/infinum/sentinel/ui/shared/Constants.kt
@@ -14,5 +14,7 @@ internal object Constants {
const val NOTIFY_TO_EXPIRE: String = "KEY_NOTIFY_TO_EXPIRE"
const val EXPIRE_IN_AMOUNT: String = "KEY_EXPIRE_IN_AMOUNT"
const val EXPIRE_IN_UNIT: String = "KEY_EXPIRE_IN_UNIT"
+ const val WORKER_CLASS_NAME = "WORKER_CLASS_NAME"
+ const val WORKER_ID = "WORKER_ID"
}
}
diff --git a/sentinel/src/main/res/drawable/sentinel_ic_sort.xml b/sentinel/src/main/res/drawable/sentinel_ic_sort.xml
new file mode 100644
index 0000000..7e84ccd
--- /dev/null
+++ b/sentinel/src/main/res/drawable/sentinel_ic_sort.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/sentinel/src/main/res/layout/sentinel_view_item_preference.xml b/sentinel/src/main/res/layout/sentinel_view_item_preference.xml
index b894bb5..d1bbd0d 100644
--- a/sentinel/src/main/res/layout/sentinel_view_item_preference.xml
+++ b/sentinel/src/main/res/layout/sentinel_view_item_preference.xml
@@ -1,18 +1,49 @@
-
+ android:orientation="horizontal"
+ android:paddingBottom="8dp">
+
+
+
+
+
+
+
+
+
+
Fragment arguments
Fragment Saved State
+ Sort preferences by name
+ Hide/expand the preferences
Preferences editor
Key
Current value
diff --git a/tool-timber/src/main/kotlin/com/infinum/sentinel/SentinelFileTree.kt b/tool-timber/src/main/kotlin/com/infinum/sentinel/SentinelFileTree.kt
index b09cb45..3fdbde5 100644
--- a/tool-timber/src/main/kotlin/com/infinum/sentinel/SentinelFileTree.kt
+++ b/tool-timber/src/main/kotlin/com/infinum/sentinel/SentinelFileTree.kt
@@ -4,9 +4,11 @@ import android.content.Context
import com.infinum.sentinel.ui.logger.models.BaseEntry
import com.infinum.sentinel.ui.logger.models.FlowBuffer
import com.infinum.sentinel.ui.logger.models.Level
+import com.infinum.sentinel.ui.shared.TimberToolConstants.LOG_DATE_TIME_FORMAT
import com.infinum.sentinel.ui.shared.LogFileResolver
import java.io.File
-import java.util.Calendar
+import java.text.SimpleDateFormat
+import java.util.Locale
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
@@ -21,6 +23,8 @@ internal class SentinelFileTree(
private val logFileResolver = LogFileResolver(context)
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
+ val dateTimeFormat = SimpleDateFormat(LOG_DATE_TIME_FORMAT, Locale.getDefault())
+
MainScope().launch {
withContext(Dispatchers.IO) {
val entry = Entry(
@@ -34,7 +38,7 @@ internal class SentinelFileTree(
buffer.enqueue(entry)
val file: File = logFileResolver.createOrOpenFile()
- val line = entry.asLineString()
+ val line = entry.asLineString(dateTimeFormat)
file.appendText(line)
}
diff --git a/tool-timber/src/main/kotlin/com/infinum/sentinel/TimberInitializer.kt b/tool-timber/src/main/kotlin/com/infinum/sentinel/TimberInitializer.kt
index 8125b82..804a728 100644
--- a/tool-timber/src/main/kotlin/com/infinum/sentinel/TimberInitializer.kt
+++ b/tool-timber/src/main/kotlin/com/infinum/sentinel/TimberInitializer.kt
@@ -3,7 +3,6 @@ package com.infinum.sentinel
import android.content.Context
import androidx.startup.Initializer
import com.infinum.sentinel.ui.logger.models.FlowBuffer
-import kotlinx.coroutines.MainScope
import timber.log.Timber
public class TimberInitializer : Initializer> {
diff --git a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerActivity.kt b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerActivity.kt
index fc6a2c9..c0235f9 100644
--- a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerActivity.kt
+++ b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerActivity.kt
@@ -36,7 +36,6 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import timber.log.Timber
-
public class LoggerActivity : AppCompatActivity() {
private companion object {
@@ -94,21 +93,21 @@ public class LoggerActivity : AppCompatActivity() {
with(binding) {
toolbar.setNavigationOnClickListener { finish() }
toolbar.subtitle = (
- packageManager.getApplicationLabel(
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- packageManager.getApplicationInfo(
- packageName,
- PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())
- )
- } else {
- @Suppress("DEPRECATION")
- packageManager.getApplicationInfo(
- packageName,
- PackageManager.GET_META_DATA
- )
- }
- ) as? String
- ) ?: getString(R.string.sentinel_name)
+ packageManager.getApplicationLabel(
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ packageManager.getApplicationInfo(
+ packageName,
+ PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())
+ )
+ } else {
+ @Suppress("DEPRECATION")
+ packageManager.getApplicationInfo(
+ packageName,
+ PackageManager.GET_META_DATA
+ )
+ }
+ ) as? String
+ ) ?: getString(R.string.sentinel_name)
toolbar.setOnMenuItemClickListener {
when (it.itemId) {
R.id.search -> {
diff --git a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerAdapter.kt b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerAdapter.kt
index 46d750f..05c0004 100644
--- a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerAdapter.kt
+++ b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerAdapter.kt
@@ -5,12 +5,17 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
import com.infinum.sentinel.SentinelFileTree
import com.infinum.sentinel.databinding.SentinelItemLogBinding
+import com.infinum.sentinel.ui.shared.TimberToolConstants.LOG_DATE_TIME_FORMAT
+import java.text.SimpleDateFormat
+import java.util.Locale
internal class LoggerAdapter(
private val onListChanged: (Boolean) -> Unit,
private val onClick: (SentinelFileTree.Entry) -> Unit
) : ListAdapter(LoggerDiffUtil()) {
+ private val dateTimeFormat = SimpleDateFormat(LOG_DATE_TIME_FORMAT, Locale.getDefault())
+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LoggerViewHolder =
LoggerViewHolder(
SentinelItemLogBinding.inflate(
@@ -21,7 +26,11 @@ internal class LoggerAdapter(
)
override fun onBindViewHolder(holder: LoggerViewHolder, position: Int) {
- holder.bind(getItem(position), onClick)
+ holder.bind(
+ item = getItem(position),
+ dateTimeFormat = dateTimeFormat,
+ onClick = onClick
+ )
}
override fun onViewRecycled(holder: LoggerViewHolder) {
diff --git a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerViewHolder.kt b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerViewHolder.kt
index 5be2992..ce2361e 100644
--- a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerViewHolder.kt
+++ b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/LoggerViewHolder.kt
@@ -14,7 +14,11 @@ internal class LoggerViewHolder(
private val binding: SentinelItemLogBinding
) : RecyclerView.ViewHolder(binding.root) {
- fun bind(item: SentinelFileTree.Entry?, onClick: (SentinelFileTree.Entry) -> Unit) {
+ fun bind(
+ item: SentinelFileTree.Entry?,
+ dateTimeFormat: SimpleDateFormat,
+ onClick: (SentinelFileTree.Entry) -> Unit
+ ) {
item?.let { entry ->
with(binding) {
levelView.setBackgroundColor(
@@ -31,7 +35,7 @@ internal class LoggerViewHolder(
}
)
)
- timestampView.text = SimpleDateFormat.getDateTimeInstance().format(Date(entry.timestamp))
+ timestampView.text = dateTimeFormat.format(Date(entry.timestamp))
tagView.text = entry.tag
entry.stackTrace?.let {
stackTraceView.text = it
diff --git a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/models/BaseEntry.kt b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/models/BaseEntry.kt
index 7ec2e2b..9feadbf 100644
--- a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/models/BaseEntry.kt
+++ b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/models/BaseEntry.kt
@@ -1,6 +1,7 @@
package com.infinum.sentinel.ui.logger.models
-import java.io.File
+import java.text.SimpleDateFormat
+import java.util.Date
import org.json.JSONObject
internal open class BaseEntry(
@@ -10,7 +11,6 @@ internal open class BaseEntry(
open val message: String? = null,
open val stackTrace: String? = null
) {
-
fun asJSONString(): String =
JSONObject()
.put("level", level)
@@ -20,9 +20,9 @@ internal open class BaseEntry(
.put("stackTrace", stackTrace)
.toString()
- fun asLineString(): String =
+ fun asLineString(dateTimeFormat: SimpleDateFormat): String =
buildString {
- append(timestamp)
+ append(dateTimeFormat.format(Date(timestamp)))
append(" LEVEL: ")
append(level)
append(" TAG: ")
diff --git a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/models/FlowBuffer.kt b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/models/FlowBuffer.kt
index d51ee6d..19c1af5 100644
--- a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/models/FlowBuffer.kt
+++ b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logger/models/FlowBuffer.kt
@@ -28,8 +28,8 @@ internal class FlowBuffer {
} else {
queue.reversed().filter {
it.tag?.lowercase()?.contains(query.lowercase()) == true ||
- it.message?.lowercase()?.contains(query.lowercase()) == true ||
- it.stackTrace?.lowercase()?.contains(query.lowercase()) == true
+ it.message?.lowercase()?.contains(query.lowercase()) == true ||
+ it.stackTrace?.lowercase()?.contains(query.lowercase()) == true
}
}
)
diff --git a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsActivity.kt b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsActivity.kt
index 65a0da0..8f3e1e6 100644
--- a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsActivity.kt
+++ b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsActivity.kt
@@ -29,7 +29,6 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-
public class LogsActivity : AppCompatActivity() {
private companion object {
@@ -79,21 +78,21 @@ public class LogsActivity : AppCompatActivity() {
with(binding) {
toolbar.setNavigationOnClickListener { finish() }
toolbar.subtitle = (
- packageManager.getApplicationLabel(
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
- packageManager.getApplicationInfo(
- packageName,
- PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())
- )
- } else {
- @Suppress("DEPRECATION")
- packageManager.getApplicationInfo(
- packageName,
- PackageManager.GET_META_DATA
- )
- }
- ) as? String
- ) ?: getString(R.string.sentinel_name)
+ packageManager.getApplicationLabel(
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ packageManager.getApplicationInfo(
+ packageName,
+ PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())
+ )
+ } else {
+ @Suppress("DEPRECATION")
+ packageManager.getApplicationInfo(
+ packageName,
+ PackageManager.GET_META_DATA
+ )
+ }
+ ) as? String
+ ) ?: getString(R.string.sentinel_name)
recyclerView.layoutManager = LinearLayoutManager(
recyclerView.context,
diff --git a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsAdapter.kt b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsAdapter.kt
index 8913309..55abf53 100644
--- a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsAdapter.kt
+++ b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsAdapter.kt
@@ -3,10 +3,11 @@ package com.infinum.sentinel.ui.logs
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.ListAdapter
-import com.infinum.sentinel.SentinelFileTree
-import com.infinum.sentinel.databinding.SentinelItemLogBinding
import com.infinum.sentinel.databinding.SentinelItemLogFileBinding
+import com.infinum.sentinel.ui.shared.TimberToolConstants.LOG_DATE_TIME_FORMAT
import java.io.File
+import java.text.SimpleDateFormat
+import java.util.Locale
internal class LogsAdapter(
private val onListChanged: (Boolean) -> Unit,
@@ -14,6 +15,8 @@ internal class LogsAdapter(
private val onShare: (File) -> Unit
) : ListAdapter(LogsDiffUtil()) {
+ private val dateTimeFormat = SimpleDateFormat(LOG_DATE_TIME_FORMAT, Locale.getDefault())
+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LogsViewHolder =
LogsViewHolder(
SentinelItemLogFileBinding.inflate(
@@ -24,7 +27,12 @@ internal class LogsAdapter(
)
override fun onBindViewHolder(holder: LogsViewHolder, position: Int) {
- holder.bind(getItem(position), onDelete, onShare)
+ holder.bind(
+ item = getItem(position),
+ dateTimeFormat = dateTimeFormat,
+ onDelete = onDelete,
+ onShare = onShare
+ )
}
override fun onViewRecycled(holder: LogsViewHolder) {
diff --git a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsViewHolder.kt b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsViewHolder.kt
index 61c2d60..da7df10 100644
--- a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsViewHolder.kt
+++ b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/logs/LogsViewHolder.kt
@@ -1,12 +1,7 @@
package com.infinum.sentinel.ui.logs
-import androidx.core.content.ContextCompat
-import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
-import com.infinum.sentinel.R
-import com.infinum.sentinel.SentinelFileTree
import com.infinum.sentinel.databinding.SentinelItemLogFileBinding
-import com.infinum.sentinel.ui.logger.models.Level
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
@@ -15,11 +10,11 @@ internal class LogsViewHolder(
private val binding: SentinelItemLogFileBinding
) : RecyclerView.ViewHolder(binding.root) {
- fun bind(item: File?, onDelete: (File) -> Unit, onShare: (File) -> Unit) {
+ fun bind(item: File?, dateTimeFormat: SimpleDateFormat, onDelete: (File) -> Unit, onShare: (File) -> Unit) {
item?.let { entry ->
with(binding) {
messageView.text = entry.name
- timestampView.text = SimpleDateFormat.getDateTimeInstance().format(Date(entry.lastModified()))
+ timestampView.text = dateTimeFormat.format(Date(entry.lastModified()))
deleteButton.setOnClickListener { onDelete(entry) }
shareButton.setOnClickListener { onShare(entry) }
}
diff --git a/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/shared/TimberToolConstants.kt b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/shared/TimberToolConstants.kt
new file mode 100644
index 0000000..1ae9d57
--- /dev/null
+++ b/tool-timber/src/main/kotlin/com/infinum/sentinel/ui/shared/TimberToolConstants.kt
@@ -0,0 +1,5 @@
+package com.infinum.sentinel.ui.shared
+
+internal object TimberToolConstants {
+ const val LOG_DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
+}