Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Check `fastlane/Appfile` and `fastlane/Fastfile` for more information.

## CI/CD configuration with Bitrise (updated on Dec 12th 2021)

We are going to start using a tool called Bitrise to configure de CI/CD pipelines for mobiles apps.
We are going to start using a tool called Bitrise to configure the CI/CD pipelines for mobiles apps.

--> For Android apps you can find how to do it in this link: https://www.notion.so/rootstrap/Android-CI-CD-26d4abd4f2454224be8f617110147366

Expand Down Expand Up @@ -115,6 +115,20 @@ in order to track the login event.
- For MixPanel, you have to replace the API key:
`<string name="mixpanel_api_key">mixpanel_api_key</string>`


## Utility extensions
We have a bunch of pre-made extensions usually used on every project to accelerate feature development.
you can access them in the util.extensions package. They include but are not limited to :

- `Fragment.collectOnLifeCycle(...)` extension to reduce the boiler plate code and indentation when
collecting flows from a fragment.
- `ProgressBar.progressTo(...)` extension to animate progress updates in one line with ease
and with good support for older android versions.
- `TextView.setClickableKeyword(...)` extension to add clickable functions to words or prhases inside a
Textview, allowing to also change their color, font (for example, to bold the keyword), and underline
- `TextView.setColoredKeyword(...) ` extension to change the color of a word or prhase in a Textview.


## Code Quality Standards
In order to meet the required code quality standards, this project uses [Ktlint](https://github.com/pinterest/ktlint) and [Detekt](https://github.com/arturbosch/detekt)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.rootstrap.android.ui.custom

import android.graphics.Paint
import android.graphics.Typeface
import android.text.TextPaint
import android.text.style.TypefaceSpan

/**
* Allows to apply a custom font in an spannableString
*
* Taken from https://stackoverflow.com/questions/10675070/multiple-typeface-in-single-textview
* with slightly modifications
*/
class CustomTypefaceSpan(private val newType: Typeface) : TypefaceSpan("") {

override fun updateDrawState(ds: TextPaint) {
applyCustomTypeFace(ds, newType)
}

override fun updateMeasureState(paint: TextPaint) {
applyCustomTypeFace(paint, newType)
}

companion object {

private const val ITALIC_SKEW_FACTOR = -0.25F

private fun applyCustomTypeFace(paint: Paint, tf: Typeface) {
val oldStyle: Int
val old = paint.typeface
oldStyle = old?.style ?: 0
val fake = oldStyle and tf.style.inv()
if (fake and Typeface.BOLD != 0) {
paint.isFakeBoldText = true
}
if (fake and Typeface.ITALIC != 0) {
paint.textSkewX = ITALIC_SKEW_FACTOR
}
paint.typeface = tf
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.rootstrap.android.util.extensions

import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch

/**
* Allows the collection of an unlimited amount of flows in an inline style without needing to
* add boilerplate indentations.
*
* The flows are all collected inside the same lifecycleState but it can be customized. By default
* it is Lifecycle.State.STARTED.
*
* This extension can be called as many times as needed without problems,
* but generally you will only require to call it once thanks to the vararg operator.
*
* If called with a single Flow Pair the type of the flow is inferred automatically, otherwise
* you will need to cast the flow values when needed.
*
* Example of use : <br>
* - Single flow collection :
* > `collectOnLifeCycle(Pair(viewModel.eventsFlow) { it.collect { event -> onEvents(event) } })`
* - Multi flow collection :
* > Just appending a trailing "," and adding a new Pair allows you to collect an additional
* flow per pair
*/
fun <T> Fragment.collectOnLifeCycle(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is cool

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! :D It simplifies a lot the fragment's code haha

vararg flowPairs: Pair<Flow<T>, suspend (Flow<T>) -> Unit>,
lifecycleState: Lifecycle.State = Lifecycle.State.STARTED
) {
lifecycleScope.launch {
repeatOnLifecycle(lifecycleState) {
flowPairs.forEach {
launch {
it.second(it.first)
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.rootstrap.android.util.extensions

import android.animation.Animator
import android.animation.ObjectAnimator
import android.view.animation.DecelerateInterpolator
import android.widget.ProgressBar
import androidx.core.animation.addListener

private const val DEFAULT_ANIMATION_TIME = 500L

/**
* Smoothly animates the progress of the progress bar to the specified value
*/
fun ProgressBar.progressTo(
newlyProgress: Int,
timeInMillis: Long = DEFAULT_ANIMATION_TIME,
onEndListener: ((Animator) -> Unit)? = null
) {
ObjectAnimator.ofInt(this, "progress", progress, newlyProgress).apply {
duration = timeInMillis
interpolator = DecelerateInterpolator()
setAutoCancel(true)
onEndListener?.let {
addListener(onEnd = it)
}
}.start()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.rootstrap.android.util.extensions

import android.graphics.Typeface
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.TextPaint
import android.text.method.LinkMovementMethod
import android.text.style.CharacterStyle
import android.text.style.ClickableSpan
import android.view.View
import android.widget.TextView
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
import com.rootstrap.android.R
import com.rootstrap.android.ui.custom.CustomTypefaceSpan

/**
* Sets the first occurrence of the keyword string in this TextView's text as clickable and attach the
* given OnClickListener function to it.
*
* Additionally, it tints the keyword using the app's colorPrimary color and adds an underline to it
* so it looks and behaves like an Hyperlink.
*
* This behavior can be customized with the keywordColor and underline params and you can also change
* the keyword's typeFace with the typeFace param, allowing you to make it bold or apply
* other kinds of effects.
*
* You can add multiple clickable keywords by just calling this method as many times as you need in
* the same textview.
*
* The next example illustrates how to add a link to open a web browser:
*```
* mySuggestionText.text = "For more information go to the admin web"
* mySuggestionText.setClickableKeyword("admin web") {
* // Get admin url and open the admin web via an intent
* }
*```
*/
fun TextView.setClickableKeyword(
Copy link
Copy Markdown
Collaborator

@amaury901130 amaury901130 Mar 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a comment description here. //** ...... *//

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a KDoc with an example usage 👍🏼

keyword: String,
onClickListener: () -> Unit,
@ColorRes keywordColor: Int = R.color.colorPrimary,
underline: Boolean = true,
typeFace: Typeface? = null
) {
val span: SpannableStringBuilder = getTextAsSpannable()

val start = text.indexOf(keyword, 0)

val clickableSpan = object : ClickableSpan() {
override fun onClick(widget: View) = onClickListener()
override fun updateDrawState(ds: TextPaint) {
ds.color = ContextCompat.getColor(context, keywordColor)
ds.isUnderlineText = underline
}
}

typeFace?.let {
span.setSpan(CustomTypefaceSpan(typeFace), start, start + keyword.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
}
span.setSpan(clickableSpan, start, start + keyword.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)

if (movementMethod !is LinkMovementMethod) {
movementMethod = LinkMovementMethod.getInstance()
}

text = span
}

/**
* changes the color of the first occurrence of the keyword string in this TextView's text.
*
* It accept a color resource as a second parameter and by default it uses the app's colorPrimary color.
*/
fun TextView.setColoredKeyword(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a KDoc here too. Thanks! 👍🏼

keyword: String,
@ColorRes keywordColor: Int = R.color.colorPrimary
) {
val span: SpannableStringBuilder = getTextAsSpannable()
val start = text.indexOf(keyword, 0)
val coloredSpan = object : CharacterStyle() {
override fun updateDrawState(ds: TextPaint) {
ds.color = ContextCompat.getColor(context, keywordColor)
}
}
span.setSpan(coloredSpan, start, start + keyword.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
text = span
}

private fun TextView.getTextAsSpannable() =
if (text is SpannableStringBuilder) text as SpannableStringBuilder
else SpannableStringBuilder(text)
Binary file added buildSrc/build/classes/kotlin/main/Libs.class
Binary file not shown.
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions buildSrc/build/kotlin/buildSrcjar-classes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/Users/rodrigosoria/Documents/Rootstrap/projects/Android-base/repos/android-base/buildSrc/build/classes/kotlin/main/Libs.class:/Users/rodrigosoria/Documents/Rootstrap/projects/Android-base/repos/android-base/buildSrc/build/classes/kotlin/main/Versions.class
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1
0
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added buildSrc/build/libs/buildSrc.jar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
implementation-classpath=/Users/rodrigosoria/Documents/Rootstrap/projects/Android-base/repos/android-base/buildSrc/build/classes/java/main\:/Users/rodrigosoria/Documents/Rootstrap/projects/Android-base/repos/android-base/buildSrc/build/classes/groovy/main\:/Users/rodrigosoria/Documents/Rootstrap/projects/Android-base/repos/android-base/buildSrc/build/classes/kotlin/main\:/Users/rodrigosoria/Documents/Rootstrap/projects/Android-base/repos/android-base/buildSrc/build/resources/main
Empty file.
8 changes: 8 additions & 0 deletions buildSrc/build/source-roots/buildSrc/source-roots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
src/main/resources
src/main/java
src/main/groovy
src/main/kotlin
src/test/resources
src/test/java
src/test/groovy
src/test/kotlin
2 changes: 2 additions & 0 deletions buildSrc/build/tmp/jar/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Manifest-Version: 1.0