Skip to content

Commit

Permalink
[Enhancement] - User can see Payment Methods screen (#367)
Browse files Browse the repository at this point in the history
* setting up payment methods screen

* added strings and query for payment methods

* added custom scalar type, viewmodel for viewHolder

* added formatter to viewholder and added dimens for payment methods

* fixed text styling for the list item

* added new lines to new classes

* wrote viewmodel tests for paymentmethods

* added Locale default for date formatting

* fixed drawables

* switched src to background

* removed double dependency and fixed the manifest

* fixed line spacing

* fixed schema issue

* fixed manifest line

* fixed creditcard schema

* fixed constraint layout version and added new line to list item

* fixed custom type mapping formatting

* fixed list item text spacing

* addressed PR feedback

* removed error methods

* fixed date test

* added test for when adding cards fails
  • Loading branch information
Rashad Cureton committed Nov 1, 2018
1 parent bd7ff9d commit 2436858
Show file tree
Hide file tree
Showing 48 changed files with 1,216 additions and 23 deletions.
3 changes: 2 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ buildscript {

apollo {
customTypeMapping['Email'] = "java.lang.String"
customTypeMapping['Date'] = "java.util.Date"
}

afterEvaluate {
Expand Down Expand Up @@ -209,7 +210,7 @@ repositories {
final apollo = "0.5.0"
final auto_parcel_version = "0.3.1"
final butterknife_version = "7.0.1"
final constraint_layout_version = "1.1.0"
final constraint_layout_version = "1.1.3"
final crashlytics_version = "2.9.4@aar"
final dagger_version = "2.11"
final exoplayer_version = "2.7.0"
Expand Down
5 changes: 3 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@
android:value=".ui.activities.DiscoveryActivity" />
</activity>
<activity android:name=".ui.activities.ChangeEmailActivity" />
<activity android:name=".ui.activities.ChangePasswordActivity"/>
<activity android:name=".ui.activities.EditProfileActivity"/>
<activity android:name=".ui.activities.ChangePasswordActivity" />
<activity android:name=".ui.activities.EditProfileActivity" />
<activity
android:name=".ui.activities.CheckoutActivity"
android:parentActivityName=".ui.activities.ProjectActivity"
Expand Down Expand Up @@ -191,6 +191,7 @@
</activity>
<activity android:name=".ui.activities.NewsletterActivity" />
<activity android:name=".ui.activities.NotificationsActivity" />
<activity android:name=".ui.activities.PaymentMethodsActivity"/>
<activity android:name=".ui.activities.PrivacyActivity" />
<activity
android:name=".ui.activities.ProjectNotificationSettingsActivity"
Expand Down
85 changes: 75 additions & 10 deletions app/src/main/assets/json/server-config.json

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions app/src/main/graphql/payments.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
query UserPayments {
me {
storedCards {
nodes {
id
expirationDate
lastFour
state
paymentType
type
}
}
}
}
2 changes: 2 additions & 0 deletions app/src/main/java/com/kickstarter/ApplicationModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.kickstarter.libs.KoalaTrackingClient;
import com.kickstarter.libs.Logout;
import com.kickstarter.libs.PushNotifications;
import com.kickstarter.libs.graphql.DateAdapter;
import com.kickstarter.libs.graphql.EmailAdapter;
import com.kickstarter.libs.preferences.BooleanPreference;
import com.kickstarter.libs.preferences.BooleanPreferenceType;
Expand Down Expand Up @@ -174,6 +175,7 @@ static ApolloClient provideApolloClient(final @NonNull Build build, final @NonNu
final OkHttpClient okHttpClient = builder.build();

return ApolloClient.builder()
.addCustomTypeAdapter(CustomType.DATE, new DateAdapter())
.addCustomTypeAdapter(CustomType.EMAIL, new EmailAdapter())
.serverUrl(webEndpoint + "/graph")
.okHttpClient(okHttpClient)
Expand Down
24 changes: 24 additions & 0 deletions app/src/main/java/com/kickstarter/libs/graphql/DateAdapter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.kickstarter.libs.graphql

import com.apollographql.apollo.response.CustomTypeAdapter
import com.apollographql.apollo.response.CustomTypeValue
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*

class DateAdapter: CustomTypeAdapter<Date> {

private val DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())

override fun encode(value: Date): CustomTypeValue<*> {
return CustomTypeValue.GraphQLString(DATE_FORMAT.format(value))
}

override fun decode(value: CustomTypeValue<*>): Date {
try {
return DATE_FORMAT.parse(value.value.toString())
} catch (exception: ParseException) {
throw RuntimeException(exception)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,24 @@ package com.kickstarter.mock.services
import UpdateUserCurrencyMutation
import UpdateUserEmailMutation
import UpdateUserPasswordMutation
import UserPaymentsQuery
import UserPrivacyQuery
import com.kickstarter.services.ApolloClientType
import rx.Observable
import type.CreditCardPaymentType
import type.CreditCardState
import type.CreditCardTypes
import type.CurrencyCode
import java.util.*

open class MockApolloClient : ApolloClientType {
override fun getStoredCards(): Observable<UserPaymentsQuery.Data> {
return Observable.just(UserPaymentsQuery.Data(UserPaymentsQuery.Me("",
UserPaymentsQuery.StoredCards("", List<UserPaymentsQuery.Node>(1
) { _ -> UserPaymentsQuery.Node("","4333", Date(), "1234",
CreditCardState.ACTIVE, CreditCardPaymentType.CREDIT_CARD, CreditCardTypes.VISA )}))))
}

override fun updateUserCurrencyPreference(currency: CurrencyCode): Observable<UpdateUserCurrencyMutation.Data> {
return Observable.just(UpdateUserCurrencyMutation.Data(UpdateUserCurrencyMutation.UpdateUserProfile("",
UpdateUserCurrencyMutation.User("", "USD"))))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ package com.kickstarter.services
import UpdateUserCurrencyMutation
import UpdateUserEmailMutation
import UpdateUserPasswordMutation
import UserPaymentsQuery
import UserPrivacyQuery
import rx.Observable
import type.CurrencyCode

interface ApolloClientType {
fun getStoredCards(): Observable<UserPaymentsQuery.Data>

fun updateUserCurrencyPreference(currency: CurrencyCode): Observable<UpdateUserCurrencyMutation.Data>

fun updateUserEmail(email: String, currentPassword: String): Observable<UpdateUserEmailMutation.Data>
Expand Down
22 changes: 22 additions & 0 deletions app/src/main/java/com/kickstarter/services/KSApolloClient.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.kickstarter.services
import UpdateUserCurrencyMutation
import UpdateUserEmailMutation
import UpdateUserPasswordMutation
import UserPaymentsQuery
import UserPrivacyQuery
import com.apollographql.apollo.ApolloCall
import com.apollographql.apollo.ApolloClient
Expand All @@ -13,6 +14,27 @@ import rx.subjects.PublishSubject
import type.CurrencyCode

class KSApolloClient(val service: ApolloClient) : ApolloClientType {
override fun getStoredCards(): Observable<UserPaymentsQuery.Data> {
return Observable.defer {
val ps = PublishSubject.create<UserPaymentsQuery.Data>()
service.query(UserPaymentsQuery.builder().build())
.enqueue(object : ApolloCall.Callback<UserPaymentsQuery.Data>() {
override fun onFailure(exception: ApolloException) {
ps.onError(exception)
}

override fun onResponse(response: Response<UserPaymentsQuery.Data>) {
if (response.hasErrors()) {
ps.onError(Exception(response.errors().first().message()))
}
ps.onNext(response.data())
ps.onCompleted()
}
})
return@defer ps
}
}

override fun updateUserCurrencyPreference(currency: CurrencyCode): Observable<UpdateUserCurrencyMutation.Data> {
return Observable.defer {
val ps = PublishSubject.create<UpdateUserCurrencyMutation.Data>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class AccountActivity : BaseActivity<AccountViewModel.ViewModel>() {

change_email_row.setOnClickListener { startActivity(Intent(this, ChangeEmailActivity::class.java)) }
change_password_row.setOnClickListener { startActivity(Intent(this, ChangePasswordActivity::class.java)) }
payment_methods_row.setOnClickListener { startActivity(Intent(this, PaymentMethodsActivity::class.java)) }
privacy_row.setOnClickListener { startActivity(Intent(this, PrivacyActivity::class.java)) }
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.kickstarter.ui.activities

import UserPaymentsQuery
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import com.kickstarter.R
import com.kickstarter.libs.BaseActivity
import com.kickstarter.libs.qualifiers.RequiresActivityViewModel
import com.kickstarter.ui.adapters.PaymentMethodsAdapter
import com.kickstarter.viewmodels.PaymentMethodsViewModel
import kotlinx.android.synthetic.main.activity_payment_method.*
import rx.android.schedulers.AndroidSchedulers

@RequiresActivityViewModel(PaymentMethodsViewModel.ViewModel::class)
class PaymentMethodsActivity : BaseActivity<PaymentMethodsViewModel.ViewModel>() {

private lateinit var adapter: PaymentMethodsAdapter

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_payment_method)

setupRecyclerview()

this.viewModel.outputs.getCards()
.compose(bindToLifecycle())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { setCards(it) }

}

private fun setCards(cards: MutableList<UserPaymentsQuery.Node>) = this.adapter.populateCards(cards)

private fun setupRecyclerview() {
this.adapter = PaymentMethodsAdapter(this.viewModel)
recycler_view.adapter = this.adapter
recycler_view.layoutManager = LinearLayoutManager(this)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.kickstarter.ui.adapters

import UserPaymentsQuery
import android.view.View
import com.kickstarter.R
import com.kickstarter.ui.viewholders.KSViewHolder
import com.kickstarter.ui.viewholders.PaymentMethodsViewHolder

class PaymentMethodsAdapter(private val delegate: PaymentMethodsViewHolder.Delegate): KSAdapter() {

interface Delegate: PaymentMethodsViewHolder.Delegate

override fun layout(sectionRow: SectionRow): Int = R.layout.list_item_payment_methods

override fun viewHolder(layout: Int, view: View): KSViewHolder = PaymentMethodsViewHolder(view, delegate)

fun populateCards(cards: MutableList<UserPaymentsQuery.Node>) {
addSection(cards)
notifyDataSetChanged()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.kickstarter.ui.viewholders

import UserPaymentsQuery
import android.support.annotation.NonNull
import android.view.View
import com.kickstarter.R
import com.kickstarter.libs.rx.transformers.Transformers.observeForUI
import com.kickstarter.viewmodels.PaymentMethodsViewHolderViewModel
import kotlinx.android.synthetic.main.list_item_payment_methods.view.*

class PaymentMethodsViewHolder(@NonNull view: View, @NonNull delegate: Delegate) : KSViewHolder(view) {

private val ksString = environment().ksString()
private val vm: PaymentMethodsViewHolderViewModel.ViewModel = PaymentMethodsViewHolderViewModel.ViewModel(environment())

private val creditCardExpirationString = this.context().getString(R.string.Credit_card_expiration)
private val cardEndingInString = this.context().getString(R.string.Card_ending_in_last_four)

interface Delegate

init {

this.vm.outputs.type()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe {
itemView.credit_card_logo.setImageResource(it)
}

this.vm.outputs.expirationDate()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe {
setExpirationDateTextView(it)
}

this.vm.outputs.lastFour()
.compose(bindToLifecycle())
.compose(observeForUI())
.subscribe {
setLastFourTextView(it)
}

}

override fun bindData(data: Any?) {
val cards = requireNotNull(data as UserPaymentsQuery.Node)
this.vm.inputs.card(cards)
}

private fun setExpirationDateTextView(date: String) {
itemView.credit_card_expiration_date.text = this.ksString.format(this.creditCardExpirationString,
"expiration_date", date)
}

private fun setLastFourTextView(lastFour: String) {
itemView.credit_card_last_four_digits.text = this.ksString.format(this.cardEndingInString, "last_four", lastFour)
}

}
Loading

0 comments on commit 2436858

Please sign in to comment.