Skip to content

Commit

Permalink
Updated log screen with new arch
Browse files Browse the repository at this point in the history
  • Loading branch information
diareuse committed Apr 22, 2019
1 parent f21241d commit 7cc8c01
Show file tree
Hide file tree
Showing 15 changed files with 629 additions and 71 deletions.
2 changes: 2 additions & 0 deletions app/src/main/java/com/topjohnwu/magisk/di/ViewModelsModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.topjohnwu.magisk.di
import com.topjohnwu.magisk.ui.MainViewModel
import com.topjohnwu.magisk.ui.hide.HideViewModel
import com.topjohnwu.magisk.ui.home.HomeViewModel
import com.topjohnwu.magisk.ui.log.LogViewModel
import com.topjohnwu.magisk.ui.module.ModuleViewModel
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
import org.koin.androidx.viewmodel.dsl.viewModel
Expand All @@ -15,4 +16,5 @@ val viewModelModules = module {
viewModel { SuperuserViewModel(get(), get(), get(), get()) }
viewModel { HideViewModel(get(), get()) }
viewModel { ModuleViewModel(get()) }
viewModel { LogViewModel(get(), get()) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.topjohnwu.magisk.model.entity.recycler

import com.skoumal.teanity.databinding.ComparableRvItem
import com.topjohnwu.magisk.R

class ConsoleRvItem(val item: String) : ComparableRvItem<ConsoleRvItem>() {
override val layoutRes: Int = R.layout.item_console

override fun contentSameAs(other: ConsoleRvItem) = itemSameAs(other)
override fun itemSameAs(other: ConsoleRvItem) = item == other.item
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.topjohnwu.magisk.model.entity.recycler

import androidx.databinding.ObservableList
import com.skoumal.teanity.databinding.ComparableRvItem
import com.skoumal.teanity.util.DiffObservableList
import com.skoumal.teanity.util.KObservableField
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.model.entity.SuLogEntry
import com.topjohnwu.magisk.utils.toggle

class LogRvItem : ComparableRvItem<LogRvItem>() {
override val layoutRes: Int = R.layout.item_page_log

val items = DiffObservableList(callback)

fun update(list: List<LogItemRvItem>) {
list.firstOrNull()?.isExpanded?.value = true
items.update(list)
}

//two of these will never be present, safe to assume it's unique
override fun contentSameAs(other: LogRvItem): Boolean = false

override fun itemSameAs(other: LogRvItem): Boolean = false
}

class LogItemRvItem(
val items: ObservableList<ComparableRvItem<*>>
) : ComparableRvItem<LogItemRvItem>() {
override val layoutRes: Int = R.layout.item_superuser_log

val date = items.filterIsInstance<LogItemEntryRvItem>().firstOrNull()
?.item?.dateString.orEmpty()
val isExpanded = KObservableField(false)

fun toggle() = isExpanded.toggle()

override fun contentSameAs(other: LogItemRvItem): Boolean = items
.any { !other.items.contains(it) }

override fun itemSameAs(other: LogItemRvItem): Boolean = date == other.date
}

class LogItemEntryRvItem(val item: SuLogEntry) : ComparableRvItem<LogItemEntryRvItem>() {
override val layoutRes: Int = R.layout.item_superuser_log_entry

val isExpanded = KObservableField(false)

fun toggle() = isExpanded.toggle()

override fun contentSameAs(other: LogItemEntryRvItem) = item.fromUid == other.item.fromUid &&
item.toUid == other.item.toUid &&
item.fromPid == other.item.fromPid &&
item.packageName == other.item.packageName &&
item.command == other.item.command &&
item.action == other.item.action &&
item.date == other.item.date

override fun itemSameAs(other: LogItemEntryRvItem) = item.appName == other.item.appName
}

class MagiskLogRvItem : ComparableRvItem<MagiskLogRvItem>() {
override val layoutRes: Int = R.layout.item_page_magisk_log

val items = DiffObservableList(callback)

fun update(list: List<ConsoleRvItem>) {
items.update(list)
}

//two of these will never be present, safe to assume it's unique
override fun contentSameAs(other: MagiskLogRvItem): Boolean = false

override fun itemSameAs(other: MagiskLogRvItem): Boolean = false
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ class ViewActionEvent(val action: Activity.() -> Unit) : ViewEvent()
class OpenFilePickerEvent : ViewEvent()

class OpenChangelogEvent(val item: Repo) : ViewEvent()
class InstallModuleEvent(val item: Repo) : ViewEvent()
class InstallModuleEvent(val item: Repo) : ViewEvent()

class PageChangedEvent : ViewEvent()
45 changes: 0 additions & 45 deletions app/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.java

This file was deleted.

53 changes: 53 additions & 0 deletions app/src/main/java/com/topjohnwu/magisk/ui/log/LogFragment.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.topjohnwu.magisk.ui.log


import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import com.skoumal.teanity.viewevents.ViewEvent
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.databinding.FragmentLogBinding
import com.topjohnwu.magisk.model.events.PageChangedEvent
import com.topjohnwu.magisk.ui.base.MagiskFragment
import org.koin.androidx.viewmodel.ext.android.viewModel

class LogFragment : MagiskFragment<LogViewModel, FragmentLogBinding>() {

override val layoutRes: Int = R.layout.fragment_log
override val viewModel: LogViewModel by viewModel()

override fun onEventDispatched(event: ViewEvent) {
super.onEventDispatched(event)
when (event) {
is PageChangedEvent -> magiskActivity.invalidateOptionsMenu()
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.logTabs.setupWithViewPager(binding.logContainer, true)
}

override fun onStart() {
super.onStart()
setHasOptionsMenu(true)
magiskActivity.setTitle(R.string.log)
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_log, menu)
menu.findItem(R.id.menu_save).isVisible = viewModel.currentPage.value == 1
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_save -> viewModel.saveLog()
R.id.menu_clear -> viewModel.clearLog()
R.id.menu_refresh -> viewModel.refresh()
}
return true
}

}
122 changes: 122 additions & 0 deletions app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package com.topjohnwu.magisk.ui.log

import android.content.res.Resources
import androidx.databinding.ObservableArrayList
import com.skoumal.teanity.databinding.ComparableRvItem
import com.skoumal.teanity.extensions.addOnPropertyChangedCallback
import com.skoumal.teanity.extensions.doOnSuccessUi
import com.skoumal.teanity.extensions.subscribeK
import com.skoumal.teanity.util.DiffObservableList
import com.skoumal.teanity.util.KObservableField
import com.skoumal.teanity.viewevents.SnackbarEvent
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.Const
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.data.database.MagiskDB
import com.topjohnwu.magisk.model.entity.recycler.*
import com.topjohnwu.magisk.model.events.PageChangedEvent
import com.topjohnwu.magisk.ui.base.MagiskViewModel
import com.topjohnwu.magisk.utils.toSingle
import com.topjohnwu.magisk.utils.zip
import com.topjohnwu.superuser.Shell
import io.reactivex.Single
import me.tatarka.bindingcollectionadapter2.BindingViewPagerAdapter
import me.tatarka.bindingcollectionadapter2.OnItemBind
import java.io.File
import java.io.IOException
import java.util.*

class LogViewModel(
private val resources: Resources,
private val database: MagiskDB
) : MagiskViewModel(), BindingViewPagerAdapter.PageTitles<ComparableRvItem<*>> {

val items = DiffObservableList(ComparableRvItem.callback)
val itemBinding = OnItemBind<ComparableRvItem<*>> { itemBinding, _, item ->
item.bind(itemBinding)
itemBinding.bindExtra(BR.viewModel, this@LogViewModel)
}
val currentPage = KObservableField(0)
private val currentItem get() = items[currentPage.value]

private val logItem get() = items[0] as LogRvItem
private val magiskLogItem get() = items[1] as MagiskLogRvItem

init {
currentPage.addOnPropertyChangedCallback {
it ?: return@addOnPropertyChangedCallback
PageChangedEvent().publish()
}

items.addAll(listOf(LogRvItem(), MagiskLogRvItem()))
refresh()
}

override fun getPageTitle(position: Int, item: ComparableRvItem<*>?) = when (item) {
is LogRvItem -> resources.getString(R.string.superuser)
is MagiskLogRvItem -> resources.getString(R.string.magisk)
else -> ""
}

fun refresh() = zip(updateLogs(), updateMagiskLog()) { _, _ -> true }
.subscribeK()
.add()

fun saveLog() {
val now = Calendar.getInstance()
val filename = "magisk_log_%04d%02d%02d_%02d%02d%02d.log".format(
now.get(Calendar.YEAR), now.get(Calendar.MONTH) + 1,
now.get(Calendar.DAY_OF_MONTH), now.get(Calendar.HOUR_OF_DAY),
now.get(Calendar.MINUTE), now.get(Calendar.SECOND)
)

val logFile = File(Const.EXTERNAL_PATH, filename)
try {
logFile.createNewFile()
} catch (e: IOException) {
return
}

Shell.su("cat ${Const.MAGISK_LOG} > $logFile").submit {
SnackbarEvent(logFile.path).publish()
}
}

fun clearLog() = when (currentItem) {
is LogRvItem -> clearLogs { refresh() }
is MagiskLogRvItem -> clearMagiskLogs { refresh() }
else -> Unit
}

private fun clearLogs(callback: () -> Unit) {
Single.fromCallable { database.clearLogs() }
.subscribeK {
SnackbarEvent(R.string.logs_cleared).publish()
callback()
}
.add()
}

private fun clearMagiskLogs(callback: () -> Unit) {
Shell.su("echo -n > " + Const.MAGISK_LOG).submit {
SnackbarEvent(R.string.logs_cleared).publish()
callback()
}
}

private fun updateLogs() = Single.fromCallable { database.logs }
.flattenAsFlowable { it }
.map { it.map { LogItemEntryRvItem(it) } }
.map { LogItemRvItem(ObservableArrayList<ComparableRvItem<*>>().apply { addAll(it) }) }
.toList()
.doOnSuccessUi { logItem.update(it) }

private fun updateMagiskLog() = Shell.su("tail -n 5000 ${Const.MAGISK_LOG}").toSingle()
.map { it.exec() }
.map { it.out }
.flattenAsFlowable { it }
.map { ConsoleRvItem(it) }
.toList()
.doOnSuccessUi { magiskLogItem.update(it) }

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import androidx.annotation.DrawableRes
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.Toolbar
import androidx.databinding.BindingAdapter
import androidx.databinding.InverseBindingAdapter
import androidx.databinding.InverseBindingListener
import androidx.drawerlayout.widget.DrawerLayout
import androidx.viewpager.widget.ViewPager
import com.google.android.material.navigation.NavigationView
import com.topjohnwu.magisk.R
import com.topjohnwu.magisk.model.entity.state.IndeterminateState
Expand Down Expand Up @@ -57,3 +60,24 @@ fun setChecked(view: AppCompatImageView, isChecked: IndeterminateState) {
}
)
}

@BindingAdapter("position")
fun setPosition(view: ViewPager, position: Int) {
view.currentItem = position
}

@InverseBindingAdapter(attribute = "position", event = "positionChanged")
fun getPosition(view: ViewPager) = view.currentItem

@BindingAdapter("positionChanged")
fun setPositionChangedListener(view: ViewPager, listener: InverseBindingListener) {
view.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageSelected(position: Int) = listener.onChange()
override fun onPageScrollStateChanged(state: Int) = listener.onChange()
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) = listener.onChange()
})
}
6 changes: 5 additions & 1 deletion app/src/main/java/com/topjohnwu/magisk/utils/XRx.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.topjohnwu.magisk.utils

import io.reactivex.Single
import io.reactivex.functions.BiFunction

fun <T : Any> T.toSingle() = Single.just(this)
fun <T : Any> T.toSingle() = Single.just(this)

fun <T1, T2, R> zip(t1: Single<T1>, t2: Single<T2>, zipper: (T1, T2) -> R) =
Single.zip(t1, t2, BiFunction<T1, T2, R> { rt1, rt2 -> zipper(rt1, rt2) })
Loading

0 comments on commit 7cc8c01

Please sign in to comment.