From 8371f9c53a3afc52ba0d186e118ea5a4c20602f7 Mon Sep 17 00:00:00 2001 From: Kevin Gorham Date: Fri, 27 Mar 2020 16:45:32 -0400 Subject: [PATCH] New: Feedback screen in profile. --- .../cash/z/ecc/android/feedback/Report.kt | 9 + .../android/ui/profile/FeedbackFragment.kt | 92 ++++++ .../ecc/android/ui/profile/ProfileFragment.kt | 15 +- .../res/color/selector_feedback_button.xml | 6 + app/src/main/res/layout/fragment_feedback.xml | 271 ++++++++++++++++++ .../main/res/navigation/mobile_navigation.xml | 8 +- app/src/main/res/values/strings.xml | 10 +- 7 files changed, 400 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/cash/z/ecc/android/ui/profile/FeedbackFragment.kt create mode 100644 app/src/main/res/color/selector_feedback_button.xml create mode 100644 app/src/main/res/layout/fragment_feedback.xml diff --git a/app/src/main/java/cash/z/ecc/android/feedback/Report.kt b/app/src/main/java/cash/z/ecc/android/feedback/Report.kt index 3ec359a..b6899b3 100644 --- a/app/src/main/java/cash/z/ecc/android/feedback/Report.kt +++ b/app/src/main/java/cash/z/ecc/android/feedback/Report.kt @@ -43,6 +43,12 @@ object Report { object ImportCompleted : Restore("importcompleted", 50) object Success : Restore("success", 100) } + + sealed class UserFeedback(stepName: String, step: Int, vararg properties: Pair) : Feedback.Funnel("feedback", stepName, step, *properties) { + object Started : UserFeedback("started", 0) + object Cancelled : UserFeedback("cancelled", 1) + class Submitted(rating: Int, question1: String, question2: String, question3: String) : UserFeedback("submitted", 100, "rating" to rating, "question1" to question1, "question2" to question2, "question3" to question3) + } } object Error { @@ -84,6 +90,7 @@ object Report { DETAIL("wallet.detail"), LANDING, PROFILE, + FEEDBACK, RECEIVE, RESTORE, SCAN, @@ -120,6 +127,8 @@ object Report { PROFILE_VIEW_USER_LOGS("profile.view.user.logs"), PROFILE_VIEW_DEV_LOGS("profile.view.dev.logs"), PROFILE_SEND_FEEDBACK("profile.send.feedback"), + FEEDBACK_CANCEL("feedback.cancel"), + FEEDBACK_SUBMIT("feedback.submit"), RECEIVE_SCAN("receive.scan"), RECEIVE_BACK("receive.back"), RESTORE_DONE("restore.done"), diff --git a/app/src/main/java/cash/z/ecc/android/ui/profile/FeedbackFragment.kt b/app/src/main/java/cash/z/ecc/android/ui/profile/FeedbackFragment.kt new file mode 100644 index 0000000..c8c75d7 --- /dev/null +++ b/app/src/main/java/cash/z/ecc/android/ui/profile/FeedbackFragment.kt @@ -0,0 +1,92 @@ +package cash.z.ecc.android.ui.profile + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewTreeObserver +import android.view.WindowManager +import android.widget.Toast +import androidx.core.view.doOnLayout +import cash.z.ecc.android.databinding.FragmentFeedbackBinding +import cash.z.ecc.android.di.viewmodel.viewModel +import cash.z.ecc.android.feedback.Report +import cash.z.ecc.android.feedback.Report.Funnel.UserFeedback +import cash.z.ecc.android.feedback.Report.Tap.FEEDBACK_CANCEL +import cash.z.ecc.android.feedback.Report.Tap.FEEDBACK_SUBMIT +import cash.z.ecc.android.ui.base.BaseFragment + + +/** + * Fragment representing the home screen of the app. This is the screen most often seen by the user when launching the + * application. + */ +class FeedbackFragment : BaseFragment() { + override val screen = Report.Screen.FEEDBACK + + override fun inflate(inflater: LayoutInflater): FragmentFeedbackBinding = + FragmentFeedbackBinding.inflate(inflater) + + private lateinit var ratings: Array + +// private val padder = ViewTreeObserver.OnGlobalLayoutListener { +// Toast.makeText(mainActivity, "LAYOUT", Toast.LENGTH_SHORT).show() +// } + + // + // LifeCycle + // + + override fun onResume() { + super.onResume() +// mainActivity!!.window.decorView.viewTreeObserver.addOnGlobalLayoutListener(padder) +// mainActivity!!.findViewById(android.R.id.content).viewTreeObserver.addOnGlobalLayoutListener(padder) + } + + override fun onPause() { + super.onPause() +// mainActivity!!.window.decorView.viewTreeObserver.removeOnGlobalLayoutListener(padder) +// mainActivity!!.findViewById(android.R.id.content).viewTreeObserver.removeOnGlobalLayoutListener(padder) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + with(binding) { + backButtonHitArea.setOnClickListener(::onFeedbackCancel) + buttonSubmit.setOnClickListener(::onFeedbackSubmit) + + ratings = arrayOf(feedbackExp1, feedbackExp2, feedbackExp3, feedbackExp4, feedbackExp5) + ratings.forEach { + it.setOnClickListener(::onRatingClicked) + } + } + } + + + // + // Private API + // + + private fun onFeedbackSubmit(view: View) { + Toast.makeText(mainActivity, "Thanks for the feedback!", Toast.LENGTH_LONG).show() + tapped(FEEDBACK_SUBMIT) + + val q1 = binding.inputQuestion1.editText?.text.toString() + val q2 = binding.inputQuestion2.editText?.text.toString() + val q3 = binding.inputQuestion3.editText?.text.toString() + val rating = ratings.indexOfFirst { it.isActivated } + 1 + + mainActivity?.reportFunnel(UserFeedback.Submitted(rating, q1, q2, q3)) + + mainActivity?.navController?.navigateUp() + } + private fun onFeedbackCancel(view: View) { + tapped(FEEDBACK_CANCEL) + mainActivity?.reportFunnel(UserFeedback.Cancelled) + mainActivity?.navController?.navigateUp() + } + + private fun onRatingClicked(view: View) { + ratings.forEach { it.isActivated = false } + view.isActivated = !view.isActivated + } +} diff --git a/app/src/main/java/cash/z/ecc/android/ui/profile/ProfileFragment.kt b/app/src/main/java/cash/z/ecc/android/ui/profile/ProfileFragment.kt index e59fa5b..4d4088a 100644 --- a/app/src/main/java/cash/z/ecc/android/ui/profile/ProfileFragment.kt +++ b/app/src/main/java/cash/z/ecc/android/ui/profile/ProfileFragment.kt @@ -1,6 +1,5 @@ package cash.z.ecc.android.ui.profile -import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle @@ -17,6 +16,7 @@ import cash.z.ecc.android.ext.onClickNavBack import cash.z.ecc.android.ext.onClickNavTo import cash.z.ecc.android.feedback.FeedbackFile import cash.z.ecc.android.feedback.Report +import cash.z.ecc.android.feedback.Report.Funnel.UserFeedback import cash.z.ecc.android.feedback.Report.Tap.* import cash.z.ecc.android.ui.base.BaseFragment import cash.z.wallet.sdk.ext.toAbbreviatedAddress @@ -39,6 +39,11 @@ class ProfileFragment : BaseFragment() { super.onViewCreated(view, savedInstanceState) binding.hitAreaClose.onClickNavBack() { tapped(PROFILE_CLOSE) } binding.buttonBackup.onClickNavTo(R.id.action_nav_profile_to_nav_backup) { tapped(PROFILE_BACKUP) } + binding.buttonFeedback.onClickNavTo(R.id.action_nav_profile_to_nav_feedback) { + tapped(PROFILE_SEND_FEEDBACK) + mainActivity?.reportFunnel(UserFeedback.Started) + Unit + } binding.textVersion.text = BuildConfig.VERSION_NAME onClick(binding.buttonLogs) { tapped(PROFILE_VIEW_USER_LOGS) @@ -49,10 +54,6 @@ class ProfileFragment : BaseFragment() { onViewDevLogs() true } - onClick(binding.buttonFeedback) { - tapped(PROFILE_SEND_FEEDBACK) - onSendFeedback() - } } override fun onResume() { @@ -95,10 +96,6 @@ class ProfileFragment : BaseFragment() { startActivity(Intent.createChooser(intent, "Share Log File")) } - private fun onSendFeedback() { - mainActivity?.showSnackbar("Feedback feature coming soon!") - } - private fun userLogFile(): File? { return mainActivity?.feedbackCoordinator?.findObserver()?.file } diff --git a/app/src/main/res/color/selector_feedback_button.xml b/app/src/main/res/color/selector_feedback_button.xml new file mode 100644 index 0000000..dcd144b --- /dev/null +++ b/app/src/main/res/color/selector_feedback_button.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_feedback.xml b/app/src/main/res/layout/fragment_feedback.xml new file mode 100644 index 0000000..4a2096a --- /dev/null +++ b/app/src/main/res/layout/fragment_feedback.xml @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml index d81f703..6eb8400 100644 --- a/app/src/main/res/navigation/mobile_navigation.xml +++ b/app/src/main/res/navigation/mobile_navigation.xml @@ -65,7 +65,6 @@ android:id="@+id/nav_detail" android:name="cash.z.ecc.android.ui.detail.WalletDetailFragment" tools:layout="@layout/fragment_detail" /> - + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f6267ba..f8fb643 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -8,7 +8,15 @@ Enter a shielded Zcash address Enter an amount to send - Your transaction is shielded and your address is not available to the recipient Your transaction is shielded but your address will be sent to the recipient via the memo + + + Any details you\'d like to share? + Was your balance clear? + What feature would you like to see next? + My experience was . . . + My balance was . . . + I\'d like . . . +