[go: nahoru, domu]

Skip to content

Commit

Permalink
Created NotificationsTypes fragment
Browse files Browse the repository at this point in the history
1) Why?
-> androidx.preference does not support addition of Child Preference Screens programtically no longer.
Reference: https://stackoverflow.com/questions/60029806/why-does-the-nested-preferencescreen-not-open-when-using-androidx
(Cites documentation as proof of result)

2) Why `ChildNotificationSettingsFragment`?
-> To automatically change toolbar's state.

3) Why Change `NotificationsSettingsActivity`?
-> The new androidx implementation requires the use of `PreferenceFragmentCompat` and to navigate to child preference screens, we need the parent activity to implement
`PreferenceFragmentCompat.OnPreferenceStartFragmentCallback`
  • Loading branch information
07jasjeet committed Jan 10, 2024
1 parent 7bd1a5f commit d2d3cb1
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.wordpress.android.ui.prefs.notifications

import android.os.Bundle
import android.view.Gravity
import android.view.View
import androidx.preference.PreferenceFragmentCompat
import androidx.transition.Slide
import androidx.transition.Transition
import androidx.transition.TransitionManager
import com.google.android.material.appbar.AppBarLayout
import org.wordpress.android.R

/** Child Notification fragments should inherit from this class in order to make navigation consistent.*/
abstract class ChildNotificationSettingsFragment: PreferenceFragmentCompat() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setMainSwitchVisibility(View.GONE)
}

override fun onDestroy() {
super.onDestroy()
setMainSwitchVisibility(View.VISIBLE)
}

private fun setMainSwitchVisibility(visibility: Int) {
with(requireActivity()) {
val mainSwitchToolBarView = findViewById<PrefMainSwitchToolbarView>(R.id.main_switch)
val rootView = findViewById<AppBarLayout>(R.id.app_bar_layout)
val transition: Transition = Slide(Gravity.TOP)
transition.duration = 200
transition.addTarget(R.id.main_switch)

TransitionManager.beginDelayedTransition(rootView, transition)
mainSwitchToolBarView.visibility = visibility
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import android.widget.CompoundButton
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.commit
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
Expand All @@ -29,7 +32,8 @@ import javax.inject.Named
import android.R as AndroidR

@AndroidEntryPoint
class NotificationsSettingsActivity : LocaleAwareActivity(), MainSwitchToolbarListener {
class NotificationsSettingsActivity : LocaleAwareActivity(),
MainSwitchToolbarListener, PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
@Inject
lateinit var updateNotificationSettingsUseCase: UpdateNotificationSettingsUseCase

Expand All @@ -52,10 +56,9 @@ class NotificationsSettingsActivity : LocaleAwareActivity(), MainSwitchToolbarLi
setUpMainSwitch()

if (savedInstanceState == null) {
@Suppress("DEPRECATION")
fragmentManager.beginTransaction()
.add(R.id.fragment_container, NotificationsSettingsFragment())
.commit()
supportFragmentManager.commit {
add(R.id.fragment_container, NotificationsSettingsFragment())
}
}

messageContainer = findViewById(R.id.notifications_settings_message_container)
Expand All @@ -82,6 +85,33 @@ class NotificationsSettingsActivity : LocaleAwareActivity(), MainSwitchToolbarLi
return super.onOptionsItemSelected(item)
}

@Suppress("DEPRECATION")
override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference): Boolean {
val args = pref.extras
val fragment = supportFragmentManager.fragmentFactory.instantiate(
classLoader,
pref.fragment!!
)

val titleView = findViewById<TextView>(R.id.toolbar_title)
titleView.text = pref.title

fragment.arguments = args
fragment.setTargetFragment(caller, 0)
// Replace the existing Fragment with the new Fragment.
supportFragmentManager.commit {
setCustomAnimations(
R.anim.fade_in,
R.anim.fade_out,
R.anim.fade_in,
R.anim.fade_out,
)
replace(R.id.fragment_container, fragment)
addToBackStack(null)
}
return true
}

@Subscribe(threadMode = MAIN)
fun onEventMainThread(event: NotificationsSettingsStatusChanged) {
if (TextUtils.isEmpty(event.message)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
package org.wordpress.android.ui.prefs.notifications

import android.graphics.PorterDuff
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import androidx.annotation.DrawableRes
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceManager
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import org.wordpress.android.R
import org.wordpress.android.WordPress
import org.wordpress.android.models.NotificationsSettings
import org.wordpress.android.ui.RequestCodes
import org.wordpress.android.ui.bloggingreminders.BloggingReminderUtils
import org.wordpress.android.ui.bloggingreminders.BloggingRemindersViewModel
import org.wordpress.android.ui.notifications.utils.NotificationsUtils
import org.wordpress.android.ui.utils.UiHelpers
import org.wordpress.android.ui.utils.UiString
import org.wordpress.android.util.AppLog
import org.wordpress.android.util.extensions.getColorStateListFromAttribute
import javax.inject.Inject

class NotificationsSettingsTypesFragment: ChildNotificationSettingsFragment() {
companion object {
const val ARG_BLOG_ID = "ARG_BLOG_ID"
const val ARG_NOTIFICATION_CHANNEL = "ARG_NOTIFICATION_CHANNEL"
const val ARG_NOTIFICATIONS_ENABLED = "ARG_NOTIFICATIONS_ENABLED"

private const val BLOGGING_REMINDERS_BOTTOM_SHEET_TAG = "blogging-reminders-dialog-tag"
}

@Inject
lateinit var mViewModelFactory: ViewModelProvider.Factory

@Inject
lateinit var mUiHelpers: UiHelpers

private var mDeviceId: String? = null
private var mNotificationsSettings: NotificationsSettings? = null
private var mNotificationsEnabled: Boolean = false
private var mBloggingRemindersViewModel: BloggingRemindersViewModel? = null
private val mBloggingRemindersSummariesBySiteId: MutableMap<Long?, UiString?> = HashMap()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
(requireActivity().application as WordPress).component().inject(this)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initBloggingReminders()
}

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

loadNotificationsSettings()

val settings = PreferenceManager.getDefaultSharedPreferences(requireActivity())
mDeviceId = settings.getString(NotificationsUtils.WPCOM_PUSH_DEVICE_SERVER_ID, "")

val blogId: Long
val channel: NotificationsSettings.Channel
requireArguments().apply {
blogId = getLong(ARG_BLOG_ID)
channel = NotificationsSettings.Channel.toNotificationChannel(getInt(ARG_NOTIFICATION_CHANNEL))
mNotificationsEnabled = getBoolean(ARG_NOTIFICATIONS_ENABLED)
}

val context = requireContext()
val category = PreferenceCategory(context)
category.setTitle(R.string.notification_types)
preferenceScreen.addPreference(category)

val timelinePreference = NotificationsSettingsDialogPreferenceX(
context = context, attrs = null, channel = channel, type = NotificationsSettings.Type.TIMELINE,
blogId = blogId, settings = mNotificationsSettings!!, listener = mOnSettingsChangedListener,
dialogTitleRes = R.string.notifications_tab
).apply {
setPreferenceIcon(R.drawable.ic_bell_white_24dp)
setTitle(R.string.notifications_tab)
setSummary(R.string.notifications_tab_summary)
key = getString(R.string.notifications_tab)
}
category.addPreference(timelinePreference)

val emailPreference = NotificationsSettingsDialogPreferenceX(
context = context, attrs = null, channel = channel, type = NotificationsSettings.Type.EMAIL,
blogId = blogId, settings = mNotificationsSettings!!, listener = mOnSettingsChangedListener,
dialogTitleRes = R.string.email
).apply {
setPreferenceIcon(R.drawable.ic_mail_white_24dp)
setTitle(R.string.email)
setSummary(R.string.notifications_email_summary)
key = getString(R.string.email)
}
category.addPreference(emailPreference)

if (!TextUtils.isEmpty(mDeviceId)) {
val devicePreference = NotificationsSettingsDialogPreferenceX(
context = context, attrs = null, channel = channel, type = NotificationsSettings.Type.DEVICE,
blogId = blogId, settings = mNotificationsSettings!!, listener = mOnSettingsChangedListener,
bloggingRemindersProvider = mBloggingRemindersProvider, dialogTitleRes = R.string.app_notifications
).apply {
setPreferenceIcon(R.drawable.ic_phone_white_24dp)
setTitle(R.string.app_notifications)
setSummary(R.string.notifications_push_summary)
key = getString(R.string.app_notifications)
isEnabled = mNotificationsEnabled
}
category.addPreference(devicePreference)
}
}

@Suppress("DEPRECATION", "Warnings")
override fun onDisplayPreferenceDialog(preference: Preference) {
if (preference is NotificationsSettingsDialogPreferenceX) {
if (parentFragmentManager.findFragmentByTag(NotificationsSettingsDialogFragment.TAG) != null) {
return
}

with(preference) {
NotificationsSettingsDialogFragment(
channel = channel,
type = type,
blogId = blogId,
settings = settings,
onNotificationsSettingsChangedListener = listener,
bloggingRemindersProvider = bloggingRemindersProvider,
title = context.getString(dialogTitleRes)
).apply {
setTargetFragment(
this@NotificationsSettingsTypesFragment,
RequestCodes.NOTIFICATION_SETTINGS
)
}.show(
parentFragmentManager,
NotificationsSettingsDialogFragment.TAG
)
}
} else {
super.onDisplayPreferenceDialog(preference)
}
}

private val mOnSettingsChangedListener =
NotificationsSettingsDialogPreference.OnNotificationsSettingsChangedListener { channel, type, blogId, newValues ->
if (!isAdded) {
return@OnNotificationsSettingsChangedListener
}

// Construct a new settings JSONObject to send back to WP.com
val settingsObject = JSONObject()
when (channel!!) {
NotificationsSettings.Channel.BLOGS -> try {
val blogObject = JSONObject()
blogObject.put(NotificationsSettings.KEY_BLOG_ID, blogId)
val blogsArray = JSONArray()
if (type == NotificationsSettings.Type.DEVICE) {
newValues.put(NotificationsSettings.KEY_DEVICE_ID, mDeviceId!!.toLong())
val devicesArray = JSONArray()
devicesArray.put(newValues)
blogObject.put(NotificationsSettings.KEY_DEVICES, devicesArray)
blogsArray.put(blogObject)
} else {
blogObject.put(type.toString(), newValues)
blogsArray.put(blogObject)
}
settingsObject.put(NotificationsSettings.KEY_BLOGS, blogsArray)
} catch (e: JSONException) {
AppLog.e(AppLog.T.NOTIFS, "Could not build notification settings object")
}

NotificationsSettings.Channel.OTHER -> try {
val otherObject = JSONObject()
if (type == NotificationsSettings.Type.DEVICE) {
newValues.put(NotificationsSettings.KEY_DEVICE_ID, mDeviceId!!.toLong())
val devicesArray = JSONArray()
devicesArray.put(newValues)
otherObject.put(NotificationsSettings.KEY_DEVICES, devicesArray)
} else {
otherObject.put(type.toString(), newValues)
}
settingsObject.put(NotificationsSettings.KEY_OTHER, otherObject)
} catch (e: JSONException) {
AppLog.e(AppLog.T.NOTIFS, "Could not build notification settings object")
}

NotificationsSettings.Channel.WPCOM -> try {
settingsObject.put(NotificationsSettings.KEY_WPCOM, newValues)
} catch (e: JSONException) {
AppLog.e(AppLog.T.NOTIFS, "Could not build notification settings object")
}
}
if (settingsObject.length() > 0) {
WordPress.getRestClientUtilsV1_1()
.post("/me/notifications/settings", settingsObject, null, null, null)
}
}

private val mBloggingRemindersProvider: NotificationsSettingsDialogPreference.BloggingRemindersProvider = object :
NotificationsSettingsDialogPreference.BloggingRemindersProvider {
override fun getSummary(blogId: Long): String? {
val uiString = mBloggingRemindersSummariesBySiteId[blogId]
return if (uiString != null) mUiHelpers.getTextOfUiString(requireContext(), uiString).toString() else null
}

override fun onClick(blogId: Long) {
mBloggingRemindersViewModel!!.onNotificationSettingsItemClicked(blogId)
}
}

private fun initBloggingReminders() {
if (!isAdded) {
return
}
(activity as AppCompatActivity?)?.let { activity ->
mBloggingRemindersViewModel = ViewModelProvider(
activity,
mViewModelFactory
)[BloggingRemindersViewModel::class.java]
BloggingReminderUtils.observeBottomSheet(
mBloggingRemindersViewModel!!.isBottomSheetShowing,
activity,
BLOGGING_REMINDERS_BOTTOM_SHEET_TAG
) { activity.supportFragmentManager }
mBloggingRemindersViewModel!!.notificationsSettingsUiState
.observe(activity) { map ->
mBloggingRemindersSummariesBySiteId.putAll(map)
}
}
}

private fun loadNotificationsSettings() {
val settingsJson: JSONObject = try {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity())
JSONObject(
sharedPreferences.getString(NotificationsUtils.WPCOM_PUSH_DEVICE_NOTIFICATION_SETTINGS, "")!!
)
} catch (e: JSONException) {
AppLog.e(AppLog.T.NOTIFS, "Could not parse notifications settings JSON")
return
}
if (mNotificationsSettings == null) {
mNotificationsSettings = NotificationsSettings(settingsJson)
} else {
mNotificationsSettings!!.updateJson(settingsJson)
}
}

private fun NotificationsSettingsDialogPreferenceX.setPreferenceIcon(@DrawableRes drawableRes: Int) {
setIcon(drawableRes)
icon?.setTintMode(PorterDuff.Mode.SRC_IN)
icon?.setTintList(context.getColorStateListFromAttribute(R.attr.wpColorOnSurfaceMedium))
}
}
Loading

0 comments on commit d2d3cb1

Please sign in to comment.