Skip to content

Commit

Permalink
Release 0.14.3
Browse files Browse the repository at this point in the history
  • Loading branch information
mohan88 committed Nov 11, 2020
1 parent 6319ae3 commit 950fe6a
Show file tree
Hide file tree
Showing 20 changed files with 304 additions and 271 deletions.
2 changes: 1 addition & 1 deletion buildSrc/src/main/java/TinkLinkVersion.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ object TinkLinkVersion {

private const val major = 0
private const val minor = 14
private const val patch = 2
private const val patch = 3

const val name = "$major.$minor.$patch"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ internal class ConsentViewModel() : ViewModel() {
val privacyPolicyUrl = consentContext.privacyPolicy()

private val _clientDescription = MutableLiveData<OAuthClientDescription>()
val clientDescription: LiveData<OAuthClientDescription> = _clientDescription

val scopeDescriptions: MutableList<ScopeDescription> = mutableListOf()

Expand All @@ -40,14 +41,9 @@ internal class ConsentViewModel() : ViewModel() {
val isUnverified: LiveData<Boolean> =
Transformations.map(_clientDescription) { it?.verified == false }

val showConsentInformation: LiveData<Boolean> =
Transformations.map(_clientDescription) { it?.aggregator == false }

val clientName: LiveData<String> = Transformations.map(_clientDescription) { it?.clientName }

val showTinkLogo: LiveData<Boolean> =
Transformations.map(_clientDescription) { it?.aggregator == false }

val showTermsAndConditions: LiveData<Boolean> =
Transformations.map(_clientDescription) { it?.aggregator == false }
fun showTermsAndConsent(clientDescription: OAuthClientDescription) =
!clientDescription.aggregator
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,27 @@ internal class MutableCredentialsField : LinearLayout, CredentialsField {
getFilledField().validate()
.also {
textInputLayout.error =
if (it is Field.ValidationResult.ValidationError) it.errorMessage else null
if (it is Field.ValidationResult.ValidationError) {
when (it) {
is Field.ValidationResult.ValidationError.Invalid -> {
it.errorMessage
}

is Field.ValidationResult.ValidationError.MaxLengthLimit -> {
context.getString(
R.string.tink_credentials_field_validation_error_maxLengthLimit,
field.validationRules.maxLength
)
}

is Field.ValidationResult.ValidationError.MinLengthLimit -> {
context.getString(
R.string.tink_credentials_field_validation_error_minLengthLimit,
field.validationRules.minLength
)
}
}
} else null
}
.let { it == Field.ValidationResult.Valid }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ import com.tink.link.authentication.AuthenticationTask.ThirdPartyAuthentication.
import com.tink.link.ui.R
import com.tink.link.ui.TinkLinkUiActivity
import com.tink.link.ui.extensions.LinkInfo
import com.tink.link.ui.extensions.convertCallToActionText
import com.tink.link.ui.extensions.hideKeyboard
import com.tink.link.ui.extensions.setTextWithLinks
import com.tink.link.ui.extensions.setTextWithUrlMarkdown
import com.tink.link.ui.extensions.toArrayList
import com.tink.link.ui.extensions.toView
import com.tink.model.credentials.Credentials
import com.tink.model.provider.Provider
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.tink_fragment_credentials.*
import kotlinx.android.synthetic.main.tink_fragment_credentials.authenticateCredentialsLayout
import kotlinx.android.synthetic.main.tink_layout_consent.*
import kotlinx.android.synthetic.main.tink_layout_credentials_authenticate.*
import kotlinx.android.synthetic.main.tink_layout_toolbar.toolbar
import kotlinx.android.synthetic.main.tink_layout_toolbar_with_logo.*
import kotlinx.android.synthetic.main.tink_layout_toolbar_with_logo.view.*

private const val BANK_ID_ACTION_SAME_DEVICE = 1
private const val BANK_ID_ACTION_OTHER_DEVICE = 2
Expand Down Expand Up @@ -66,13 +66,17 @@ internal class CredentialsFragment : Fragment(R.layout.tink_fragment_credentials

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
toolbar.title = getString(R.string.tink_credentials_authentication_title)
toolbar.setNavigationOnClickListener {
toolbarWithLogo.toolbarTitleView.text = provider.displayName
toolbarWithLogo.setNavigationOnClickListener {
(activity as? TinkLinkUiActivity)?.closeTinkLinkUi(
TinkLinkUiActivity.RESULT_CANCELLED
)
}

provider.images?.icon?.let {
Picasso.get().load(it).into(toolbarWithLogo.logoView)
}

when (credentialsOperationArgs) {
is CredentialsOperationArgs.Create,
is CredentialsOperationArgs.Update -> { showFullCredentialsFlow() }
Expand Down Expand Up @@ -143,20 +147,13 @@ internal class CredentialsFragment : Fragment(R.layout.tink_fragment_credentials
authenticateCredentialsLayout.visibility = View.GONE
addCredentialsLayout.visibility = View.VISIBLE
consentViewModel.apply {
showConsentInformation.observe(viewLifecycleOwner) {
userGroup.visibility = if (it == true) View.VISIBLE else View.GONE
}
clientName.observe(viewLifecycleOwner) {
setConsentInformation(it)
}
showTermsAndConditions.observe(viewLifecycleOwner) {
termsAndConditionsText.visibility =
if (it == true) {
setTermsAndConditions(termsAndConditionsUrl, privacyPolicyUrl)
View.VISIBLE
} else {
View.GONE
}
clientDescription.observe(viewLifecycleOwner) {
if (showTermsAndConsent(it)) {
termsAndConsentText.visibility = View.VISIBLE
setTermsAndConsentText(termsAndConditionsUrl, privacyPolicyUrl, it.clientName)
} else {
termsAndConsentText.visibility = View.GONE
}
}
isUnverified.observe(viewLifecycleOwner) {
unverifiedWarning.visibility =
Expand All @@ -167,12 +164,13 @@ internal class CredentialsFragment : Fragment(R.layout.tink_fragment_credentials
}
}

provider.images?.icon?.let {
Picasso.get().load(it).into(logo)
if (provider.fields.isEmpty()) {
showEmptyFieldsFlow()
} else {
emptyFieldsGroup.isVisible = false
credentialsFieldsHelpTextGroup.isVisible = true
}

bankName.text = provider.displayName

val fields = provider.fields.map { field ->
credentialsOperationArgs
.takeIf { it is CredentialsOperationArgs.Update }
Expand Down Expand Up @@ -209,6 +207,14 @@ internal class CredentialsFragment : Fragment(R.layout.tink_fragment_credentials
submitFilledFields()
}

if (provider.helpText.isNotBlank()) {
providerHelpText.visibility = View.VISIBLE
providerHelpText.setTextWithUrlMarkdown(provider.helpText)
providerHelpText.movementMethod = LinkMovementMethod.getInstance()
} else {
providerHelpText.visibility = View.GONE
}

createCredentialsBtn.setOnClickListener { submitFilledFields() }

footer.post {
Expand All @@ -218,6 +224,16 @@ internal class CredentialsFragment : Fragment(R.layout.tink_fragment_credentials
}
}

private fun showEmptyFieldsFlow() {
credentialsFieldsHelpTextGroup.isVisible = false
emptyFieldsGroup.isVisible = true
provider.images?.icon?.let {
Picasso.get().load(it).into(emptyFieldsBankLogo)
}
emptyFieldsLoginText.text =
getString(R.string.tink_credentials_empty_fields_login, provider.displayName)
}

private fun showAuthenticateFlow() {
addCredentialsLayout.visibility = View.GONE
authenticateCredentialsLayout.visibility = View.VISIBLE
Expand Down Expand Up @@ -258,41 +274,49 @@ internal class CredentialsFragment : Fragment(R.layout.tink_fragment_credentials
}
}

private fun setConsentInformation(clientName: String) {
private fun setTermsAndConsentText(
termsAndConditionsUrl: Uri,
privacyPolicyUrl: Uri,
clientName: String?
) {
val links = mutableListOf<LinkInfo>(
LinkInfo.Url(
getString(R.string.tink_credentials_terms_and_conditions),
termsAndConditionsUrl.toString()
),
LinkInfo.Url(
getString(R.string.tink_credentials_privacy_policy),
privacyPolicyUrl.toString(),
)
)
val readMoreText = getString(R.string.tink_credentials_consent_information_read_more)
consentInformation.text =
getString(
var consentText = ""
// Add consent text if client name is not null
if (clientName != null) {
consentText = getString(
R.string.tink_credentials_consent_information_text,
clientName,
readMoreText
).convertCallToActionText(
ctaText = readMoreText,
action = { showConsentInformation() },
context = requireContext()
getString(R.string.tink_credentials_consent_information_read_more)
)
consentInformation.movementMethod = LinkMovementMethod.getInstance()
}

private fun setTermsAndConditions(termsAndConditionsUrl: Uri, privacyPolicyUrl: Uri) {
// Add CTA text to list of links to be shown in the final text
links.add(
LinkInfo.CallToAction(
displayText = readMoreText,
action = { showConsentInformation() }
)
)
}
val termsText = getString(
R.string.tink_credentials_terms_text,
getString(R.string.tink_credentials_terms_and_conditions),
getString(R.string.tink_credentials_privacy_policy)
getString(R.string.tink_credentials_privacy_policy),
consentText
)
termsAndConditionsText.setTextWithLinks(
termsAndConsentText.setTextWithLinks(
fullText = termsText,
links = listOf(
LinkInfo(
termsAndConditionsUrl.toString(),
getString(R.string.tink_credentials_terms_and_conditions)
),
LinkInfo(
privacyPolicyUrl.toString(),
getString(R.string.tink_credentials_privacy_policy)
)
)
links = links
)
termsAndConditionsText.movementMethod = LinkMovementMethod.getInstance()
termsAndConsentText.movementMethod = LinkMovementMethod.getInstance()
}

private fun showConsentInformation() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,30 @@ import androidx.core.content.res.ResourcesCompat
import com.tink.link.ui.R
import java.util.regex.Pattern

internal fun String.convertCallToActionText(
ctaText: String,
action: () -> Unit,
context: Context
): CharSequence {
val startIndex = indexOf(ctaText)
val spannableString = SpannableString.valueOf(this)
.apply {
setSpan(
TinkCallToActionSpan(context, action),
startIndex,
startIndex + ctaText.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
return SpannedString(spannableString)
}

internal fun TextView.setTextWithLinks(fullText: String, links: List<LinkInfo>) {
val spannableString = SpannableString.valueOf(fullText)
.apply {
for (link in links) {
val startIndex = indexOf(link.linkText)
setSpan(
TinkUrlSpan(link.url, context),
startIndex,
startIndex + link.linkText.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
val startIndex = indexOf(link.displayText)
when (link) {
is LinkInfo.Url -> {
setSpan(
TinkUrlSpan(link.url, context),
startIndex,
startIndex + link.displayText.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}

is LinkInfo.CallToAction -> {
setSpan(
TinkCallToActionSpan(context, link.action),
startIndex,
startIndex + link.displayText.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
}
}
}
text = SpannedString(spannableString)
Expand All @@ -61,13 +56,13 @@ internal fun String.convertUrlMarkdownToSpan(context: Context): SpannableString
val url = matcher.toMatchResult().group(2)
val startIndex = matcher.start(1) - 1
if (!url.isNullOrEmpty() && !linkText.isNullOrEmpty()) {
val linkInfo = LinkInfo(url, linkText)
val linkInfo = LinkInfo.Url(url, linkText)
val fullText = matcher.replaceAll(linkText)
return SpannableString.valueOf(fullText).apply {
setSpan(
TinkUrlSpan(linkInfo.url, context),
startIndex,
startIndex + linkInfo.linkText.length,
startIndex + linkInfo.displayText.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
Expand Down Expand Up @@ -112,4 +107,11 @@ internal class TinkUrlSpan(url: String, val context: Context) : URLSpan(url) {
}
}

internal data class LinkInfo(val url: String, val linkText: String)
internal sealed class LinkInfo {

abstract val displayText: String

data class Url(override val displayText: String, val url: String) : LinkInfo()

data class CallToAction(override val displayText: String, val action: () -> Unit) : LinkInfo()
}
14 changes: 7 additions & 7 deletions link-ui/src/main/res/drawable/tink_logo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,36 @@
android:pathData="M4.2883,12.4665C3.2687,12.4665 2.9241,11.9752 2.9241,11.2595V8.0856H5.1583V6.6248H2.9241V4.0781H1.1997V6.6248H0V8.1004H1.0948V11.3037C1.0948,12.9275 2.159,14.0002 4.0181,14.0002C4.5428,14.0002 5.008,13.911 5.2625,13.8062L5.2021,12.3011C4.9179,12.4215 4.618,12.4665 4.2883,12.4665Z"
android:strokeAlpha="0.2"
android:fillColor="#262626"
android:fillAlpha="0.2"/>
android:fillAlpha="0.5"/>
<path
android:pathData="M8.1575,6.6245H6.3281V13.9254H8.1575V6.6245Z"
android:strokeAlpha="0.2"
android:fillColor="#262626"
android:fillAlpha="0.2"/>
android:fillAlpha="0.5"/>
<path
android:pathData="M13.4517,6.5508C12.342,6.5508 11.5777,7.0126 11.1431,7.6833L11.0828,6.6253H9.3286V13.9262H11.158V9.7836C11.158,8.7854 11.8024,8.1148 12.7923,8.1148C13.7218,8.1148 14.2019,8.7257 14.2019,9.7542V13.9262H16.0461V9.3365C16.0461,7.653 15.086,6.5508 13.4517,6.5508Z"
android:strokeAlpha="0.2"
android:fillColor="#262626"
android:fillAlpha="0.2"/>
android:fillAlpha="0.5"/>
<path
android:pathData="M21.2083,9.6493L23.9515,6.6244H21.7628L18.989,9.7836V4.0786H17.1597V13.9262H18.989V12.0788L20.0384,10.9316L22.1528,13.9262H24.2366L21.2083,9.6493Z"
android:strokeAlpha="0.2"
android:fillColor="#262626"
android:fillAlpha="0.2"/>
android:fillAlpha="0.5"/>
<path
android:pathData="M8.1575,4.0786H6.3281V5.6852H8.1575V4.0786Z"
android:strokeAlpha="0.2"
android:fillColor="#262626"
android:fillAlpha="0.2"/>
android:fillAlpha="0.5"/>
<path
android:pathData="M24.8218,2.2658C26.0843,2.2658 27.108,1.2512 27.108,0H28.9374C28.9374,2.2527 27.0948,4.0779 24.8226,4.0779V2.2658H24.8218Z"
android:strokeAlpha="0.2"
android:fillColor="#262626"
android:fillAlpha="0.2"/>
android:fillAlpha="0.5"/>
<path
android:pathData="M30.9483,4.0789C29.6857,4.0789 28.662,5.0935 28.662,6.3447C28.662,7.5959 29.6857,8.6104 30.9483,8.6104V10.4234C28.6752,10.4234 26.8335,8.5973 26.8335,6.3455C26.8335,4.0936 28.6761,2.2676 30.9483,2.2676V4.0789Z"
android:strokeAlpha="0.2"
android:fillColor="#262626"
android:fillAlpha="0.2"/>
android:fillAlpha="0.5"/>
</group>
</vector>
Loading

0 comments on commit 950fe6a

Please sign in to comment.