Compare commits
61 Commits
master
...
ubrir/deve
| Author | SHA1 | Date |
|---|---|---|
|
|
085cf09dbb | |
|
|
809f3aba9f | |
|
|
f4c81cf2a2 | |
|
|
2696cd3af8 | |
|
|
57486cab51 | |
|
|
1259b40d05 | |
|
|
fb3365478a | |
|
|
57e6ca80e3 | |
|
|
405ff7459f | |
|
|
87b7863b46 | |
|
|
09ce885353 | |
|
|
e3da08a47b | |
|
|
7ce02f1c24 | |
|
|
243fb8a761 | |
|
|
3dbe35fedf | |
|
|
bdffe6305d | |
|
|
63d932b944 | |
|
|
3278562ff4 | |
|
|
5beefaeb31 | |
|
|
8041b66f8d | |
|
|
d57d8d083e | |
|
|
411401a4ec | |
|
|
41690204fe | |
|
|
09161d3877 | |
|
|
c9343855f7 | |
|
|
53adefddbb | |
|
|
194f1862c6 | |
|
|
0c8b444f20 | |
|
|
4ab4161610 | |
|
|
47b1c76fdf | |
|
|
4bf9d0991b | |
|
|
58c9f12d3c | |
|
|
6cc66fd242 | |
|
|
501fddd72d | |
|
|
3a6afded87 | |
|
|
9c67b0fa18 | |
|
|
19044fefa8 | |
|
|
fd51f7f67b | |
|
|
89271b79b8 | |
|
|
e65752731f | |
|
|
949b53f79d | |
|
|
231356bb82 | |
|
|
14d099806f | |
|
|
39289f61f4 | |
|
|
a616a39f27 | |
|
|
2ddc08c22b | |
|
|
adc53e6a7b | |
|
|
2bc496562e | |
|
|
79c9336c33 | |
|
|
527df2be1c | |
|
|
b54daede13 | |
|
|
0889ed2e9b | |
|
|
a615d54f3e | |
|
|
060aa5bb6a | |
|
|
8b0d17d5cc | |
|
|
8d4c5244a4 | |
|
|
f5f8183924 | |
|
|
a710d30b67 | |
|
|
c7e24038dd | |
|
|
184140b967 | |
|
|
5edc752686 |
|
|
@ -1,10 +1,10 @@
|
|||
apply plugin: 'kotlin-android'
|
||||
|
||||
rootProject.ext {
|
||||
compileSdk = 30
|
||||
compileSdk = 29
|
||||
|
||||
minSdk = 21
|
||||
targetSdk = 30
|
||||
targetSdk = 29
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ package ru.touchin.templates.logansquare;
|
|||
import androidx.annotation.Nullable;
|
||||
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.log.LcGroup;
|
||||
import ru.touchin.templates.ApiModel;
|
||||
|
||||
/**
|
||||
|
|
@ -38,7 +39,9 @@ public abstract class LoganSquareJsonModel extends ApiModel {
|
|||
*/
|
||||
protected static void validateNotNull(@Nullable final Object object) throws ValidationException {
|
||||
if (object == null) {
|
||||
throw new ValidationException("Not nullable object is null or missed at " + Lc.getCodePoint(null, 1));
|
||||
ValidationException exception = new ValidationException("Not nullable object is null or missed at " + Lc.getCodePoint(null, 1));
|
||||
LcGroup.API_VALIDATION.e(exception, "Invalid item");
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,13 @@
|
|||
package ru.touchin.extensions
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import ru.touchin.roboswag.core.log.Lc
|
||||
import android.provider.Browser
|
||||
|
||||
fun Context.safeStartActivity(intent: Intent, options: Bundle? = null) =
|
||||
try {
|
||||
startActivity(intent, options)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Lc.e(e, "Couldn't find activity with this parameters")
|
||||
}
|
||||
fun Context.safeStartActivity(intent: Intent, options: Bundle? = null, resolveFlags: Int = 0): Boolean =
|
||||
packageManager.resolveActivity(intent, resolveFlags)?.let { startActivity(intent, options) } != null
|
||||
|
||||
fun Context.openBrowser(url: String) = Intent(Intent.ACTION_VIEW)
|
||||
.setData(Uri.parse(url))
|
||||
|
|
@ -34,3 +28,4 @@ fun Context.openBrowserWithHeaders(url: String, headersMap: Map<String, String>)
|
|||
fun Context.callToPhoneNumber(phoneNumber: String) = Intent(Intent.ACTION_VIEW)
|
||||
.setData(Uri.parse("tel:$phoneNumber"))
|
||||
.let { intent -> safeStartActivity(intent) }
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import androidx.annotation.CallSuper
|
|||
*/
|
||||
open class RxViewModel(
|
||||
private val destroyable: BaseDestroyable = BaseDestroyable(),
|
||||
private val liveDataDispatcher: BaseLiveDataDispatcher = BaseLiveDataDispatcher(destroyable)
|
||||
private val liveDataDispatcher: LiveDataDispatcher = BaseLiveDataDispatcher(destroyable)
|
||||
) : ViewModel(), Destroyable by destroyable, LiveDataDispatcher by liveDataDispatcher {
|
||||
|
||||
@CallSuper
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
package ru.touchin.lifecycle.viewmodel
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import io.reactivex.Completable
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.Maybe
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.disposables.Disposable
|
||||
import ru.touchin.lifecycle.event.ContentEvent
|
||||
import ru.touchin.lifecycle.event.Event
|
||||
|
||||
class TestableLiveDataDispatcher(
|
||||
private val destroyable: BaseDestroyable = BaseDestroyable()
|
||||
) : LiveDataDispatcher, Destroyable by destroyable {
|
||||
|
||||
override fun <T> Flowable<out T>.dispatchTo(liveData: MutableLiveData<ContentEvent<T>>): Disposable {
|
||||
return untilDestroy(
|
||||
{ data -> liveData.value = ContentEvent.Success(data) },
|
||||
{ throwable -> liveData.value = ContentEvent.Error(throwable, liveData.value?.data) },
|
||||
{ liveData.value = ContentEvent.Complete(liveData.value?.data) })
|
||||
}
|
||||
|
||||
override fun <T> Observable<out T>.dispatchTo(liveData: MutableLiveData<ContentEvent<T>>): Disposable {
|
||||
return untilDestroy(
|
||||
{ data -> liveData.value = ContentEvent.Success(data) },
|
||||
{ throwable -> liveData.value = ContentEvent.Error(throwable, liveData.value?.data) },
|
||||
{ liveData.value = ContentEvent.Complete(liveData.value?.data) })
|
||||
}
|
||||
|
||||
override fun <T> Single<out T>.dispatchTo(liveData: MutableLiveData<ContentEvent<T>>): Disposable {
|
||||
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 {
|
||||
return untilDestroy(
|
||||
{ data -> liveData.value = ContentEvent.Success(data) },
|
||||
{ throwable -> liveData.value = ContentEvent.Error(throwable, liveData.value?.data) },
|
||||
{ liveData.value = ContentEvent.Complete(liveData.value?.data) })
|
||||
}
|
||||
|
||||
override fun Completable.dispatchTo(liveData: MutableLiveData<Event>): Disposable {
|
||||
return untilDestroy(
|
||||
{ liveData.value = Event.Complete },
|
||||
{ throwable -> liveData.value = Event.Error(throwable) })
|
||||
}
|
||||
}
|
||||
|
|
@ -10,4 +10,13 @@ sealed class ContentEvent<out T>(open val data: T?) {
|
|||
|
||||
data class Complete<out T>(override val data: T? = null) : ContentEvent<T>(data)
|
||||
|
||||
fun <P> transform(transformation: (T?) -> P): ContentEvent<P> {
|
||||
return when(this) {
|
||||
is Loading -> Loading(transformation(data))
|
||||
is Success -> Success(transformation(data))
|
||||
is Complete -> Complete(transformation(data))
|
||||
is Error -> Error(throwable, transformation(data))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ dependencies {
|
|||
|
||||
implementation "com.google.android.gms:play-services-location"
|
||||
|
||||
implementation "com.huawei.hms:location:$versions.hmsLocation"
|
||||
|
||||
constraints {
|
||||
implementation("com.google.android.gms:play-services-location") {
|
||||
version {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package ru.touchin.livedata.location
|
||||
|
||||
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||
import android.Manifest.permission.ACCESS_FINE_LOCATION
|
||||
import android.content.Context
|
||||
import android.location.Location
|
||||
import android.os.Looper
|
||||
import androidx.annotation.RequiresPermission
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import com.huawei.hms.location.FusedLocationProviderClient
|
||||
import com.huawei.hms.location.LocationAvailability
|
||||
import com.huawei.hms.location.LocationCallback
|
||||
import com.huawei.hms.location.LocationRequest
|
||||
import com.huawei.hms.location.LocationResult
|
||||
import com.huawei.hms.location.LocationServices
|
||||
|
||||
class HuaweiLocationLiveData(
|
||||
context: Context,
|
||||
private val request: LocationRequest
|
||||
) : LiveData<Location>() {
|
||||
|
||||
private val fusedLocationClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
|
||||
private val locationCallback = object : LocationCallback() {
|
||||
override fun onLocationResult(result: LocationResult) {
|
||||
postValue(result.lastLocation)
|
||||
}
|
||||
|
||||
override fun onLocationAvailability(availability: LocationAvailability) {
|
||||
if (!availability.isLocationAvailable) postValue(null)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresPermission(anyOf = [ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION])
|
||||
override fun observe(owner: LifecycleOwner, observer: Observer<in Location>) {
|
||||
super.observe(owner, observer)
|
||||
}
|
||||
|
||||
@RequiresPermission(anyOf = [ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION])
|
||||
override fun onActive() {
|
||||
startListening()
|
||||
}
|
||||
|
||||
override fun onInactive() {
|
||||
stopListening()
|
||||
}
|
||||
|
||||
private fun stopListening() {
|
||||
fusedLocationClient.removeLocationUpdates(locationCallback)
|
||||
}
|
||||
|
||||
@RequiresPermission(anyOf = [ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION])
|
||||
private fun startListening() {
|
||||
fusedLocationClient.requestLocationUpdates(
|
||||
request,
|
||||
locationCallback,
|
||||
Looper.getMainLooper()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,8 +29,6 @@ import android.util.Log;
|
|||
*/
|
||||
public class ConsoleLogProcessor extends LogProcessor {
|
||||
|
||||
private static final int MAX_LOG_LENGTH = 4000;
|
||||
|
||||
public ConsoleLogProcessor(@NonNull final LcLevel lclevel) {
|
||||
super(lclevel);
|
||||
}
|
||||
|
|
@ -46,18 +44,8 @@ public class ConsoleLogProcessor extends LogProcessor {
|
|||
public void processLogMessage(@NonNull final LcGroup group, @NonNull final LcLevel level,
|
||||
@NonNull final String tag, @NonNull final String message, @Nullable final Throwable throwable) {
|
||||
final String messageToLog = normalize(message + (throwable != null ? '\n' + Log.getStackTraceString(throwable) : ""));
|
||||
final int length = messageToLog.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int newline = messageToLog.indexOf('\n', i);
|
||||
newline = newline != -1 ? newline : length;
|
||||
do {
|
||||
final int end = Math.min(newline, i + MAX_LOG_LENGTH);
|
||||
Log.println(level.getPriority(), tag, messageToLog.substring(i, end));
|
||||
i = end;
|
||||
}
|
||||
while (i < newline);
|
||||
}
|
||||
|
||||
Log.println(level.getPriority(), tag, messageToLog);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ dependencies {
|
|||
|
||||
implementation("androidx.lifecycle:lifecycle-common-java8") {
|
||||
version {
|
||||
require '2.2.0'
|
||||
require '2.6.2'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics;
|
|||
|
||||
import net.danlew.android.joda.JodaTimeAndroid;
|
||||
|
||||
import ru.touchin.hardware.ProcessKt;
|
||||
import ru.touchin.roboswag.core.log.ConsoleLogProcessor;
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.log.LcGroup;
|
||||
|
|
@ -46,7 +47,7 @@ public abstract class TouchinApp extends Application {
|
|||
enableStrictMode();
|
||||
Lc.initialize(new ConsoleLogProcessor(LcLevel.VERBOSE), true);
|
||||
LcGroup.UI_LIFECYCLE.disable();
|
||||
} else {
|
||||
} else if (ProcessKt.isOnMainProcess(this)) {
|
||||
try {
|
||||
final FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
|
||||
crashlytics.setCrashlyticsCollectionEnabled(true);
|
||||
|
|
|
|||
|
|
@ -7,36 +7,19 @@ dependencies {
|
|||
implementation project(":logging")
|
||||
implementation project(":navigation-base")
|
||||
|
||||
implementation 'androidx.multidex:multidex'
|
||||
|
||||
implementation 'net.danlew:android.joda'
|
||||
|
||||
implementation "androidx.appcompat:appcompat"
|
||||
|
||||
implementation("com.crashlytics.sdk.android:crashlytics")
|
||||
implementation "androidx.lifecycle:lifecycle-common-java8"
|
||||
|
||||
constraints {
|
||||
implementation("androidx.multidex:multidex") {
|
||||
version {
|
||||
require '2.0.1'
|
||||
}
|
||||
}
|
||||
|
||||
implementation("net.danlew:android.joda") {
|
||||
version {
|
||||
require '2.10.2'
|
||||
}
|
||||
}
|
||||
|
||||
implementation("androidx.appcompat:appcompat") {
|
||||
version {
|
||||
require '1.0.2'
|
||||
}
|
||||
}
|
||||
|
||||
implementation("com.crashlytics.sdk.android:crashlytics") {
|
||||
implementation("androidx.lifecycle:lifecycle-common-java8") {
|
||||
version {
|
||||
require '2.10.0'
|
||||
require '2.6.2'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ open class ViewControllerFragment<TActivity : FragmentActivity, TState : Parcela
|
|||
|
||||
lateinit var state: TState private set
|
||||
|
||||
lateinit var viewControllerClass: Class<ViewController<TActivity, TState>> private set
|
||||
var viewControllerClass: Class<ViewController<TActivity, TState>>? = null
|
||||
private set
|
||||
|
||||
private var viewController: ViewController<out TActivity, out TState>? = null
|
||||
|
||||
|
|
@ -241,14 +242,14 @@ open class ViewControllerFragment<TActivity : FragmentActivity, TState : Parcela
|
|||
creationContext: ViewController.CreationContext,
|
||||
savedInstanceState: Bundle?
|
||||
): ViewController<out TActivity, out TState> {
|
||||
if (viewControllerClass.constructors.size != 1) {
|
||||
if (viewControllerClass?.constructors?.size != 1) {
|
||||
throw IllegalStateException("There should be single constructor for $viewControllerClass")
|
||||
}
|
||||
val constructor = viewControllerClass.constructors[0]
|
||||
return when (constructor.parameterTypes.size) {
|
||||
val constructor = viewControllerClass?.constructors?.get(0)
|
||||
return when (constructor?.parameterTypes?.size) {
|
||||
1 -> constructor.newInstance(creationContext)
|
||||
2 -> constructor.newInstance(creationContext, savedInstanceState)
|
||||
else -> throw IllegalArgumentException("Wrong constructor parameters count: ${constructor.parameterTypes.size}")
|
||||
else -> throw IllegalArgumentException("Wrong constructor parameters count: ${constructor?.parameterTypes?.size}")
|
||||
} as ViewController<out TActivity, out TState>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,8 @@ open class ViewController<TActivity : FragmentActivity, TState : Parcelable>(
|
|||
lifecycle.addObserver(LifecycleLoggingObserver(this))
|
||||
}
|
||||
|
||||
override fun getLifecycle(): Lifecycle = fragment.viewLifecycleOwner.lifecycle
|
||||
override val lifecycle: Lifecycle
|
||||
get() = fragment.viewLifecycleOwner.lifecycle
|
||||
|
||||
/**
|
||||
* Look for a child view with the given id. If this view has the given id, return this view.
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ open class ViewControllerNavigation<TActivity : FragmentActivity>(
|
|||
*/
|
||||
fun <TState : Parcelable> setViewControllerAsTop(
|
||||
viewControllerClass: Class<out ViewController<out TActivity, TState>>,
|
||||
state: TState,
|
||||
state: TState?,
|
||||
addToStack: Boolean = true,
|
||||
tag: String? = null,
|
||||
transactionSetup: ((FragmentTransaction) -> Unit)? = null
|
||||
|
|
@ -149,7 +149,7 @@ open class ViewControllerNavigation<TActivity : FragmentActivity>(
|
|||
*/
|
||||
fun <TState : Parcelable> setInitialViewController(
|
||||
viewControllerClass: Class<out ViewController<out TActivity, TState>>,
|
||||
state: TState,
|
||||
state: TState?,
|
||||
tag: String? = null,
|
||||
transactionSetup: ((FragmentTransaction) -> Unit)? = null
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
package ru.touchin.roboswag.navigation_viewcontroller.viewcontrollers
|
||||
|
||||
import android.os.Parcelable
|
||||
import android.view.View
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class ViewControllerViewBindingDelegate<T : ViewBinding, TActivity : FragmentActivity, TState : Parcelable>(
|
||||
val viewController: ViewController<TActivity, TState>,
|
||||
val viewBindingFactory: (View) -> T
|
||||
) : ReadOnlyProperty<ViewController<TActivity, TState>, T> {
|
||||
private var binding: T? = null
|
||||
|
||||
init {
|
||||
viewController.lifecycle.addObserver(object : DefaultLifecycleObserver {
|
||||
override fun onCreate(owner: LifecycleOwner) {
|
||||
viewController.fragment.viewLifecycleOwnerLiveData.observe(viewController) { viewLifecycleOwner ->
|
||||
viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
binding = null
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun getValue(thisRef: ViewController<TActivity, TState>, property: KProperty<*>): T {
|
||||
val binding = binding
|
||||
if (binding != null) {
|
||||
return binding
|
||||
}
|
||||
|
||||
return viewBindingFactory(viewController.view).also { this.binding = it }
|
||||
}
|
||||
}
|
||||
|
||||
fun <T : ViewBinding, TActivity : FragmentActivity, TState : Parcelable>
|
||||
ViewController<TActivity, TState>.viewBinding(viewBindingFactory: (View) -> T) =
|
||||
ViewControllerViewBindingDelegate(this, viewBindingFactory)
|
||||
|
|
@ -10,7 +10,7 @@ dependencies {
|
|||
constraints {
|
||||
implementation("androidx.recyclerview:recyclerview") {
|
||||
version {
|
||||
require '1.0.0'
|
||||
require '1.1.0'
|
||||
}
|
||||
}
|
||||
implementation("androidx.core:core-ktx") {
|
||||
|
|
|
|||
|
|
@ -69,7 +69,28 @@ open class DelegationListAdapter<TItem>(config: AsyncDifferConfig<TItem>) : Recy
|
|||
*
|
||||
* @param list The new list to be displayed.
|
||||
*/
|
||||
fun submitList(list: List<TItem>) = differ.submitList(list)
|
||||
fun submitList(list: List<TItem>?) = differ.submitList(list)
|
||||
|
||||
/**
|
||||
* Submits a new list to be diffed, and displayed.
|
||||
*
|
||||
* The commit callback can be used to know when the List is committed, but note that it
|
||||
* may not be executed. If List B is submitted immediately after List A, and is
|
||||
* committed directly, the callback associated with List A will not be run.
|
||||
*
|
||||
* @param newList The new List.
|
||||
* @param commitCallback Optional runnable that is executed when the List is committed, if
|
||||
* it is committed.
|
||||
*/
|
||||
fun submitList(list: List<TItem>?, commitCallback: (() -> Unit)?) = differ.submitList(list, commitCallback)
|
||||
|
||||
/**
|
||||
* Same as [submitList] with fast simple remove all items of a previous list
|
||||
*/
|
||||
fun replaceList(list: List<TItem>) {
|
||||
submitList(null)
|
||||
submitList(list)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current List - any diffing to present this list has already been computed and
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ public final class CalendarUtils {
|
|||
final int firstDayInNextMonth = nextMonthFirstDay.getDayOfWeek() - 1;
|
||||
|
||||
if (daysLeftInWeek != 0) {
|
||||
calendarItems.add(new CalendarEmptyItem(shift, shift + daysLeftInWeek));
|
||||
calendarItems.add(new CalendarEmptyItem(shift, shift + daysLeftInWeek - 1));
|
||||
shift += daysLeftInWeek;
|
||||
}
|
||||
calendarItems.add(new CalendarHeaderItem(nextMonthFirstDay.getYear(), nextMonthFirstDay.getMonthOfYear() - 1, shift, shift));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package ru.touchin.hardware
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import android.os.Process
|
||||
|
||||
fun Context.isOnMainProcess(): Boolean {
|
||||
val applicationContext = this.applicationContext
|
||||
val runningAppProcesses = (applicationContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager)
|
||||
.runningAppProcesses
|
||||
if (runningAppProcesses != null && runningAppProcesses.size != 0) {
|
||||
for (runningProcessInfo in runningAppProcesses) {
|
||||
val isCurrentProcess = runningProcessInfo.pid == Process.myPid()
|
||||
val isMainProcessName = this.packageName == runningProcessInfo.processName
|
||||
if (isCurrentProcess && isMainProcessName) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -16,11 +16,11 @@ import ru.touchin.extensions.indexesOf
|
|||
*/
|
||||
fun String.getSpannedTextWithUrls(
|
||||
removeUnderline: Boolean = true,
|
||||
flags: Int = HtmlCompat.FROM_HTML_MODE_COMPACT
|
||||
htmlFormatFlags: Int = HtmlCompat.FROM_HTML_MODE_COMPACT
|
||||
): Spanned {
|
||||
// HtmlCompat.fromHtml doesn't respect line breaks
|
||||
val text = this.replace(lineBreakRegex, "<br/>")
|
||||
val spannableText = SpannableString(HtmlCompat.fromHtml(text, flags))
|
||||
val spannableText = SpannableString(HtmlCompat.fromHtml(text, htmlFormatFlags))
|
||||
|
||||
// Linkify removes all previous URLSpan's, we need to save all created spans for reapply after Linkify
|
||||
val spans = spannableText.getUrlSpans()
|
||||
|
|
@ -29,7 +29,7 @@ fun String.getSpannedTextWithUrls(
|
|||
spannableText.setSpan(it.span, it.start, it.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
|
||||
if (!removeUnderline) {
|
||||
if (removeUnderline) {
|
||||
spannableText.getUrlSpans()
|
||||
.forEach { urlSpan ->
|
||||
spannableText.removeSpan(urlSpan.span)
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ class LoadingContentView @JvmOverloads constructor(
|
|||
showChild(R.id.error_with_repeat)
|
||||
}
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,14 @@ public class Switcher extends FrameLayout {
|
|||
@Nullable
|
||||
private Animation outAnimation;
|
||||
|
||||
public void setOutAnimation(@Nullable Animation outAnimation) {
|
||||
this.outAnimation = outAnimation;
|
||||
}
|
||||
|
||||
public void setInAnimation(@Nullable Animation inAnimation) {
|
||||
this.inAnimation = inAnimation;
|
||||
}
|
||||
|
||||
public Switcher(@NonNull final Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue