Compare commits
9 Commits
master
...
project/bo
| Author | SHA1 | Date |
|---|---|---|
|
|
88af4f9791 | |
|
|
20166724c1 | |
|
|
141ed18bec | |
|
|
71c5587bad | |
|
|
87a473f73f | |
|
|
12de015db4 | |
|
|
48b8be39e6 | |
|
|
cf6200dc2d | |
|
|
be9c0a5e69 |
38
build.gradle
38
build.gradle
|
|
@ -1,7 +1,9 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'me.tatarka.retrolambda'
|
||||
|
||||
android {
|
||||
compileSdkVersion compileSdk
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion "25.0.3"
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
|
|
@ -15,40 +17,36 @@ android {
|
|||
|
||||
repositories {
|
||||
maven { url 'https://maven.fabric.io/public' }
|
||||
maven { url "http://dl.bintray.com/touchin/touchin-tools" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(path: ':libraries:components')
|
||||
compile project(path: ':libraries:components')
|
||||
|
||||
api 'net.danlew:android.joda:2.9.9'
|
||||
api 'com.android.support:multidex:1.0.2'
|
||||
api "io.reactivex:rxandroid:$rxAndroidVersion"
|
||||
api "io.reactivex:rxjava:$rxJavaVersion"
|
||||
compile 'net.danlew:android.joda:2.9.9'
|
||||
compile 'com.android.support:multidex:1.0.1'
|
||||
compile 'io.reactivex:rxandroid:1.2.1'
|
||||
|
||||
compileOnly "com.android.support:appcompat-v7:$supportLibraryVersion"
|
||||
compileOnly "com.android.support:recyclerview-v7:$supportLibraryVersion"
|
||||
provided 'com.android.support:appcompat-v7:25.3.1'
|
||||
provided 'com.android.support:recyclerview-v7:25.3.1'
|
||||
|
||||
compileOnly 'com.squareup.retrofit2:retrofit:2.3.0'
|
||||
compileOnly('com.google.http-client:google-http-client-jackson2:1.23.0') {
|
||||
provided 'com.squareup.retrofit2:retrofit:2.3.0'
|
||||
provided('com.google.http-client:google-http-client-jackson2:1.22.0') {
|
||||
exclude(group: 'org.apache.httpcomponents', module: 'httpclient')
|
||||
}
|
||||
|
||||
compileOnly 'com.facebook.fresco:fresco:1.5.0'
|
||||
compileOnly 'ru.touchin:logansquare:1.4.1'
|
||||
provided 'com.facebook.fresco:fresco:1.4.0'
|
||||
provided 'com.bluelinelabs:logansquare:1.3.7'
|
||||
|
||||
compileOnly 'com.scottyab:aes-crypto:0.0.4'
|
||||
provided 'com.scottyab:aes-crypto:0.0.4'
|
||||
|
||||
// don't use latest(1.0 and above) because they don't support Socket.IO server 1.x version
|
||||
//noinspection NewerVersionAvailable
|
||||
compileOnly('io.socket:socket.io-client:0.9.0') {
|
||||
provided('io.socket:socket.io-client:1.0.0') {
|
||||
exclude group: 'org.json', module: 'json'
|
||||
}
|
||||
|
||||
compileOnly('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
|
||||
transitive = true
|
||||
provided('com.crashlytics.sdk.android:crashlytics:2.6.7@aar') {
|
||||
transitive = true;
|
||||
}
|
||||
|
||||
compileOnly 'com.facebook.stetho:stetho:1.5.0'
|
||||
provided 'com.facebook.stetho:stetho:1.5.0'
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
package com.bluelinelabs.logansquare;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Utility class for the {@link ru.touchin.templates.logansquare.LoganSquareJsonFactory}. This resides in LoganSquare's
|
||||
* main package in order to take advantage of the package-visible ConcreteParameterizedType class, which is essential
|
||||
* to the support of generic classes in the Retrofit converter.
|
||||
*/
|
||||
public final class ConverterUtils {
|
||||
|
||||
@NonNull
|
||||
public static ParameterizedType parameterizedTypeOf(@NonNull final Type type) {
|
||||
return new ParameterizedType.ConcreteParameterizedType(type);
|
||||
}
|
||||
|
||||
private ConverterUtils() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -50,9 +50,9 @@ public abstract class ApiModel implements Serializable {
|
|||
* @param collectionValidationRule Rule explaining what to do if invalid items found;
|
||||
* @throws ValidationException Exception of validation.
|
||||
*/
|
||||
@SuppressWarnings({"PMD.PreserveStackTrace", "PMD.CyclomaticComplexity"})
|
||||
@SuppressWarnings("PMD.PreserveStackTrace")
|
||||
// PreserveStackTrace: it's ok - we are logging it on Lc.e()
|
||||
public static void validateCollection(@NonNull final Collection collection, @NonNull final CollectionValidationRule collectionValidationRule)
|
||||
protected static void validateCollection(@NonNull final Collection collection, @NonNull final CollectionValidationRule collectionValidationRule)
|
||||
throws ValidationException {
|
||||
boolean haveValidItem = false;
|
||||
int position = 0;
|
||||
|
|
@ -60,10 +60,6 @@ public abstract class ApiModel implements Serializable {
|
|||
while (iterator.hasNext()) {
|
||||
final Object item = iterator.next();
|
||||
if (!(item instanceof ApiModel)) {
|
||||
if (item != null) {
|
||||
// let's just think that all of items are not ApiModels
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +113,7 @@ public abstract class ApiModel implements Serializable {
|
|||
//do nothing
|
||||
}
|
||||
|
||||
public enum CollectionValidationRule {
|
||||
protected enum CollectionValidationRule {
|
||||
EXCEPTION_IF_ANY_INVALID,
|
||||
EXCEPTION_IF_ALL_INVALID,
|
||||
REMOVE_INVALID_ITEMS,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@
|
|||
|
||||
package ru.touchin.templates;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.ConnectivityManager;
|
||||
|
|
@ -27,6 +29,7 @@ import android.net.NetworkInfo;
|
|||
import android.net.wifi.WifiManager;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
|
|
@ -34,8 +37,8 @@ import java.io.UnsupportedEncodingException;
|
|||
import java.util.UUID;
|
||||
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.observables.RxAndroidUtils;
|
||||
import rx.Observable;
|
||||
import rx.Subscriber;
|
||||
|
||||
/**
|
||||
* Utility class that is providing common methods related to android device.
|
||||
|
|
@ -106,8 +109,13 @@ public final class DeviceUtils {
|
|||
*/
|
||||
@NonNull
|
||||
public static NetworkType getNetworkType(@NonNull final Context context) {
|
||||
final ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
final NetworkInfo info = cm.getActiveNetworkInfo();
|
||||
final ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
return getNetworkType(connectivityManager);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static NetworkType getNetworkType(@NonNull final ConnectivityManager connectivityManager) {
|
||||
final NetworkInfo info = connectivityManager.getActiveNetworkInfo();
|
||||
if (info == null || !info.isConnected()) {
|
||||
return NetworkType.NONE;
|
||||
}
|
||||
|
|
@ -154,7 +162,6 @@ public final class DeviceUtils {
|
|||
return getNetworkType(context) != NetworkType.NONE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns observable to observe is device connected to Wi-Fi network.
|
||||
*
|
||||
|
|
@ -163,12 +170,38 @@ public final class DeviceUtils {
|
|||
*/
|
||||
@NonNull
|
||||
public static Observable<Boolean> observeIsConnectedToWifi(@NonNull final Context context) {
|
||||
return RxAndroidUtils.observeBroadcastEvent(context, new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION))
|
||||
.map(intent -> {
|
||||
final NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
|
||||
return networkInfo != null && networkInfo.isConnected();
|
||||
})
|
||||
.distinctUntilChanged();
|
||||
return Observable.switchOnNext(Observable.fromCallable(() -> {
|
||||
final WifiStateReceiver wifiStateReceiver = new WifiStateReceiver();
|
||||
return Observable
|
||||
.<Boolean>create(subscriber -> {
|
||||
subscriber.onNext(DeviceUtils.getNetworkType(context) == DeviceUtils.NetworkType.WI_FI);
|
||||
wifiStateReceiver.setSubscriber(subscriber);
|
||||
context.registerReceiver(wifiStateReceiver, WifiStateReceiver.INTENT_FILTER);
|
||||
})
|
||||
.doOnUnsubscribe(() -> context.unregisterReceiver(wifiStateReceiver))
|
||||
.distinctUntilChanged();
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns observable to observe is device connected to the internet.
|
||||
*
|
||||
* @param context Context to register BroadcastReceiver to check connection to the internet;
|
||||
* @return Observable of internet connection status.
|
||||
*/
|
||||
@NonNull
|
||||
public static Observable<Boolean> observeIsNetworkConnected(@NonNull final Context context) {
|
||||
return Observable.switchOnNext(Observable.fromCallable(() -> {
|
||||
final NetworkStateReceiver networkStateReceiver = new NetworkStateReceiver();
|
||||
return Observable
|
||||
.<Boolean>create(subscriber -> {
|
||||
subscriber.onNext(isNetworkConnected(context));
|
||||
networkStateReceiver.setSubscriber(subscriber);
|
||||
context.registerReceiver(networkStateReceiver, NetworkStateReceiver.INTENT_FILTER);
|
||||
})
|
||||
.doOnUnsubscribe(() -> context.unregisterReceiver(networkStateReceiver))
|
||||
.distinctUntilChanged();
|
||||
}));
|
||||
}
|
||||
|
||||
private DeviceUtils() {
|
||||
|
|
@ -220,4 +253,48 @@ public final class DeviceUtils {
|
|||
|
||||
}
|
||||
|
||||
private static class WifiStateReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final IntentFilter INTENT_FILTER = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
||||
|
||||
@Nullable
|
||||
private Subscriber<? super Boolean> subscriber;
|
||||
|
||||
public void setSubscriber(@Nullable final Subscriber<? super Boolean> subscriber) {
|
||||
this.subscriber = subscriber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
|
||||
final NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
|
||||
if (subscriber != null) {
|
||||
subscriber.onNext(networkInfo != null && networkInfo.isConnected());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class NetworkStateReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final IntentFilter INTENT_FILTER = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||
@Nullable
|
||||
private ConnectivityManager connectivityManager;
|
||||
|
||||
@Nullable
|
||||
private Subscriber<? super Boolean> subscriber;
|
||||
|
||||
public void setSubscriber(@Nullable final Subscriber<? super Boolean> subscriber) {
|
||||
this.subscriber = subscriber;
|
||||
}
|
||||
|
||||
public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
|
||||
if (connectivityManager == null) {
|
||||
connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
}
|
||||
if (subscriber != null) {
|
||||
subscriber.onNext(isNetworkConnected(context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ package ru.touchin.templates;
|
|||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Intent;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.ColorRes;
|
||||
|
|
@ -62,14 +62,9 @@ public abstract class TouchinActivity<TLogic extends Logic> extends ViewControll
|
|||
* @param primaryColorRes Color of application to show in task bar.
|
||||
*/
|
||||
protected void setupTaskDescriptor(@NonNull final String label, @DrawableRes final int iconRes, @ColorRes final int primaryColorRes) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
final ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription(label,
|
||||
iconRes,
|
||||
ContextCompat.getColor(this, primaryColorRes));
|
||||
setTaskDescription(taskDescription);
|
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
final ActivityManager.TaskDescription taskDescription = new ActivityManager.TaskDescription(label,
|
||||
BitmapFactory.decodeResource(getResources(), iconRes),
|
||||
((BitmapDrawable) ContextCompat.getDrawable(this, iconRes)).getBitmap(),
|
||||
ContextCompat.getColor(this, primaryColorRes));
|
||||
setTaskDescription(taskDescription);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import java.util.List;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.fabric.sdk.android.Fabric;
|
||||
import ru.touchin.roboswag.components.adapters.ObservableCollectionAdapter;
|
||||
import ru.touchin.roboswag.components.navigation.fragments.ViewControllerFragment;
|
||||
import ru.touchin.roboswag.components.utils.UiUtils;
|
||||
import ru.touchin.roboswag.components.views.TypefacedEditText;
|
||||
|
|
@ -92,7 +91,6 @@ public abstract class TouchinApp extends Application {
|
|||
JodaTimeAndroid.init(this);
|
||||
if (isDebug()) {
|
||||
enableStrictMode();
|
||||
ObservableCollectionAdapter.setInDebugMode();
|
||||
ViewControllerFragment.setInDebugMode();
|
||||
TypefacedEditText.setInDebugMode();
|
||||
TypefacedTextView.setInDebugMode();
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import ru.touchin.roboswag.core.log.Lc;
|
|||
import ru.touchin.roboswag.core.utils.ServiceBinder;
|
||||
import ru.touchin.roboswag.core.utils.ShouldNotHappenException;
|
||||
import rx.Completable;
|
||||
import rx.CompletableSubscriber;
|
||||
import rx.Observable;
|
||||
import rx.Single;
|
||||
import rx.SingleSubscriber;
|
||||
|
|
@ -227,7 +226,7 @@ public abstract class TouchinService<TLogic extends Logic> extends Service {
|
|||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param completable {@link Completable} to subscribe until onDestroy;
|
||||
* @param onCompletedAction Action which will raise on every {@link CompletableSubscriber#onCompleted()} item;
|
||||
* @param onCompletedAction Action which will raise on every {@link Completable.CompletableSubscriber#onCompleted()} item;
|
||||
* @return {@link Subscription} which is wrapping source completable to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
|
|
@ -241,8 +240,8 @@ public abstract class TouchinService<TLogic extends Logic> extends Service {
|
|||
* Don't forget to process errors if completable can emit them.
|
||||
*
|
||||
* @param completable {@link Single} to subscribe until onDestroy;
|
||||
* @param onCompletedAction Action which will raise on {@link CompletableSubscriber#onCompleted()} item;
|
||||
* @param onErrorAction Action which will raise on every {@link CompletableSubscriber#onError(Throwable)} throwable;
|
||||
* @param onCompletedAction Action which will raise on {@link Completable.CompletableSubscriber#onCompleted()} item;
|
||||
* @param onErrorAction Action which will raise on every {@link Completable.CompletableSubscriber#onError(Throwable)} throwable;
|
||||
* @return {@link Subscription} which is wrapping source completable to unsubscribe from it onDestroy.
|
||||
*/
|
||||
@NonNull
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@ public abstract class CalendarAdapter<TDayViewHolder extends RecyclerView.ViewHo
|
|||
public static final int MONTHS_IN_YEAR = 12;
|
||||
public static final long ONE_DAY_LENGTH = TimeUnit.DAYS.toMillis(1);
|
||||
|
||||
private List<CalendarItem> calendarItems;
|
||||
@NonNull
|
||||
private final List<CalendarItem> calendarItems;
|
||||
@Nullable
|
||||
private Integer startSelectionPosition;
|
||||
@Nullable
|
||||
|
|
@ -71,10 +72,6 @@ public abstract class CalendarAdapter<TDayViewHolder extends RecyclerView.ViewHo
|
|||
if (monthsNames != null && monthsNames.length == MONTHS_IN_YEAR) {
|
||||
this.monthsNames = monthsNames;
|
||||
}
|
||||
updateCalendarItems(startDate, endDate);
|
||||
}
|
||||
|
||||
public final void updateCalendarItems(@NonNull final DateTime startDate, @NonNull final DateTime endDate) {
|
||||
calendarItems = CalendarUtils.fillRanges(startDate, endDate);
|
||||
if (calendarItems.isEmpty()) {
|
||||
throw new ShouldNotHappenException("There is no items in calendar with startDate: " + DateTimeFormat.fullDate().print(startDate)
|
||||
|
|
@ -89,12 +86,12 @@ public abstract class CalendarAdapter<TDayViewHolder extends RecyclerView.ViewHo
|
|||
* @param endSelectionDate Last date that should be selected (inclusive).
|
||||
*/
|
||||
public void setSelectedRange(@Nullable final DateTime startSelectionDate, @Nullable final DateTime endSelectionDate) {
|
||||
startSelectionPosition = startSelectionDate != null
|
||||
? CalendarUtils.findPositionByDate(calendarItems, startSelectionDate.withTimeAtStartOfDay().getMillis())
|
||||
: null;
|
||||
endSelectionPosition = endSelectionDate != null
|
||||
? CalendarUtils.findPositionByDate(calendarItems, endSelectionDate.withTimeAtStartOfDay().getMillis())
|
||||
: null;
|
||||
if (startSelectionDate != null) {
|
||||
startSelectionPosition = CalendarUtils.findPositionByDate(calendarItems, startSelectionDate.withTimeAtStartOfDay().getMillis());
|
||||
}
|
||||
if (endSelectionDate != null) {
|
||||
endSelectionPosition = CalendarUtils.findPositionByDate(calendarItems, endSelectionDate.withTimeAtStartOfDay().getMillis());
|
||||
}
|
||||
|
||||
notifySelectedDaysChanged();
|
||||
}
|
||||
|
|
@ -135,16 +132,6 @@ public abstract class CalendarAdapter<TDayViewHolder extends RecyclerView.ViewHo
|
|||
notifyItemRangeChanged(startSelectionPosition, endSelectionPosition - startSelectionPosition);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected List<CalendarItem> getCalendarItems() {
|
||||
return calendarItems;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected String getMonthsNameByHeaderCalendarItem(@NonNull final CalendarHeaderItem item) {
|
||||
return monthsNames != null ? monthsNames[item.getMonth()] : String.valueOf(item.getMonth());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) {
|
||||
|
|
@ -250,7 +237,7 @@ public abstract class CalendarAdapter<TDayViewHolder extends RecyclerView.ViewHo
|
|||
}
|
||||
|
||||
//TODO fix suppress
|
||||
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"})
|
||||
@SuppressWarnings("PMD.CyclomaticComplexity")
|
||||
private void bindDay(@NonNull final TDayViewHolder holder, final int position, @NonNull final CalendarItem calendarItem) {
|
||||
final String currentDay = String.valueOf(((CalendarDayItem) calendarItem).getPositionOfFirstDay()
|
||||
+ position - calendarItem.getStartRange());
|
||||
|
|
@ -258,18 +245,13 @@ public abstract class CalendarAdapter<TDayViewHolder extends RecyclerView.ViewHo
|
|||
+ (position - calendarItem.getStartRange()) * ONE_DAY_LENGTH);
|
||||
final ComparingToToday dateState = ((CalendarDayItem) calendarItem).getComparingToToday();
|
||||
if (startSelectionPosition != null && position == startSelectionPosition) {
|
||||
if (endSelectionPosition == null || endSelectionPosition.equals(startSelectionPosition)
|
||||
|| startSelectionPosition > endSelectionPosition) {
|
||||
if (endSelectionPosition == null || endSelectionPosition.equals(startSelectionPosition)) {
|
||||
bindDayItem(holder, currentDay, currentDate, SelectionMode.SELECTED_ONE_ONLY, dateState);
|
||||
return;
|
||||
}
|
||||
bindDayItem(holder, currentDay, currentDate, SelectionMode.SELECTED_FIRST, dateState);
|
||||
return;
|
||||
}
|
||||
if (startSelectionPosition != null && endSelectionPosition != null && startSelectionPosition > endSelectionPosition) {
|
||||
bindDayItem(holder, currentDay, currentDate, SelectionMode.NOT_SELECTED, dateState);
|
||||
return;
|
||||
}
|
||||
if (endSelectionPosition != null && position == endSelectionPosition) {
|
||||
bindDayItem(holder, currentDay, currentDate, SelectionMode.SELECTED_LAST, dateState);
|
||||
return;
|
||||
|
|
@ -303,10 +285,6 @@ public abstract class CalendarAdapter<TDayViewHolder extends RecyclerView.ViewHo
|
|||
return calendarItems.isEmpty() ? 0 : calendarItems.get(calendarItems.size() - 1).getEndRange();
|
||||
}
|
||||
|
||||
protected boolean isEndPositionExist() {
|
||||
return endSelectionPosition != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selection mode that shows the type of selection of a calendar cell.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import android.content.Context;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.StaggeredGridLayoutManager;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
|
|
@ -46,31 +45,11 @@ public class CalendarRecyclerView extends RecyclerView {
|
|||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
|
||||
//ConstructorCallsOverridableMethod: it's OK
|
||||
public CalendarRecyclerView(@NonNull final Context context, @Nullable final AttributeSet attrs, final int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
initialize();
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
setupCacheForMonthsOnScreenCount(3);
|
||||
final StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(7, StaggeredGridLayoutManager.VERTICAL);
|
||||
layoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
|
||||
setLayoutManager(layoutManager);
|
||||
setItemAnimator(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setups recycler cache for smooth scroll without lagging based on month that could be displayed on screen.
|
||||
*
|
||||
* @param maxMonthOnScreen Maximum months count on screen.
|
||||
*/
|
||||
public void setupCacheForMonthsOnScreenCount(final int maxMonthOnScreen) {
|
||||
getRecycledViewPool().setMaxRecycledViews(CalendarAdapter.HEADER_ITEM_TYPE, HEADER_MAX_ELEMENTS_IN_A_ROW * (maxMonthOnScreen + 1));
|
||||
getRecycledViewPool().setMaxRecycledViews(CalendarAdapter.EMPTY_ITEM_TYPE, EMPTY_MAX_ELEMENTS_IN_A_ROW * (maxMonthOnScreen * 2 + 1));
|
||||
// we need such much views to prevent cache/gap animations of StaggeredGridLayoutManager
|
||||
getRecycledViewPool().setMaxRecycledViews(CalendarAdapter.DAY_ITEM_TYPE, DAY_MAX_ELEMENTS_IN_A_ROW * (maxMonthOnScreen * 5 + 1));
|
||||
getRecycledViewPool().setMaxRecycledViews(CalendarAdapter.HEADER_ITEM_TYPE, HEADER_MAX_ELEMENTS_IN_A_ROW * 3);
|
||||
getRecycledViewPool().setMaxRecycledViews(CalendarAdapter.EMPTY_ITEM_TYPE, EMPTY_MAX_ELEMENTS_IN_A_ROW * 3);
|
||||
getRecycledViewPool().setMaxRecycledViews(CalendarAdapter.DAY_ITEM_TYPE, DAY_MAX_ELEMENTS_IN_A_ROW * 3);
|
||||
setItemViewCacheSize(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public final class CalendarUtils {
|
|||
* @param calendarItems List of {@link CalendarItem} where need to find specific element;
|
||||
* @param position Position of adapter;
|
||||
* @return Position of Header that respond to requested position.
|
||||
* Returns null if Header or related CalendarItem was not found for specified position.
|
||||
* Returns null if Header or related CalendarItem was not found for specified position.
|
||||
*/
|
||||
@Nullable
|
||||
public static Integer findPositionOfSelectedMonth(@NonNull final List<CalendarItem> calendarItems, final long position) {
|
||||
|
|
@ -76,7 +76,7 @@ public final class CalendarUtils {
|
|||
* @param calendarItems List of {@link CalendarItem} where need to find specific element;
|
||||
* @param date Requested date in milliseconds.
|
||||
* @return Position of Calendar cell that that has specific date.
|
||||
* Returns null if CalendarItem was not found for specified position.
|
||||
* Returns null if CalendarItem was not found for specified position.
|
||||
*/
|
||||
@Nullable
|
||||
public static Integer findPositionByDate(@NonNull final List<CalendarItem> calendarItems, final long date) {
|
||||
|
|
|
|||
|
|
@ -31,9 +31,9 @@ import java.util.concurrent.Executors;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import ru.touchin.roboswag.core.log.Lc;
|
||||
import ru.touchin.roboswag.core.observables.collections.Change;
|
||||
import ru.touchin.roboswag.core.observables.collections.ObservableCollection;
|
||||
import ru.touchin.roboswag.core.observables.collections.ObservableList;
|
||||
import rx.Completable;
|
||||
import rx.Observable;
|
||||
import rx.Scheduler;
|
||||
import rx.Subscription;
|
||||
|
|
@ -76,10 +76,17 @@ public abstract class Chat<TOutgoingMessage> {
|
|||
final List<TOutgoingMessage> reversedMessages = new ArrayList<>(initialMessages);
|
||||
Collections.reverse(reversedMessages);
|
||||
return Observable.from(reversedMessages)
|
||||
.concatWith(sendingMessages.observeChanges().concatMap(changes ->
|
||||
changes.getInsertedItems().isEmpty() ? Observable.empty() : Observable.from(changes.getInsertedItems())))
|
||||
.concatWith(sendingMessages.observeChanges().concatMap(changes -> {
|
||||
final Collection<TOutgoingMessage> insertedMessages = new ArrayList<>();
|
||||
for (final Change<TOutgoingMessage> change : changes.getChanges()) {
|
||||
if (change.getType() == Change.Type.INSERTED) {
|
||||
insertedMessages.addAll(change.getChangedItems());
|
||||
}
|
||||
}
|
||||
return insertedMessages.isEmpty() ? Observable.empty() : Observable.from(insertedMessages);
|
||||
}))
|
||||
//observe on some scheduler?
|
||||
.flatMap(message -> internalSendMessage(message).toObservable());
|
||||
.flatMap(this::internalSendMessage);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -168,14 +175,6 @@ public abstract class Chat<TOutgoingMessage> {
|
|||
retrySendingRequest.onNext(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to cancel sending current message.
|
||||
*/
|
||||
@NonNull
|
||||
public Observable<?> observeCancelEvent(@NonNull final TOutgoingMessage message) {
|
||||
return Observable.never();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates chat so it will stop sending messages.
|
||||
*/
|
||||
|
|
@ -189,9 +188,9 @@ public abstract class Chat<TOutgoingMessage> {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
private Completable internalSendMessage(@NonNull final TOutgoingMessage message) {
|
||||
private Observable<?> internalSendMessage(@NonNull final TOutgoingMessage message) {
|
||||
final SubscriptionHolder subscriptionHolder = new SubscriptionHolder();
|
||||
return Completable
|
||||
return Observable
|
||||
.create(subscriber -> {
|
||||
subscriptionHolder.subscription = sendingScheduler.createWorker().schedule(() -> {
|
||||
final CountDownLatch blocker = new CountDownLatch(1);
|
||||
|
|
@ -202,7 +201,6 @@ public abstract class Chat<TOutgoingMessage> {
|
|||
.first()
|
||||
.switchMap(shouldSendMessage -> shouldSendMessage
|
||||
? createSendMessageObservable(message).ignoreElements() : Observable.empty())
|
||||
.takeUntil(observeCancelEvent(message))
|
||||
.retryWhen(attempts -> attempts.switchMap(ignored -> {
|
||||
isSendingInError.onNext(true);
|
||||
return Observable
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@ import java.io.ByteArrayOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import ru.touchin.roboswag.components.utils.storables.PreferenceStore;
|
||||
import ru.touchin.roboswag.core.observables.storable.Converter;
|
||||
|
|
@ -83,6 +85,26 @@ public final class GoogleJsonPreferences {
|
|||
.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> Storable<String, Set<T>, String> jsonSetStorable(@NonNull final String name,
|
||||
@NonNull final Class<T> jsonItemClass,
|
||||
@NonNull final SharedPreferences preferences) {
|
||||
return new Storable.Builder<>(name, Set.class, String.class, new PreferenceStore<>(preferences), new JsonSetConverter<>(jsonItemClass))
|
||||
.setObserveStrategy(Storable.ObserveStrategy.CACHE_ACTUAL_VALUE)
|
||||
.build();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static <T> NonNullStorable<String, Set<T>, String> jsonSetStorable(@NonNull final String name,
|
||||
@NonNull final Class<T> jsonItemClass,
|
||||
@NonNull final SharedPreferences preferences,
|
||||
@NonNull final Set<T> defaultValue) {
|
||||
return new Storable.Builder<>(name, Set.class, String.class, new PreferenceStore<>(preferences), new JsonSetConverter<>(jsonItemClass))
|
||||
.setObserveStrategy(Storable.ObserveStrategy.CACHE_ACTUAL_VALUE)
|
||||
.setDefaultValue(defaultValue)
|
||||
.build();
|
||||
}
|
||||
|
||||
private GoogleJsonPreferences() {
|
||||
}
|
||||
|
||||
|
|
@ -146,4 +168,29 @@ public final class GoogleJsonPreferences {
|
|||
|
||||
}
|
||||
|
||||
public static class JsonSetConverter<T> extends JsonConverter<Set<T>> {
|
||||
|
||||
@NonNull
|
||||
private final Class<T> itemClass;
|
||||
|
||||
public JsonSetConverter(@NonNull final Class<T> itemClass) {
|
||||
super();
|
||||
this.itemClass = itemClass;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Set<T> toObject(@NonNull final Type jsonObjectType, @NonNull final Type stringType, @Nullable final String storeValue) {
|
||||
if (storeValue == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new HashSet<>(GoogleJsonModel.DEFAULT_JSON_FACTORY.createJsonParser(storeValue).parseArray(HashSet.class, itemClass));
|
||||
} catch (final IOException exception) {
|
||||
throw new ShouldNotHappenException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,34 +35,24 @@ public class LoganSquareEnumConverter<T extends Enum & LoganSquareEnum> extends
|
|||
|
||||
@NonNull
|
||||
private final T[] enumValues;
|
||||
@Nullable
|
||||
private final T defaultValue;
|
||||
|
||||
public LoganSquareEnumConverter(@NonNull final T[] enumValues) {
|
||||
this(enumValues, null);
|
||||
}
|
||||
|
||||
public LoganSquareEnumConverter(@NonNull final T[] enumValues, @Nullable final T defaultValue) {
|
||||
super();
|
||||
this.enumValues = enumValues;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public T getFromString(@Nullable final String string) {
|
||||
if (string == null) {
|
||||
return defaultValue;
|
||||
return null;
|
||||
}
|
||||
for (final T value : enumValues) {
|
||||
if (value.getValueName().equals(string)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
if (defaultValue != null) {
|
||||
return defaultValue;
|
||||
}
|
||||
throw new ShouldNotHappenException("Enum parsing exception for value: " + string);
|
||||
throw new ShouldNotHappenException();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public class LoganSquareJodaTimeConverter implements TypeConverter<DateTime> {
|
|||
@Override
|
||||
public DateTime parse(@NonNull final JsonParser jsonParser) throws IOException {
|
||||
final String dateString = jsonParser.getValueAsString();
|
||||
if (dateString == null || dateString.isEmpty()) {
|
||||
if (dateString == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
|
|
@ -60,9 +60,9 @@ public class LoganSquareJodaTimeConverter implements TypeConverter<DateTime> {
|
|||
@NonNull final JsonGenerator jsonGenerator)
|
||||
throws IOException {
|
||||
if (fieldName != null) {
|
||||
jsonGenerator.writeStringField(fieldName, object != null && !object.toString().isEmpty() ? object.toString() : null);
|
||||
jsonGenerator.writeStringField(fieldName, object != null ? object.toString() : null);
|
||||
} else {
|
||||
jsonGenerator.writeString(object != null && !object.toString().isEmpty() ? object.toString() : null);
|
||||
jsonGenerator.writeString(object != null ? object.toString() : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,20 +20,14 @@
|
|||
package ru.touchin.templates.logansquare;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.bluelinelabs.logansquare.ConverterUtils;
|
||||
import com.bluelinelabs.logansquare.LoganSquare;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.ResponseBody;
|
||||
|
|
@ -44,7 +38,7 @@ import ru.touchin.templates.retrofit.JsonResponseBodyConverter;
|
|||
|
||||
/**
|
||||
* Created by Gavriil Sitnikov on 2/06/2016.
|
||||
* LoganSquareConverter class to use with {@link Retrofit} to parse and generate models based on Logan Square library.
|
||||
* LoganSquareConverter class to use with {@link Retrofit} to parse and generate models based on Google Jackson library {@link JacksonFactory}.
|
||||
*/
|
||||
public class LoganSquareJsonFactory extends Converter.Factory {
|
||||
|
||||
|
|
@ -65,16 +59,6 @@ public class LoganSquareJsonFactory extends Converter.Factory {
|
|||
return new LoganSquareRequestBodyConverter<>();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Converter<?, String> stringConverter(@NonNull final Type type, @NonNull final Annotation[] annotations, @NonNull final Retrofit retrofit) {
|
||||
if (type instanceof Class && ((Class) type).getSuperclass() == Enum.class) {
|
||||
return new LoganSquareStringEnumConverter<>();
|
||||
} else {
|
||||
return super.stringConverter(type, annotations, retrofit);
|
||||
}
|
||||
}
|
||||
|
||||
public static class LoganSquareJsonResponseBodyConverter<T> extends JsonResponseBodyConverter<T> {
|
||||
|
||||
@NonNull
|
||||
|
|
@ -89,23 +73,7 @@ public class LoganSquareJsonFactory extends Converter.Factory {
|
|||
@NonNull
|
||||
@Override
|
||||
protected T parseResponse(@NonNull final ResponseBody value) throws IOException {
|
||||
if (type instanceof ParameterizedType) {
|
||||
final ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
final Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||
final Type firstType = typeArguments[0];
|
||||
|
||||
final Type rawType = parameterizedType.getRawType();
|
||||
if (rawType == Map.class) {
|
||||
return (T) LoganSquare.parseMap(value.byteStream(), (Class<?>) typeArguments[1]);
|
||||
} else if (rawType == List.class) {
|
||||
return (T) LoganSquare.parseList(value.byteStream(), (Class<?>) firstType);
|
||||
} else {
|
||||
// Generics
|
||||
return (T) LoganSquare.parse(value.byteStream(), ConverterUtils.parameterizedTypeOf(type));
|
||||
}
|
||||
} else {
|
||||
return (T) LoganSquare.parse(value.byteStream(), (Class) type);
|
||||
}
|
||||
return (T) LoganSquare.parse(value.byteStream(), (Class) type);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -113,29 +81,11 @@ public class LoganSquareJsonFactory extends Converter.Factory {
|
|||
public static class LoganSquareRequestBodyConverter<T> extends JsonRequestBodyConverter<T> {
|
||||
|
||||
@Override
|
||||
protected void writeValueToByteArray(@NonNull final T value, @NonNull final ByteArrayOutputStream byteArrayOutputStream) throws IOException {
|
||||
protected void writeValueToByteArray(@NonNull final T value, @NonNull final ByteArrayOutputStream byteArrayOutputStream)
|
||||
throws IOException {
|
||||
LoganSquare.serialize(value, byteArrayOutputStream);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class LoganSquareStringEnumConverter<T> implements Converter<T, String> {
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings({"unchecked", "TryFinallyCanBeTryWithResources"})
|
||||
@Override
|
||||
public String convert(@NonNull final T value) throws IOException {
|
||||
final StringWriter writer = new StringWriter();
|
||||
try {
|
||||
final JsonGenerator generator = LoganSquare.JSON_FACTORY.createGenerator(writer);
|
||||
LoganSquare.typeConverterFor((Class<T>) value.getClass()).serialize(value, null, false, generator);
|
||||
generator.close();
|
||||
return writer.toString().replaceAll("\"", "");
|
||||
} finally {
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -203,9 +203,23 @@ public abstract class HttpRequest<T> {
|
|||
@NonNull
|
||||
public Observable<T> execute() {
|
||||
return Observable
|
||||
.fromCallable(RequestController::new)
|
||||
.<RequestController>create(subscriber -> {
|
||||
try {
|
||||
subscriber.onNext(new RequestController());
|
||||
} catch (final IOException exception) {
|
||||
subscriber.onError(exception);
|
||||
}
|
||||
subscriber.onCompleted();
|
||||
})
|
||||
.switchMap(requestController -> Observable
|
||||
.fromCallable(() -> executeSyncInternal(requestController))
|
||||
.<T>create(requestSubscriber -> {
|
||||
try {
|
||||
requestSubscriber.onNext(executeSyncInternal(requestController));
|
||||
} catch (final IOException exception) {
|
||||
requestSubscriber.onError(exception);
|
||||
}
|
||||
requestSubscriber.onCompleted();
|
||||
})
|
||||
.subscribeOn(Schedulers.io())
|
||||
.unsubscribeOn(Schedulers.io())
|
||||
.doOnUnsubscribe(requestController.call::cancel));
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ import android.support.annotation.NonNull;
|
|||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.SocketException;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
|
|
@ -59,46 +57,20 @@ public abstract class JsonResponseBodyConverter<T> implements Converter<Response
|
|||
Lc.assertion(exception);
|
||||
}
|
||||
throw exception;
|
||||
} finally {
|
||||
value.close();
|
||||
}
|
||||
|
||||
if (result instanceof ApiModel) {
|
||||
validateModel((ApiModel) result);
|
||||
}
|
||||
if (result instanceof Collection) {
|
||||
validateCollection((Collection) result);
|
||||
}
|
||||
if (result instanceof Map) {
|
||||
validateCollection(((Map) result).values());
|
||||
try {
|
||||
((ApiModel) result).validate();
|
||||
} catch (final ApiModel.ValidationException validationException) {
|
||||
Lc.assertion(validationException);
|
||||
throw validationException;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void validateModel(@NonNull final ApiModel result) throws IOException {
|
||||
try {
|
||||
result.validate();
|
||||
} catch (final ApiModel.ValidationException validationException) {
|
||||
Lc.assertion(validationException);
|
||||
throw validationException;
|
||||
}
|
||||
}
|
||||
|
||||
private void validateCollection(@NonNull final Collection result) throws IOException {
|
||||
try {
|
||||
ApiModel.validateCollection(result, getValidateCollectionRule());
|
||||
} catch (final ApiModel.ValidationException validationException) {
|
||||
Lc.assertion(validationException);
|
||||
throw validationException;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected ApiModel.CollectionValidationRule getValidateCollectionRule() {
|
||||
return ApiModel.CollectionValidationRule.EXCEPTION_IF_ANY_INVALID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses response to specific object.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -85,21 +85,29 @@ public abstract class SocketConnection {
|
|||
@NonNull
|
||||
private Observable<Pair<Socket, State>> createSocketObservable() {
|
||||
return Observable
|
||||
.fromCallable(this::createSocket)
|
||||
.<Socket>create(subscriber -> {
|
||||
try {
|
||||
final Socket socket = createSocket();
|
||||
subscriber.onNext(socket);
|
||||
} catch (final Exception exception) {
|
||||
Lc.assertion(exception);
|
||||
}
|
||||
subscriber.onCompleted();
|
||||
})
|
||||
.switchMap(socket -> Observable
|
||||
.<Pair<Socket, State>>create(emitter -> {
|
||||
socket.on(Socket.EVENT_CONNECT, args -> emitter.onNext(new Pair<>(socket, State.CONNECTED)));
|
||||
socket.on(Socket.EVENT_CONNECTING, args -> emitter.onNext(new Pair<>(socket, State.CONNECTING)));
|
||||
socket.on(Socket.EVENT_CONNECT_ERROR, args -> emitter.onNext(new Pair<>(socket, State.CONNECTION_ERROR)));
|
||||
socket.on(Socket.EVENT_CONNECT_TIMEOUT, args -> emitter.onNext(new Pair<>(socket, State.CONNECTION_ERROR)));
|
||||
socket.on(Socket.EVENT_DISCONNECT, args -> emitter.onNext(new Pair<>(socket, State.DISCONNECTED)));
|
||||
socket.on(Socket.EVENT_RECONNECT_ATTEMPT, args -> emitter.onNext(new Pair<>(socket, State.CONNECTING)));
|
||||
socket.on(Socket.EVENT_RECONNECTING, args -> emitter.onNext(new Pair<>(socket, State.CONNECTING)));
|
||||
socket.on(Socket.EVENT_RECONNECT, args -> emitter.onNext(new Pair<>(socket, State.CONNECTED)));
|
||||
socket.on(Socket.EVENT_RECONNECT_ERROR, args -> emitter.onNext(new Pair<>(socket, State.CONNECTION_ERROR)));
|
||||
socket.on(Socket.EVENT_RECONNECT_FAILED, args -> emitter.onNext(new Pair<>(socket, State.CONNECTION_ERROR)));
|
||||
emitter.onNext(new Pair<>(socket, State.DISCONNECTED));
|
||||
}, rx.Emitter.BackpressureMode.LATEST)
|
||||
.<Pair<Socket, State>>create(subscriber -> {
|
||||
socket.on(Socket.EVENT_CONNECT, args -> subscriber.onNext(new Pair<>(socket, State.CONNECTED)));
|
||||
socket.on(Socket.EVENT_CONNECTING, args -> subscriber.onNext(new Pair<>(socket, State.CONNECTING)));
|
||||
socket.on(Socket.EVENT_CONNECT_ERROR, args -> subscriber.onNext(new Pair<>(socket, State.CONNECTION_ERROR)));
|
||||
socket.on(Socket.EVENT_CONNECT_TIMEOUT, args -> subscriber.onNext(new Pair<>(socket, State.CONNECTION_ERROR)));
|
||||
socket.on(Socket.EVENT_DISCONNECT, args -> subscriber.onNext(new Pair<>(socket, State.DISCONNECTED)));
|
||||
socket.on(Socket.EVENT_RECONNECT_ATTEMPT, args -> subscriber.onNext(new Pair<>(socket, State.CONNECTING)));
|
||||
socket.on(Socket.EVENT_RECONNECTING, args -> subscriber.onNext(new Pair<>(socket, State.CONNECTING)));
|
||||
socket.on(Socket.EVENT_RECONNECT, args -> subscriber.onNext(new Pair<>(socket, State.CONNECTED)));
|
||||
socket.on(Socket.EVENT_RECONNECT_ERROR, args -> subscriber.onNext(new Pair<>(socket, State.CONNECTION_ERROR)));
|
||||
socket.on(Socket.EVENT_RECONNECT_FAILED, args -> subscriber.onNext(new Pair<>(socket, State.CONNECTION_ERROR)));
|
||||
subscriber.onNext(new Pair<>(socket, State.DISCONNECTED));
|
||||
})
|
||||
.distinctUntilChanged()
|
||||
.doOnSubscribe(() -> {
|
||||
if (autoConnectOnAnySubscription) {
|
||||
|
|
@ -131,13 +139,13 @@ public abstract class SocketConnection {
|
|||
//unchecked: it's OK as we are caching raw observables
|
||||
protected <T> Observable<T> observeEvent(@NonNull final SocketEvent<T> socketEvent) {
|
||||
return Observable.switchOnNext(Observable
|
||||
.fromCallable(() -> {
|
||||
.<Observable<T>>create(observableSubscriber -> {
|
||||
Observable<T> result = (Observable<T>) messagesObservableCache.get(socketEvent);
|
||||
if (result == null) {
|
||||
result = getSocket()
|
||||
.switchMap(socket -> Observable
|
||||
.<T>create(emitter -> socket.on(socketEvent.getName(), new SocketListener<>(socketEvent, emitter::onNext)),
|
||||
rx.Emitter.BackpressureMode.BUFFER)
|
||||
.<T>create(subscriber ->
|
||||
socket.on(socketEvent.getName(), new SocketListener<>(socketEvent, subscriber::onNext)))
|
||||
.unsubscribeOn(scheduler)
|
||||
.doOnUnsubscribe(() -> {
|
||||
socket.off(socketEvent.getName());
|
||||
|
|
@ -147,7 +155,8 @@ public abstract class SocketConnection {
|
|||
.refCount();
|
||||
messagesObservableCache.put(socketEvent, result);
|
||||
}
|
||||
return result;
|
||||
observableSubscriber.onNext(result);
|
||||
observableSubscriber.onCompleted();
|
||||
})
|
||||
.subscribeOn(scheduler));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,6 @@ public class ValidationState implements Serializable {
|
|||
|
||||
/**
|
||||
* Returns unique code of the {@link ValidationState}.
|
||||
*
|
||||
* @return code or the ValidationState.
|
||||
*/
|
||||
public int getCode() {
|
||||
|
|
@ -68,7 +67,6 @@ public class ValidationState implements Serializable {
|
|||
|
||||
/**
|
||||
* Don't forget to override this method!
|
||||
*
|
||||
* @param object that you want to compare.
|
||||
* @return true if objects equals and false otherwise.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ public interface ViewWithError {
|
|||
* Shows error
|
||||
* Pass here error state.
|
||||
* It is not correct to pass here {@link ValidationState#VALID} or {@link ValidationState#INITIAL}
|
||||
*
|
||||
* @param validationState error state. Can be other than {@link ValidationState} if you have successor of base {@link ValidationState}.
|
||||
*/
|
||||
void showError(@NonNull final ValidationState validationState);
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ public class BooleanValidationController extends ValidationController<Boolean, B
|
|||
|
||||
/**
|
||||
* This method validates bounded view.
|
||||
*
|
||||
* @param activatedObservable emits true when we need to show error on empty fields. Eg when user clicks on Done button but he missed some
|
||||
* necessary fields to fill.
|
||||
* @return observable without any concrete type. Simply subscribe to this method to make it works.
|
||||
|
|
|
|||
|
|
@ -98,7 +98,8 @@ public class EditTextValidationController<TModel extends Serializable>
|
|||
/**
|
||||
* If we don't want to show error when focus is lost.
|
||||
*
|
||||
* @param showErrorOnFocusOut show an error or don't show an error.
|
||||
* @param showErrorOnFocusOut show an error or don't show an error.
|
||||
*
|
||||
*/
|
||||
public void setShowErrorOnFocusOut(final boolean showErrorOnFocusOut) {
|
||||
this.showErrorOnFocusOut = showErrorOnFocusOut;
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@ import rx.Observable;
|
|||
* Created by Ilia Kurtov on 24/01/2017.
|
||||
* {@link ValidationController} for models that have the same modal as wrapper model. You can use it when you simply need to be sure
|
||||
* that user have selected some item and it is not null.
|
||||
*
|
||||
* @param <TModel> type of the model.
|
||||
* @param <TModel> type of the model.
|
||||
* @param <TValidator> corresponding {@link Validator}
|
||||
*/
|
||||
public class SimpleValidationController<TModel extends Serializable, TValidator extends Validator<TModel, TModel>>
|
||||
|
|
@ -25,7 +24,6 @@ public class SimpleValidationController<TModel extends Serializable, TValidator
|
|||
|
||||
/**
|
||||
* This method validates bounded view.
|
||||
*
|
||||
* @param activatedObservable emits true when we need to show error on empty fields. Eg when user clicks on Done button but he missed some
|
||||
* necessary fields to fill.
|
||||
* @return observable without any concrete type. Simply subscribe to this method to make it works.
|
||||
|
|
|
|||
|
|
@ -53,11 +53,10 @@ public class ValidationController
|
|||
/**
|
||||
* Bind to this observable to connect view and model. If you provide first argument (viewStateObservable) - the connection would be two-way.
|
||||
* If not - one-way. This method changes updates view with current {@link ValidationState}.
|
||||
*
|
||||
* @param viewStateObservable input view state {@link Observable}.
|
||||
* Eg it can be observable with input text from the {@link android.widget.EditText}
|
||||
* @param updateViewAction action that updates current state of the bounded view.
|
||||
* @param viewWithError view that implements {@link ViewWithError} interface and could reacts to the validation errors.
|
||||
* @param updateViewAction action that updates current state of the bounded view.
|
||||
* @param viewWithError view that implements {@link ViewWithError} interface and could reacts to the validation errors.
|
||||
* @return observable without any concrete type. Simply subscribe to this method to make it works.
|
||||
*/
|
||||
@NonNull
|
||||
|
|
@ -69,7 +68,7 @@ public class ValidationController
|
|||
: Observable.empty();
|
||||
return Observable
|
||||
.merge(getValidator().getWrapperModel().observe()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnNext(updateViewAction),
|
||||
getValidator().getValidationState().observe()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
|
@ -85,7 +84,6 @@ public class ValidationController
|
|||
|
||||
/**
|
||||
* Helper function to check if validation state in error state ot not
|
||||
*
|
||||
* @param validationState the state you want to check for the errors.
|
||||
* @return true if validation state is in error and false otherwise.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ public abstract class EditTextValidator<TModel extends Serializable> extends Val
|
|||
* This flag needed to force showing errors. You don't want to show final error when you start to enter data in some field at first time.
|
||||
* But if user leaves this view and final check not passed - you need to force to show an error till user not enters correct data and leaves
|
||||
* the view.
|
||||
*
|
||||
* @return {@link NonNullChangeable} with current state of the flag - do we need to show errors from final checks while user types.
|
||||
*/
|
||||
@NonNull
|
||||
|
|
@ -61,7 +60,6 @@ public abstract class EditTextValidator<TModel extends Serializable> extends Val
|
|||
|
||||
/**
|
||||
* Use this method to get or set final check.
|
||||
*
|
||||
* @return final check.
|
||||
*/
|
||||
@NonNull
|
||||
|
|
@ -71,7 +69,6 @@ public abstract class EditTextValidator<TModel extends Serializable> extends Val
|
|||
|
||||
/**
|
||||
* Use this method to get or set primary check.
|
||||
*
|
||||
* @return primary check.
|
||||
*/
|
||||
@NonNull
|
||||
|
|
@ -122,7 +119,6 @@ public abstract class EditTextValidator<TModel extends Serializable> extends Val
|
|||
|
||||
/**
|
||||
* Validates text with primary check.
|
||||
*
|
||||
* @param text - input text.
|
||||
* @return {@link Observable} with the result of the primary check.
|
||||
*/
|
||||
|
|
@ -133,7 +129,6 @@ public abstract class EditTextValidator<TModel extends Serializable> extends Val
|
|||
|
||||
/**
|
||||
* Validates text with final check.
|
||||
*
|
||||
* @param text - input text.
|
||||
* @return {@link Observable} with the result of the final check.
|
||||
*/
|
||||
|
|
@ -145,10 +140,9 @@ public abstract class EditTextValidator<TModel extends Serializable> extends Val
|
|||
/**
|
||||
* Validates text with primary and final check consequentially and returns {@link Observable} with {@link HalfNullablePair} of final state
|
||||
* and resulting model.
|
||||
*
|
||||
* @param text - input text.
|
||||
* @return pair with final {@link ValidationState} that is always not null and a model that we get after converting the text.
|
||||
* Model can be null if validation fails on primary or final checks.
|
||||
* Model can be null if validation fails on primary or final checks.
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -12,14 +12,12 @@ import rx.Observable;
|
|||
/**
|
||||
* Created by Ilia Kurtov on 24/01/2017.
|
||||
* Class that simplifies work with {@link Validator}'s that have the same wrapper model and model type.
|
||||
*
|
||||
* @param <TModel> model that should be bounded with a view.
|
||||
*/
|
||||
public class SameTypeValidator<TModel extends Serializable> extends Validator<TModel, TModel> {
|
||||
|
||||
/**
|
||||
* Simply returns the same model without any converting.
|
||||
*
|
||||
* @param wrapperModel input model.
|
||||
* @return the same model as input parameter.
|
||||
* @throws Throwable - in this case no throwable would be thrown.
|
||||
|
|
@ -33,10 +31,9 @@ public class SameTypeValidator<TModel extends Serializable> extends Validator<TM
|
|||
|
||||
/**
|
||||
* Validates {@link TModel} and returns {@link Observable} with {@link HalfNullablePair} of final state and resulting model.
|
||||
*
|
||||
* @param wrapperModel - not null value that should be validated.
|
||||
* @return pair with final {@link ValidationState} that is always not null and a model that we get after converting the {@link TModel}.
|
||||
* Model can be null if validation fails.
|
||||
* Model can be null if validation fails.
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ public abstract class Validator<TWrapperModel extends Serializable, TModel exten
|
|||
|
||||
/**
|
||||
* This method converts {@link TWrapperModel} into a {@link TModel}.
|
||||
*
|
||||
* @param wrapperModel - not null value that should be converted into a {@link TModel} object.
|
||||
* @return converted wrapperModel into a {@link TModel}.
|
||||
* @throws Throwable for the cases when converting cannot be processed.
|
||||
|
|
@ -64,7 +63,6 @@ public abstract class Validator<TWrapperModel extends Serializable, TModel exten
|
|||
|
||||
/**
|
||||
* Call this method to get {@link Changeable} with {@link TWrapperModel} inside it that should be connected to its bounded view.
|
||||
*
|
||||
* @return {@link Changeable} with {@link TWrapperModel}.
|
||||
*/
|
||||
@NonNull
|
||||
|
|
@ -74,7 +72,6 @@ public abstract class Validator<TWrapperModel extends Serializable, TModel exten
|
|||
|
||||
/**
|
||||
* Returns current {@link ValidationState} or its successor. Needed to connect with bounded view and react to this state changes.
|
||||
*
|
||||
* @return current validation state.
|
||||
*/
|
||||
@NonNull
|
||||
|
|
@ -85,7 +82,6 @@ public abstract class Validator<TWrapperModel extends Serializable, TModel exten
|
|||
/**
|
||||
* This method needed to get {@link ValidationState} that needed to be shown when bounded view is empty and you need to show to user reminder,
|
||||
* that he or she needs to fill this view.
|
||||
*
|
||||
* @return {@link ValidationState} that should be shown for an empty field.
|
||||
*/
|
||||
@NonNull
|
||||
|
|
@ -95,10 +91,9 @@ public abstract class Validator<TWrapperModel extends Serializable, TModel exten
|
|||
|
||||
/**
|
||||
* Validates {@link TWrapperModel} and returns {@link Observable} with {@link HalfNullablePair} of final state and resulting model.
|
||||
*
|
||||
* @param wrapperModel - not null value that should be validated.
|
||||
* @return pair with final {@link ValidationState} that is always not null and a model that we get after converting the {@link TWrapperModel}.
|
||||
* Model can be null if validation fails.
|
||||
* Model can be null if validation fails.
|
||||
*/
|
||||
@NonNull
|
||||
public abstract Observable<HalfNullablePair<ValidationState, TModel>> fullValidateAndGetModel(@NonNull final TWrapperModel wrapperModel);
|
||||
|
|
|
|||
Loading…
Reference in New Issue