Add configurable chunked storage limits
This commit is contained in:
@@ -25,23 +25,32 @@ import androidx.fragment.app.Fragment
|
||||
class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
|
||||
private var binding: FragmentViewLogsBinding? = null
|
||||
private val expandedIds = mutableSetOf<String>()
|
||||
private val rows = mutableListOf<LogRow>()
|
||||
private var loadedEntries = 0
|
||||
private var loading = false
|
||||
private var noMoreRows = false
|
||||
private var loadGeneration = 0
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentViewLogsBinding.bind(view)
|
||||
binding!!.logsRefresh.setOnRefreshListener(::loadLogs)
|
||||
binding!!.logsRefresh.setOnRefreshListener { loadLogs(reset = true) }
|
||||
binding!!.logScroll.setOnScrollChangeListener { _, _, scrollY, _, _ ->
|
||||
binding?.scrollToTop?.visibility = if (scrollY > dp(SCROLL_TO_TOP_THRESHOLD_DP)) View.VISIBLE else View.GONE
|
||||
val scroll = binding?.logScroll ?: return@setOnScrollChangeListener
|
||||
if (!noMoreRows && !loading && scrollY >= scroll.getChildAt(0).height - scroll.height - dp(LOAD_MORE_THRESHOLD_DP)) {
|
||||
loadLogs(reset = false)
|
||||
}
|
||||
}
|
||||
binding!!.scrollToTop.setOnClickListener {
|
||||
binding?.logScroll?.smoothScrollTo(0, 0)
|
||||
}
|
||||
loadLogs()
|
||||
loadLogs(reset = true)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
loadLogs()
|
||||
loadLogs(reset = true)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
@@ -49,26 +58,40 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun loadLogs() {
|
||||
private fun loadLogs(reset: Boolean) {
|
||||
if (loading) return
|
||||
if (!reset && noMoreRows) return
|
||||
val context = requireContext().applicationContext
|
||||
if (reset) {
|
||||
rows.clear()
|
||||
loadedEntries = 0
|
||||
noMoreRows = false
|
||||
loadGeneration++
|
||||
}
|
||||
val generation = loadGeneration
|
||||
loading = true
|
||||
binding?.logsRefresh?.isRefreshing = true
|
||||
Thread {
|
||||
val imageStore = EncryptedImageStore(context)
|
||||
val rows = EncryptedNotificationLogStore(context).readAll()
|
||||
.sortedByDescending { it.recordedAtEpochMillis }
|
||||
.map { entry -> LogRow(entry, entry.imageId?.let(imageStore::read)) }
|
||||
val entries = EncryptedNotificationLogStore(context).readNewest(loadedEntries, PAGE_SIZE)
|
||||
activity?.runOnUiThread {
|
||||
binding?.let { render(it, rows) }
|
||||
if (generation == loadGeneration) {
|
||||
loadedEntries += entries.size
|
||||
noMoreRows = entries.size < PAGE_SIZE
|
||||
val addedRows = entries.map(::LogRow)
|
||||
rows += addedRows
|
||||
binding?.let { render(it, addedRows, reset) }
|
||||
}
|
||||
loading = false
|
||||
binding?.logsRefresh?.isRefreshing = false
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun render(view: FragmentViewLogsBinding, rows: List<LogRow>) {
|
||||
view.logRows.removeAllViews()
|
||||
private fun render(view: FragmentViewLogsBinding, addedRows: List<LogRow>, reset: Boolean) {
|
||||
if (reset) view.logRows.removeAllViews()
|
||||
view.emptyView.visibility = if (rows.isEmpty()) View.VISIBLE else View.GONE
|
||||
val settings = LogViewSettingsStore(requireContext()).load()
|
||||
rows.filter { eventFor(it.entry.action) in settings.visibleEvents }
|
||||
addedRows.filter { eventFor(it.entry.action) in settings.visibleEvents }
|
||||
.forEach { row -> view.logRows.addView(logRowView(row, settings)) }
|
||||
}
|
||||
|
||||
@@ -159,18 +182,23 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
|
||||
setPadding(0, dp(4), 0, 0)
|
||||
})
|
||||
}
|
||||
if (expanded) {
|
||||
row.imageBytes?.let { bytes ->
|
||||
BitmapFactory.decodeByteArray(bytes, 0, bytes.size)?.let { bitmap ->
|
||||
addView(ImageView(context).apply {
|
||||
setImageBitmap(bitmap)
|
||||
adjustViewBounds = true
|
||||
maxHeight = dp(240)
|
||||
contentDescription = "Notification image"
|
||||
setPadding(0, dp(4), 0, 0)
|
||||
})
|
||||
}
|
||||
if (expanded && row.entry.imageId != null) {
|
||||
val image = ImageView(context).apply {
|
||||
adjustViewBounds = true
|
||||
maxHeight = dp(240)
|
||||
contentDescription = "Notification image"
|
||||
setPadding(0, dp(4), 0, 0)
|
||||
}
|
||||
addView(image)
|
||||
val imageId = row.entry.imageId
|
||||
val appContext = requireContext().applicationContext
|
||||
Thread {
|
||||
EncryptedImageStore(appContext).read(imageId)?.let { bytes ->
|
||||
BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
|
||||
}?.let { bitmap ->
|
||||
activity?.runOnUiThread { if (image.isAttachedToWindow) image.setImageBitmap(bitmap) }
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
setOnClickListener { onToggleExpanded() }
|
||||
setOnLongClickListener { showDeleteDialog(row.entry.id) }
|
||||
@@ -225,7 +253,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
|
||||
.setPositiveButton("Delete") { _, _ ->
|
||||
Thread {
|
||||
EncryptedNotificationLogStore(requireContext().applicationContext).delete(entryId)
|
||||
activity?.runOnUiThread(::loadLogs)
|
||||
activity?.runOnUiThread { loadLogs(reset = true) }
|
||||
}.start()
|
||||
}
|
||||
.show()
|
||||
@@ -244,12 +272,14 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) {
|
||||
|
||||
private fun dp(value: Int): Int = (value * resources.displayMetrics.density).toInt()
|
||||
|
||||
private data class LogRow(val entry: NotificationLogEntry, val imageBytes: ByteArray?)
|
||||
private data class LogRow(val entry: NotificationLogEntry)
|
||||
private data class MetadataValue(val text: String, val textSize: Float, val indented: Boolean = false, val bold: Boolean = false)
|
||||
|
||||
private companion object {
|
||||
const val LEFT_PILL_WEIGHT = 0.42f
|
||||
const val RIGHT_PILL_WEIGHT = 0.58f
|
||||
const val SCROLL_TO_TOP_THRESHOLD_DP = 120
|
||||
const val LOAD_MORE_THRESHOLD_DP = 480
|
||||
const val PAGE_SIZE = 80
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user