Fancy toggle button for main menu

This commit is contained in:
partisan 2025-05-14 14:31:05 +02:00
parent 1691891a4d
commit fafe7e2cd5
11 changed files with 109 additions and 19 deletions

View file

@ -1,27 +1,43 @@
package partisan.weforge.xyz.pulse
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ToggleButton
import androidx.fragment.app.Fragment
import com.google.android.material.button.MaterialButton
class MainFragment : Fragment() {
private lateinit var prefs: Preferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val view = inflater.inflate(R.layout.fragment_main, container, false)
prefs = Preferences(requireContext())
val toggle = view.findViewById<ToggleButton>(R.id.toggle)
toggle.isChecked = prefs.isEnabled
toggle.setOnCheckedChangeListener { _, isChecked ->
prefs.isEnabled = isChecked
val toggle = view.findViewById<MaterialButton>(R.id.toggle)
toggle.isCheckable = true
toggle.isChecked = prefs.isServiceEnabledByUser
toggle.setOnClickListener {
// the button toggles itself internally since it's checkable
val isNowChecked = toggle.isChecked
prefs.isServiceEnabledByUser = isNowChecked
// Log.d("ButtonState", """
// User toggle: $isNowChecked
// Prefs effective state (hasPerms): ${prefs.isEnabled}
// """.trimIndent())
toggle.post {
toggle.jumpDrawablesToCurrentState()
toggle.invalidate()
}
}
return view

View file

@ -4,9 +4,9 @@ import android.content.Context
import androidx.core.content.edit
import androidx.preference.PreferenceManager
class Preferences(ctx: Context) {
class Preferences(private val context: Context) {
companion object {
private const val ENABLED = "enabled"
private const val REDIRECTION_DELAY = "redirection_delay"
private const val POPUP_POSITION = "popup_position_y"
private const val POPUP_ENABLED = "popup_enabled"
@ -17,11 +17,19 @@ class Preferences(ctx: Context) {
private const val SERVICE_ENABLED = "service_enabled"
}
private val prefs = PreferenceManager.getDefaultSharedPreferences(ctx)
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
var isEnabled: Boolean
get() = prefs.getBoolean(ENABLED, prefs.getBoolean(SERVICE_ENABLED, false))
set(value) = prefs.edit { putBoolean(ENABLED, value) }
// Whether user enabled/disabled the service manually by tiggle button
var isServiceEnabledByUser: Boolean
get() = prefs.getBoolean(SERVICE_ENABLED, false)
set(value) = prefs.edit { putBoolean(SERVICE_ENABLED, value) }
// True only if all required permissions + toggle are satisfied
val isEnabled: Boolean
get() = isServiceEnabledByUser &&
hasGeneralPermissions(context) &&
hasDrawOverlays(context) &&
hasCallRedirectionRole(context)
var popupEnabled: Boolean
get() = prefs.getBoolean(POPUP_ENABLED, true)

View file

@ -64,7 +64,6 @@ class WelcomeActivity : AppCompatActivity() {
requestRoleLauncher.launch(roleManager?.createRequestRoleIntent(RoleManager.ROLE_CALL_REDIRECTION))
}
else -> {
prefs.isEnabled = true
showConfettiAndContinue()
}
}

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="?attr/colorPrimary"/>
<item android:color="?attr/colorSurfaceContainer"/>
</selector>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="?attr/colorOnPrimaryContainer"/>
<item android:color="?attr/colorOnSurfaceVariant"/>
</selector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M13,3h-2v10h2L13,3zM17.83,5.17l-1.42,1.42C17.99,7.86 19,9.81 19,12c0,3.87 -3.13,7 -7,7s-7,-3.13 -7,-7c0,-2.19 1.01,-4.14 2.58,-5.42L6.17,5.17C4.23,6.82 3,9.26 3,12c0,4.97 4.03,9 9,9s9,-4.03 9,-9c0,-2.74 -1.23,-5.18 -3.17,-6.83z"/>
</vector>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true">
<shape android:shape="oval">
<solid android:color="?attr/colorPrimary" />
</shape>
</item>
<item>
<shape android:shape="oval">
<solid android:color="?attr/colorSurfaceContainerLowest" />
</shape>
</item>
</selector>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="?attr/colorSurfaceContainerLowest" />
<stroke
android:width="2dp"
android:color="?attr/colorOutline"/>
</shape>

View file

@ -1,12 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ToggleButton
<View
android:layout_width="104dp"
android:layout_height="104dp"
android:layout_gravity="center"
android:background="@drawable/toggle_button_bg_outline" />
<com.google.android.material.button.MaterialButton
android:id="@+id/toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp" />
android:layout_width="96dp"
android:layout_height="96dp"
android:layout_gravity="center"
android:checkable="true"
android:insetTop="0dp"
android:insetBottom="0dp"
android:insetLeft="0dp"
android:insetRight="0dp"
android:text=""
app:icon="@drawable/ic_power_settings_new_24"
app:iconTint="@color/toggle_button_icon"
app:backgroundTint="@color/toggle_button_bg"
app:iconSize="48dp"
app:iconGravity="textTop"
app:iconPadding="0dp"
app:cornerRadius="48dp" />
</FrameLayout>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="RoundIconShape" parent="">
<item name="cornerFamily">rounded</item>
<item name="cornerSize">100%</item>
</style>
</resources>

View file

@ -8,8 +8,9 @@
<item name="colorSecondary">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<item name="colorSurface">@color/white</item>
<item name="colorSurface">@color/white</item>
<item name="colorOnSurface">@color/black</item>
<item name="textAppearanceBodyMedium">@style/TextAppearance.Material3.BodyMedium</item>
<item name="colorSurfaceContainerLowest">?attr/colorSurfaceContainerLowest</item>
</style>
</resources>