Skip to content
This repository has been archived by the owner on Sep 3, 2023. It is now read-only.

Commit

Permalink
Add setting for floating button controls - hook it up to overlay perm…
Browse files Browse the repository at this point in the history
…ission and UI
  • Loading branch information
afollestad committed Jan 10, 2019
1 parent 6a46e6c commit f6a9f73
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 37 deletions.
Expand Up @@ -17,7 +17,7 @@ package com.afollestad.mnmlscreenrecord.di

import com.afollestad.mnmlscreenrecord.common.Qualifiers.IO_DISPATCHER
import com.afollestad.mnmlscreenrecord.common.Qualifiers.MAIN_DISPATCHER
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_ALWAYS_SHOW_NOTIFICATION
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_ALWAYS_SHOW_CONTROLS
import com.afollestad.mnmlscreenrecord.ui.main.MainViewModel
import org.koin.androidx.viewmodel.ext.koin.viewModel
import org.koin.dsl.module.module
Expand All @@ -36,7 +36,7 @@ val viewModelModule = module {
get(),
get(),
get(),
get(name = PREF_ALWAYS_SHOW_NOTIFICATION)
get(name = PREF_ALWAYS_SHOW_CONTROLS)
)
}
}
Expand Up @@ -15,50 +15,103 @@
*/
package com.afollestad.mnmlscreenrecord.ui.settings.sub

import android.content.Intent
import android.os.Bundle
import android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION
import androidx.preference.SwitchPreference
import com.afollestad.mnmlscreenrecord.R
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_ALWAYS_SHOW_NOTIFICATION
import com.afollestad.mnmlscreenrecord.common.misc.toUri
import com.afollestad.mnmlscreenrecord.common.permissions.PermissionChecker
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_ALWAYS_SHOW_CONTROLS
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_FLOATING_CONTROLS
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_STOP_ON_SCREEN_OFF
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_STOP_ON_SHAKE
import com.afollestad.mnmlscreenrecord.common.rx.attachLifecycle
import com.afollestad.mnmlscreenrecord.engine.permission.OverlayExplanationCallback
import com.afollestad.mnmlscreenrecord.engine.permission.OverlayExplanationDialog
import com.afollestad.mnmlscreenrecord.ui.settings.base.BaseSettingsFragment
import com.afollestad.rxkprefs.Pref
import org.koin.android.ext.android.inject

/** @author Aidan Follestad (@afollestad) */
class SettingsControlsFragment : BaseSettingsFragment() {
class SettingsControlsFragment : BaseSettingsFragment(), OverlayExplanationCallback {
companion object {
private const val DRAW_OVER_OTHER_APP_PERMISSION = 68
}

private val permissionChecker by inject<PermissionChecker>()

private val stopOnScreenOffPref by inject<Pref<Boolean>>(name = PREF_STOP_ON_SCREEN_OFF)
private val alwaysShowNotificationPref by inject<Pref<Boolean>>(
name = PREF_ALWAYS_SHOW_NOTIFICATION
private val alwaysShowControlsPref by inject<Pref<Boolean>>(
name = PREF_ALWAYS_SHOW_CONTROLS
)
private val stopOnShakePref by inject<Pref<Boolean>>(name = PREF_STOP_ON_SHAKE)
private val floatingControlsPref by inject<Pref<Boolean>>(name = PREF_FLOATING_CONTROLS)

override fun onCreatePreferences(
savedInstanceState: Bundle?,
rootKey: String?
) {
setPreferencesFromResource(R.xml.settings_controls, rootKey)

setupAlwaysShowNotificationPref()
setupAlwaysShowControlsPref()
setupStopOnScreenOffPref()
setupStopOnShakePref()
setupFloatingControlsPref()
}

private fun setupAlwaysShowNotificationPref() {
val alwaysShowNotificationEntry =
findPreference(PREF_ALWAYS_SHOW_NOTIFICATION) as SwitchPreference
alwaysShowNotificationEntry.setOnPreferenceChangeListener { _, newValue ->
alwaysShowNotificationPref.set(newValue as Boolean)
private fun setupAlwaysShowControlsPref() {
val alwaysShowControlsEntry =
findPreference(PREF_ALWAYS_SHOW_CONTROLS) as SwitchPreference
alwaysShowControlsEntry.setOnPreferenceChangeListener { _, newValue ->
alwaysShowControlsPref.set(newValue as Boolean)
true
}
alwaysShowNotificationPref.observe()
alwaysShowControlsPref.observe()
.distinctUntilChanged()
.subscribe { alwaysShowNotificationEntry.isChecked = it }
.subscribe { alwaysShowControlsEntry.isChecked = it }
.attachLifecycle(this)
}

private fun setupFloatingControlsPref() {
val floatingControlsEntry =
findPreference(PREF_FLOATING_CONTROLS) as SwitchPreference
floatingControlsEntry.setOnPreferenceChangeListener { _, newValue ->
if (permissionChecker.hasOverlayPermission()) {
floatingControlsPref.set(newValue as Boolean)
true
} else {
OverlayExplanationDialog.show(this@SettingsControlsFragment)
false
}
}
floatingControlsPref.observe()
.subscribe { floatingControlsEntry.isChecked = it }
.attachLifecycle(this)
}

override fun onShouldAskForOverlayPermission() {
val intent = Intent(
ACTION_MANAGE_OVERLAY_PERMISSION,
"package:${activity?.packageName}".toUri()
)
startActivityForResult(
intent,
DRAW_OVER_OTHER_APP_PERMISSION
)
}

override fun onActivityResult(
requestCode: Int,
resultCode: Int,
data: Intent?
) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == DRAW_OVER_OTHER_APP_PERMISSION && permissionChecker.hasOverlayPermission()) {
floatingControlsPref.set(true)
}
}

private fun setupStopOnScreenOffPref() {
val stopOnScreenOffEntry = findPreference(PREF_STOP_ON_SCREEN_OFF) as SwitchPreference
stopOnScreenOffEntry.setOnPreferenceChangeListener { _, newValue ->
Expand Down
22 changes: 13 additions & 9 deletions app/src/main/res/values/strings_settings.xml
Expand Up @@ -79,15 +79,6 @@
When your screen is turned off, nothing special will happen.
</string>

<string name="setting_always_show_notification">Always Show Notification</string>
<string name="setting_always_show_notification_on">
The persistent controls notification is shown when the app is launched, and won\'t go
away until you dismiss it with the \'X\' button.
</string>
<string name="setting_always_show_notification_off">
The persistent controls notification is only show when capture is in-progress.
</string>

<string name="setting_stop_on_shake">Stop on Shake</string>
<string name="setting_stop_on_shake_on">
Shaking your device will stop any active screen recording.
Expand All @@ -96,6 +87,19 @@
Shaking your device won\'t do anything special.
</string>

<string name="setting_floating_controls">Floating Controls</string>
<string name="setting_floating_controls_on">
A floating button is overlaid on your screen to quickly start &amp; stop recording.
</string>
<string name="setting_floating_controls_off">The floating button is disabled.</string>

<string name="setting_always_show_controls">Always Show Controls</string>
<string name="setting_always_show_controls_on">
Controls such as the notification &amp; the floating button are shown when the app is launched,
and won\'t go away until you dismiss the notification or floating button.
</string>
<string name="setting_always_show_controls_off">Controls are only shown when capture is in-progress.</string>

<!-- Misc -->
<string name="select">Select</string>

Expand Down
21 changes: 14 additions & 7 deletions app/src/main/res/xml/settings_controls.xml
Expand Up @@ -5,13 +5,6 @@
android:layout="@layout/custom_preference_category"
android:title="@string/setting_category_controls">

<SwitchPreference
android:key="always_show_controls_notification"
android:layout="@layout/custom_preference"
android:summaryOff="@string/setting_always_show_notification_off"
android:summaryOn="@string/setting_always_show_notification_on"
android:title="@string/setting_always_show_notification"/>

<SwitchPreference
android:key="stop_on_screen_off"
android:layout="@layout/custom_preference"
Expand All @@ -26,6 +19,20 @@
android:summaryOn="@string/setting_stop_on_shake_on"
android:title="@string/setting_stop_on_shake"/>

<SwitchPreference
android:key="always_show_controls_notification"
android:layout="@layout/custom_preference"
android:summaryOff="@string/setting_always_show_controls_off"
android:summaryOn="@string/setting_always_show_controls_on"
android:title="@string/setting_always_show_controls"/>

<SwitchPreference
android:key="floating_controls"
android:layout="@layout/custom_preference"
android:summaryOff="@string/setting_floating_controls_off"
android:summaryOn="@string/setting_floating_controls_on"
android:title="@string/setting_floating_controls"/>

</PreferenceCategory>

</PreferenceScreen>
Expand Up @@ -17,13 +17,14 @@ package com.afollestad.mnmlscreenrecord.common

import android.os.Environment.DIRECTORY_DCIM
import android.os.Environment.getExternalStoragePublicDirectory
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_ALWAYS_SHOW_NOTIFICATION
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_ALWAYS_SHOW_CONTROLS
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_AUDIO_BIT_RATE
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_COUNTDOWN
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_DARK_MODE
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_DARK_MODE_AUTOMATIC
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_DARK_MODE_END
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_DARK_MODE_START
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_FLOATING_CONTROLS
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_FRAME_RATE
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_RECORDINGS_FOLDER
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_RECORD_AUDIO
Expand Down Expand Up @@ -100,11 +101,15 @@ val prefModule = module {
get<RxkPrefs>().boolean(PREF_STOP_ON_SCREEN_OFF, true)
}

factory(name = PREF_ALWAYS_SHOW_NOTIFICATION) {
get<RxkPrefs>().boolean(PREF_ALWAYS_SHOW_NOTIFICATION, false)
factory(name = PREF_ALWAYS_SHOW_CONTROLS) {
get<RxkPrefs>().boolean(PREF_ALWAYS_SHOW_CONTROLS, false)
}

factory(name = PREF_STOP_ON_SHAKE) {
get<RxkPrefs>().boolean(PREF_STOP_ON_SHAKE, true)
}

factory(name = PREF_FLOATING_CONTROLS) {
get<RxkPrefs>().boolean(PREF_FLOATING_CONTROLS, false)
}
}
Expand Up @@ -37,7 +37,8 @@ object PrefNames {
const val PREF_RECORDINGS_FOLDER = "recordings_folder"

// Controls
const val PREF_ALWAYS_SHOW_NOTIFICATION = "always_show_controls_notification"
const val PREF_ALWAYS_SHOW_CONTROLS = "always_show_controls_notification"
const val PREF_STOP_ON_SCREEN_OFF = "stop_on_screen_off"
const val PREF_STOP_ON_SHAKE = "stop_on_shake"
const val PREF_FLOATING_CONTROLS = "floating_controls"
}
Expand Up @@ -20,6 +20,7 @@ import android.content.DialogInterface
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.callbacks.onCancel
Expand Down Expand Up @@ -47,11 +48,25 @@ class OverlayExplanationDialog : DialogFragment() {
Crashlytics.log("Not showing OverlayExplanationDialog due to IllegalStateException.")
}
}

fun <T> show(context: T) where T : Fragment, T : OverlayExplanationCallback {
val dialog = OverlayExplanationDialog()
try {
dialog.show(context.childFragmentManager, TAG)
} catch (_: java.lang.IllegalStateException) {
Crashlytics.log("Not showing OverlayExplanationDialog due to IllegalStateException.")
}
}
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val context = activity ?: throw IllegalStateException("Oh no!")
val callback = context as OverlayExplanationCallback
var callback = context as? OverlayExplanationCallback
if (callback == null) {
callback = parentFragment as? OverlayExplanationCallback ?: throw IllegalStateException(
"Couldn't find callback from Activity or parent Fragment."
)
}

try {
return MaterialDialog(context)
Expand Down
Expand Up @@ -26,7 +26,7 @@ import androidx.lifecycle.LifecycleOwner
import com.afollestad.mnmlscreenrecord.common.intent.IntentReceiver
import com.afollestad.mnmlscreenrecord.common.lifecycle.SimpleLifecycle
import com.afollestad.mnmlscreenrecord.common.permissions.PermissionChecker
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_ALWAYS_SHOW_NOTIFICATION
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_ALWAYS_SHOW_CONTROLS
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_STOP_ON_SCREEN_OFF
import com.afollestad.mnmlscreenrecord.common.prefs.PrefNames.PREF_STOP_ON_SHAKE
import com.afollestad.mnmlscreenrecord.common.rx.attachLifecycle
Expand Down Expand Up @@ -79,7 +79,7 @@ class BackgroundService : Service(), LifecycleOwner {

private val stopOnScreenOffPref by inject<Pref<Boolean>>(name = PREF_STOP_ON_SCREEN_OFF)
private val alwaysShowNotificationPref by inject<Pref<Boolean>>(
name = PREF_ALWAYS_SHOW_NOTIFICATION
name = PREF_ALWAYS_SHOW_CONTROLS
)
private val stopOnShakePref by inject<Pref<Boolean>>(name = PREF_STOP_ON_SHAKE)

Expand Down

0 comments on commit f6a9f73

Please sign in to comment.