Merge branch 'master' into vtb/fix-inner-navigation

This commit is contained in:
alex 2020-04-14 15:58:13 +03:00
commit 98acd9af0c
7 changed files with 38 additions and 34 deletions

View File

@ -7,8 +7,6 @@ Roboswag - библиотека решений, ускоряющих разра
* Andoroid Api: 19
* Kotlin: 1.3.11
* Gradle: 3.2.1
* Gradle CPD Plugin: 1.1
* Detekt Plugin: 1.0.0-RC12
## Основная архитектура
За основу архитектуры взят подход от Google - MVVM на основе [Android Architecture Components](https://developer.android.com/jetpack/docs/guide). Данный подход популярен в сообществе Android разработки, позволяет разбивать код на мелкие и независимые части, что ускоряет разработку и последующую поддержку приложения.
@ -22,10 +20,6 @@ Roboswag позволяет сочетать эти три решения в о
## Основные инструменты библиотеки
### Работа с RecyclerView
RecyclerView - один из самых часто используемых инструментов Android разработчика. Модуль [recyclerview-adapters](/recyclerview-adapters) позволяет сделать работу с RecyclerView более гибкой и делает работу самого элемента быстрее.
### BuildScripts
[BuildScrpts](https://github.com/TouchInstinct/BuildScripts) - набор скриптов, автоматизирующих разработку. Один из главных скриптов - staticAnalysis - инструмент для автоматической проверки кода на соответствие правилам компании.
### Api Generator
Внутренний инструмент компании Touch Instinct для генерации общего кода на разные платформы - Android, iOS и Server. Описанные в одном месте общие классы и Http методы используются на разных платформах. Данный инструмент позволяет сократить время разработки в два раза.
### Работа с SharedPreferences
Чтобы сохранять простые данные в память смартфона, используются SharedPreferences. Модуль [storable](/storable) разработан для облегчения работы с SharedPreferences.
### Утилиты и extension функции

View File

@ -1,5 +1,4 @@
buildscript {
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
@ -24,22 +23,3 @@ allprojects {
task clean(type: Delete) {
delete rootProject.buildDir
}
ext {
versions = [
compileSdk : 29,
appcompat : '1.0.2',
androidx : '1.0.0',
material : '1.0.0',
lifecycle : '2.0.0',
dagger : '2.17',
retrofit : '2.4.0',
rxJava : '2.2.2',
rxAndroid : '2.1.0',
crashlytics : '2.9.5',
location : '16.0.0',
coreKtx : '1.0.1',
yandex_mapkit: '3.4.0',
google_maps : '16.1.0'
]
}

View File

@ -1,5 +1,6 @@
package ru.touchin.lifecycle.viewmodel
import android.os.Looper
import androidx.lifecycle.MutableLiveData
import io.reactivex.Completable
import io.reactivex.Flowable
@ -13,7 +14,7 @@ import ru.touchin.lifecycle.event.Event
class BaseLiveDataDispatcher(private val destroyable: BaseDestroyable = BaseDestroyable()) : LiveDataDispatcher, Destroyable by destroyable {
override fun <T> Flowable<out T>.dispatchTo(liveData: MutableLiveData<ContentEvent<T>>): Disposable {
liveData.value = ContentEvent.Loading(liveData.value?.data)
liveData.setLoadingEvent()
return untilDestroy(
{ data -> liveData.value = ContentEvent.Success(data) },
{ throwable -> liveData.value = ContentEvent.Error(throwable, liveData.value?.data) },
@ -21,7 +22,7 @@ class BaseLiveDataDispatcher(private val destroyable: BaseDestroyable = BaseDest
}
override fun <T> Observable<out T>.dispatchTo(liveData: MutableLiveData<ContentEvent<T>>): Disposable {
liveData.value = ContentEvent.Loading(liveData.value?.data)
liveData.setLoadingEvent()
return untilDestroy(
{ data -> liveData.value = ContentEvent.Success(data) },
{ throwable -> liveData.value = ContentEvent.Error(throwable, liveData.value?.data) },
@ -29,14 +30,14 @@ class BaseLiveDataDispatcher(private val destroyable: BaseDestroyable = BaseDest
}
override fun <T> Single<out T>.dispatchTo(liveData: MutableLiveData<ContentEvent<T>>): Disposable {
liveData.value = ContentEvent.Loading(liveData.value?.data)
liveData.setLoadingEvent()
return untilDestroy(
{ data -> liveData.value = ContentEvent.Success(data) },
{ throwable -> liveData.value = ContentEvent.Error(throwable, liveData.value?.data) })
}
override fun <T> Maybe<out T>.dispatchTo(liveData: MutableLiveData<ContentEvent<T>>): Disposable {
liveData.value = ContentEvent.Loading(liveData.value?.data)
liveData.setLoadingEvent()
return untilDestroy(
{ data -> liveData.value = ContentEvent.Success(data) },
{ throwable -> liveData.value = ContentEvent.Error(throwable, liveData.value?.data) },
@ -44,10 +45,29 @@ class BaseLiveDataDispatcher(private val destroyable: BaseDestroyable = BaseDest
}
override fun Completable.dispatchTo(liveData: MutableLiveData<Event>): Disposable {
liveData.value = Event.Loading
liveData.setLoadingEvent()
return untilDestroy(
{ liveData.value = Event.Complete },
{ throwable -> liveData.value = Event.Error(throwable) })
}
private fun <T> MutableLiveData<ContentEvent<T>>.setLoadingEvent() {
val loadingContent = ContentEvent.Loading(this.value?.data)
if (Looper.getMainLooper().thread == Thread.currentThread()) {
this.value = loadingContent
} else {
this.postValue(loadingContent)
}
}
@JvmName("setCompletableLoadingEvent")
private fun MutableLiveData<Event>.setLoadingEvent() {
val loadingContent = Event.Loading
if (Looper.getMainLooper().thread == Thread.currentThread()) {
this.value = loadingContent
} else {
this.postValue(loadingContent)
}
}
}

View File

@ -12,6 +12,10 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
}
dependencies {

View File

@ -27,7 +27,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "androidx.appcompat:appcompat:$versions.appcompat"
implementation("com.crashlytics.sdk.android:crashlytics:$versions.crashlytics@aar") {
transitive = true
}

View File

@ -61,6 +61,7 @@ class BottomNavigationController(
fun detach() = callback?.let(fragmentManager::unregisterFragmentLifecycleCallbacks)
@Suppress("detekt.ComplexMethod")
fun navigateTo(@IdRes itemId: Int, state: Parcelable? = null) {
// Find view controller class that needs to open
val (viewControllerClass, defaultViewControllerState, saveStateOnSwitching) = viewControllers[itemId] ?: return

View File

@ -13,8 +13,9 @@ fun String.getSpannedTextWithUrls(
removeUnderline: Boolean = true,
flags: Int = HtmlCompat.FROM_HTML_MODE_COMPACT
): Spanned {
val spannableText = SpannableString(HtmlCompat.fromHtml(this, flags))
// HtmlCompat.fromHtml doesn't respect line breaks
val text = this.replace(lineBreakRegex, "<br/>")
val spannableText = SpannableString(HtmlCompat.fromHtml(text, flags))
// Linkify removes all previous URLSpan's, we need to save all created spans for reapply after Linkify
val spans = spannableText.getUrlSpans()
@ -38,6 +39,10 @@ fun String.getSpannedTextWithUrls(
return spannableText
}
private val lineBreakRegex by lazy(LazyThreadSafetyMode.NONE) {
"\r?\n".toRegex()
}
private fun SpannableString.getUrlSpans() = getSpans(0, length, URLSpan::class.java)
.map { UrlSpanWithBorders(it, this.getSpanStart(it), this.getSpanEnd(it)) }