Skip to content

Commit

Permalink
Merge branch 'patrollerTasks_design' into patrollerTasks_warn_design
Browse files Browse the repository at this point in the history
  • Loading branch information
cooltey committed Oct 23, 2023
2 parents 8abba69 + 8a2da14 commit 50df663
Show file tree
Hide file tree
Showing 36 changed files with 846 additions and 46 deletions.
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@

<activity android:name=".suggestededits.SuggestedEditsImageRecsOnboardingActivity" />

<activity android:name=".suggestededits.SuggestedEditsRecentEditsOnboardingActivity" />

<activity
android:name=".watchlist.WatchlistActivity"
android:label="@string/watchlist_title"
Expand Down
165 changes: 155 additions & 10 deletions app/src/main/java/org/wikipedia/diff/ArticleEditDetailsFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.widget.PopupMenu
Expand All @@ -26,6 +28,8 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputEditText
import org.wikipedia.Constants.InvokeSource
import org.wikipedia.R
import org.wikipedia.activity.FragmentUtil
Expand All @@ -44,13 +48,15 @@ import org.wikipedia.page.PageTitle
import org.wikipedia.page.edithistory.EditHistoryListActivity
import org.wikipedia.page.linkpreview.LinkPreviewDialog
import org.wikipedia.readinglist.AddToReadingListDialog
import org.wikipedia.settings.Prefs
import org.wikipedia.staticdata.UserAliasData
import org.wikipedia.staticdata.UserTalkAliasData
import org.wikipedia.talk.TalkReplyActivity
import org.wikipedia.talk.TalkTopicsActivity
import org.wikipedia.talk.UserTalkPopupHelper
import org.wikipedia.util.ClipboardUtil
import org.wikipedia.util.DateUtil
import org.wikipedia.util.DimenUtil
import org.wikipedia.util.FeedbackUtil
import org.wikipedia.util.L10nUtil
import org.wikipedia.util.Resource
Expand Down Expand Up @@ -84,12 +90,23 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
val message = if (it.resultCode == TalkReplyActivity.RESULT_EDIT_SUCCESS) R.string.talk_warn_submitted else R.string.talk_warn_submitted_and_saved
val snackbar = FeedbackUtil.makeSnackbar(requireActivity(), getString(message))
snackbar.setAction(R.string.patroller_tasks_patrol_edit_snackbar_view) {
startActivity(TalkTopicsActivity.newIntent(requireContext(), pageTitle, InvokeSource.DIFF_ACTIVITY)) }
startActivity(TalkTopicsActivity.newIntent(requireContext(), pageTitle, InvokeSource.DIFF_ACTIVITY))
}
snackbar.show()
}
}
}

private val sequentialTooltipRunnable = Runnable {
if (!isAdded) {
return@Runnable
}
val balloon = FeedbackUtil.getTooltip(requireContext(), getString(R.string.patroller_diff_tooltip_one), autoDismiss = true, showDismissButton = true, dismissButtonText = R.string.image_recommendation_tooltip_next, countNum = 1, countTotal = 2)
balloon.showAlignBottom(binding.oresDamagingButton)
balloon.relayShowAlignBottom(FeedbackUtil.getTooltip(requireContext(), getString(R.string.patroller_diff_tooltip_two), autoDismiss = true, showDismissButton = true, countNum = 2, countTotal = 2), binding.oresGoodFaithButton)
// TODO: log tooltip?
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
_binding = FragmentArticleEditDetailsBinding.inflate(inflater, container, false)
Expand Down Expand Up @@ -145,10 +162,7 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L

viewModel.thankStatus.observe(viewLifecycleOwner) {
if (it is Resource.Success) {
FeedbackUtil.showMessage(requireActivity(), getString(R.string.thank_success_message,
viewModel.revisionTo?.user))
binding.thankIcon.setImageResource(R.drawable.ic_heart_24)
binding.thankButton.isEnabled = false
showThankSnackbar()
editHistoryInteractionEvent?.logThankSuccess()
} else if (it is Resource.Error) {
setErrorState(it.throwable)
Expand All @@ -173,7 +187,7 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
if (it is Resource.Success) {
setLoadingState()
viewModel.getRevisionDetails(it.data.edit!!.newRevId)
FeedbackUtil.makeSnackbar(requireActivity(), getString(R.string.revision_undo_success)).show()
showUndoSnackbar()
editHistoryInteractionEvent?.logUndoSuccess()
callback()?.onUndoSuccess()
} else if (it is Resource.Error) {
Expand All @@ -198,7 +212,7 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
if (it is Resource.Success) {
setLoadingState()
viewModel.getRevisionDetails(it.data.rollback?.revision ?: 0)
FeedbackUtil.makeSnackbar(requireActivity(), getString(R.string.revision_rollback_success), FeedbackUtil.LENGTH_DEFAULT).show()
showRollbackSnackbar()
callback()?.onRollbackSuccess()
} else if (it is Resource.Error) {
it.throwable.printStackTrace()
Expand Down Expand Up @@ -235,6 +249,7 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
}

override fun onDestroyView() {
binding.scrollContainer.removeCallbacks(sequentialTooltipRunnable)
_binding = null
super.onDestroyView()
}
Expand Down Expand Up @@ -317,6 +332,10 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
}
updateWatchButton(isWatched, hasWatchlistExpiry)

binding.warnButton.setOnClickListener {
// TODO: implement this
}

binding.errorView.backClickListener = View.OnClickListener { requireActivity().finish() }
}

Expand Down Expand Up @@ -351,9 +370,7 @@ class ArticleEditDetailsFragment : Fragment(), WatchlistExpiryDialog.Callback, L
true
}
R.id.menu_report_feature -> {
FeedbackUtil.composeFeedbackEmail(requireContext(),
getString(R.string.email_report_patroller_tasks_subject),
getString(R.string.email_report_patroller_tasks_body))
showFeedbackOptionsDialog(true)
true
}
else -> false
Expand All @@ -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)
Expand Down Expand Up @@ -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()
}
}

Expand Down Expand Up @@ -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())
Expand All @@ -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)
Expand All @@ -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<TextView>(R.id.optionSatisfied).setOnClickListener(clickListener)
feedbackView.findViewById<TextView>(R.id.optionNeutral).setOnClickListener(clickListener)
feedbackView.findViewById<TextView>(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<TextInputEditText>(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<View>(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
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
27 changes: 18 additions & 9 deletions app/src/main/java/org/wikipedia/onboarding/OnboardingPageView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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
}
}
}
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/java/org/wikipedia/settings/Prefs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -697,4 +697,16 @@ object Prefs {
get() = JsonUtil.decodeFromString<Set<String>>(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)
}
Loading

0 comments on commit 50df663

Please sign in to comment.