Improve Pi-hole interactions
This commit is contained in:
parent
9479c5b40e
commit
fdbd55cdf8
8 changed files with 56 additions and 34 deletions
|
@ -15,6 +15,7 @@ android {
|
|||
}
|
||||
buildTypes {
|
||||
release {
|
||||
debuggable true
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
@ -33,17 +34,17 @@ dependencies {
|
|||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'androidx.core:core-ktx:1.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'com.google.android.material:material:1.2.0-alpha02'
|
||||
implementation 'com.google.android.material:material:1.2.0-alpha04'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'androidx.security:security-crypto:1.0.0-alpha02'
|
||||
implementation 'androidx.preference:preference:1.1.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
def navigation_version = '2.1.0'
|
||||
def navigation_version = '2.2.0'
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version"
|
||||
implementation "androidx.navigation:navigation-ui-ktx:$navigation_version"
|
||||
def lifecycle_version = '2.1.0'
|
||||
def lifecycle_version = '2.2.0'
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
|
||||
def acraVersion = '5.1.3'
|
||||
|
|
|
@ -44,28 +44,35 @@ class MainFragment : Fragment(), CoroutineScope {
|
|||
}
|
||||
viewModel.monitorSummary()
|
||||
}
|
||||
viewModel.summary.observe(this, Observer { summary ->
|
||||
viewModel.status.observe(this, Observer {
|
||||
showProgress(false)
|
||||
val (statusColor, statusText) = if (
|
||||
summary.status == Status.DISABLED
|
||||
) {
|
||||
enableButton?.visibility = View.VISIBLE
|
||||
disableButtons?.visibility = View.GONE
|
||||
Pair(R.color.colorDisabled, R.string.status_disabled)
|
||||
} else {
|
||||
enableButton?.visibility = View.GONE
|
||||
disableButtons?.visibility = View.VISIBLE
|
||||
Pair(R.color.colorEnabled, R.string.status_enabled)
|
||||
val (statusColor, statusText) = when (it) {
|
||||
Status.DISABLED -> {
|
||||
enableButton?.visibility = View.VISIBLE
|
||||
disableButtons?.visibility = View.GONE
|
||||
Pair(R.color.colorDisabled, R.string.status_disabled)
|
||||
}
|
||||
Status.ENABLED -> {
|
||||
enableButton?.visibility = View.GONE
|
||||
disableButtons?.visibility = View.VISIBLE
|
||||
Pair(R.color.colorEnabled, R.string.status_enabled)
|
||||
}
|
||||
else -> {
|
||||
enableButton?.visibility = View.GONE
|
||||
disableButtons?.visibility = View.GONE
|
||||
Pair(R.color.colorUnknown, R.string.status_unknown)
|
||||
}
|
||||
}
|
||||
status?.let {
|
||||
status?.let { textView ->
|
||||
val status = getString(statusText)
|
||||
val statusLabel = getString(R.string.label_status, status)
|
||||
val start = statusLabel.indexOf(status)
|
||||
val end = start + status.length
|
||||
val statusSpan = SpannableString(statusLabel)
|
||||
statusSpan[start, end] = StyleSpan(Typeface.BOLD)
|
||||
statusSpan[start, end] = ForegroundColorSpan(getColor(it.context, statusColor))
|
||||
it.text = statusSpan
|
||||
statusSpan[start, end] =
|
||||
ForegroundColorSpan(getColor(textView.context, statusColor))
|
||||
textView.text = statusSpan
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -124,7 +131,7 @@ class MainFragment : Fragment(), CoroutineScope {
|
|||
}
|
||||
disableCustomTimeButton?.setOnClickListener {
|
||||
val dialogView = LayoutInflater.from(it.context)
|
||||
.inflate(R.layout.dialog_disable_custom_time, null, false)
|
||||
.inflate(R.layout.dialog_disable_custom_time, view as ViewGroup, false)
|
||||
AlertDialog.Builder(it.context)
|
||||
.setTitle(R.string.action_disable_custom)
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
|
|
|
@ -3,23 +3,27 @@ package com.wbrawner.pihelper
|
|||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.wbrawner.piholeclient.PiHoleApiService
|
||||
import com.wbrawner.piholeclient.Summary
|
||||
import kotlinx.coroutines.NonCancellable.isActive
|
||||
import com.wbrawner.piholeclient.Status
|
||||
import com.wbrawner.piholeclient.StatusProvider
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.yield
|
||||
import java.lang.Exception
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
class PiHelperViewModel(
|
||||
private val apiService: PiHoleApiService
|
||||
) : ViewModel() {
|
||||
val summary = MutableLiveData<Summary>()
|
||||
val status = MutableLiveData<Status>()
|
||||
private var action: (suspend () -> StatusProvider)? = null
|
||||
get() = field ?: defaultAction
|
||||
private var defaultAction = suspend {
|
||||
apiService.getSummary()
|
||||
}
|
||||
|
||||
suspend fun monitorSummary() {
|
||||
while (coroutineContext.isActive) {
|
||||
try {
|
||||
loadSummary()
|
||||
status.postValue(action!!.invoke().status)
|
||||
action = null
|
||||
} catch (ignored: Exception) {
|
||||
break
|
||||
}
|
||||
|
@ -27,15 +31,15 @@ class PiHelperViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun loadSummary() {
|
||||
summary.postValue(apiService.getSummary())
|
||||
}
|
||||
|
||||
suspend fun enablePiHole() {
|
||||
apiService.enable()
|
||||
action = {
|
||||
apiService.enable()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun disablePiHole(duration: Long? = null) {
|
||||
apiService.disable(duration)
|
||||
action = {
|
||||
apiService.disable(duration)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ class RetrieveApiKeyFragment : Fragment(), CoroutineScope {
|
|||
sharedElementEnterTransition = TransitionInflater.from(context)
|
||||
.inflateTransition(android.R.transition.move)
|
||||
viewModel.authenticated.observe(this, Observer {
|
||||
if (!it) return@Observer
|
||||
findNavController().navigate(R.id.action_retrieveApiKeyFragment_to_mainFragment)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -4,4 +4,5 @@
|
|||
<color name="colorOnSurface">#f1f1f1</color>
|
||||
<color name="colorEnabled">@color/colorGreenLight</color>
|
||||
<color name="colorDisabled">@color/colorRedLight</color>
|
||||
<color name="colorButtonSecondary">#999999</color>
|
||||
</resources>
|
|
@ -10,6 +10,7 @@
|
|||
<color name="colorOnSurface">#000000</color>
|
||||
<color name="colorWhite">#ffffff</color>
|
||||
<color name="colorEnabled">@color/colorGreenDark</color>
|
||||
<color name="colorUnknown">@color/colorButtonSecondary</color>
|
||||
<color name="colorDisabled">@color/colorRedDark</color>
|
||||
<color name="colorSurface">@color/colorWhite</color>
|
||||
<color name="colorTransparent">#00000000</color>
|
||||
|
|
|
@ -30,4 +30,5 @@
|
|||
<string name="title_crash_notification">Pi-Helper Crashed!</string>
|
||||
<string name="text_crash_notification">Would you please consider sending the crash report to me?</string>
|
||||
<string name="channel_crash_notification">Crash Reports</string>
|
||||
<string name="status_unknown">Unknown</string>
|
||||
</resources>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.wbrawner.piholeclient
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.squareup.moshi.Json
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
|
@ -35,13 +36,14 @@ data class Summary(
|
|||
val ipReplies: String?,
|
||||
@Json(name = "privacy_level")
|
||||
val privacyLevel: String,
|
||||
val status: Status,
|
||||
override val status: Status,
|
||||
@Json(name = "gravity_last_updated")
|
||||
val gravity: Gravity?,
|
||||
val type: String?,
|
||||
val version: Int?
|
||||
)
|
||||
) : StatusProvider
|
||||
|
||||
@Keep
|
||||
enum class Status {
|
||||
@Json(name = "enabled")
|
||||
ENABLED,
|
||||
|
@ -69,11 +71,15 @@ data class VersionResponse(val version: Int)
|
|||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class TopItemsResponse(
|
||||
@Json(name = "top_queries") val topQueries: List<String>,
|
||||
@Json(name = "top_queries") val topQueries: Map<String, String>,
|
||||
@Json(name = "top_ads") val topAds: List<String>
|
||||
)
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
data class StatusResponse(
|
||||
override val status: Status
|
||||
) : StatusProvider
|
||||
|
||||
interface StatusProvider {
|
||||
val status: Status
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue