Update the glance section

This commit is contained in:
Tommaso Berlose
2020-10-13 16:55:42 +02:00
parent abafe108c6
commit 0a0c5a90a7
60 changed files with 665 additions and 709 deletions

View File

@ -16,13 +16,18 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
@ -33,14 +38,14 @@ import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.tommasoberlose.anotherwidget.R
import com.tommasoberlose.anotherwidget.components.BottomSheetMenu
import com.tommasoberlose.anotherwidget.components.CustomNotesDialog
import com.tommasoberlose.anotherwidget.components.GlanceProviderSortMenu
import com.tommasoberlose.anotherwidget.components.MaterialBottomSheetDialog
import com.tommasoberlose.anotherwidget.components.*
import com.tommasoberlose.anotherwidget.databinding.FragmentGlanceSettingsBinding
import com.tommasoberlose.anotherwidget.global.Constants
import com.tommasoberlose.anotherwidget.global.Preferences
import com.tommasoberlose.anotherwidget.helpers.AlarmHelper
import com.tommasoberlose.anotherwidget.helpers.GlanceProviderHelper
import com.tommasoberlose.anotherwidget.helpers.MediaPlayerHelper
import com.tommasoberlose.anotherwidget.models.GlanceProvider
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver
import com.tommasoberlose.anotherwidget.receivers.ActivityDetectionReceiver.Companion.FITNESS_OPTIONS
import com.tommasoberlose.anotherwidget.ui.activities.MainActivity
@ -54,6 +59,8 @@ import kotlinx.android.synthetic.main.fragment_glance_settings.*
import kotlinx.android.synthetic.main.fragment_glance_settings.scrollView
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.idik.lib.slimadapter.SlimAdapter
import java.util.*
class GlanceTabFragment : Fragment() {
@ -62,6 +69,8 @@ class GlanceTabFragment : Fragment() {
fun newInstance() = GlanceTabFragment()
}
private var dialog: GlanceSettingsDialog? = null
private lateinit var adapter: SlimAdapter
private lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
@ -87,10 +96,125 @@ class GlanceTabFragment : Fragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
action_show_steps.isVisible = requireContext().checkIfFitInstalled()
// List
adapter = SlimAdapter.create()
providers_list.setHasFixedSize(true)
val mLayoutManager = LinearLayoutManager(context)
providers_list.layoutManager = mLayoutManager
adapter = SlimAdapter.create()
adapter
.register<GlanceProvider>(R.layout.glance_provider_item) { item, injector ->
val provider = Constants.GlanceProviderId.from(item.id)!!
injector
.text(R.id.title, item.title)
.with<ImageView>(R.id.icon) {
it.setImageDrawable(ContextCompat.getDrawable(requireContext(), item.icon))
}
.clicked(R.id.item) {
if (Preferences.showGlance) {
if (provider == Constants.GlanceProviderId.CUSTOM_INFO) {
CustomNotesDialog(requireContext()).show()
} else {
dialog = GlanceSettingsDialog(requireActivity(), provider) {
adapter.notifyItemRangeChanged(0, adapter.data.size)
}
dialog?.setOnDismissListener {
dialog = null
}
dialog?.show()
}
}
}
when (provider) {
Constants.GlanceProviderId.PLAYING_SONG -> {
when {
NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName) -> {
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
injector.invisible(R.id.error_icon)
injector.text(R.id.label, if (Preferences.showMusic) getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
}
Preferences.showMusic -> {
injector.visible(R.id.error_icon)
injector.text(R.id.label, getString(R.string.settings_not_visible))
}
else -> {
injector.invisible(R.id.error_icon)
injector.text(R.id.label, getString(R.string.settings_not_visible))
}
}
}
Constants.GlanceProviderId.NEXT_CLOCK_ALARM -> {
injector.text(R.id.label, if (Preferences.showNextAlarm && !AlarmHelper.isAlarmProbablyWrong(requireContext())) getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
injector.visibility(R.id.error_icon, if (Preferences.showNextAlarm && AlarmHelper.isAlarmProbablyWrong(requireContext())) View.VISIBLE else View.GONE)
}
Constants.GlanceProviderId.BATTERY_LEVEL_LOW -> {
injector.text(R.id.label, if (Preferences.showBatteryCharging) getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
injector.invisible(R.id.error_icon)
}
Constants.GlanceProviderId.CUSTOM_INFO -> {
injector.text(R.id.label, if (Preferences.customNotes != "") getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
injector.invisible(R.id.error_icon)
}
Constants.GlanceProviderId.GOOGLE_FIT_STEPS -> {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || activity?.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION) == true) {
injector.text(R.id.label, if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(R.string.settings_not_visible))
injector.invisible(R.id.error_icon)
} else if (Preferences.showDailySteps) {
ActivityDetectionReceiver.unregisterFence(requireContext())
injector.visible(R.id.error_icon)
injector.text(R.id.label, getString(R.string.settings_not_visible))
} else {
ActivityDetectionReceiver.unregisterFence(requireContext())
injector.text(R.id.label, getString(R.string.settings_not_visible))
injector.invisible(R.id.error_icon)
}
}
}
}
.attachTo(providers_list)
val mIth = ItemTouchHelper(
object : ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP or ItemTouchHelper.DOWN,
0
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder
): Boolean {
val fromPos = viewHolder.adapterPosition
val toPos = target.adapterPosition
// move item in `fromPos` to `toPos` in adapter.
adapter.notifyItemMoved(fromPos, toPos)
val list = GlanceProviderHelper.getGlanceProviders(requireContext())
Collections.swap(list, fromPos, toPos)
GlanceProviderHelper.saveGlanceProviderOrder(list)
return true
}
override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
return 1f
}
override fun onSwiped(
viewHolder: RecyclerView.ViewHolder,
direction: Int
) {
// remove from adapter
}
})
mIth.attachToRecyclerView(providers_list)
adapter.updateData(
GlanceProviderHelper.getGlanceProviders(requireContext())
.mapNotNull { GlanceProviderHelper.getGlanceProviderById(requireContext(), it) }
)
providers_list.isNestedScrollingEnabled = false
setupListener()
updateNextAlarmWarningUi()
}
private fun subscribeUi(
@ -105,45 +229,9 @@ class GlanceTabFragment : Fragment() {
show_glance_label.text = if (it) getString(R.string.description_show_glance_visible) else getString(R.string.description_show_glance_not_visible)
}
})
viewModel.showMusic.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
checkNotificationPermission()
}
})
viewModel.showNextAlarm.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
updateNextAlarmWarningUi()
}
})
viewModel.showBatteryCharging.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_low_battery_level_warning_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
})
viewModel.showDailySteps.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_steps_label?.text = if (it) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
checkFitnessPermission()
})
viewModel.customInfo.observe(viewLifecycleOwner, Observer {
maintainScrollPosition {
show_custom_notes_label?.text = if (it == "") getString(R.string.settings_not_visible) else it
}
})
viewModel.musicPlayersFilter.observe(viewLifecycleOwner, Observer {
})
}
private fun setupListener() {
action_show_glance.setOnClickListener {
Preferences.showGlance = !Preferences.showGlance
}
@ -151,134 +239,20 @@ class GlanceTabFragment : Fragment() {
show_glance_switch.setOnCheckedChangeListener { _, enabled: Boolean ->
Preferences.showGlance = enabled
}
action_sort_glance_providers.setOnClickListener {
GlanceProviderSortMenu(requireContext())
.show()
}
action_show_music.setOnClickListener {
if (Preferences.showGlance) {
BottomSheetMenu<Boolean>(
requireContext(),
header = getString(R.string.settings_show_music_title)
).setSelectedValue(Preferences.showMusic)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
Preferences.showMusic = value
}.show()
}
}
action_show_next_alarm.setOnClickListener {
if (Preferences.showGlance) {
BottomSheetMenu<Boolean>(
requireContext(),
header = getString(R.string.settings_show_next_alarm_title)
).setSelectedValue(Preferences.showNextAlarm)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
Preferences.showNextAlarm = value
}.show()
}
}
action_show_next_alarm.setOnLongClickListener {
with(requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
val alarm = nextAlarmClock
if (alarm != null && alarm.showIntent != null) {
val pm = requireContext().packageManager as PackageManager
val appNameOrPackage = try {
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
} catch (e: Exception) {
alarm.showIntent?.creatorPackage ?: ""
}
MaterialBottomSheetDialog(requireContext(), message = getString(R.string.next_alarm_warning).format(appNameOrPackage))
.setPositiveButton(getString(android.R.string.ok))
.show()
}
}
true
}
action_show_low_battery_level_warning.setOnClickListener {
if (Preferences.showGlance) {
BottomSheetMenu<Boolean>(
requireContext(),
header = getString(R.string.settings_low_battery_level_title)
).setSelectedValue(Preferences.showBatteryCharging)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
Preferences.showBatteryCharging = value
}.show()
}
}
action_show_steps.setOnClickListener {
if (Preferences.showGlance) {
BottomSheetMenu<Boolean>(
requireContext(),
header = getString(R.string.settings_daily_steps_title)
).setSelectedValue(Preferences.showDailySteps)
.addItem(getString(R.string.settings_visible), true)
.addItem(getString(R.string.settings_not_visible), false)
.addOnSelectItemListener { value ->
if (value) {
val account: GoogleSignInAccount? = GoogleSignIn.getLastSignedInAccount(requireContext())
if (!GoogleSignIn.hasPermissions(account, FITNESS_OPTIONS)) {
val mGoogleSignInClient = GoogleSignIn.getClient(requireActivity(), GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN).addExtension(FITNESS_OPTIONS).build())
startActivityForResult(mGoogleSignInClient.signInIntent, 2)
} else {
Preferences.showDailySteps = true
}
} else {
Preferences.showDailySteps = false
}
}.show()
}
}
action_show_custom_notes.setOnClickListener {
if (Preferences.showGlance) {
CustomNotesDialog(requireContext()).show()
}
}
action_filter_music_players.setOnClickListener {
startActivity(Intent(requireContext(), MusicPlayersFilterActivity::class.java))
}
}
private fun updateNextAlarmWarningUi() {
with(requireContext().getSystemService(Context.ALARM_SERVICE) as AlarmManager) {
val alarm = nextAlarmClock
if (AlarmHelper.isAlarmProbablyWrong(requireContext()) && alarm != null && alarm.showIntent != null) {
val pm = requireContext().packageManager as PackageManager
val appNameOrPackage = try {
pm.getApplicationLabel(pm.getApplicationInfo(alarm.showIntent?.creatorPackage ?: "", 0))
} catch (e: Exception) {
alarm.showIntent?.creatorPackage ?: ""
}
show_next_alarm_warning.text = getString(R.string.next_alarm_warning).format(appNameOrPackage)
} else {
show_next_alarm_label?.text = if (Preferences.showNextAlarm) getString(R.string.settings_visible) else getString(
R.string.settings_not_visible)
}
}
}
private val nextAlarmChangeBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
updateNextAlarmWarningUi()
adapter.notifyItemChanged(1)
}
}
override fun onStart() {
super.onStart()
activity?.registerReceiver(nextAlarmChangeBroadcastReceiver, IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED))
if (dialog != null) {
dialog?.show()
}
}
override fun onStop() {
@ -286,50 +260,6 @@ class GlanceTabFragment : Fragment() {
super.onStop()
}
private fun checkNotificationPermission() {
when {
NotificationManagerCompat.getEnabledListenerPackages(requireContext()).contains(requireContext().packageName) -> {
notification_permission_alert?.isVisible = false
MediaPlayerHelper.updatePlayingMediaInfo(requireContext())
show_music_label?.text = if (Preferences.showMusic) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
}
Preferences.showMusic -> {
notification_permission_alert?.isVisible = true
show_music_label?.text = getString(R.string.settings_request_notification_access)
notification_permission_alert?.setOnClickListener {
activity?.startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
}
}
else -> {
show_music_label?.text = getString(R.string.settings_not_visible)
notification_permission_alert?.isVisible = false
}
}
}
private fun checkFitnessPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || activity?.checkGrantedPermission(Manifest.permission.ACTIVITY_RECOGNITION) == true) {
fitness_permission_alert?.isVisible = false
if (Preferences.showDailySteps) {
ActivityDetectionReceiver.registerFence(requireContext())
} else {
ActivityDetectionReceiver.unregisterFence(requireContext())
}
show_steps_label?.text = if (Preferences.showDailySteps) getString(R.string.settings_visible) else getString(R.string.settings_not_visible)
} else if (Preferences.showDailySteps) {
ActivityDetectionReceiver.unregisterFence(requireContext())
fitness_permission_alert?.isVisible = true
show_steps_label?.text = getString(R.string.settings_request_fitness_access)
fitness_permission_alert?.setOnClickListener {
requireFitnessPermission()
}
} else {
ActivityDetectionReceiver.unregisterFence(requireContext())
show_steps_label?.text = getString(R.string.settings_not_visible)
fitness_permission_alert?.isVisible = false
}
}
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
@ -338,9 +268,15 @@ class GlanceTabFragment : Fragment() {
when (requestCode) {
1 -> {
if (resultCode == Activity.RESULT_OK) {
checkFitnessPermission()
adapter.notifyItemChanged(2)
if (dialog != null) {
dialog?.show()
}
} else {
Preferences.showDailySteps = false
if (dialog != null) {
dialog?.show()
}
}
}
2-> {
@ -353,42 +289,22 @@ class GlanceTabFragment : Fragment() {
account,
FITNESS_OPTIONS)
} else {
checkFitnessPermission()
adapter.notifyItemChanged(2)
if (dialog != null) {
dialog?.show()
}
}
} catch (e: ApiException) {
e.printStackTrace()
Preferences.showDailySteps = false
if (dialog != null) {
dialog?.show()
}
}
}
}
}
private fun requireFitnessPermission() {
Dexter.withContext(requireContext())
.withPermissions(
"com.google.android.gms.permission.ACTIVITY_RECOGNITION",
"android.gms.permission.ACTIVITY_RECOGNITION",
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) Manifest.permission.ACTIVITY_RECOGNITION else "com.google.android.gms.permission.ACTIVITY_RECOGNITION"
).withListener(object: MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
report?.let {
if (report.areAllPermissionsGranted()){
checkFitnessPermission()
}
}
}
override fun onPermissionRationaleShouldBeShown(
permissions: MutableList<PermissionRequest>?,
token: PermissionToken?
) {
// Remember to invoke this method when the custom rationale is closed
// or just by default if you don't want to use any custom rationale.
token?.continuePermissionRequest()
}
})
.check()
}
private fun maintainScrollPosition(callback: () -> Unit) {
scrollView.isScrollable = false
callback.invoke()
@ -400,6 +316,6 @@ class GlanceTabFragment : Fragment() {
override fun onResume() {
super.onResume()
checkNotificationPermission()
adapter.notifyItemRangeChanged(0, adapter.data.size)
}
}