Merge pull request #203 from nighthawk24/feature/settings

Create Settings layout, fragment & view model
This commit is contained in:
Kevin Gorham 2020-09-23 23:52:15 -04:00 committed by GitHub
commit 453cd1d995
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 322 additions and 17 deletions

View File

@ -1,6 +1,8 @@
package cash.z.ecc.android.di.module
import android.content.Context
import cash.z.ecc.android.ext.Const
import cash.z.ecc.android.lockbox.LockBox
import cash.z.ecc.android.sdk.Initializer
import dagger.Module
import dagger.Provides
@ -8,10 +10,17 @@ import dagger.Reusable
@Module
class InitializerModule {
private val host = "lightwalletd.electriccoin.co"
private val port = 9067
companion object {
const val defaultHost = "lightwalletd.electriccoin.co"
const val defaultPort = 9067
}
// TODO: Read SecurePrefs
// private val host: String = sharedPreferences.getString(Const.Pref.SERVER_NAME, defaultHost) ?: defaultHost
// private val port: Int = sharedPreferences.getInt(Const.Pref.SERVER_PORT, defaultPort)
@Provides
@Reusable
fun provideInitializer(appContext: Context) = Initializer(appContext, host, port)
fun provideInitializer(appContext: Context) = Initializer(appContext, defaultHost, defaultPort)
}

View File

@ -13,6 +13,7 @@ import cash.z.ecc.android.ui.profile.ProfileViewModel
import cash.z.ecc.android.ui.receive.ReceiveViewModel
import cash.z.ecc.android.ui.scan.ScanViewModel
import cash.z.ecc.android.ui.send.SendViewModel
import cash.z.ecc.android.ui.settings.SettingsViewModel
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
@ -58,6 +59,12 @@ abstract class ViewModelsSynchronizerModule {
@IntoMap
@ViewModelKey(ProfileViewModel::class)
abstract fun bindProfileViewModel(implementation: ProfileViewModel): ViewModel
@SynchronizerScope
@Binds
@IntoMap
@ViewModelKey(SettingsViewModel::class)
abstract fun bindSettingsViewModel(implementation: SettingsViewModel): ViewModel
/**
* Factory for view models that are not created until the Synchronizer exists. Only VMs that

View File

@ -17,5 +17,7 @@ object Const {
object Pref {
const val FIRST_USE_VIEW_TX = "const.pref.first_use_view_tx"
const val FEEDBACK_ENABLED = "const.pref.feedback_enabled"
const val SERVER_NAME = "const.pref.server_name"
const val SERVER_PORT = "const.pref.server_port"
}
}

View File

@ -38,6 +38,7 @@ class ProfileFragment : BaseFragment<FragmentProfileBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.hitAreaSettings.onClickNavTo(R.id.action_nav_profile_to_nav_settings)
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) {

View File

@ -0,0 +1,76 @@
package cash.z.ecc.android.ui.settings
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import cash.z.ecc.android.di.viewmodel.viewModel
import cash.z.ecc.android.databinding.FragmentSettingsBinding
import cash.z.ecc.android.ext.onClickNavBack
import cash.z.ecc.android.ui.base.BaseFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
class SettingsFragment : BaseFragment<FragmentSettingsBinding>() {
private val viewModel: SettingsViewModel by viewModel()
override fun inflate(inflater: LayoutInflater): FragmentSettingsBinding =
FragmentSettingsBinding.inflate(inflater)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
getCurrentServer()
binding.hitAreaClose.onClickNavBack()
binding.buttonUpdate.setOnClickListener(View.OnClickListener {
validateServerHost(view)
})
binding.buttonReset.setOnClickListener(View.OnClickListener {
resetServer()
showUpdateServerDialog(view)
})
}
private fun getCurrentServer() {
binding.inputTextLightwalletdServer.setText(viewModel.getServerHost())
binding.inputTextLightwalletdPort.setText(viewModel.getServerPort().toString())
}
private fun resetServer() {
}
private fun validateServerHost(view: View) {
var isError = false
if (binding.inputTextLightwalletdServer.text.toString().contains("http")) {
binding.lightwalletdServer.error = "Please remove http:// or https://"
isError = true
} else {
binding.lightwalletdServer.error = null
}
if (Integer.valueOf(binding.inputTextLightwalletdPort.text.toString()) > 65535) {
binding.lightwalletdPort.error = "Please enter port number below 65535"
isError = true
} else {
binding.lightwalletdPort.error = null
}
if (!isError) {
showUpdateServerDialog(view)
}
}
private fun showUpdateServerDialog(view: View) {
MaterialAlertDialogBuilder(view.context)
.setTitle("Modify lightwalletd Server?")
.setMessage("WARNING: Entering an invalid or compromised lighthttpd server might result in misconfiguration or loss of funds.")
.setCancelable(false)
.setPositiveButton("Update") { dialog, _ ->
dialog.dismiss()
updateServer()
}
.setNegativeButton("Cancel") { dialog, _ ->
dialog.dismiss()
}
.show()
}
private fun updateServer() {
}
}

View File

@ -0,0 +1,30 @@
package cash.z.ecc.android.ui.settings
import androidx.lifecycle.ViewModel
import cash.z.ecc.android.di.module.InitializerModule
import cash.z.ecc.android.sdk.Synchronizer
import cash.z.ecc.android.sdk.ext.twig
import javax.inject.Inject
class SettingsViewModel @Inject constructor() : ViewModel() {
@Inject
lateinit var synchronizer: Synchronizer
fun updateServer(host: String, port: Int) {
// TODO: Update the SecurePrefs here
}
fun getServerHost(): String {
return InitializerModule.defaultHost
}
fun getServerPort(): Int {
return InitializerModule.defaultPort
}
override fun onCleared() {
super.onCleared()
twig("SettingsViewModel cleared!")
}
}

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="@color/zcashWhite_50">
<path
android:fillColor="@android:color/white"
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
</vector>

View File

@ -311,6 +311,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:elevation="6dp"
app:tint="@color/colorAccent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintEnd_toEndOf="parent"

View File

@ -35,6 +35,33 @@
android:orientation="vertical"
app:layout_constraintGuide_percent="0.85" />
<View
android:id="@+id/hit_area_settings"
android:layout_width="68dp"
android:layout_height="68dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:alpha="0.3"
android:background="@android:color/transparent"
android:elevation="6dp"
app:layout_constraintStart_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/guideline_hit_area_top" />
<ImageView
android:id="@+id/icon_settings"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="44dp"
android:elevation="6dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.064"
app:layout_constraintWidth_percent="0.08"
app:srcCompat="@drawable/ic_settings" />
<ImageView
android:id="@+id/icon_close"
android:layout_width="0dp"
@ -81,24 +108,23 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
style="@style/TextAppearance.AppCompat.Body1"
android:textSize="20dp"
android:text="Shielded User"
android:textSize="20sp"
android:text="@string/profile_shielded_user"
app:layout_constraintTop_toBottomOf="@id/icon_profile"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/text_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Zcash.TextAppearance.AddressPart"
android:textSize="16dp"
android:text="zs1g7cqw...9qmvyzgm"
android:textSize="16sp"
tools:text="zs1g7cqw...9qmvyzgm"
android:textColor="@color/text_light_dimmed"
app:layout_constraintTop_toBottomOf="@id/text_username"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/image_copy"
@ -129,7 +155,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/Zcash.Button"
android:text="Send Feedback"
android:text="@string/profile_send_feedback"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="#000000"
android:gravity="center"
@ -145,7 +171,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/Zcash.Button.OutlinedButton"
android:text="Backup Wallet"
android:text="@string/profile_backup_wallet"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="@color/text_light"
android:gravity="center"
@ -161,7 +187,7 @@
android:layout_marginTop="16dp"
style="@style/TextAppearance.AppCompat.Body1"
android:textSize="16sp"
android:text="See Application Logs"
android:text="@string/profile_see_application_logs"
android:textColor="@color/selector_button_text_light_dimmed"
app:layout_constraintTop_toBottomOf="@id/button_backup"
app:layout_constraintEnd_toEndOf="parent"
@ -180,7 +206,7 @@
android:paddingBottom="8dp"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:text="ECC Wallet"
android:text="@string/profile_ecc_wallet"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="@color/selector_button_text_light"
app:layout_constraintEnd_toEndOf="@id/guideline_content_end"
@ -194,9 +220,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:text="v1.0.0-alpha05"
android:text="@string/profile_app_version"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="@color/text_light_dimmed"
app:layout_constraintBaseline_toBaselineOf="@id/text_banner_message"
app:layout_constraintEnd_toEndOf="@id/text_banner_message" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,121 @@
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background_home">
<ImageView
android:id="@+id/icon_profile"
android:layout_width="0dp"
android:layout_height="0dp"
android:elevation="6dp"
android:tint="@color/text_light_dimmed"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.912"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.064"
app:layout_constraintWidth_percent="0.08"
app:srcCompat="@drawable/ic_cancel" />
<View
android:id="@+id/hit_area_close"
android:layout_width="68dp"
android:layout_height="68dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:background="@android:color/transparent"
android:elevation="6dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginTop="92dp"
android:text="@string/settings_change_lightwalletd_server"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="@color/text_light"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/lightwalletd_server"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="24dp"
app:errorEnabled="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
tools:layout_editor_absoluteX="1dp"
tools:layout_editor_absoluteY="133dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/input_text_lightwalletd_server"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/settings_server_address" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/lightwalletd_port"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="24dp"
app:errorEnabled="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/lightwalletd_server"
tools:layout_editor_absoluteX="1dp"
tools:layout_editor_absoluteY="133dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/input_text_lightwalletd_port"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/settings_server_port"
android:inputType="number"
android:maxLength="5" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/button_update"
style="@style/Zcash.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="16dp"
android:text="@string/settings_update"
app:layout_constraintEnd_toStartOf="@+id/button_reset"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/lightwalletd_port" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_reset"
style="@style/Zcash.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="24dp"
android:text="@string/settings_reset_to_default_host"
android:textColor="@color/text_light"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/button_update"
app:layout_constraintTop_toBottomOf="@+id/lightwalletd_port" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -69,11 +69,18 @@
<action
android:id="@+id/action_nav_profile_to_nav_feedback"
app:destination="@id/nav_feedback" />
<action
android:id="@+id/action_nav_profile_to_nav_settings"
app:destination="@id/nav_settings" />
</fragment>
<fragment
android:id="@+id/nav_feedback"
android:name="cash.z.ecc.android.ui.profile.FeedbackFragment"
tools:layout="@layout/fragment_feedback" />
<fragment
android:id="@+id/nav_settings"
android:name="cash.z.ecc.android.ui.settings.SettingsFragment"
tools:layout="@layout/fragment_settings" />
<!-- -->
<!-- Send Navigation -->

View File

@ -40,6 +40,21 @@
<string name="feedback_hint_2">My balance was . . .</string>
<string name="feedback_hint_3">I\'d like . . .</string>
<!-- Profile -->
<string name="profile_shielded_user">Shielded User</string>
<string name="profile_send_feedback">Send Feedback</string>
<string name="profile_backup_wallet">Backup Wallet</string>
<string name="profile_see_application_logs">See Application Logs</string>
<string name="profile_ecc_wallet">ECC Wallet</string>
<string name="profile_app_version">v1.0.0-alpha05</string>
<!-- Settings-->
<string name="settings_change_lightwalletd_server">Change lightwalletd server:</string>
<string name="settings_server_address">Server Address</string>
<string name="settings_server_port">Server Port</string>
<string name="settings_update">Update</string>
<string name="settings_reset_to_default_host">Reset to Default Host</string>
<!-- Dialogs -->
<string name="dialog_not_again">Don\'t show me again</string>
<string name="dialog_first_use_view_tx_title">Potential Privacy Risk</string>
@ -51,5 +66,4 @@
<string name="app_name">ECC Wallet</string>
<string name="mixpanel_project">a178e1ef062133fc121079cb12fa43c7</string>
</resources>