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'
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
rootProject.ext {
|
rootProject.ext {
|
||||||
compileSdk = 30
|
compileSdk = 29
|
||||||
|
|
||||||
minSdk = 21
|
minSdk = 21
|
||||||
targetSdk = 30
|
targetSdk = 29
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ package ru.touchin.templates.logansquare;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import ru.touchin.roboswag.core.log.Lc;
|
import ru.touchin.roboswag.core.log.Lc;
|
||||||
|
import ru.touchin.roboswag.core.log.LcGroup;
|
||||||
import ru.touchin.templates.ApiModel;
|
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 {
|
protected static void validateNotNull(@Nullable final Object object) throws ValidationException {
|
||||||
if (object == null) {
|
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
|
package ru.touchin.extensions
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import ru.touchin.roboswag.core.log.Lc
|
|
||||||
import android.provider.Browser
|
import android.provider.Browser
|
||||||
|
|
||||||
fun Context.safeStartActivity(intent: Intent, options: Bundle? = null) =
|
fun Context.safeStartActivity(intent: Intent, options: Bundle? = null, resolveFlags: Int = 0): Boolean =
|
||||||
try {
|
packageManager.resolveActivity(intent, resolveFlags)?.let { startActivity(intent, options) } != null
|
||||||
startActivity(intent, options)
|
|
||||||
} catch (e: ActivityNotFoundException) {
|
|
||||||
Lc.e(e, "Couldn't find activity with this parameters")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Context.openBrowser(url: String) = Intent(Intent.ACTION_VIEW)
|
fun Context.openBrowser(url: String) = Intent(Intent.ACTION_VIEW)
|
||||||
.setData(Uri.parse(url))
|
.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)
|
fun Context.callToPhoneNumber(phoneNumber: String) = Intent(Intent.ACTION_VIEW)
|
||||||
.setData(Uri.parse("tel:$phoneNumber"))
|
.setData(Uri.parse("tel:$phoneNumber"))
|
||||||
.let { intent -> safeStartActivity(intent) }
|
.let { intent -> safeStartActivity(intent) }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import androidx.annotation.CallSuper
|
||||||
*/
|
*/
|
||||||
open class RxViewModel(
|
open class RxViewModel(
|
||||||
private val destroyable: BaseDestroyable = BaseDestroyable(),
|
private val destroyable: BaseDestroyable = BaseDestroyable(),
|
||||||
private val liveDataDispatcher: BaseLiveDataDispatcher = BaseLiveDataDispatcher(destroyable)
|
private val liveDataDispatcher: LiveDataDispatcher = BaseLiveDataDispatcher(destroyable)
|
||||||
) : ViewModel(), Destroyable by destroyable, LiveDataDispatcher by liveDataDispatcher {
|
) : ViewModel(), Destroyable by destroyable, LiveDataDispatcher by liveDataDispatcher {
|
||||||
|
|
||||||
@CallSuper
|
@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)
|
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.google.android.gms:play-services-location"
|
||||||
|
|
||||||
|
implementation "com.huawei.hms:location:$versions.hmsLocation"
|
||||||
|
|
||||||
constraints {
|
constraints {
|
||||||
implementation("com.google.android.gms:play-services-location") {
|
implementation("com.google.android.gms:play-services-location") {
|
||||||
version {
|
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 {
|
public class ConsoleLogProcessor extends LogProcessor {
|
||||||
|
|
||||||
private static final int MAX_LOG_LENGTH = 4000;
|
|
||||||
|
|
||||||
public ConsoleLogProcessor(@NonNull final LcLevel lclevel) {
|
public ConsoleLogProcessor(@NonNull final LcLevel lclevel) {
|
||||||
super(lclevel);
|
super(lclevel);
|
||||||
}
|
}
|
||||||
|
|
@ -46,18 +44,8 @@ public class ConsoleLogProcessor extends LogProcessor {
|
||||||
public void processLogMessage(@NonNull final LcGroup group, @NonNull final LcLevel level,
|
public void processLogMessage(@NonNull final LcGroup group, @NonNull final LcLevel level,
|
||||||
@NonNull final String tag, @NonNull final String message, @Nullable final Throwable throwable) {
|
@NonNull final String tag, @NonNull final String message, @Nullable final Throwable throwable) {
|
||||||
final String messageToLog = normalize(message + (throwable != null ? '\n' + Log.getStackTraceString(throwable) : ""));
|
final String messageToLog = normalize(message + (throwable != null ? '\n' + Log.getStackTraceString(throwable) : ""));
|
||||||
final int length = messageToLog.length();
|
|
||||||
for (int i = 0; i < length; i++) {
|
Log.println(level.getPriority(), tag, messageToLog);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ dependencies {
|
||||||
|
|
||||||
implementation("androidx.lifecycle:lifecycle-common-java8") {
|
implementation("androidx.lifecycle:lifecycle-common-java8") {
|
||||||
version {
|
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 net.danlew.android.joda.JodaTimeAndroid;
|
||||||
|
|
||||||
|
import ru.touchin.hardware.ProcessKt;
|
||||||
import ru.touchin.roboswag.core.log.ConsoleLogProcessor;
|
import ru.touchin.roboswag.core.log.ConsoleLogProcessor;
|
||||||
import ru.touchin.roboswag.core.log.Lc;
|
import ru.touchin.roboswag.core.log.Lc;
|
||||||
import ru.touchin.roboswag.core.log.LcGroup;
|
import ru.touchin.roboswag.core.log.LcGroup;
|
||||||
|
|
@ -46,7 +47,7 @@ public abstract class TouchinApp extends Application {
|
||||||
enableStrictMode();
|
enableStrictMode();
|
||||||
Lc.initialize(new ConsoleLogProcessor(LcLevel.VERBOSE), true);
|
Lc.initialize(new ConsoleLogProcessor(LcLevel.VERBOSE), true);
|
||||||
LcGroup.UI_LIFECYCLE.disable();
|
LcGroup.UI_LIFECYCLE.disable();
|
||||||
} else {
|
} else if (ProcessKt.isOnMainProcess(this)) {
|
||||||
try {
|
try {
|
||||||
final FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
|
final FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
|
||||||
crashlytics.setCrashlyticsCollectionEnabled(true);
|
crashlytics.setCrashlyticsCollectionEnabled(true);
|
||||||
|
|
|
||||||
|
|
@ -7,36 +7,19 @@ dependencies {
|
||||||
implementation project(":logging")
|
implementation project(":logging")
|
||||||
implementation project(":navigation-base")
|
implementation project(":navigation-base")
|
||||||
|
|
||||||
implementation 'androidx.multidex:multidex'
|
|
||||||
|
|
||||||
implementation 'net.danlew:android.joda'
|
|
||||||
|
|
||||||
implementation "androidx.appcompat:appcompat"
|
implementation "androidx.appcompat:appcompat"
|
||||||
|
implementation "androidx.lifecycle:lifecycle-common-java8"
|
||||||
implementation("com.crashlytics.sdk.android:crashlytics")
|
|
||||||
|
|
||||||
constraints {
|
constraints {
|
||||||
implementation("androidx.multidex:multidex") {
|
|
||||||
version {
|
|
||||||
require '2.0.1'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
implementation("net.danlew:android.joda") {
|
|
||||||
version {
|
|
||||||
require '2.10.2'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
implementation("androidx.appcompat:appcompat") {
|
implementation("androidx.appcompat:appcompat") {
|
||||||
version {
|
version {
|
||||||
require '1.0.2'
|
require '1.0.2'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation("com.crashlytics.sdk.android:crashlytics") {
|
implementation("androidx.lifecycle:lifecycle-common-java8") {
|
||||||
version {
|
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 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
|
private var viewController: ViewController<out TActivity, out TState>? = null
|
||||||
|
|
||||||
|
|
@ -241,14 +242,14 @@ open class ViewControllerFragment<TActivity : FragmentActivity, TState : Parcela
|
||||||
creationContext: ViewController.CreationContext,
|
creationContext: ViewController.CreationContext,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): ViewController<out TActivity, out TState> {
|
): ViewController<out TActivity, out TState> {
|
||||||
if (viewControllerClass.constructors.size != 1) {
|
if (viewControllerClass?.constructors?.size != 1) {
|
||||||
throw IllegalStateException("There should be single constructor for $viewControllerClass")
|
throw IllegalStateException("There should be single constructor for $viewControllerClass")
|
||||||
}
|
}
|
||||||
val constructor = viewControllerClass.constructors[0]
|
val constructor = viewControllerClass?.constructors?.get(0)
|
||||||
return when (constructor.parameterTypes.size) {
|
return when (constructor?.parameterTypes?.size) {
|
||||||
1 -> constructor.newInstance(creationContext)
|
1 -> constructor.newInstance(creationContext)
|
||||||
2 -> constructor.newInstance(creationContext, savedInstanceState)
|
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>
|
} as ViewController<out TActivity, out TState>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,8 @@ open class ViewController<TActivity : FragmentActivity, TState : Parcelable>(
|
||||||
lifecycle.addObserver(LifecycleLoggingObserver(this))
|
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.
|
* 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(
|
fun <TState : Parcelable> setViewControllerAsTop(
|
||||||
viewControllerClass: Class<out ViewController<out TActivity, TState>>,
|
viewControllerClass: Class<out ViewController<out TActivity, TState>>,
|
||||||
state: TState,
|
state: TState?,
|
||||||
addToStack: Boolean = true,
|
addToStack: Boolean = true,
|
||||||
tag: String? = null,
|
tag: String? = null,
|
||||||
transactionSetup: ((FragmentTransaction) -> Unit)? = null
|
transactionSetup: ((FragmentTransaction) -> Unit)? = null
|
||||||
|
|
@ -149,7 +149,7 @@ open class ViewControllerNavigation<TActivity : FragmentActivity>(
|
||||||
*/
|
*/
|
||||||
fun <TState : Parcelable> setInitialViewController(
|
fun <TState : Parcelable> setInitialViewController(
|
||||||
viewControllerClass: Class<out ViewController<out TActivity, TState>>,
|
viewControllerClass: Class<out ViewController<out TActivity, TState>>,
|
||||||
state: TState,
|
state: TState?,
|
||||||
tag: String? = null,
|
tag: String? = null,
|
||||||
transactionSetup: ((FragmentTransaction) -> Unit)? = 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 {
|
constraints {
|
||||||
implementation("androidx.recyclerview:recyclerview") {
|
implementation("androidx.recyclerview:recyclerview") {
|
||||||
version {
|
version {
|
||||||
require '1.0.0'
|
require '1.1.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
implementation("androidx.core:core-ktx") {
|
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.
|
* @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
|
* 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;
|
final int firstDayInNextMonth = nextMonthFirstDay.getDayOfWeek() - 1;
|
||||||
|
|
||||||
if (daysLeftInWeek != 0) {
|
if (daysLeftInWeek != 0) {
|
||||||
calendarItems.add(new CalendarEmptyItem(shift, shift + daysLeftInWeek));
|
calendarItems.add(new CalendarEmptyItem(shift, shift + daysLeftInWeek - 1));
|
||||||
shift += daysLeftInWeek;
|
shift += daysLeftInWeek;
|
||||||
}
|
}
|
||||||
calendarItems.add(new CalendarHeaderItem(nextMonthFirstDay.getYear(), nextMonthFirstDay.getMonthOfYear() - 1, shift, shift));
|
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(
|
fun String.getSpannedTextWithUrls(
|
||||||
removeUnderline: Boolean = true,
|
removeUnderline: Boolean = true,
|
||||||
flags: Int = HtmlCompat.FROM_HTML_MODE_COMPACT
|
htmlFormatFlags: Int = HtmlCompat.FROM_HTML_MODE_COMPACT
|
||||||
): Spanned {
|
): Spanned {
|
||||||
// HtmlCompat.fromHtml doesn't respect line breaks
|
// HtmlCompat.fromHtml doesn't respect line breaks
|
||||||
val text = this.replace(lineBreakRegex, "<br/>")
|
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
|
// Linkify removes all previous URLSpan's, we need to save all created spans for reapply after Linkify
|
||||||
val spans = spannableText.getUrlSpans()
|
val spans = spannableText.getUrlSpans()
|
||||||
|
|
@ -29,7 +29,7 @@ fun String.getSpannedTextWithUrls(
|
||||||
spannableText.setSpan(it.span, it.start, it.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
spannableText.setSpan(it.span, it.start, it.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!removeUnderline) {
|
if (removeUnderline) {
|
||||||
spannableText.getUrlSpans()
|
spannableText.getUrlSpans()
|
||||||
.forEach { urlSpan ->
|
.forEach { urlSpan ->
|
||||||
spannableText.removeSpan(urlSpan.span)
|
spannableText.removeSpan(urlSpan.span)
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ class LoadingContentView @JvmOverloads constructor(
|
||||||
showChild(R.id.error_with_repeat)
|
showChild(R.id.error_with_repeat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,14 @@ public class Switcher extends FrameLayout {
|
||||||
@Nullable
|
@Nullable
|
||||||
private Animation outAnimation;
|
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) {
|
public Switcher(@NonNull final Context context) {
|
||||||
this(context, null);
|
this(context, null);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue