diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index acb88ff2716..8ed9afea212 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -263,6 +263,8 @@
+
+
{
- FeedbackUtil.composeFeedbackEmail(requireContext(),
- getString(R.string.email_report_patroller_tasks_subject),
- getString(R.string.email_report_patroller_tasks_body))
+ showFeedbackOptionsDialog(true)
true
}
else -> false
@@ -370,6 +387,15 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
}
}
+ private fun maybeShowOneTimeSequentialRecentEditsTooltips() {
+ if (Prefs.showOneTimeSequentialRecentEditsDiffTooltip && viewModel.fromRecentEdits &&
+ binding.oresDamagingButton.isVisible && binding.oresGoodFaithButton.isVisible) {
+ Prefs.showOneTimeSequentialRecentEditsDiffTooltip = false
+ binding.scrollContainer.removeCallbacks(sequentialTooltipRunnable)
+ binding.scrollContainer.postDelayed(sequentialTooltipRunnable, 500)
+ }
+ }
+
private fun setErrorState(t: Throwable) {
L.e(t)
binding.errorView.setError(t)
@@ -433,6 +459,8 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
binding.oresGoodFaithButton.isVisible = true
binding.oresGoodFaithButton.text = getString(R.string.edit_intent, ((it.ores?.goodfaithProb ?: 0f) * 100f).toInt().toString().plus("%"))
binding.oresGoodFaithButton.setOnClickListener(openQualityAndIntentFiltersPage)
+
+ maybeShowOneTimeSequentialRecentEditsTooltips()
}
}
@@ -492,10 +520,34 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
ExclusiveBottomSheetPresenter.show(childFragmentManager, WatchlistExpiryDialog.newInstance(expiry))
}
}
+ snackbar.addCallback(object : Snackbar.Callback() {
+ override fun onDismissed(transientBottomBar: Snackbar, @DismissEvent event: Int) {
+ if (!isAdded || viewModel.watchlistExpiryChanged) {
+ return
+ }
+ showFeedbackOptionsDialog()
+ }
+ })
snackbar.show()
}
}
+ private fun showThankSnackbar() {
+ val snackbar = FeedbackUtil.makeSnackbar(requireActivity(), getString(R.string.thank_success_message,
+ viewModel.revisionTo?.user))
+ binding.thankIcon.setImageResource(R.drawable.ic_heart_24)
+ binding.thankButton.isEnabled = false
+ snackbar.addCallback(object : Snackbar.Callback() {
+ override fun onDismissed(transientBottomBar: Snackbar, @DismissEvent event: Int) {
+ if (!isAdded) {
+ return
+ }
+ showFeedbackOptionsDialog()
+ }
+ })
+ snackbar.show()
+ }
+
private fun showThankDialog() {
val parent = FrameLayout(requireContext())
val dialog = MaterialAlertDialogBuilder(requireActivity())
@@ -521,6 +573,19 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
dialog.show()
}
+ private fun showUndoSnackbar() {
+ val snackbar = FeedbackUtil.makeSnackbar(requireActivity(), getString(R.string.revision_undo_success))
+ snackbar.addCallback(object : Snackbar.Callback() {
+ override fun onDismissed(transientBottomBar: Snackbar, @DismissEvent event: Int) {
+ if (!isAdded) {
+ return
+ }
+ showFeedbackOptionsDialog()
+ }
+ })
+ snackbar.show()
+ }
+
private fun showRollbackDialog() {
MaterialAlertDialogBuilder(requireActivity())
.setMessage(R.string.revision_rollback_dialog_title)
@@ -534,6 +599,85 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
.show()
}
+ private fun showRollbackSnackbar() {
+ val snackbar = FeedbackUtil.makeSnackbar(requireActivity(), getString(R.string.revision_rollback_success))
+ snackbar.addCallback(object : Snackbar.Callback() {
+ override fun onDismissed(transientBottomBar: Snackbar, @DismissEvent event: Int) {
+ if (!isAdded) {
+ return
+ }
+ showFeedbackOptionsDialog()
+ }
+ })
+ snackbar.show()
+ }
+
+ private fun showFeedbackOptionsDialog(skipPreference: Boolean = false) {
+ if (!skipPreference && !Prefs.showOneTimeRecentEditsFeedbackForm) {
+ return
+ }
+
+ var dialog: AlertDialog? = null
+ val feedbackView = layoutInflater.inflate(R.layout.dialog_patrol_edit_feedback_options, null)
+
+ val clickListener = View.OnClickListener {
+ viewModel.feedbackOption = (it as TextView).text.toString()
+ dialog?.dismiss()
+ if (viewModel.feedbackOption == getString(R.string.patroller_diff_feedback_dialog_option_satisfied)) {
+ // TODO: send to the event logging since it is satisfied
+ showFeedbackSnackbarAndTooltip()
+ } else {
+ showFeedbackInputDialog()
+ }
+ }
+
+ feedbackView.findViewById(R.id.optionSatisfied).setOnClickListener(clickListener)
+ feedbackView.findViewById(R.id.optionNeutral).setOnClickListener(clickListener)
+ feedbackView.findViewById(R.id.optionUnsatisfied).setOnClickListener(clickListener)
+
+ dialog = MaterialAlertDialogBuilder(requireActivity())
+ .setTitle(R.string.patroller_diff_feedback_dialog_title)
+ .setCancelable(false)
+ .setView(feedbackView)
+ .show()
+ }
+
+ private fun showFeedbackInputDialog() {
+ val feedbackView = layoutInflater.inflate(R.layout.dialog_patrol_edit_feedback_input, null)
+ val feedbackInput = feedbackView.findViewById(R.id.feedbackInput).text.toString()
+ MaterialAlertDialogBuilder(requireActivity())
+ .setTitle(R.string.patroller_diff_feedback_dialog_feedback_title)
+ .setCancelable(false)
+ .setView(feedbackView)
+ .setPositiveButton(R.string.patroller_diff_feedback_dialog_submit) { _, _ ->
+ viewModel.feedbackInput = feedbackInput
+ // TODO: send to the event logging
+ showFeedbackSnackbarAndTooltip()
+ }
+ .show()
+ }
+
+ private fun showFeedbackSnackbarAndTooltip() {
+ FeedbackUtil.showMessage(this@ArticleEditDetailsFragment, R.string.patroller_diff_feedback_submitted_snackbar)
+ binding.root.postDelayed({
+ val anchorView = requireActivity().findViewById(R.id.more_options)
+ if (isAdded && anchorView != null && Prefs.showOneTimeRecentEditsFeedbackForm) {
+ FeedbackUtil.getTooltip(
+ requireActivity(),
+ getString(R.string.patroller_diff_feedback_tooltip),
+ arrowAnchorPadding = -DimenUtil.roundedDpToPx(7f),
+ topOrBottomMargin = 0,
+ aboveOrBelow = false,
+ autoDismiss = false,
+ showDismissButton = true
+ ).apply {
+ showAlignBottom(anchorView)
+ Prefs.showOneTimeRecentEditsFeedbackForm = false
+ }
+ }
+ }, 100)
+ }
+
private fun updateActionButtons() {
binding.undoButton.isVisible = viewModel.revisionFrom != null && AccountUtil.isLoggedIn
binding.thankButton.isEnabled = true
@@ -549,6 +693,7 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
override fun onExpirySelect(expiry: WatchlistExpiry) {
viewModel.watchOrUnwatch(isWatched, expiry, false)
ExclusiveBottomSheetPresenter.dismiss(childFragmentManager)
+ showFeedbackOptionsDialog()
}
override fun onLinkPreviewLoadPage(title: PageTitle, entry: HistoryEntry, inNewTab: Boolean) {
diff --git a/app/src/main/java/org/wikipedia/diff/ArticleEditDetailsViewModel.kt b/app/src/main/java/org/wikipedia/diff/ArticleEditDetailsViewModel.kt
index 5d0369ca1a3..0e93e25b113 100644
--- a/app/src/main/java/org/wikipedia/diff/ArticleEditDetailsViewModel.kt
+++ b/app/src/main/java/org/wikipedia/diff/ArticleEditDetailsViewModel.kt
@@ -53,6 +53,9 @@ class ArticleEditDetailsViewModel(bundle: Bundle) : ViewModel() {
var canGoForward = false
var hasRollbackRights = false
+ var feedbackOption = ""
+ var feedbackInput = ""
+
val diffSize get() = if (revisionFrom != null) revisionTo!!.size - revisionFrom!!.size else revisionTo!!.size
init {
diff --git a/app/src/main/java/org/wikipedia/onboarding/OnboardingPageView.kt b/app/src/main/java/org/wikipedia/onboarding/OnboardingPageView.kt
index 2b33881cea5..f2d58bae11f 100644
--- a/app/src/main/java/org/wikipedia/onboarding/OnboardingPageView.kt
+++ b/app/src/main/java/org/wikipedia/onboarding/OnboardingPageView.kt
@@ -21,7 +21,7 @@ import org.wikipedia.databinding.ViewOnboardingPageBinding
import org.wikipedia.onboarding.OnboardingPageView.LanguageListAdapter.OptionsViewHolder
import org.wikipedia.page.LinkMovementMethodExt
import org.wikipedia.util.StringUtil
-import java.util.*
+import java.util.Locale
class OnboardingPageView constructor(context: Context, attrs: AttributeSet? = null) : ConstraintLayout(context, attrs) {
interface Callback {
@@ -44,8 +44,7 @@ class OnboardingPageView constructor(context: Context, attrs: AttributeSet? = nu
init {
attrs?.let { attrSet ->
context.withStyledAttributes(attrSet, R.styleable.OnboardingPageView) {
- val centeredImage = AppCompatResources.getDrawable(context,
- getResourceId(R.styleable.OnboardingPageView_centeredImage, -1))
+ val imageResource = getResourceId(R.styleable.OnboardingPageView_centeredImage, -1)
val primaryText = getString(R.styleable.OnboardingPageView_primaryText)
val secondaryText = getString(R.styleable.OnboardingPageView_secondaryText)
val tertiaryText = getString(R.styleable.OnboardingPageView_tertiaryText)
@@ -54,18 +53,26 @@ class OnboardingPageView constructor(context: Context, attrs: AttributeSet? = nu
val showListView = getBoolean(R.styleable.OnboardingPageView_showListView, false)
val background = getDrawable(R.styleable.OnboardingPageView_background)
val imageSize = getDimension(R.styleable.OnboardingPageView_imageSize, 0f)
+ val showPatrollerTasksButtons = getBoolean(R.styleable.OnboardingPageView_patrollerTasksButtons, false)
background?.let { setBackground(it) }
- binding.imageViewCentered.setImageDrawable(centeredImage)
- if (imageSize > 0 && centeredImage != null && centeredImage.intrinsicHeight > 0) {
- val aspect = centeredImage.intrinsicWidth.toFloat() / centeredImage.intrinsicHeight
- binding.imageViewCentered.updateLayoutParams {
- width = imageSize.toInt()
- height = (imageSize / aspect).toInt()
+ binding.imageViewCentered.isVisible = imageResource != -1
+ if (imageSize > 0 && imageResource != -1) {
+ val centeredImage = AppCompatResources.getDrawable(context, imageResource)
+ if (centeredImage != null && centeredImage.intrinsicHeight > 0) {
+ binding.imageViewCentered.setImageDrawable(centeredImage)
+ val aspect =
+ centeredImage.intrinsicWidth.toFloat() / centeredImage.intrinsicHeight
+ binding.imageViewCentered.updateLayoutParams {
+ width = imageSize.toInt()
+ height = (imageSize / aspect).toInt()
+ }
}
}
binding.primaryTextView.visibility = if (primaryText.isNullOrEmpty()) GONE else VISIBLE
binding.primaryTextView.text = primaryText
+ binding.secondaryTextView.visibility = if (secondaryText.isNullOrEmpty()) GONE else VISIBLE
binding.secondaryTextView.text = StringUtil.fromHtml(secondaryText)
+ binding.tertiaryTextView.visibility = if (tertiaryText.isNullOrEmpty()) GONE else VISIBLE
binding.tertiaryTextView.text = tertiaryText
binding.acceptRejectContainer.isVisible = acceptRejectButtons
setUpLanguageListContainer(showListView, listDataType)
@@ -77,6 +84,8 @@ class OnboardingPageView constructor(context: Context, attrs: AttributeSet? = nu
}
binding.acceptButton.setOnClickListener { callback?.onAcceptOrReject(this@OnboardingPageView, true) }
binding.rejectButton.setOnClickListener { callback?.onAcceptOrReject(this@OnboardingPageView, false) }
+
+ binding.patrollerTasksButtonsContainer?.root?.isVisible = showPatrollerTasksButtons
}
}
}
diff --git a/app/src/main/java/org/wikipedia/settings/Prefs.kt b/app/src/main/java/org/wikipedia/settings/Prefs.kt
index ad48429daf6..f672739401d 100644
--- a/app/src/main/java/org/wikipedia/settings/Prefs.kt
+++ b/app/src/main/java/org/wikipedia/settings/Prefs.kt
@@ -697,4 +697,16 @@ object Prefs {
get() = JsonUtil.decodeFromString>(PrefsIoUtil.getString(R.string.preference_key_recent_edits_included_type_codes, null))
?: SuggestedEditsRecentEditsFilterTypes.DEFAULT_FILTER_TYPE_SET.map { it.id }
set(types) = PrefsIoUtil.setString(R.string.preference_key_recent_edits_included_type_codes, JsonUtil.encodeToString(types))
+
+ var recentEditsOnboardingShown
+ get() = PrefsIoUtil.getBoolean(R.string.preference_key_recent_edits_onboarding_shown, false)
+ set(value) = PrefsIoUtil.setBoolean(R.string.preference_key_recent_edits_onboarding_shown, value)
+
+ var showOneTimeSequentialRecentEditsDiffTooltip
+ get() = PrefsIoUtil.getBoolean(R.string.preference_key_show_sequential_recent_edits_diff_tooltip, true)
+ set(value) = PrefsIoUtil.setBoolean(R.string.preference_key_show_sequential_recent_edits_diff_tooltip, value)
+
+ var showOneTimeRecentEditsFeedbackForm
+ get() = PrefsIoUtil.getBoolean(R.string.preference_key_show_recent_edits_feedback_form, true)
+ set(value) = PrefsIoUtil.setBoolean(R.string.preference_key_show_recent_edits_feedback_form, value)
}
diff --git a/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsCardsFragment.kt b/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsCardsFragment.kt
index d0266743beb..838a3588df9 100644
--- a/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsCardsFragment.kt
+++ b/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsCardsFragment.kt
@@ -4,9 +4,14 @@ import android.app.Activity.RESULT_OK
import android.content.Intent
import android.graphics.drawable.Animatable
import android.os.Bundle
-import android.view.*
+import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
+import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
+import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import androidx.appcompat.app.AppCompatActivity
@@ -27,7 +32,13 @@ import org.wikipedia.dataclient.ServiceFactory
import org.wikipedia.dataclient.mwapi.MwQueryPage
import org.wikipedia.dataclient.mwapi.SiteMatrix
import org.wikipedia.descriptions.DescriptionEditActivity
-import org.wikipedia.descriptions.DescriptionEditActivity.Action.*
+import org.wikipedia.descriptions.DescriptionEditActivity.Action.ADD_CAPTION
+import org.wikipedia.descriptions.DescriptionEditActivity.Action.ADD_DESCRIPTION
+import org.wikipedia.descriptions.DescriptionEditActivity.Action.ADD_IMAGE_TAGS
+import org.wikipedia.descriptions.DescriptionEditActivity.Action.IMAGE_RECOMMENDATIONS
+import org.wikipedia.descriptions.DescriptionEditActivity.Action.TRANSLATE_CAPTION
+import org.wikipedia.descriptions.DescriptionEditActivity.Action.TRANSLATE_DESCRIPTION
+import org.wikipedia.descriptions.DescriptionEditActivity.Action.VANDALISM_PATROL
import org.wikipedia.page.PageTitle
import org.wikipedia.settings.Prefs
import org.wikipedia.suggestededits.SuggestionsActivity.Companion.EXTRA_SOURCE_ADDED_CONTRIBUTION
@@ -94,7 +105,10 @@ class SuggestedEditsCardsFragment : Fragment(), MenuProvider, SuggestedEditsItem
super.onViewCreated(view, savedInstanceState)
requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
setInitialUiState()
- binding.cardsViewPager.offscreenPageLimit = 2
+ // Disable offscreenPageLimit for recentEdits can avoid the tooltips showing incorrectly.
+ if (action != VANDALISM_PATROL) {
+ binding.cardsViewPager.offscreenPageLimit = 2
+ }
binding.cardsViewPager.registerOnPageChangeCallback(viewPagerListener) // addOnPageChangeListener(viewPagerListener)
resetViewPagerItemAdapter()
diff --git a/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsRecentEditsActivity.kt b/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsRecentEditsActivity.kt
index 70c07f4b690..88e85595c57 100644
--- a/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsRecentEditsActivity.kt
+++ b/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsRecentEditsActivity.kt
@@ -2,9 +2,17 @@ package org.wikipedia.suggestededits
import android.content.Context
import android.content.Intent
+import android.os.Bundle
import org.wikipedia.activity.SingleFragmentActivity
+import org.wikipedia.settings.Prefs
class SuggestedEditsRecentEditsActivity : SingleFragmentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ maybeShowOnboarding()
+ }
+
public override fun createFragment(): SuggestedEditsRecentEditsFragment {
return SuggestedEditsRecentEditsFragment.newInstance()
}
@@ -13,6 +21,13 @@ class SuggestedEditsRecentEditsActivity : SingleFragmentActivity(), OnboardingFragment.Callback {
+ override fun onComplete() {
+ setResult(RESULT_OK, intent)
+ finish()
+ }
+
+ override fun createFragment(): SuggestedEditsRecentEditsOnboardingFragment {
+ return SuggestedEditsRecentEditsOnboardingFragment.newInstance()
+ }
+
+ companion object {
+ fun newIntent(context: Context): Intent {
+ return Intent(context, SuggestedEditsRecentEditsOnboardingActivity::class.java)
+ }
+ }
+}
diff --git a/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsRecentEditsOnboardingFragment.kt b/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsRecentEditsOnboardingFragment.kt
new file mode 100644
index 00000000000..56d574a684a
--- /dev/null
+++ b/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsRecentEditsOnboardingFragment.kt
@@ -0,0 +1,76 @@
+package org.wikipedia.suggestededits
+
+import android.net.Uri
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.os.bundleOf
+import androidx.fragment.app.Fragment
+import androidx.viewpager2.adapter.FragmentStateAdapter
+import org.wikipedia.R
+import org.wikipedia.activity.FragmentUtil
+import org.wikipedia.onboarding.OnboardingFragment
+import org.wikipedia.onboarding.OnboardingPageView
+import org.wikipedia.settings.Prefs
+import org.wikipedia.util.FeedbackUtil
+import org.wikipedia.util.UriUtil
+
+class SuggestedEditsRecentEditsOnboardingFragment : OnboardingFragment(), OnboardingPageView.Callback {
+ override val doneButtonText = R.string.onboarding_get_started
+ override val showDoneButton = Prefs.isEventLoggingEnabled
+
+ override fun getAdapter(): FragmentStateAdapter {
+ return DescriptionEditTutorialPagerAdapter(this)
+ }
+
+ internal inner class DescriptionEditTutorialPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
+ override fun getItemCount(): Int {
+ return if (!Prefs.isEventLoggingEnabled) pages.size else pages.size - 1
+ }
+
+ override fun createFragment(position: Int): Fragment {
+ return ItemFragment().apply { arguments = bundleOf(ARG_POSITION to position) }
+ }
+ }
+
+ override fun onAcceptOrReject(view: OnboardingPageView, accept: Boolean) {
+ if ((view.tag as Int) == 2) {
+ Prefs.isEventLoggingEnabled = accept
+ requireActivity().finish()
+ }
+ }
+
+ override fun onLinkClick(view: OnboardingPageView, url: String) {
+ when (url) {
+ "#privacy" -> FeedbackUtil.showPrivacyPolicy(requireContext())
+ else -> UriUtil.handleExternalLink(requireActivity(), Uri.parse(url))
+ }
+ }
+
+ override fun onListActionButtonClicked(view: OnboardingPageView) { }
+
+ class ItemFragment : Fragment() {
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
+ super.onCreateView(inflater, container, savedInstanceState)
+ val position = requireArguments().getInt(ARG_POSITION, 0)
+ val view = inflater.inflate(pages[position], container, false) as OnboardingPageView
+ view.tag = position
+ view.callback = callback
+ return view
+ }
+
+ private val callback
+ get() = FragmentUtil.getCallback(this, OnboardingPageView.Callback::class.java)
+ }
+
+ companion object {
+ const val ARG_POSITION = "position"
+ val pages = arrayOf(
+ R.layout.inflate_patroller_tasks_onboarding_page_one,
+ R.layout.inflate_patroller_tasks_onboarding_page_two,
+ R.layout.inflate_initial_onboarding_page_three
+ )
+ fun newInstance() = SuggestedEditsRecentEditsOnboardingFragment()
+ }
+}
diff --git a/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsTasksFragment.kt b/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsTasksFragment.kt
index 70765cc8b14..6f71f0542ea 100644
--- a/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsTasksFragment.kt
+++ b/app/src/main/java/org/wikipedia/suggestededits/SuggestedEditsTasksFragment.kt
@@ -338,7 +338,6 @@ class SuggestedEditsTasksFragment : Fragment() {
imageRecommendationsTask.description = getString(R.string.suggested_edits_image_recommendations_task_detail)
imageRecommendationsTask.imageDrawable = R.drawable.ic_add_image
imageRecommendationsTask.primaryAction = getString(R.string.suggested_edits_task_action_text_add)
- imageRecommendationsTask.new = !Prefs.suggestedEditsImageRecsOnboardingShown
vandalismPatrolTask = SuggestedEditsTask()
vandalismPatrolTask.title = getString(R.string.suggested_edits_edit_patrol)
@@ -346,6 +345,7 @@ class SuggestedEditsTasksFragment : Fragment() {
vandalismPatrolTask.primaryAction = getString(R.string.suggested_edits_edit_patrol_review)
vandalismPatrolTask.imageDrawable = R.drawable.ic_patrol_24
vandalismPatrolTask.primaryActionIcon = R.drawable.ic_check_black_24dp
+ vandalismPatrolTask.new = !Prefs.recentEditsOnboardingShown
displayedTasks.add(vandalismPatrolTask)
diff --git a/app/src/main/res/drawable/illustration_patroller_tasks.xml b/app/src/main/res/drawable/illustration_patroller_tasks.xml
new file mode 100644
index 00000000000..9a61d00bb1e
--- /dev/null
+++ b/app/src/main/res/drawable/illustration_patroller_tasks.xml
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_patrol_edit_feedback_input.xml b/app/src/main/res/layout/dialog_patrol_edit_feedback_input.xml
new file mode 100644
index 00000000000..99f76f0e1b8
--- /dev/null
+++ b/app/src/main/res/layout/dialog_patrol_edit_feedback_input.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/dialog_patrol_edit_feedback_options.xml b/app/src/main/res/layout/dialog_patrol_edit_feedback_options.xml
new file mode 100644
index 00000000000..d4f1423a291
--- /dev/null
+++ b/app/src/main/res/layout/dialog_patrol_edit_feedback_options.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/inflate_patroller_tasks_onboarding_page_one.xml b/app/src/main/res/layout/inflate_patroller_tasks_onboarding_page_one.xml
new file mode 100644
index 00000000000..99bdb7151c2
--- /dev/null
+++ b/app/src/main/res/layout/inflate_patroller_tasks_onboarding_page_one.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/inflate_patroller_tasks_onboarding_page_two.xml b/app/src/main/res/layout/inflate_patroller_tasks_onboarding_page_two.xml
new file mode 100644
index 00000000000..e188fc13d80
--- /dev/null
+++ b/app/src/main/res/layout/inflate_patroller_tasks_onboarding_page_two.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_onboarding_page.xml b/app/src/main/res/layout/view_onboarding_page.xml
index a86f7532149..0d9ecd2de83 100644
--- a/app/src/main/res/layout/view_onboarding_page.xml
+++ b/app/src/main/res/layout/view_onboarding_page.xml
@@ -65,6 +65,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_edit_details.xml b/app/src/main/res/menu/menu_edit_details.xml
index a05ed7a6676..f88abb24b69 100644
--- a/app/src/main/res/menu/menu_edit_details.xml
+++ b/app/src/main/res/menu/menu_edit_details.xml
@@ -2,7 +2,7 @@