New: Feedback screen in profile.

This commit is contained in:
Kevin Gorham 2020-03-27 16:45:32 -04:00
parent 6e44614207
commit 8371f9c53a
No known key found for this signature in database
GPG Key ID: CCA55602DF49FC38
7 changed files with 400 additions and 11 deletions

View File

@ -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<String, Any>) : 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"),

View File

@ -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<FragmentFeedbackBinding>() {
override val screen = Report.Screen.FEEDBACK
override fun inflate(inflater: LayoutInflater): FragmentFeedbackBinding =
FragmentFeedbackBinding.inflate(inflater)
private lateinit var ratings: Array<View>
// 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<View>(android.R.id.content).viewTreeObserver.addOnGlobalLayoutListener(padder)
}
override fun onPause() {
super.onPause()
// mainActivity!!.window.decorView.viewTreeObserver.removeOnGlobalLayoutListener(padder)
// mainActivity!!.findViewById<View>(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
}
}

View File

@ -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<FragmentProfileBinding>() {
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<FragmentProfileBinding>() {
onViewDevLogs()
true
}
onClick(binding.buttonFeedback) {
tapped(PROFILE_SEND_FEEDBACK)
onSendFeedback()
}
}
override fun onResume() {
@ -95,10 +96,6 @@ class ProfileFragment : BaseFragment<FragmentProfileBinding>() {
startActivity(Intent.createChooser(intent, "Share Log File"))
}
private fun onSendFeedback() {
mainActivity?.showSnackbar("Feedback feature coming soon!")
}
private fun userLogFile(): File? {
return mainActivity?.feedbackCoordinator?.findObserver<FeedbackFile>()?.file
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="false" android:color="@color/text_light"/>
<item android:state_activated="true" android:color="@color/colorPrimary" />
</selector>

View File

@ -0,0 +1,271 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Back Button -->
<ImageView
android:id="@+id/back_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:tint="@color/text_light"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.05"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.065"
app:srcCompat="@drawable/ic_arrow_back_black_24dp" />
<View
android:id="@+id/back_button_hit_area"
android:layout_width="56dp"
android:layout_height="56dp"
android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.01"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.045" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/back_button"
app:layout_constraintStart_toStartOf="parent"
android:fillViewport="true">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/content_feedback"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_content_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.1" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline_content_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.9" />
<TextView
android:id="@+id/text_feedback_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Please rank your experience"
android:textColor="@color/text_light"
android:textSize="22sp"
app:layout_constraintStart_toEndOf="@id/guideline_content_start"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_feedback_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="We improve and iterate with YOUR feedback"
android:textColor="@color/text_light"
android:textSize="12sp"
app:layout_constraintStart_toEndOf="@id/guideline_content_start"
app:layout_constraintTop_toBottomOf="@id/text_feedback_title" />
<View
android:id="@+id/background_buttons"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_marginTop="16dp"
android:background="@color/zcashBlack_54"
app:layout_constraintTop_toBottomOf="@id/text_feedback_subtitle" />
<TextView
android:id="@+id/feedback_exp_1"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/background_circle"
android:backgroundTint="@color/selector_feedback_button"
android:gravity="center"
android:text="1"
android:textColor="@color/text_dark"
android:textSize="30dp"
app:layout_constraintBottom_toBottomOf="@id/background_buttons"
app:layout_constraintEnd_toStartOf="@id/feedback_exp_2"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="@id/guideline_content_start"
app:layout_constraintTop_toTopOf="@id/background_buttons" />
<TextView
android:id="@+id/feedback_exp_2"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/background_circle"
android:backgroundTint="@color/selector_feedback_button"
android:gravity="center"
android:text="2"
android:textColor="@color/text_dark"
android:textSize="30dp"
app:layout_constraintBottom_toBottomOf="@id/background_buttons"
app:layout_constraintEnd_toStartOf="@id/feedback_exp_3"
app:layout_constraintStart_toEndOf="@id/feedback_exp_1"
app:layout_constraintTop_toTopOf="@id/background_buttons" />
<TextView
android:id="@+id/feedback_exp_3"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/background_circle"
android:backgroundTint="@color/selector_feedback_button"
android:gravity="center"
android:text="3"
android:textColor="@color/text_dark"
android:textSize="30dp"
app:layout_constraintBottom_toBottomOf="@id/background_buttons"
app:layout_constraintEnd_toStartOf="@id/feedback_exp_4"
app:layout_constraintStart_toEndOf="@id/feedback_exp_2"
app:layout_constraintTop_toTopOf="@id/background_buttons" />
<TextView
android:id="@+id/feedback_exp_4"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/background_circle"
android:backgroundTint="@color/selector_feedback_button"
android:gravity="center"
android:text="4"
android:textColor="@color/text_dark"
android:textSize="30dp"
app:layout_constraintBottom_toBottomOf="@id/background_buttons"
app:layout_constraintEnd_toStartOf="@id/feedback_exp_5"
app:layout_constraintStart_toEndOf="@id/feedback_exp_3"
app:layout_constraintTop_toTopOf="@id/background_buttons" />
<TextView
android:id="@+id/feedback_exp_5"
android:layout_width="50dp"
android:layout_height="50dp"
android:background="@drawable/background_circle"
android:backgroundTint="@color/selector_feedback_button"
android:gravity="center"
android:text="5"
android:textColor="@color/text_dark"
android:textSize="30dp"
app:layout_constraintBottom_toBottomOf="@id/background_buttons"
app:layout_constraintEnd_toEndOf="@id/guideline_content_end"
app:layout_constraintStart_toEndOf="@id/feedback_exp_4"
app:layout_constraintTop_toTopOf="@id/background_buttons" />
<TextView
android:id="@+id/text_question_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/feedback_question_1"
android:textColor="@color/text_light"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="@id/guideline_content_start"
app:layout_constraintTop_toBottomOf="@id/background_buttons" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/input_question_1"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:hint="@string/feedback_hint_1"
app:layout_constraintEnd_toEndOf="@id/guideline_content_end"
app:layout_constraintStart_toStartOf="@id/guideline_content_start"
app:layout_constraintTop_toBottomOf="@id/text_question_1">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:lines="3" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="@+id/text_question_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/feedback_question_2"
android:textColor="@color/text_light"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="@id/guideline_content_start"
app:layout_constraintTop_toBottomOf="@id/input_question_1" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/input_question_2"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:hint="@string/feedback_hint_2"
app:layout_constraintEnd_toEndOf="@id/guideline_content_end"
app:layout_constraintStart_toStartOf="@id/guideline_content_start"
app:layout_constraintTop_toBottomOf="@id/text_question_2">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:lines="3" />
</com.google.android.material.textfield.TextInputLayout>
<TextView
android:id="@+id/text_question_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/feedback_question_3"
android:textColor="@color/text_light"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="@id/guideline_content_start"
app:layout_constraintTop_toBottomOf="@id/input_question_2" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/input_question_3"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:hint="@string/feedback_hint_3"
app:layout_constraintEnd_toEndOf="@id/guideline_content_end"
app:layout_constraintStart_toStartOf="@id/guideline_content_start"
app:layout_constraintTop_toBottomOf="@id/text_question_3">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="top"
android:lines="3" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/button_submit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
style="@style/Zcash.Button"
android:gravity="center"
android:padding="12dp"
android:text="Send Feedback"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="#000000"
app:layout_constraintEnd_toEndOf="@id/guideline_content_end"
app:layout_constraintStart_toStartOf="@id/guideline_content_start"
app:layout_constraintTop_toBottomOf="@id/input_question_3" />
<Space
android:id="@+id/extra_padding_for_scrolling"
android:layout_width="match_parent"
android:layout_height="400dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/button_submit" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -65,7 +65,6 @@
android:id="@+id/nav_detail"
android:name="cash.z.ecc.android.ui.detail.WalletDetailFragment"
tools:layout="@layout/fragment_detail" />
<fragment
android:id="@+id/nav_profile"
android:name="cash.z.ecc.android.ui.profile.ProfileFragment"
@ -73,7 +72,14 @@
<action
android:id="@+id/action_nav_profile_to_nav_backup"
app:destination="@id/nav_backup" />
<action
android:id="@+id/action_nav_profile_to_nav_feedback"
app:destination="@id/nav_feedback" />
</fragment>
<fragment
android:id="@+id/nav_feedback"
android:name="cash.z.ecc.android.ui.profile.FeedbackFragment"
tools:layout="@layout/fragment_feedback" />
<!-- -->
<!-- Send Navigation -->

View File

@ -8,7 +8,15 @@
<!-- Send Flow -->
<string name="send_hint_input_zcash_address">Enter a shielded Zcash address</string>
<string name="send_hint_input_zcash_amount">Enter an amount to send</string>
<string name="send_memo_excluded_message">Your transaction is shielded and your address is not available to the recipient</string>
<string name="send_memo_included_message">Your transaction is shielded but your address will be sent to the recipient via the memo</string>
<!-- Feedback -->
<string name="feedback_question_1">Any details you\'d like to share?</string>
<string name="feedback_question_2">Was your balance clear?</string>
<string name="feedback_question_3">What feature would you like to see next?</string>
<string name="feedback_hint_1">My experience was . . .</string>
<string name="feedback_hint_2">My balance was . . .</string>
<string name="feedback_hint_3">I\'d like . . .</string>
</resources>