Initial commit
commit
a9d1051aa8
|
@ -0,0 +1,9 @@
|
||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CompilerConfiguration">
|
||||||
|
<resourceExtensions />
|
||||||
|
<wildcardResourcePatterns>
|
||||||
|
<entry name="!?*.java" />
|
||||||
|
<entry name="!?*.form" />
|
||||||
|
<entry name="!?*.class" />
|
||||||
|
<entry name="!?*.groovy" />
|
||||||
|
<entry name="!?*.scala" />
|
||||||
|
<entry name="!?*.flex" />
|
||||||
|
<entry name="!?*.kt" />
|
||||||
|
<entry name="!?*.clj" />
|
||||||
|
<entry name="!?*.aj" />
|
||||||
|
</wildcardResourcePatterns>
|
||||||
|
<annotationProcessing>
|
||||||
|
<profile default="true" name="Default" enabled="false">
|
||||||
|
<processorPath useClasspath="true" />
|
||||||
|
</profile>
|
||||||
|
</annotationProcessing>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<component name="CopyrightManager">
|
||||||
|
<settings default="" />
|
||||||
|
</component>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<component name="ProjectDictionaryState">
|
||||||
|
<dictionary name="ensar" />
|
||||||
|
</component>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding">
|
||||||
|
<file url="PROJECT" charset="UTF-8" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="GradleSettings">
|
||||||
|
<option name="linkedExternalProjectsSettings">
|
||||||
|
<GradleProjectSettings>
|
||||||
|
<option name="distributionType" value="LOCAL" />
|
||||||
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="gradleHome" value="$APPLICATION_HOME_DIR$/gradle/gradle-2.14.1" />
|
||||||
|
<option name="modules">
|
||||||
|
<set>
|
||||||
|
<option value="$PROJECT_DIR$" />
|
||||||
|
<option value="$PROJECT_DIR$/app" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
<option name="resolveModulePerSourceSet" value="false" />
|
||||||
|
</GradleProjectSettings>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="EntryPointsManager">
|
||||||
|
<entry_points version="2.0" />
|
||||||
|
</component>
|
||||||
|
<component name="MavenImportPreferences">
|
||||||
|
<option name="generalSettings">
|
||||||
|
<MavenGeneralSettings>
|
||||||
|
<option name="mavenHome" value="Bundled (Maven 3)" />
|
||||||
|
</MavenGeneralSettings>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="NullableNotNullManager">
|
||||||
|
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
|
||||||
|
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
|
||||||
|
<option name="myNullables">
|
||||||
|
<value>
|
||||||
|
<list size="4">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
|
||||||
|
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
|
||||||
|
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
<option name="myNotNulls">
|
||||||
|
<value>
|
||||||
|
<list size="4">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
|
||||||
|
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
|
||||||
|
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
|
||||||
|
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectInspectionProfilesVisibleTreeState">
|
||||||
|
<entry key="Project Default">
|
||||||
|
<profile-state>
|
||||||
|
<expanded-state>
|
||||||
|
<State>
|
||||||
|
<id />
|
||||||
|
</State>
|
||||||
|
</expanded-state>
|
||||||
|
<selected-state>
|
||||||
|
<State>
|
||||||
|
<id>Android</id>
|
||||||
|
</State>
|
||||||
|
</selected-state>
|
||||||
|
</profile-state>
|
||||||
|
</entry>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||||
|
<OptionsSetting value="true" id="Add" />
|
||||||
|
<OptionsSetting value="true" id="Remove" />
|
||||||
|
<OptionsSetting value="true" id="Checkout" />
|
||||||
|
<OptionsSetting value="true" id="Update" />
|
||||||
|
<OptionsSetting value="true" id="Status" />
|
||||||
|
<OptionsSetting value="true" id="Edit" />
|
||||||
|
<ConfirmationsSetting value="0" id="Add" />
|
||||||
|
<ConfirmationsSetting value="0" id="Remove" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectType">
|
||||||
|
<option name="id" value="Android" />
|
||||||
|
</component>
|
||||||
|
<component name="masterDetails">
|
||||||
|
<states>
|
||||||
|
<state key="ProjectJDKs.UI">
|
||||||
|
<settings>
|
||||||
|
<last-edited>1.7</last-edited>
|
||||||
|
<splitter-proportions>
|
||||||
|
<option name="proportions">
|
||||||
|
<list>
|
||||||
|
<option value="0.2" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</splitter-proportions>
|
||||||
|
</settings>
|
||||||
|
</state>
|
||||||
|
<state key="ScopeChooserConfigurable.UI">
|
||||||
|
<settings>
|
||||||
|
<splitter-proportions>
|
||||||
|
<option name="proportions">
|
||||||
|
<list>
|
||||||
|
<option value="0.2" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</splitter-proportions>
|
||||||
|
</settings>
|
||||||
|
</state>
|
||||||
|
</states>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/RealTimeTalk.iml" filepath="$PROJECT_DIR$/RealTimeTalk.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RunConfigurationProducerService">
|
||||||
|
<option name="ignoredProducers">
|
||||||
|
<set>
|
||||||
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||||
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||||
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||||
|
</set>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1 @@
|
||||||
|
/build
|
|
@ -0,0 +1,44 @@
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 24
|
||||||
|
buildToolsVersion "24.0.3"
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "com.smarthomies.realtimetalk"
|
||||||
|
minSdkVersion 16
|
||||||
|
targetSdkVersion 24
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataBinding {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||||
|
exclude group: 'com.android.support', module: 'support-annotations'
|
||||||
|
})
|
||||||
|
compile 'com.android.support:appcompat-v7:24.2.1'
|
||||||
|
compile 'com.android.support:design:24.2.1'
|
||||||
|
compile 'com.google.code.gson:gson:2.8.0'
|
||||||
|
compile 'com.squareup.retrofit2:retrofit:2.1.0'
|
||||||
|
compile 'com.squareup.okhttp:okhttp:2.6.0'
|
||||||
|
compile 'com.squareup.okhttp:okhttp-urlconnection:2.6.0'
|
||||||
|
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
|
||||||
|
compile 'com.jakewharton.rxbinding:rxbinding:0.4.0'
|
||||||
|
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
|
||||||
|
compile 'io.reactivex:rxandroid:1.2.1'
|
||||||
|
compile 'io.reactivex:rxjava:1.2.0'
|
||||||
|
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
|
||||||
|
compile 'com.squareup.picasso:picasso:2.5.2'
|
||||||
|
testCompile 'junit:junit:4.12'
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# By default, the flags in this file are appended to flags specified
|
||||||
|
# in /Users/ensar/Library/Android/sdk/tools/proguard/proguard-android.txt
|
||||||
|
# You can edit the include path and order by changing the proguardFiles
|
||||||
|
# directive in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# Add any project specific keep options here:
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.smarthomies.realtimetalk;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.support.test.InstrumentationRegistry;
|
||||||
|
import android.support.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumentation test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
public void useAppContext() throws Exception {
|
||||||
|
// Context of the app under test.
|
||||||
|
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||||
|
|
||||||
|
assertEquals("com.smarthomies.realtimetalk", appContext.getPackageName());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.smarthomies.realtimetalk">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:name=".RTTApp"
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
<activity
|
||||||
|
android:name=".views.activities.LoginActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar"
|
||||||
|
android:windowSoftInputMode="adjustPan">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:name=".views.activities.MainActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar"/>
|
||||||
|
<activity
|
||||||
|
android:name=".views.activities.SearchActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar"
|
||||||
|
android:parentActivityName=".views.activities.MainActivity"/>
|
||||||
|
<activity android:name=".views.activities.RegistrationActivity"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar"/>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
|
@ -0,0 +1,98 @@
|
||||||
|
package com.smarthomies.realtimetalk;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.FragmentManager;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.utils.NavigationSubject;
|
||||||
|
|
||||||
|
import rx.functions.Action1;
|
||||||
|
import rx.subscriptions.CompositeSubscription;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 23/10/16.
|
||||||
|
*/
|
||||||
|
public abstract class RTTActivity extends AppCompatActivity {
|
||||||
|
public static final String TAG = RTTActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
public static final String EXTRA_BUNDLE = "EXTRA_BUNDLE";
|
||||||
|
|
||||||
|
private CompositeSubscription compositeSubscription;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
compositeSubscription = new CompositeSubscription();
|
||||||
|
compositeSubscription.add(NavigationSubject.getInstance().subscribe(new Action1<Pair<Class<? extends RTTActivity>, Bundle>>() {
|
||||||
|
@Override
|
||||||
|
public void call(Pair<Class<? extends RTTActivity>, Bundle> classBundlePair) {
|
||||||
|
if(classBundlePair == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Class activity = classBundlePair.first;
|
||||||
|
Bundle bundle = classBundlePair.second;
|
||||||
|
Intent intent = new Intent(RTTActivity.this, activity);
|
||||||
|
intent.putExtra(EXTRA_BUNDLE, bundle);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
compositeSubscription.add(NavigationSubject.getFragmentNavigationInstance().subscribe(new Action1<Pair<Class<? extends RTTFragment>, Bundle>>() {
|
||||||
|
@Override
|
||||||
|
public void call(Pair<Class<? extends RTTFragment>, Bundle> classBundlePair) {
|
||||||
|
RTTActivity.this.startFragment(classBundlePair.first, RTTActivity.this.getFragmentContainerRId(),classBundlePair.second);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
subscribeToSubjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
if (compositeSubscription != null && !compositeSubscription.isUnsubscribed()) {
|
||||||
|
compositeSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
unsubscribeFromSubjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void subscribeToSubjects() {}
|
||||||
|
|
||||||
|
protected void unsubscribeFromSubjects() {}
|
||||||
|
|
||||||
|
protected int getFragmentContainerRId() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startFragment(Class<? extends RTTFragment> fragmentClass, int containerId, Bundle bundle) {
|
||||||
|
String fragmentName = fragmentClass.getCanonicalName();
|
||||||
|
RTTFragment fragment;
|
||||||
|
|
||||||
|
try {
|
||||||
|
FragmentManager fm = getSupportFragmentManager();
|
||||||
|
|
||||||
|
// Find fragment by name
|
||||||
|
fragment = (RTTFragment) fm.findFragmentByTag(fragmentName);
|
||||||
|
|
||||||
|
if(fragment == null) {
|
||||||
|
// Create new fragment
|
||||||
|
fragment = fragmentClass.newInstance();
|
||||||
|
|
||||||
|
// Check for bundle
|
||||||
|
if (bundle != null) {
|
||||||
|
fragment.setArguments(bundle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fm.beginTransaction().replace(containerId, fragment, fragmentName).commit();
|
||||||
|
fm.executePendingTransactions();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Error starting fragment : " + fragmentName, e);
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.smarthomies.realtimetalk;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.utils.RTTAppHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 31/10/16.
|
||||||
|
*/
|
||||||
|
public class RTTApp extends Application {
|
||||||
|
public static final String TAG = RTTApp.class.getSimpleName();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
|
||||||
|
RTTAppHelper.getInstance().initWithContext(getApplicationContext());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.smarthomies.realtimetalk;
|
||||||
|
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 23/10/16.
|
||||||
|
*/
|
||||||
|
public class RTTFragment extends Fragment {
|
||||||
|
public static final String TAG = RTTFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
protected void subscribeToSubjects() {}
|
||||||
|
|
||||||
|
protected void unsubscribeFromSubjects() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
subscribeToSubjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
unsubscribeFromSubjects();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package com.smarthomies.realtimetalk.managers;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.models.db.User;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.AuthenticationResponse;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.LoginRequest;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.RegistrationRequest;
|
||||||
|
import com.smarthomies.realtimetalk.services.AuthenticationAPIService;
|
||||||
|
import com.smarthomies.realtimetalk.utils.RTTAppHelper;
|
||||||
|
|
||||||
|
import rx.Observable;
|
||||||
|
import rx.functions.Action1;
|
||||||
|
import rx.functions.Func1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 01/11/16.
|
||||||
|
*/
|
||||||
|
public class AuthenticationManager {
|
||||||
|
public static final String TAG = AuthenticationManager.class.getSimpleName();
|
||||||
|
|
||||||
|
public Observable<AuthenticationResponse> loginUser(String username, String password) {
|
||||||
|
return AuthenticationAPIService.getInstance().login(getLoginRequest(username, password)).doOnNext(processAuthenticationResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<AuthenticationResponse> registerUser(User user, final String username, final String password) {
|
||||||
|
RegistrationRequest registrationRequest = getRegistrationRequest(user, username, password);
|
||||||
|
return AuthenticationAPIService.getInstance().register(registrationRequest)
|
||||||
|
.flatMap(new Func1<AuthenticationResponse, Observable<LoginRequest>>() {
|
||||||
|
@Override
|
||||||
|
public Observable<LoginRequest> call(AuthenticationResponse authenticationResponse) {
|
||||||
|
return Observable.just(getLoginRequest(username, password));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.flatMap(requestLogin).doOnNext(processAuthenticationResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Func1<LoginRequest, Observable<AuthenticationResponse>> requestLogin = new Func1<LoginRequest, Observable<AuthenticationResponse>>() {
|
||||||
|
@Override
|
||||||
|
public Observable<AuthenticationResponse> call(LoginRequest request) {
|
||||||
|
return AuthenticationAPIService.getInstance().login(request);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Action1<AuthenticationResponse> processAuthenticationResponse = new Action1<AuthenticationResponse>() {
|
||||||
|
@Override
|
||||||
|
public void call(AuthenticationResponse authenticationResponse) {
|
||||||
|
RTTAppHelper.getInstance().saveToken(authenticationResponse.getToken());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private RegistrationRequest getRegistrationRequest(User user, String username, String password) {
|
||||||
|
RegistrationRequest registrationRequest = new RegistrationRequest();
|
||||||
|
registrationRequest.setUsername(username);
|
||||||
|
registrationRequest.setPassword(password);
|
||||||
|
registrationRequest.setEmail(user.getEmail());
|
||||||
|
registrationRequest.setFirstName(user.getFirstName());
|
||||||
|
registrationRequest.setLastName(user.getLastName());
|
||||||
|
return registrationRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoginRequest getLoginRequest(String username, String password) {
|
||||||
|
return new LoginRequest(username, password);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.smarthomies.realtimetalk.managers;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.models.network.SearchRequest;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.UsersResponse;
|
||||||
|
import com.smarthomies.realtimetalk.services.ContactsAPIService;
|
||||||
|
|
||||||
|
import rx.Observable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 01/11/16.
|
||||||
|
*/
|
||||||
|
public class ContactsManager {
|
||||||
|
public static final String TAG = ContactsManager.class.getSimpleName();
|
||||||
|
|
||||||
|
public Observable<UsersResponse> searchForUsers(String searchString) {
|
||||||
|
return ContactsAPIService.getInstance().search(getSearchRequest(searchString));
|
||||||
|
}
|
||||||
|
|
||||||
|
private SearchRequest getSearchRequest(String searchString) {
|
||||||
|
SearchRequest searchRequest = new SearchRequest();
|
||||||
|
searchRequest.setSearch(searchString);
|
||||||
|
return searchRequest;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package com.smarthomies.realtimetalk.models.db;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 01/11/16.
|
||||||
|
*/
|
||||||
|
public class User{
|
||||||
|
public static final String TAG = User.class.getSimpleName();
|
||||||
|
|
||||||
|
@SerializedName("first_name")
|
||||||
|
private String firstName;
|
||||||
|
@SerializedName("last_name")
|
||||||
|
private String lastName;
|
||||||
|
@SerializedName("email")
|
||||||
|
private String email;
|
||||||
|
@SerializedName("profile_picture")
|
||||||
|
private String imageUrl;
|
||||||
|
|
||||||
|
public String getFirstName() {
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstName(String firstName) {
|
||||||
|
this.firstName = firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastName() {
|
||||||
|
return lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastName(String lastName) {
|
||||||
|
this.lastName = lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getImageUrl() {
|
||||||
|
return imageUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setImageUrl(String imageUrl) {
|
||||||
|
this.imageUrl = imageUrl;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.smarthomies.realtimetalk.models.network;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 31/10/16.
|
||||||
|
*/
|
||||||
|
public class AuthenticationResponse {
|
||||||
|
public static final String TAG = AuthenticationResponse.class.getSimpleName();
|
||||||
|
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.smarthomies.realtimetalk.models.network;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 31/10/16.
|
||||||
|
*/
|
||||||
|
public class LoginRequest {
|
||||||
|
public static final String TAG = LoginRequest.class.getSimpleName();
|
||||||
|
|
||||||
|
public LoginRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoginRequest(String username, String password) {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package com.smarthomies.realtimetalk.models.network;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 31/10/16.
|
||||||
|
*/
|
||||||
|
public class RegistrationRequest {
|
||||||
|
public static final String TAG = RegistrationRequest.class.getSimpleName();
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
private String email;
|
||||||
|
private String firstName;
|
||||||
|
private String lastName;
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFirstName() {
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstName(String firstName) {
|
||||||
|
this.firstName = firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastName() {
|
||||||
|
return lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastName(String lastName) {
|
||||||
|
this.lastName = lastName;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.smarthomies.realtimetalk.models.network;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 06/12/16.
|
||||||
|
*/
|
||||||
|
public class SearchRequest {
|
||||||
|
public static final String TAG = SearchRequest.class.getSimpleName();
|
||||||
|
|
||||||
|
private String search;
|
||||||
|
|
||||||
|
public String getSearch() {
|
||||||
|
return search;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearch(String search) {
|
||||||
|
this.search = search;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.smarthomies.realtimetalk.models.network;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.models.db.User;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 06/12/16.
|
||||||
|
*/
|
||||||
|
public class UsersResponse {
|
||||||
|
public static final String TAG = UsersResponse.class.getSimpleName();
|
||||||
|
|
||||||
|
private List<User> data;
|
||||||
|
|
||||||
|
public List<User> getData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(List<User> data) {
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.smarthomies.realtimetalk.network;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.APIException;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.BadAPIRequestException;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.NetworkException;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.RemoteResourceNotFoundException;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.ResourceForbiddenException;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.UnauthorizedException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
|
||||||
|
import retrofit2.adapter.rxjava.HttpException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 31/10/16.
|
||||||
|
*/
|
||||||
|
public class APIErrorHandler {
|
||||||
|
public static final String TAG = APIErrorHandler.class.getSimpleName();
|
||||||
|
|
||||||
|
public static void handleGeneralAPIErrors(Throwable throwable)
|
||||||
|
throws APIException {
|
||||||
|
if(throwable instanceof HttpException) {
|
||||||
|
HttpException httpException = ((HttpException)throwable);
|
||||||
|
switch (httpException.response().code()) {
|
||||||
|
case HttpURLConnection.HTTP_BAD_REQUEST:
|
||||||
|
throw new BadAPIRequestException(throwable);
|
||||||
|
case HttpURLConnection.HTTP_NOT_FOUND:
|
||||||
|
throw new RemoteResourceNotFoundException(throwable);
|
||||||
|
case HttpURLConnection.HTTP_FORBIDDEN:
|
||||||
|
throw new ResourceForbiddenException(throwable);
|
||||||
|
case HttpURLConnection.HTTP_UNAUTHORIZED:
|
||||||
|
throw new UnauthorizedException(throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(throwable instanceof IOException) {
|
||||||
|
throw new NetworkException(throwable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void handleLoginErrors(Throwable throwable)
|
||||||
|
throws APIException {
|
||||||
|
handleGeneralAPIErrors(throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void handleRegistrationErrors(Throwable throwable)
|
||||||
|
throws APIException {
|
||||||
|
handleGeneralAPIErrors(throwable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void handleSearchErrors(Throwable throwable)
|
||||||
|
throws APIException {
|
||||||
|
handleGeneralAPIErrors(throwable);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.smarthomies.realtimetalk.network;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.models.network.AuthenticationResponse;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.LoginRequest;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.RegistrationRequest;
|
||||||
|
|
||||||
|
import retrofit2.http.Body;
|
||||||
|
import retrofit2.http.POST;
|
||||||
|
import retrofit2.http.PUT;
|
||||||
|
import rx.Observable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 31/10/16.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface AuthenticationAPI {
|
||||||
|
|
||||||
|
@POST(NetworkingConstants.API_LOGIN_ENDPOINT)
|
||||||
|
Observable<AuthenticationResponse> login(@Body LoginRequest request);
|
||||||
|
|
||||||
|
@PUT(NetworkingConstants.API_REGISTRATION_ENDPOINT)
|
||||||
|
Observable<AuthenticationResponse> register(@Body RegistrationRequest request);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.smarthomies.realtimetalk.network;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.models.network.SearchRequest;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.UsersResponse;
|
||||||
|
|
||||||
|
import retrofit2.http.Body;
|
||||||
|
import retrofit2.http.GET;
|
||||||
|
import retrofit2.http.POST;
|
||||||
|
import rx.Observable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 15/11/16.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface ContactsAPI {
|
||||||
|
|
||||||
|
@POST(NetworkingConstants.API_SEARCH_ENDPOINT)
|
||||||
|
Observable<UsersResponse> searchUsers(@Body SearchRequest searchRequest);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.smarthomies.realtimetalk.network;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 31/10/16.
|
||||||
|
*/
|
||||||
|
public class NetworkingConstants {
|
||||||
|
public static final String TAG = NetworkingConstants.class.getSimpleName();
|
||||||
|
|
||||||
|
public static final String API_BASE_URL = "https://realtimetalk.herokuapp.com/rest/";
|
||||||
|
public static final String API_LOGIN_ENDPOINT = "prijava";
|
||||||
|
public static final String API_REGISTRATION_ENDPOINT = "dodaj";
|
||||||
|
public static final String API_CONTACTS_ENDPOINT = "contacts";
|
||||||
|
public static final String API_SEARCH_ENDPOINT = "search";
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package com.smarthomies.realtimetalk.network;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 31/10/16.
|
||||||
|
*/
|
||||||
|
public class RestClient {
|
||||||
|
public static final String TAG = RestClient.class.getSimpleName();
|
||||||
|
|
||||||
|
private static RestClient instance;
|
||||||
|
|
||||||
|
private Retrofit retrofit;
|
||||||
|
private AuthenticationAPI authenticationAPI;
|
||||||
|
private ContactsAPI contactsAPI;
|
||||||
|
|
||||||
|
private RestClient() {
|
||||||
|
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
|
||||||
|
// set your desired log level
|
||||||
|
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||||
|
|
||||||
|
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
|
||||||
|
// add your other interceptors …
|
||||||
|
|
||||||
|
// add logging as last interceptor
|
||||||
|
httpClient.addInterceptor(logging); // <-- this is the important line!
|
||||||
|
|
||||||
|
retrofit = new Retrofit.Builder()
|
||||||
|
.baseUrl(NetworkingConstants.API_BASE_URL)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||||
|
.client(httpClient.build())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RestClient getInstance() {
|
||||||
|
if(instance == null) {
|
||||||
|
instance = new RestClient();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthenticationAPI getAuthenticationAPI() {
|
||||||
|
if(authenticationAPI == null) {
|
||||||
|
authenticationAPI = retrofit.create(AuthenticationAPI.class);
|
||||||
|
}
|
||||||
|
return authenticationAPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactsAPI getContactsAPI() {
|
||||||
|
if(contactsAPI == null) {
|
||||||
|
contactsAPI = retrofit.create(ContactsAPI.class);
|
||||||
|
}
|
||||||
|
return contactsAPI;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.smarthomies.realtimetalk.network.exceptions;
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 01/11/16.
|
||||||
|
*/
|
||||||
|
public class APIException extends Exception {
|
||||||
|
public static final String TAG = APIException.class.getSimpleName();
|
||||||
|
|
||||||
|
public APIException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public APIException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.smarthomies.realtimetalk.network.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 01/11/16.
|
||||||
|
*/
|
||||||
|
public class BadAPIRequestException extends APIException {
|
||||||
|
public static final String TAG = BadAPIRequestException.class.getSimpleName();
|
||||||
|
|
||||||
|
public BadAPIRequestException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public BadAPIRequestException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.smarthomies.realtimetalk.network.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 01/11/16.
|
||||||
|
*/
|
||||||
|
public class NetworkException extends APIException {
|
||||||
|
public static final String TAG = NetworkException.class.getSimpleName();
|
||||||
|
|
||||||
|
public NetworkException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public NetworkException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.smarthomies.realtimetalk.network.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 01/11/16.
|
||||||
|
*/
|
||||||
|
public class RemoteResourceNotFoundException extends APIException {
|
||||||
|
public static final String TAG = RemoteResourceNotFoundException.class.getSimpleName();
|
||||||
|
|
||||||
|
public RemoteResourceNotFoundException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RemoteResourceNotFoundException() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.smarthomies.realtimetalk.network.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 01/11/16.
|
||||||
|
*/
|
||||||
|
public class ResourceForbiddenException extends APIException {
|
||||||
|
public static final String TAG = ResourceForbiddenException.class.getSimpleName();
|
||||||
|
|
||||||
|
public ResourceForbiddenException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceForbiddenException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.smarthomies.realtimetalk.network.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 14/11/16.
|
||||||
|
*/
|
||||||
|
public class UnauthorizedException extends APIException {
|
||||||
|
public static final String TAG = UnauthorizedException.class.getSimpleName();
|
||||||
|
|
||||||
|
public UnauthorizedException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnauthorizedException() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package com.smarthomies.realtimetalk.services;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.models.network.AuthenticationResponse;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.LoginRequest;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.RegistrationRequest;
|
||||||
|
import com.smarthomies.realtimetalk.network.APIErrorHandler;
|
||||||
|
import com.smarthomies.realtimetalk.network.RestClient;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.APIException;
|
||||||
|
|
||||||
|
import rx.Observable;
|
||||||
|
import rx.exceptions.Exceptions;
|
||||||
|
import rx.functions.Action1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 31/10/16.
|
||||||
|
*/
|
||||||
|
public class AuthenticationAPIService {
|
||||||
|
public static final String TAG = AuthenticationAPIService.class.getSimpleName();
|
||||||
|
|
||||||
|
private static AuthenticationAPIService instance;
|
||||||
|
|
||||||
|
private AuthenticationAPIService() {}
|
||||||
|
|
||||||
|
public static AuthenticationAPIService getInstance() {
|
||||||
|
if(instance == null) {
|
||||||
|
instance = new AuthenticationAPIService();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<AuthenticationResponse> login(LoginRequest request) {
|
||||||
|
return RestClient.getInstance().getAuthenticationAPI().login(request)
|
||||||
|
.doOnError(handleLoginErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<AuthenticationResponse> register(RegistrationRequest request) {
|
||||||
|
return RestClient.getInstance().getAuthenticationAPI().register(request)
|
||||||
|
.doOnError(handleRegistrationErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Action1<Throwable> handleLoginErrors = new Action1<Throwable>() {
|
||||||
|
@Override
|
||||||
|
public void call(Throwable throwable) {
|
||||||
|
try {
|
||||||
|
APIErrorHandler.handleLoginErrors(throwable);
|
||||||
|
} catch (APIException apiException) {
|
||||||
|
throw Exceptions.propagate(apiException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Action1<Throwable> handleRegistrationErrors = new Action1<Throwable>() {
|
||||||
|
@Override
|
||||||
|
public void call(Throwable throwable) {
|
||||||
|
try {
|
||||||
|
APIErrorHandler.handleRegistrationErrors(throwable);
|
||||||
|
} catch (APIException apiException) {
|
||||||
|
throw Exceptions.propagate(apiException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.smarthomies.realtimetalk.services;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.models.network.SearchRequest;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.UsersResponse;
|
||||||
|
import com.smarthomies.realtimetalk.network.APIErrorHandler;
|
||||||
|
import com.smarthomies.realtimetalk.network.RestClient;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.APIException;
|
||||||
|
|
||||||
|
import rx.Observable;
|
||||||
|
import rx.exceptions.Exceptions;
|
||||||
|
import rx.functions.Action1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 31/10/16.
|
||||||
|
*/
|
||||||
|
public class ContactsAPIService {
|
||||||
|
public static final String TAG = ContactsAPIService.class.getSimpleName();
|
||||||
|
|
||||||
|
private static ContactsAPIService instance;
|
||||||
|
|
||||||
|
private ContactsAPIService() {}
|
||||||
|
|
||||||
|
public static ContactsAPIService getInstance() {
|
||||||
|
if(instance == null) {
|
||||||
|
instance = new ContactsAPIService();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Observable<UsersResponse> search(SearchRequest request) {
|
||||||
|
return RestClient.getInstance().getContactsAPI().searchUsers(request)
|
||||||
|
.doOnError(handleSearchErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Action1<Throwable> handleSearchErrors = new Action1<Throwable>() {
|
||||||
|
@Override
|
||||||
|
public void call(Throwable throwable) {
|
||||||
|
try {
|
||||||
|
APIErrorHandler.handleSearchErrors(throwable);
|
||||||
|
} catch (APIException apiException) {
|
||||||
|
throw Exceptions.propagate(apiException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.smarthomies.realtimetalk.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.RTTActivity;
|
||||||
|
import com.smarthomies.realtimetalk.RTTFragment;
|
||||||
|
|
||||||
|
import rx.subjects.PublishSubject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 04/11/16.
|
||||||
|
*/
|
||||||
|
public class NavigationSubject {
|
||||||
|
public static final String TAG = NavigationSubject.class.getSimpleName();
|
||||||
|
|
||||||
|
private static PublishSubject<Pair<Class<? extends RTTActivity>, Bundle>> navigationSubject = PublishSubject.create();
|
||||||
|
private static PublishSubject<Pair<Class<? extends RTTFragment>, Bundle>> fragmentNavigationSubject = PublishSubject.create();
|
||||||
|
|
||||||
|
public static PublishSubject<Pair<Class<? extends RTTActivity>, Bundle>> getInstance() {
|
||||||
|
return navigationSubject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PublishSubject<Pair<Class<? extends RTTFragment>, Bundle>> getFragmentNavigationInstance() {
|
||||||
|
return fragmentNavigationSubject;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package com.smarthomies.realtimetalk.utils;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 31/10/16.
|
||||||
|
*/
|
||||||
|
public class RTTAppHelper {
|
||||||
|
public static final String TAG = RTTAppHelper.class.getSimpleName();
|
||||||
|
|
||||||
|
public static final String SHARED_PREFERENCES_USER_TOKEN = "SHARED_PREFERENCES_USER_TOKEN";
|
||||||
|
|
||||||
|
private static RTTAppHelper instance;
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
private RTTAppHelper() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RTTAppHelper getInstance() {
|
||||||
|
if(instance == null) {
|
||||||
|
instance = new RTTAppHelper();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initWithContext(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveToken(String token) {
|
||||||
|
writeToSharedPrefs(SHARED_PREFERENCES_USER_TOKEN, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return readFromSharedPrefs(SHARED_PREFERENCES_USER_TOKEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeToSharedPrefs(String key, String value) {
|
||||||
|
SharedPreferences.Editor editor = context.getSharedPreferences(TAG, Context.MODE_PRIVATE).edit();
|
||||||
|
editor.putString(key, value);
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readFromSharedPrefs(String key) {
|
||||||
|
return readFromSharedPrefs(key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readFromSharedPrefs(String key, String defaultValue) {
|
||||||
|
SharedPreferences sharedPreferences = context.getSharedPreferences(TAG, Context.MODE_PRIVATE);
|
||||||
|
return sharedPreferences.getString(key, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.smarthomies.realtimetalk.utils;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.BadAPIRequestException;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.NetworkException;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.RemoteResourceNotFoundException;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.ResourceForbiddenException;
|
||||||
|
import com.smarthomies.realtimetalk.network.exceptions.UnauthorizedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 14/11/16.
|
||||||
|
*/
|
||||||
|
public class RTTErrorUtil {
|
||||||
|
public static final String TAG = RTTErrorUtil.class.getSimpleName();
|
||||||
|
|
||||||
|
public static int getErrorString(Throwable e) {
|
||||||
|
if (e instanceof BadAPIRequestException) {
|
||||||
|
return R.string.error_bad_request;
|
||||||
|
} else if (e instanceof RemoteResourceNotFoundException) {
|
||||||
|
return R.string.error_user_not_found;
|
||||||
|
} else if (e instanceof ResourceForbiddenException) {
|
||||||
|
return R.string.error_unknown;
|
||||||
|
} else if (e instanceof UnauthorizedException) {
|
||||||
|
return R.string.error_user_bad_credentials;
|
||||||
|
} else if (e instanceof NetworkException) {
|
||||||
|
return R.string.error_no_internet;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
package com.smarthomies.realtimetalk.utils;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.util.Patterns;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 03/11/16.
|
||||||
|
*/
|
||||||
|
public class RTTUtil {
|
||||||
|
public static final String TAG = RTTUtil.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final Pattern hasUppercase = Pattern.compile("\\p{javaUpperCase}");
|
||||||
|
private static final Pattern hasLowercase = Pattern.compile("\\p{javaLowerCase}");
|
||||||
|
private static final Pattern hasNumber = Pattern.compile("\\p{javaDigit}");
|
||||||
|
private static final Pattern hasSpecialChar = Pattern.compile("\\p{javaLetterOrDigit}");
|
||||||
|
|
||||||
|
public static final int PASSWORD_MINIMUM_LENGTH = 6;
|
||||||
|
public static final int PASSWORD_MAXIMUM_LENGTH = 20;
|
||||||
|
|
||||||
|
public static boolean isPasswordValid(String password) {
|
||||||
|
if (TextUtils.isEmpty(password)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.length() < 6 || password.length() > 20) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasUppercase = RTTUtil.hasUppercase.matcher(password).matches();
|
||||||
|
boolean hasLowercase = RTTUtil.hasLowercase.matcher(password).matches();
|
||||||
|
boolean hasNumber = RTTUtil.hasNumber.matcher(password).matches();
|
||||||
|
boolean hasSpecialChar = RTTUtil.hasSpecialChar.matcher(password).matches();
|
||||||
|
|
||||||
|
if (!hasNumber || !(hasUppercase || hasLowercase)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getRequiredFieldError(String value) {
|
||||||
|
if (TextUtils.isEmpty(value)) {
|
||||||
|
return R.string.error_required;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getPasswordError(String password) {
|
||||||
|
if (TextUtils.isEmpty(password)) {
|
||||||
|
return R.string.error_required;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password.length() < 6 || password.length() > 20) {
|
||||||
|
return R.string.error_password_short;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
boolean hasUppercase = RTTUtil.hasUppercase.matcher(password).matches();
|
||||||
|
boolean hasLowercase = RTTUtil.hasLowercase.matcher(password).matches();
|
||||||
|
boolean hasNumber = RTTUtil.hasNumber.matcher(password).matches();
|
||||||
|
boolean hasSpecialChar = RTTUtil.hasSpecialChar.matcher(password).matches();
|
||||||
|
|
||||||
|
// if (!hasNumber || !(hasUppercase || hasLowercase)) {
|
||||||
|
// return R.string.error_password_invalid;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getPasswordConfirmationError(String password, String passwordConfirmation) {
|
||||||
|
int confirmationError = getPasswordError(passwordConfirmation);
|
||||||
|
|
||||||
|
if(confirmationError == 0 && !passwordConfirmation.equalsIgnoreCase(password)) {
|
||||||
|
return R.string.error_password_confirmation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return confirmationError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEmailValid(String email) {
|
||||||
|
Pattern emailPattern = Patterns.EMAIL_ADDRESS;
|
||||||
|
return emailPattern.matcher(email).matches();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
package com.smarthomies.realtimetalk.viewmodels;
|
||||||
|
|
||||||
|
import android.databinding.BaseObservable;
|
||||||
|
import android.databinding.ObservableField;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.RTTActivity;
|
||||||
|
import com.smarthomies.realtimetalk.managers.AuthenticationManager;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.AuthenticationResponse;
|
||||||
|
import com.smarthomies.realtimetalk.utils.NavigationSubject;
|
||||||
|
import com.smarthomies.realtimetalk.utils.RTTUtil;
|
||||||
|
import com.smarthomies.realtimetalk.views.activities.MainActivity;
|
||||||
|
import com.smarthomies.realtimetalk.views.activities.RegistrationActivity;
|
||||||
|
|
||||||
|
import rx.functions.Action0;
|
||||||
|
import rx.functions.Action1;
|
||||||
|
import rx.schedulers.Schedulers;
|
||||||
|
import rx.subjects.AsyncSubject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 01/11/16.
|
||||||
|
*/
|
||||||
|
public class LoginViewModel extends BaseObservable {
|
||||||
|
public static final String TAG = LoginViewModel.class.getSimpleName();
|
||||||
|
|
||||||
|
private AsyncSubject<AuthenticationResponse> loginSubject;
|
||||||
|
|
||||||
|
private ObservableField<String> username = new ObservableField<>();
|
||||||
|
private ObservableField<Integer> usernameError = new ObservableField<>();
|
||||||
|
private ObservableField<String> password = new ObservableField<>();
|
||||||
|
private ObservableField<Integer> passwordError = new ObservableField<>();
|
||||||
|
|
||||||
|
private ObservableField<Boolean> requestInProgress = new ObservableField<>();
|
||||||
|
|
||||||
|
public LoginViewModel() {
|
||||||
|
requestInProgress.set(false);
|
||||||
|
loginSubject = AsyncSubject.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncSubject<AuthenticationResponse> createLoginSubject() {
|
||||||
|
loginSubject = AsyncSubject.create();
|
||||||
|
return loginSubject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncSubject<AuthenticationResponse> getLoginSubject() {
|
||||||
|
return loginSubject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loginUser() {
|
||||||
|
requestInProgress.set(true);
|
||||||
|
new AuthenticationManager().loginUser(username.get(), password.get()).subscribeOn(Schedulers.io()).subscribe(loginSubject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateFields() {
|
||||||
|
clearErrors();
|
||||||
|
|
||||||
|
passwordError.set(RTTUtil.getPasswordError(password.get()));
|
||||||
|
usernameError.set(RTTUtil.getRequiredFieldError(username.get()));
|
||||||
|
|
||||||
|
return passwordError.get() == 0 && usernameError.get() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearErrors() {
|
||||||
|
usernameError.set(0);
|
||||||
|
passwordError.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public View.OnClickListener onLoginClick() {
|
||||||
|
return new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
// if(validateFields()) {
|
||||||
|
// loginUser();
|
||||||
|
// }
|
||||||
|
onLoginDone();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public View.OnClickListener onRegisterClick() {
|
||||||
|
return new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
NavigationSubject.getInstance().onNext(new Pair<Class<? extends RTTActivity>, Bundle>(RegistrationActivity.class, null));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onLoginDone() {
|
||||||
|
NavigationSubject.getInstance().onNext(new Pair<Class<? extends RTTActivity>, Bundle>(MainActivity.class, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRequestCompleted() {
|
||||||
|
requestInProgress.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<String> getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(ObservableField<String> username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<Integer> getUsernameError() {
|
||||||
|
return usernameError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsernameError(ObservableField<Integer> usernameError) {
|
||||||
|
this.usernameError = usernameError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<String> getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(ObservableField<String> password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<Integer> getPasswordError() {
|
||||||
|
return passwordError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPasswordError(ObservableField<Integer> passwordError) {
|
||||||
|
this.passwordError = passwordError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<Boolean> getRequestInProgress() {
|
||||||
|
return requestInProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestInProgress(ObservableField<Boolean> requestInProgress) {
|
||||||
|
this.requestInProgress = requestInProgress;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.smarthomies.realtimetalk.viewmodels;
|
||||||
|
|
||||||
|
import android.databinding.BaseObservable;
|
||||||
|
import android.databinding.Bindable;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.RTTActivity;
|
||||||
|
import com.smarthomies.realtimetalk.models.db.User;
|
||||||
|
import com.smarthomies.realtimetalk.utils.NavigationSubject;
|
||||||
|
import com.smarthomies.realtimetalk.views.activities.MainActivity;
|
||||||
|
import com.smarthomies.realtimetalk.views.activities.SearchActivity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 15/11/16.
|
||||||
|
*/
|
||||||
|
public class MainViewModel extends BaseObservable {
|
||||||
|
public static final String TAG = MainViewModel.class.getSimpleName();
|
||||||
|
|
||||||
|
UserViewModel userViewModel;
|
||||||
|
|
||||||
|
public void setUser(User user) {
|
||||||
|
userViewModel = new UserViewModel(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public UserViewModel getUserViewModel() {
|
||||||
|
return userViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUserViewModel(UserViewModel userViewModel) {
|
||||||
|
this.userViewModel = userViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public View.OnClickListener onSearchClick() {
|
||||||
|
return new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
NavigationSubject.getInstance().onNext(new Pair<Class<? extends RTTActivity>, Bundle>(SearchActivity.class, null));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,265 @@
|
||||||
|
package com.smarthomies.realtimetalk.viewmodels;
|
||||||
|
|
||||||
|
import android.databinding.BaseObservable;
|
||||||
|
import android.databinding.ObservableField;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.RTTActivity;
|
||||||
|
import com.smarthomies.realtimetalk.RTTFragment;
|
||||||
|
import com.smarthomies.realtimetalk.managers.AuthenticationManager;
|
||||||
|
import com.smarthomies.realtimetalk.models.db.User;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.AuthenticationResponse;
|
||||||
|
import com.smarthomies.realtimetalk.utils.NavigationSubject;
|
||||||
|
import com.smarthomies.realtimetalk.utils.RTTUtil;
|
||||||
|
import com.smarthomies.realtimetalk.views.activities.MainActivity;
|
||||||
|
import com.smarthomies.realtimetalk.views.fragments.registration.PasswordRegistrationFragment;
|
||||||
|
import com.smarthomies.realtimetalk.views.fragments.registration.UserNameRegistrationFragment;
|
||||||
|
|
||||||
|
import rx.schedulers.Schedulers;
|
||||||
|
import rx.subjects.AsyncSubject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 01/11/16.
|
||||||
|
*/
|
||||||
|
public class RegistrationViewModel extends BaseObservable {
|
||||||
|
public static final String TAG = RegistrationViewModel.class.getSimpleName();
|
||||||
|
|
||||||
|
private AsyncSubject<AuthenticationResponse> registrationSubject;
|
||||||
|
|
||||||
|
private ObservableField<String> username = new ObservableField<>();
|
||||||
|
private ObservableField<String> firstName = new ObservableField<>();
|
||||||
|
private ObservableField<String> lastName = new ObservableField<>();
|
||||||
|
private ObservableField<String> email = new ObservableField<>();
|
||||||
|
private ObservableField<Integer> usernameError = new ObservableField<>();
|
||||||
|
private ObservableField<Integer> firstNameError = new ObservableField<>();
|
||||||
|
private ObservableField<Integer> lastNameError = new ObservableField<>();
|
||||||
|
private ObservableField<Integer> emailError = new ObservableField<>();
|
||||||
|
private ObservableField<String> password = new ObservableField<>();
|
||||||
|
private ObservableField<String> passwordConfirmation = new ObservableField<>();
|
||||||
|
private ObservableField<Integer> passwordError = new ObservableField<>();
|
||||||
|
private ObservableField<Integer> passwordConfirmationError = new ObservableField<>();
|
||||||
|
|
||||||
|
public RegistrationViewModel() {
|
||||||
|
requestInProgress.set(false);
|
||||||
|
registrationSubject = AsyncSubject.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncSubject<AuthenticationResponse> createRegistrationSubject() {
|
||||||
|
registrationSubject = AsyncSubject.create();
|
||||||
|
return registrationSubject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncSubject<AuthenticationResponse> getRegistrationSubject() {
|
||||||
|
return registrationSubject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerUser() {
|
||||||
|
requestInProgress.set(true);
|
||||||
|
User user = new User();
|
||||||
|
user.setEmail(email.get());
|
||||||
|
user.setFirstName(firstName.get());
|
||||||
|
user.setLastName(lastName.get());
|
||||||
|
new AuthenticationManager().registerUser(user, username.get(), password.get()).subscribeOn(Schedulers.io()).subscribe(registrationSubject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public View.OnClickListener onRegisterClick() {
|
||||||
|
return new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if(validatePassword()) {
|
||||||
|
registerUser();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public View.OnClickListener onExitClick() {
|
||||||
|
return new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
NavigationSubject.getInstance().onNext(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public View.OnClickListener onNamesNext() {
|
||||||
|
return new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if(validateNames()) {
|
||||||
|
NavigationSubject.getFragmentNavigationInstance().onNext(new Pair<Class<? extends RTTFragment>, Bundle>(PasswordRegistrationFragment.class, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public View.OnClickListener onInfoNext() {
|
||||||
|
return new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if(validateInfo()) {
|
||||||
|
NavigationSubject.getFragmentNavigationInstance().onNext(new Pair<Class<? extends RTTFragment>, Bundle>(UserNameRegistrationFragment.class, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateNames() {
|
||||||
|
clearNamesErrors();
|
||||||
|
|
||||||
|
firstNameError.set(RTTUtil.getRequiredFieldError(firstName.get()));
|
||||||
|
lastNameError.set(RTTUtil.getRequiredFieldError(lastName.get()));
|
||||||
|
|
||||||
|
return firstNameError.get() == 0 && lastNameError.get() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validateInfo() {
|
||||||
|
clearInfoErrors();
|
||||||
|
|
||||||
|
usernameError.set(RTTUtil.getRequiredFieldError(username.get()));
|
||||||
|
emailError.set(RTTUtil.getRequiredFieldError(email.get()));
|
||||||
|
|
||||||
|
return usernameError.get() == 0 && emailError.get() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean validatePassword() {
|
||||||
|
clearPasswordErrors();
|
||||||
|
|
||||||
|
passwordError.set(RTTUtil.getPasswordError(password.get()));
|
||||||
|
passwordConfirmationError.set(RTTUtil.getPasswordConfirmationError(password.get(), passwordConfirmation.get()));
|
||||||
|
|
||||||
|
return passwordError.get() == 0 && passwordConfirmationError.get() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearInfoErrors() {
|
||||||
|
usernameError.set(0);
|
||||||
|
emailError.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearNamesErrors() {
|
||||||
|
firstNameError.set(0);
|
||||||
|
lastNameError.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearPasswordErrors() {
|
||||||
|
passwordError.set(0);
|
||||||
|
passwordConfirmationError.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRegistrationDone() {
|
||||||
|
NavigationSubject.getInstance().onNext(new Pair<Class<? extends RTTActivity>, Bundle>(MainActivity.class, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRequestCompleted() {
|
||||||
|
requestInProgress.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private ObservableField<Boolean> requestInProgress = new ObservableField<>();
|
||||||
|
|
||||||
|
public ObservableField<String> getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(ObservableField<String> username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<String> getFirstName() {
|
||||||
|
return firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstName(ObservableField<String> firstName) {
|
||||||
|
this.firstName = firstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<String> getLastName() {
|
||||||
|
return lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastName(ObservableField<String> lastName) {
|
||||||
|
this.lastName = lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<String> getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(ObservableField<String> email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<Integer> getUsernameError() {
|
||||||
|
return usernameError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsernameError(ObservableField<Integer> usernameError) {
|
||||||
|
this.usernameError = usernameError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<Integer> getFirstNameError() {
|
||||||
|
return firstNameError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstNameError(ObservableField<Integer> firstNameError) {
|
||||||
|
this.firstNameError = firstNameError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<Integer> getLastNameError() {
|
||||||
|
return lastNameError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastNameError(ObservableField<Integer> lastNameError) {
|
||||||
|
this.lastNameError = lastNameError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<Integer> getEmailError() {
|
||||||
|
return emailError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmailError(ObservableField<Integer> emailError) {
|
||||||
|
this.emailError = emailError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<String> getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(ObservableField<String> password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<String> getPasswordConfirmation() {
|
||||||
|
return passwordConfirmation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPasswordConfirmation(ObservableField<String> passwordConfirmation) {
|
||||||
|
this.passwordConfirmation = passwordConfirmation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<Integer> getPasswordError() {
|
||||||
|
return passwordError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPasswordError(ObservableField<Integer> passwordError) {
|
||||||
|
this.passwordError = passwordError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<Integer> getPasswordConfirmationError() {
|
||||||
|
return passwordConfirmationError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPasswordConfirmationError(ObservableField<Integer> passwordConfirmationError) {
|
||||||
|
this.passwordConfirmationError = passwordConfirmationError;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<Boolean> getRequestInProgress() {
|
||||||
|
return requestInProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRequestInProgress(ObservableField<Boolean> requestInProgress) {
|
||||||
|
this.requestInProgress = requestInProgress;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
package com.smarthomies.realtimetalk.viewmodels;
|
||||||
|
|
||||||
|
import android.databinding.BaseObservable;
|
||||||
|
import android.databinding.Bindable;
|
||||||
|
import android.databinding.Observable;
|
||||||
|
import android.databinding.ObservableField;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.managers.ContactsManager;
|
||||||
|
import com.smarthomies.realtimetalk.models.db.User;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.UsersResponse;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import rx.Subscriber;
|
||||||
|
import rx.Subscription;
|
||||||
|
import rx.android.schedulers.AndroidSchedulers;
|
||||||
|
import rx.functions.Action1;
|
||||||
|
import rx.functions.Func1;
|
||||||
|
import rx.schedulers.Schedulers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 15/11/16.
|
||||||
|
*/
|
||||||
|
public class SearchViewModel extends BaseObservable {
|
||||||
|
public static final String TAG = SearchViewModel.class.getSimpleName();
|
||||||
|
|
||||||
|
private ObservableField<List<User>> users = new ObservableField<>();
|
||||||
|
private ObservableField<String> search = new ObservableField<>();
|
||||||
|
|
||||||
|
private rx.Observable<String> rxSearch;
|
||||||
|
private Subscription subscription;
|
||||||
|
|
||||||
|
public SearchViewModel() {
|
||||||
|
rxSearch = rx.Observable.create(new rx.Observable.OnSubscribe<String>() {
|
||||||
|
@Override
|
||||||
|
public void call(final Subscriber<? super String> subscriber) {
|
||||||
|
search.addOnPropertyChangedCallback(new OnPropertyChangedCallback() {
|
||||||
|
@Override
|
||||||
|
public void onPropertyChanged(Observable observable, int i) {
|
||||||
|
String query = ((ObservableField<String>) observable).get();
|
||||||
|
if(subscriber.isUnsubscribed()) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
subscriber.onNext(query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
rxSearch = rxSearch.debounce(1000, TimeUnit.MILLISECONDS);
|
||||||
|
subscription = rxSearch.flatMap(new Func1<String, rx.Observable<UsersResponse>>() {
|
||||||
|
@Override
|
||||||
|
public rx.Observable<UsersResponse> call(String s) {
|
||||||
|
return new ContactsManager().searchForUsers(s);
|
||||||
|
}
|
||||||
|
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1<UsersResponse>() {
|
||||||
|
@Override
|
||||||
|
public void call(UsersResponse usersResponse) {
|
||||||
|
users.set(usersResponse.getData());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<List<User>> getUsers() {
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsers(ObservableField<List<User>> users) {
|
||||||
|
this.users = users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableField<String> getSearch() {
|
||||||
|
return search;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearch(ObservableField<String> search) {
|
||||||
|
this.search = search;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
if(subscription != null && !subscription.isUnsubscribed()) {
|
||||||
|
subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.smarthomies.realtimetalk.viewmodels;
|
||||||
|
|
||||||
|
import android.databinding.BaseObservable;
|
||||||
|
import android.databinding.Bindable;
|
||||||
|
import android.databinding.BindingAdapter;
|
||||||
|
import android.databinding.ObservableBoolean;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.models.db.User;
|
||||||
|
import com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 15/11/16.
|
||||||
|
*/
|
||||||
|
public class UserViewModel extends BaseObservable {
|
||||||
|
public static final String TAG = UserViewModel.class.getSimpleName();
|
||||||
|
|
||||||
|
private User model;
|
||||||
|
private ObservableBoolean state = new ObservableBoolean();
|
||||||
|
|
||||||
|
public UserViewModel(User model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public String getName() {
|
||||||
|
return model.getFirstName() + " " + model.getLastName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public String getEmail() {
|
||||||
|
return model.getEmail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bindable
|
||||||
|
public String getImageUrl() {
|
||||||
|
return model.getImageUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableBoolean getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public View.OnClickListener changeContactState() {
|
||||||
|
return new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
Log.d(TAG, "onClick: ");
|
||||||
|
state.set(!state.get());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.activities;
|
||||||
|
|
||||||
|
import android.databinding.DataBindingUtil;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.RTTActivity;
|
||||||
|
import com.smarthomies.realtimetalk.databinding.ActivityLoginBinding;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.AuthenticationResponse;
|
||||||
|
import com.smarthomies.realtimetalk.utils.RTTErrorUtil;
|
||||||
|
import com.smarthomies.realtimetalk.viewmodels.LoginViewModel;
|
||||||
|
import com.smarthomies.realtimetalk.views.activities.bindingutils.OnErrorChangedCallback;
|
||||||
|
|
||||||
|
|
||||||
|
import rx.Observable;
|
||||||
|
import rx.Subscriber;
|
||||||
|
import rx.Subscription;
|
||||||
|
import rx.android.schedulers.AndroidSchedulers;
|
||||||
|
import rx.exceptions.CompositeException;
|
||||||
|
import rx.functions.Func0;
|
||||||
|
import rx.functions.Func1;
|
||||||
|
import rx.schedulers.Schedulers;
|
||||||
|
|
||||||
|
public class LoginActivity extends RTTActivity {
|
||||||
|
|
||||||
|
private LoginViewModel viewModel;
|
||||||
|
private Subscription loginSubscription;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
ActivityLoginBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_login);
|
||||||
|
viewModel = new LoginViewModel();
|
||||||
|
binding.setViewModel(viewModel);
|
||||||
|
|
||||||
|
viewModel.getPasswordError().addOnPropertyChangedCallback(new OnErrorChangedCallback(binding.tilPassword));
|
||||||
|
viewModel.getUsernameError().addOnPropertyChangedCallback(new OnErrorChangedCallback(binding.tilUsername));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void subscribeToSubjects() {
|
||||||
|
super.subscribeToSubjects();
|
||||||
|
loginSubscription = viewModel.getLoginSubject().observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(new LoginSubscriber());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void unsubscribeFromSubjects() {
|
||||||
|
super.unsubscribeFromSubjects();
|
||||||
|
if(loginSubscription != null && !loginSubscription.isUnsubscribed()) {
|
||||||
|
loginSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reconnectToLoginSubject() {
|
||||||
|
loginSubscription = viewModel.createLoginSubject().observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(new LoginSubscriber());
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LoginSubscriber extends Subscriber<AuthenticationResponse> {
|
||||||
|
@Override
|
||||||
|
public void onCompleted() {
|
||||||
|
reconnectToLoginSubject();
|
||||||
|
viewModel.onRequestCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable e) {
|
||||||
|
reconnectToLoginSubject();
|
||||||
|
viewModel.onRequestCompleted();
|
||||||
|
|
||||||
|
if (e instanceof CompositeException) {
|
||||||
|
for (Throwable ex : ((CompositeException) e).getExceptions()) {
|
||||||
|
if(ex instanceof RuntimeException) {
|
||||||
|
handleException(ex.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(AuthenticationResponse authenticationResponse) {
|
||||||
|
viewModel.onLoginDone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleException(Throwable e) {
|
||||||
|
Toast.makeText(this, RTTErrorUtil.getErrorString(e), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.activities;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.databinding.DataBindingUtil;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.design.widget.FloatingActionButton;
|
||||||
|
import android.support.design.widget.Snackbar;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.support.design.widget.NavigationView;
|
||||||
|
import android.support.v4.view.GravityCompat;
|
||||||
|
import android.support.v4.widget.DrawerLayout;
|
||||||
|
import android.support.v7.app.ActionBarDrawerToggle;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.RTTActivity;
|
||||||
|
import com.smarthomies.realtimetalk.databinding.ActivityMainBinding;
|
||||||
|
import com.smarthomies.realtimetalk.databinding.AppBarMainBinding;
|
||||||
|
import com.smarthomies.realtimetalk.databinding.NavHeaderMainBinding;
|
||||||
|
import com.smarthomies.realtimetalk.models.db.User;
|
||||||
|
import com.smarthomies.realtimetalk.viewmodels.UserViewModel;
|
||||||
|
import com.smarthomies.realtimetalk.views.adapters.UsersAdapter;
|
||||||
|
import com.smarthomies.realtimetalk.views.fragments.MainViewModelHolder;
|
||||||
|
import com.smarthomies.realtimetalk.views.fragments.registration.RegistrationViewModelHolder;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class MainActivity extends RTTActivity
|
||||||
|
implements NavigationView.OnNavigationItemSelectedListener {
|
||||||
|
|
||||||
|
private MainViewModelHolder viewModelHolder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
// Add retained to fragment manager
|
||||||
|
if(getSupportFragmentManager().findFragmentByTag(MainViewModelHolder.class.getName()) == null) {
|
||||||
|
viewModelHolder = new MainViewModelHolder();
|
||||||
|
|
||||||
|
getSupportFragmentManager()
|
||||||
|
.beginTransaction()
|
||||||
|
.add(viewModelHolder, MainViewModelHolder.class.getName())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
viewModelHolder = (MainViewModelHolder)getSupportFragmentManager().findFragmentByTag(MainViewModelHolder.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivityMainBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
|
||||||
|
AppBarMainBinding appBarMainBinding = binding.appBarMain;
|
||||||
|
User user = new User();
|
||||||
|
user.setFirstName("Ensar");
|
||||||
|
user.setLastName("Sarajcic");
|
||||||
|
user.setEmail("es.ensar@gmail.com");
|
||||||
|
user.setImageUrl("https://avatars3.githubusercontent.com/u/2764831?v=3&s=460");
|
||||||
|
viewModelHolder.getMainViewModel().setUser(user);
|
||||||
|
binding.setViewModel(viewModelHolder.getMainViewModel());
|
||||||
|
appBarMainBinding.setViewModel(viewModelHolder.getMainViewModel());
|
||||||
|
|
||||||
|
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rvUsersList);
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
|
||||||
|
UsersAdapter usersAdapter = new UsersAdapter(UsersAdapter.ViewType.LIST);
|
||||||
|
ArrayList<User> users = new ArrayList<User>();
|
||||||
|
users.add(user);
|
||||||
|
usersAdapter.setUsers(users);
|
||||||
|
|
||||||
|
recyclerView.setAdapter(usersAdapter);
|
||||||
|
|
||||||
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||||
|
|
||||||
|
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
|
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||||
|
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
|
||||||
|
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
|
||||||
|
drawer.setDrawerListener(toggle);
|
||||||
|
toggle.syncState();
|
||||||
|
|
||||||
|
binding.navView.setNavigationItemSelectedListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackPressed() {
|
||||||
|
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||||
|
if (drawer.isDrawerOpen(GravityCompat.START)) {
|
||||||
|
drawer.closeDrawer(GravityCompat.START);
|
||||||
|
} else {
|
||||||
|
super.onBackPressed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
|
getMenuInflater().inflate(R.menu.main, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
// Handle action bar item clicks here. The action bar will
|
||||||
|
// automatically handle clicks on the Home/Up button, so long
|
||||||
|
// as you specify a parent activity in AndroidManifest.xml.
|
||||||
|
int id = item.getItemId();
|
||||||
|
|
||||||
|
//noinspection SimplifiableIfStatement
|
||||||
|
if (id == R.id.action_settings) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("StatementWithEmptyBody")
|
||||||
|
@Override
|
||||||
|
public boolean onNavigationItemSelected(MenuItem item) {
|
||||||
|
// Handle navigation view item clicks here.
|
||||||
|
int id = item.getItemId();
|
||||||
|
|
||||||
|
if (id == R.id.nav_logout) {
|
||||||
|
// Handle the camera action
|
||||||
|
startActivity(new Intent(this, LoginActivity.class));
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||||
|
drawer.closeDrawer(GravityCompat.START);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MainViewModelHolder getViewModelHolder() {
|
||||||
|
return viewModelHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.activities;
|
||||||
|
|
||||||
|
import android.databinding.DataBindingUtil;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.RTTActivity;
|
||||||
|
import com.smarthomies.realtimetalk.databinding.ActivityRegistrationBinding;
|
||||||
|
import com.smarthomies.realtimetalk.views.fragments.registration.RegistrationFragment;
|
||||||
|
import com.smarthomies.realtimetalk.views.fragments.registration.RegistrationViewModelHolder;
|
||||||
|
import com.smarthomies.realtimetalk.views.fragments.registration.UserInfoRegistrationFragment;
|
||||||
|
|
||||||
|
public class RegistrationActivity extends RTTActivity {
|
||||||
|
|
||||||
|
private RegistrationViewModelHolder viewModelHolder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
// Add retained to fragment manager
|
||||||
|
if(getSupportFragmentManager().findFragmentByTag(RegistrationViewModelHolder.class.getName()) == null) {
|
||||||
|
viewModelHolder = new RegistrationViewModelHolder();
|
||||||
|
|
||||||
|
getSupportFragmentManager()
|
||||||
|
.beginTransaction()
|
||||||
|
.add(viewModelHolder, RegistrationViewModelHolder.class.getName())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
viewModelHolder = (RegistrationViewModelHolder)getSupportFragmentManager().findFragmentByTag(RegistrationViewModelHolder.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivityRegistrationBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_registration);
|
||||||
|
binding.setViewModel(viewModelHolder.getRegistrationViewModel());
|
||||||
|
|
||||||
|
startFragment(UserInfoRegistrationFragment.class, null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getFragmentContainerRId() {
|
||||||
|
return R.id.fragment_container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startFragment(Class<? extends RegistrationFragment> clazz, Bundle bundle) {
|
||||||
|
startFragment(clazz, R.id.fragment_container, bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegistrationViewModelHolder getViewModelHolder() {
|
||||||
|
return viewModelHolder;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.activities;
|
||||||
|
|
||||||
|
import android.app.SearchManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.databinding.DataBindingUtil;
|
||||||
|
import android.databinding.Observable;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.view.GravityCompat;
|
||||||
|
import android.support.v4.view.MenuItemCompat;
|
||||||
|
import android.support.v4.widget.DrawerLayout;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.support.v7.widget.SearchView;
|
||||||
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.databinding.ObservableField;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.RTTActivity;
|
||||||
|
import com.smarthomies.realtimetalk.databinding.ActivitySearchBinding;
|
||||||
|
import com.smarthomies.realtimetalk.models.db.User;
|
||||||
|
import com.smarthomies.realtimetalk.viewmodels.SearchViewModel;
|
||||||
|
import com.smarthomies.realtimetalk.views.adapters.UsersAdapter;
|
||||||
|
import com.smarthomies.realtimetalk.views.fragments.SearchViewModelHolder;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class SearchActivity extends RTTActivity {
|
||||||
|
|
||||||
|
private SearchViewModelHolder viewModelHolder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
// Add retained to fragment manager
|
||||||
|
if(getSupportFragmentManager().findFragmentByTag(SearchViewModelHolder.class.getName()) == null) {
|
||||||
|
viewModelHolder = new SearchViewModelHolder();
|
||||||
|
|
||||||
|
getSupportFragmentManager()
|
||||||
|
.beginTransaction()
|
||||||
|
.add(viewModelHolder, SearchViewModelHolder.class.getName())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
viewModelHolder = (SearchViewModelHolder)getSupportFragmentManager().findFragmentByTag(SearchViewModelHolder.class.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActivitySearchBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_search);
|
||||||
|
binding.setViewModel(viewModelHolder.getSearchViewModel());
|
||||||
|
|
||||||
|
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rvSearchList);
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
|
||||||
|
SearchViewModel searchViewModel = viewModelHolder.getSearchViewModel();
|
||||||
|
searchViewModel.getUsers().addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
|
||||||
|
@Override
|
||||||
|
public void onPropertyChanged(Observable observable, int i) {
|
||||||
|
List<User> users = ((ObservableField<List<User>>)observable).get();
|
||||||
|
UsersAdapter usersAdapter = new UsersAdapter(UsersAdapter.ViewType.SEARCH);
|
||||||
|
usersAdapter.setUsers(users);
|
||||||
|
recyclerView.setAdapter(usersAdapter);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||||
|
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
|
getMenuInflater().inflate(R.menu.search, menu);
|
||||||
|
final SearchView searchView = (SearchView) MenuItemCompat.getActionView(menu.findItem(R.id.action_search));
|
||||||
|
SearchManager searchManager = (SearchManager) getSystemService(SEARCH_SERVICE);
|
||||||
|
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
|
||||||
|
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextSubmit(String query) {
|
||||||
|
getViewModelHolder().getSearchViewModel().getSearch().set(query);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onQueryTextChange(String newText) {
|
||||||
|
getViewModelHolder().getSearchViewModel().getSearch().set(newText);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
// Handle action bar item clicks here. The action bar will
|
||||||
|
// automatically handle clicks on the Home/Up button, so long
|
||||||
|
// as you specify a parent activity in AndroidManifest.xml.
|
||||||
|
int id = item.getItemId();
|
||||||
|
|
||||||
|
//noinspection SimplifiableIfStatement
|
||||||
|
if (id == R.id.rvSearchList) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchViewModelHolder getViewModelHolder() {
|
||||||
|
return viewModelHolder;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.activities.bindingutils;
|
||||||
|
|
||||||
|
import android.databinding.BindingAdapter;
|
||||||
|
import android.support.design.widget.NavigationView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.viewmodels.UserViewModel;
|
||||||
|
import com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.databinding.NavHeaderMainBinding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 17/11/16.
|
||||||
|
*/
|
||||||
|
public class BindingAdapters {
|
||||||
|
public static final String TAG = BindingAdapters.class.getSimpleName();
|
||||||
|
|
||||||
|
@BindingAdapter("android:src")
|
||||||
|
public static void setImageUrl(ImageView view, String url) {
|
||||||
|
Picasso.with(view.getContext()).load(url).placeholder(R.mipmap.ic_launcher).into(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BindingAdapter({"headerLayout"})
|
||||||
|
public static void setHeaderViewModel(NavigationView view, UserViewModel userViewModel) {
|
||||||
|
NavHeaderMainBinding navHeaderMainBinding = NavHeaderMainBinding.inflate(LayoutInflater.from(view.getContext()));
|
||||||
|
navHeaderMainBinding.setViewModel(userViewModel);
|
||||||
|
navHeaderMainBinding.executePendingBindings();
|
||||||
|
view.addHeaderView(navHeaderMainBinding.getRoot());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.activities.bindingutils;
|
||||||
|
|
||||||
|
import android.databinding.Observable;
|
||||||
|
import android.databinding.ObservableField;
|
||||||
|
import android.support.design.widget.TextInputLayout;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 01/11/16.
|
||||||
|
*/
|
||||||
|
public class OnErrorChangedCallback extends Observable.OnPropertyChangedCallback {
|
||||||
|
|
||||||
|
private TextInputLayout layout;
|
||||||
|
|
||||||
|
public OnErrorChangedCallback(TextInputLayout textInputLayout) {
|
||||||
|
layout = textInputLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPropertyChanged(Observable observable, int i) {
|
||||||
|
Integer errorRId = ((ObservableField<Integer>) observable).get();
|
||||||
|
if (errorRId == 0) {
|
||||||
|
layout.setErrorEnabled(false);
|
||||||
|
} else {
|
||||||
|
layout.setErrorEnabled(true);
|
||||||
|
layout.setError(layout.getContext().getString(errorRId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.adapters;
|
||||||
|
|
||||||
|
import android.databinding.DataBindingUtil;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.databinding.SearchUserListItemBinding;
|
||||||
|
import com.smarthomies.realtimetalk.databinding.UserListItemBinding;
|
||||||
|
import com.smarthomies.realtimetalk.models.db.User;
|
||||||
|
import com.smarthomies.realtimetalk.viewmodels.UserViewModel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 26/11/16.
|
||||||
|
*/
|
||||||
|
public class UsersAdapter extends RecyclerView.Adapter<UsersAdapter.UserViewHolder>{
|
||||||
|
public static final String TAG = UsersAdapter.class.getSimpleName();
|
||||||
|
|
||||||
|
public enum ViewType {
|
||||||
|
LIST,
|
||||||
|
SEARCH
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<User> users;
|
||||||
|
private ViewType viewType;
|
||||||
|
|
||||||
|
public UsersAdapter(ViewType viewType) {
|
||||||
|
this.viewType = viewType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
switch (this.viewType) {
|
||||||
|
case LIST:
|
||||||
|
UserListItemBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.user_list_item, parent, false);
|
||||||
|
return new UserViewHolder(binding);
|
||||||
|
case SEARCH:
|
||||||
|
default:
|
||||||
|
SearchUserListItemBinding binding2 = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.search_user_list_item, parent, false);
|
||||||
|
return new UserViewHolder(binding2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(UserViewHolder holder, int position) {
|
||||||
|
switch (this.viewType) {
|
||||||
|
case LIST:
|
||||||
|
UserListItemBinding binding = holder.getBinding();
|
||||||
|
binding.setViewModel(new UserViewModel(users.get(position)));
|
||||||
|
break;
|
||||||
|
case SEARCH:
|
||||||
|
SearchUserListItemBinding binding2 = holder.getSearchUserListItemBinding();
|
||||||
|
binding2.setViewModel(new UserViewModel(users.get(position)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return users.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UserViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
private UserListItemBinding binding;
|
||||||
|
private SearchUserListItemBinding searchUserListItemBinding;
|
||||||
|
|
||||||
|
public UserViewHolder(UserListItemBinding userListItemBinding) {
|
||||||
|
super(userListItemBinding.getRoot());
|
||||||
|
this.binding = userListItemBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserViewHolder(SearchUserListItemBinding userListItemBinding) {
|
||||||
|
super(userListItemBinding.getRoot());
|
||||||
|
this.searchUserListItemBinding = userListItemBinding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserListItemBinding getBinding() {
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchUserListItemBinding getSearchUserListItemBinding() {
|
||||||
|
return searchUserListItemBinding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<User> getUsers() {
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsers(List<User> users) {
|
||||||
|
this.users = users;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.fragments;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.viewmodels.MainViewModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 15/11/16.
|
||||||
|
*/
|
||||||
|
public class MainViewModelHolder extends ViewModelHolder {
|
||||||
|
public static final String TAG = MainViewModelHolder.class.getSimpleName();
|
||||||
|
|
||||||
|
private MainViewModel mainViewModel = new MainViewModel();
|
||||||
|
|
||||||
|
public MainViewModel getMainViewModel() {
|
||||||
|
return mainViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMainViewModel(MainViewModel mainViewModel) {
|
||||||
|
this.mainViewModel = mainViewModel;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.fragments;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.viewmodels.SearchViewModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 15/11/16.
|
||||||
|
*/
|
||||||
|
public class SearchViewModelHolder extends ViewModelHolder {
|
||||||
|
public static final String TAG = SearchViewModelHolder.class.getSimpleName();
|
||||||
|
|
||||||
|
private SearchViewModel searchViewModel = new SearchViewModel();
|
||||||
|
|
||||||
|
public SearchViewModel getSearchViewModel() {
|
||||||
|
return searchViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearchViewModel(SearchViewModel searchViewModel) {
|
||||||
|
this.searchViewModel = searchViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
searchViewModel.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.fragments;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 13/11/16.
|
||||||
|
*/
|
||||||
|
public abstract class ViewModelHolder extends Fragment {
|
||||||
|
public static final String TAG = ViewModelHolder.class.getSimpleName();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setRetainInstance(true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.fragments.registration;
|
||||||
|
|
||||||
|
import android.databinding.DataBindingUtil;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.databinding.PasswordRegistrationBinding;
|
||||||
|
import com.smarthomies.realtimetalk.models.network.AuthenticationResponse;
|
||||||
|
import com.smarthomies.realtimetalk.utils.RTTErrorUtil;
|
||||||
|
import com.smarthomies.realtimetalk.views.activities.bindingutils.OnErrorChangedCallback;
|
||||||
|
|
||||||
|
import rx.Subscriber;
|
||||||
|
import rx.Subscription;
|
||||||
|
import rx.android.schedulers.AndroidSchedulers;
|
||||||
|
import rx.exceptions.CompositeException;
|
||||||
|
import rx.schedulers.Schedulers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 08/11/16.
|
||||||
|
*/
|
||||||
|
public class PasswordRegistrationFragment extends RegistrationFragment {
|
||||||
|
public static final String TAG = PasswordRegistrationFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
private Subscription registrationSubscription;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
PasswordRegistrationBinding binding = DataBindingUtil.inflate(inflater, R.layout.password_registration, container, false);
|
||||||
|
View view = binding.getRoot();
|
||||||
|
binding.setViewModel(getViewModel());
|
||||||
|
|
||||||
|
getViewModel().getPasswordError().addOnPropertyChangedCallback(new OnErrorChangedCallback(binding.tilPassword));
|
||||||
|
getViewModel().getPasswordConfirmationError().addOnPropertyChangedCallback(new OnErrorChangedCallback(binding.tilConfirmPassword));
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void subscribeToSubjects() {
|
||||||
|
super.subscribeToSubjects();
|
||||||
|
registrationSubscription = getViewModel().getRegistrationSubject().observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(new RegistrationSubscriber());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void unsubscribeFromSubjects() {
|
||||||
|
super.unsubscribeFromSubjects();
|
||||||
|
if(registrationSubscription != null && !registrationSubscription.isUnsubscribed()) {
|
||||||
|
registrationSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reconnectToRegistrationSubject() {
|
||||||
|
registrationSubscription = getViewModel().createRegistrationSubject().observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()).subscribe(new RegistrationSubscriber());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleException(Throwable e) {
|
||||||
|
Toast.makeText(getContext(), RTTErrorUtil.getErrorString(e), Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class RegistrationSubscriber extends Subscriber<AuthenticationResponse> {
|
||||||
|
@Override
|
||||||
|
public void onCompleted() {
|
||||||
|
reconnectToRegistrationSubject();
|
||||||
|
getViewModel().onRequestCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable e) {
|
||||||
|
reconnectToRegistrationSubject();
|
||||||
|
getViewModel().onRequestCompleted();
|
||||||
|
|
||||||
|
if (e instanceof CompositeException) {
|
||||||
|
for (Throwable ex : ((CompositeException) e).getExceptions()) {
|
||||||
|
if(ex instanceof RuntimeException) {
|
||||||
|
handleException(ex.getCause());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
handleException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNext(AuthenticationResponse authenticationResponse) {
|
||||||
|
getViewModel().onRegistrationDone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.fragments.registration;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.RTTFragment;
|
||||||
|
import com.smarthomies.realtimetalk.viewmodels.RegistrationViewModel;
|
||||||
|
import com.smarthomies.realtimetalk.views.activities.RegistrationActivity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 08/11/16.
|
||||||
|
*/
|
||||||
|
public class RegistrationFragment extends RTTFragment {
|
||||||
|
public static final String TAG = RegistrationFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
protected RegistrationViewModel getViewModel() {
|
||||||
|
return ((RegistrationActivity) getActivity()).getViewModelHolder().getRegistrationViewModel();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.fragments.registration;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.viewmodels.RegistrationViewModel;
|
||||||
|
import com.smarthomies.realtimetalk.views.fragments.ViewModelHolder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 13/11/16.
|
||||||
|
*/
|
||||||
|
public class RegistrationViewModelHolder extends ViewModelHolder {
|
||||||
|
public static final String TAG = RegistrationViewModelHolder.class.getSimpleName();
|
||||||
|
|
||||||
|
private RegistrationViewModel registrationViewModel = new RegistrationViewModel();
|
||||||
|
|
||||||
|
public RegistrationViewModel getRegistrationViewModel() {
|
||||||
|
return registrationViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegistrationViewModel(RegistrationViewModel registrationViewModel) {
|
||||||
|
this.registrationViewModel = registrationViewModel;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.fragments.registration;
|
||||||
|
|
||||||
|
import android.databinding.DataBindingUtil;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.databinding.UserInfoRegistrationBinding;
|
||||||
|
import com.smarthomies.realtimetalk.views.activities.bindingutils.OnErrorChangedCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 08/11/16.
|
||||||
|
*/
|
||||||
|
public class UserInfoRegistrationFragment extends RegistrationFragment {
|
||||||
|
public static final String TAG = UserInfoRegistrationFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
UserInfoRegistrationBinding binding = DataBindingUtil.inflate(inflater, R.layout.user_info_registration, container, false);
|
||||||
|
View view = binding.getRoot();
|
||||||
|
binding.setViewModel(getViewModel());
|
||||||
|
|
||||||
|
getViewModel().getUsernameError().addOnPropertyChangedCallback(new OnErrorChangedCallback(binding.tilUsername));
|
||||||
|
getViewModel().getEmailError().addOnPropertyChangedCallback(new OnErrorChangedCallback(binding.tilEmail));
|
||||||
|
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.smarthomies.realtimetalk.views.fragments.registration;
|
||||||
|
|
||||||
|
import android.databinding.DataBindingUtil;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import com.smarthomies.realtimetalk.R;
|
||||||
|
import com.smarthomies.realtimetalk.databinding.UserNameRegistrationBinding;
|
||||||
|
import com.smarthomies.realtimetalk.views.activities.bindingutils.OnErrorChangedCallback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ensar on 08/11/16.
|
||||||
|
*/
|
||||||
|
public class UserNameRegistrationFragment extends RegistrationFragment {
|
||||||
|
public static final String TAG = UserNameRegistrationFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
UserNameRegistrationBinding binding = DataBindingUtil.inflate(inflater, R.layout.user_name_registration, container, false);
|
||||||
|
View view = binding.getRoot();
|
||||||
|
binding.setViewModel(getViewModel());
|
||||||
|
|
||||||
|
getViewModel().getFirstNameError().addOnPropertyChangedCallback(new OnErrorChangedCallback(binding.tilFirstName));
|
||||||
|
getViewModel().getLastNameError().addOnPropertyChangedCallback(new OnErrorChangedCallback(binding.tilLastName));
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M12,12m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M9,2L7.17,4H4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2h-3.17L15,2H9zm3,15c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M22,16V4c0,-1.1 -0.9,-2 -2,-2H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2zm-11,-4l2.03,2.71L16,11l4,5H8l3,-4zM2,6v14c0,1.1 0.9,2 2,2h14v-2H4V6H2z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M22.7,19l-9.1,-9.1c0.9,-2.3 0.4,-5 -1.5,-6.9 -2,-2 -5,-2.4 -7.4,-1.3L9,6 6,9 1.6,4.7C0.4,7.1 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1,0.4 1.4,0l2.3,-2.3c0.5,-0.4 0.5,-1.1 0.1,-1.4z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportHeight="24.0"
|
||||||
|
android:viewportWidth="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M4,6H2v14c0,1.1 0.9,2 2,2h14v-2H4V6zm16,-4H8c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2zm-8,12.5v-9l6,4.5 -6,4.5z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@color/colorPrimary"></solid>
|
||||||
|
<stroke android:color="@color/white" android:width="1dp"/>
|
||||||
|
<corners android:radius="2dp"/>
|
||||||
|
</shape>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<gradient
|
||||||
|
android:angle="135"
|
||||||
|
android:centerColor="#4CAF50"
|
||||||
|
android:endColor="#2E7D32"
|
||||||
|
android:startColor="#81C784"
|
||||||
|
android:type="linear" />
|
||||||
|
</shape>
|
|
@ -0,0 +1,144 @@
|
||||||
|
<layout>
|
||||||
|
<data>
|
||||||
|
<variable name="viewModel" type="com.smarthomies.realtimetalk.viewmodels.LoginViewModel"/>
|
||||||
|
<import type="android.view.View" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
tools:context="com.smarthomies.realtimetalk.views.activities.LoginActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvLoginTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="48sp"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:fontFamily="cursive"/>
|
||||||
|
|
||||||
|
<!-- Login progress -->
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/login_progress"
|
||||||
|
style="?android:attr/progressBarStyleLarge"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="@{viewModel.requestInProgress ? View.VISIBLE : View.INVISIBLE}"
|
||||||
|
tools:visibility="visible"
|
||||||
|
android:layout_gravity="center_horizontal" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/email_login_form"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/tilUsername"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
app:counterTextAppearance="@color/colorAccent">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/tietUsername"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/prompt.username"
|
||||||
|
android:inputType="textEmailAddress"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="@={viewModel.username}"
|
||||||
|
android:freezesText="true"/>
|
||||||
|
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/tilPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
app:counterTextAppearance="@color/colorAccent"
|
||||||
|
app:passwordToggleEnabled="true"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:passwordToggleTint="@color/white.50">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/tietPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/prompt.password"
|
||||||
|
android:imeActionId="@+id/btnLogin"
|
||||||
|
android:imeActionLabel="@string/action.sign_in"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="@={viewModel.password}"
|
||||||
|
android:freezesText="true"/>
|
||||||
|
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvForgot"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="right"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/action.forgot_password"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnLogin"
|
||||||
|
style="?android:textAppearanceSmall"
|
||||||
|
android:background="@drawable/button_normal"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/action.login"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:onClick="@{viewModel.onLoginClick()}"
|
||||||
|
android:enabled="@{!viewModel.requestInProgress}"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvRegister"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="@string/action.register"
|
||||||
|
android:onClick="@{viewModel.onRegisterClick()}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<data>
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.smarthomies.realtimetalk.viewmodels.MainViewModel"
|
||||||
|
/>
|
||||||
|
</data>
|
||||||
|
<android.support.v4.widget.DrawerLayout
|
||||||
|
android:id="@+id/drawer_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
android:background="@color/colorPrimary">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/app_bar_main"
|
||||||
|
layout="@layout/app_bar_main"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<android.support.design.widget.NavigationView
|
||||||
|
android:id="@+id/nav_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="start"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
app:headerLayout="@{viewModel.userViewModel}"
|
||||||
|
app:menu="@menu/activity_main_drawer" />
|
||||||
|
|
||||||
|
</android.support.v4.widget.DrawerLayout>
|
||||||
|
</layout>
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout>
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.smarthomies.realtimetalk.viewmodels.RegistrationViewModel" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
tools:context="com.smarthomies.realtimetalk.views.activities.RegistrationActivity">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/fragment_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivBack"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
android:src="@android:drawable/ic_menu_close_clear_cancel"
|
||||||
|
android:onClick="@{viewModel.onExitClick()}"/>
|
||||||
|
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
</layout>
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<data>
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.smarthomies.realtimetalk.viewmodels.SearchViewModel"
|
||||||
|
/>
|
||||||
|
</data>
|
||||||
|
<android.support.design.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
android:background="@color/colorPrimary">
|
||||||
|
|
||||||
|
<android.support.design.widget.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:theme="@style/AppTheme.AppBarOverlay">
|
||||||
|
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorPrimary"
|
||||||
|
app:popupTheme="@style/AppTheme.PopupOverlay"/>
|
||||||
|
|
||||||
|
</android.support.design.widget.AppBarLayout>
|
||||||
|
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
android:id="@+id/rvSearchList"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="?attr/actionBarSize"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingRight="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"/>
|
||||||
|
|
||||||
|
</android.support.design.widget.CoordinatorLayout>
|
||||||
|
</layout>
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout>
|
||||||
|
<data>
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.smarthomies.realtimetalk.viewmodels.MainViewModel"/>
|
||||||
|
</data>
|
||||||
|
<android.support.design.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/main_layout"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
tools:context="com.smarthomies.realtimetalk.views.activities.MainActivity">
|
||||||
|
|
||||||
|
<android.support.design.widget.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:theme="@style/AppTheme.AppBarOverlay">
|
||||||
|
|
||||||
|
<android.support.v7.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorPrimary"
|
||||||
|
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||||
|
|
||||||
|
</android.support.design.widget.AppBarLayout>
|
||||||
|
|
||||||
|
<include layout="@layout/content_main" />
|
||||||
|
|
||||||
|
<android.support.design.widget.FloatingActionButton
|
||||||
|
android:id="@+id/fab"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_margin="@dimen/fab_margin"
|
||||||
|
app:srcCompat="@android:drawable/ic_menu_search"
|
||||||
|
android:onClick="@{viewModel.onSearchClick()}"/>
|
||||||
|
|
||||||
|
</android.support.design.widget.CoordinatorLayout>
|
||||||
|
</layout>
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout>
|
||||||
|
<data>
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.smarthomies.realtimetalk.viewmodels.MainViewModel" />
|
||||||
|
</data>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/content_main"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
tools:context="com.smarthomies.realtimetalk.views.activities.MainActivity"
|
||||||
|
tools:showIn="@layout/app_bar_main">
|
||||||
|
|
||||||
|
<android.support.v7.widget.RecyclerView
|
||||||
|
android:id="@+id/rvUsersList"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
/>
|
||||||
|
</RelativeLayout>
|
||||||
|
</layout>
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout>
|
||||||
|
<data>
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.smarthomies.realtimetalk.viewmodels.UserViewModel"/>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/nav_header_height"
|
||||||
|
android:background="@drawable/side_nav_bar"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
android:theme="@style/ThemeOverlay.AppCompat.Dark">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="@dimen/image.big"
|
||||||
|
android:layout_height="@dimen/image.big"
|
||||||
|
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||||
|
android:src="@{viewModel.imageUrl}"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="@dimen/nav_header_vertical_spacing"
|
||||||
|
android:text="@{viewModel.name}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{viewModel.email}" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
<layout>
|
||||||
|
<data>
|
||||||
|
<variable name="viewModel" type="com.smarthomies.realtimetalk.viewmodels.RegistrationViewModel"/>
|
||||||
|
<import type="android.view.View" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
tools:context="com.smarthomies.realtimetalk.views.activities.LoginActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvUserInfoTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/title.credentials"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="48sp"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:fontFamily="cursive"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvUserInfoSubTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/subtitle.credentials"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:textSize="36sp"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:fontFamily="cursive"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llForm"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginTop="37dp">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/tilPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
app:passwordToggleEnabled="true"
|
||||||
|
app:passwordToggleTint="@color/white.50"
|
||||||
|
app:counterTextAppearance="@color/colorAccent">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/tietPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/prompt.password"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="@={viewModel.password}"/>
|
||||||
|
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/tilConfirmPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
app:passwordToggleEnabled="true"
|
||||||
|
app:passwordToggleTint="@color/white.50"
|
||||||
|
app:counterTextAppearance="@color/colorAccent"
|
||||||
|
android:layout_marginTop="16dp">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/tietConfirmPassword"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/prompt.password_confirm"
|
||||||
|
android:imeActionId="@+id/login"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="@={viewModel.passwordConfirmation}"/>
|
||||||
|
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnLogin"
|
||||||
|
style="?android:textAppearanceSmall"
|
||||||
|
android:background="@drawable/button_normal"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="60dp"
|
||||||
|
android:text="@string/action.create_account"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:enabled="@{!viewModel.requestInProgress}"
|
||||||
|
android:onClick="@{viewModel.onRegisterClick()}"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.smarthomies.realtimetalk.viewmodels.UserViewModel"/>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivUserImage"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:src="@{viewModel.imageUrl}"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:id="@+id/tvUserName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toRightOf="@+id/ivUserImage"
|
||||||
|
android:layout_toLeftOf="@+id/ivState"
|
||||||
|
android:text="@{viewModel.name}"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivState"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@android:drawable/sym_action_call"
|
||||||
|
android:onClick="@{viewModel.changeContactState()}"
|
||||||
|
android:tint="@{viewModel.state ? @color/colorAccent : @color/white}"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
</layout>
|
|
@ -0,0 +1,120 @@
|
||||||
|
<layout>
|
||||||
|
<data>
|
||||||
|
<variable name="viewModel" type="com.smarthomies.realtimetalk.viewmodels.RegistrationViewModel"/>
|
||||||
|
<import type="android.view.View" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
tools:context="com.smarthomies.realtimetalk.views.activities.LoginActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvUserInfoTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/title.welcome"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="48sp"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:fontFamily="cursive"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvUserInfoSubTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/subtitle.welcome"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:textSize="36sp"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:fontFamily="cursive"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llForm"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginTop="37dp">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/tilUsername"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
app:counterTextAppearance="@color/colorAccent">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/tietUsername"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/prompt.username"
|
||||||
|
android:inputType="textVisiblePassword"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="@={viewModel.username}"/>
|
||||||
|
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/tilEmail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
app:counterTextAppearance="@color/colorAccent"
|
||||||
|
app:passwordToggleTint="@color/white.50"
|
||||||
|
android:layout_marginTop="16dp">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/tietEmail"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/prompt.email"
|
||||||
|
android:imeActionId="@+id/login"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:inputType="textEmailAddress"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:text="@={viewModel.email}"/>
|
||||||
|
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnLogin"
|
||||||
|
style="?android:textAppearanceSmall"
|
||||||
|
android:background="@drawable/button_normal"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="60dp"
|
||||||
|
android:text="@string/action.next"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:onClick="@{viewModel.onInfoNext()}"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
<variable
|
||||||
|
name="viewModel"
|
||||||
|
type="com.smarthomies.realtimetalk.viewmodels.UserViewModel"/>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/ivUserImage"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:src="@{viewModel.imageUrl}"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:id="@+id/tvUserName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:text="@{viewModel.name}"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
|
@ -0,0 +1,122 @@
|
||||||
|
<layout>
|
||||||
|
<data>
|
||||||
|
<variable name="viewModel" type="com.smarthomies.realtimetalk.viewmodels.RegistrationViewModel"/>
|
||||||
|
<import type="android.view.View" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
tools:context="com.smarthomies.realtimetalk.views.activities.LoginActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_gravity="center">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvUserInfoTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/title.introduction"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="48sp"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:fontFamily="cursive"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvUserInfoSubTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/subtitle.introduction"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:textSize="36sp"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:fontFamily="cursive"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/llForm"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginTop="37dp">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/tilFirstName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
app:counterTextAppearance="@color/colorAccent">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/tierFirstName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/prompt.first_name"
|
||||||
|
android:inputType="textPersonName"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:maxLength="30"
|
||||||
|
android:text="@={viewModel.firstName}"/>
|
||||||
|
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputLayout
|
||||||
|
android:id="@+id/tilLastName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
app:counterTextAppearance="@color/colorAccent"
|
||||||
|
app:passwordToggleTint="@color/white.50"
|
||||||
|
android:layout_marginTop="16dp">
|
||||||
|
|
||||||
|
<android.support.design.widget.TextInputEditText
|
||||||
|
android:id="@+id/tierLastName"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/prompt.last_name"
|
||||||
|
android:imeActionId="@+id/login"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:inputType="textPersonName"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHint="@color/white.50"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:maxLength="30"
|
||||||
|
android:text="@={viewModel.lastName}"/>
|
||||||
|
|
||||||
|
</android.support.design.widget.TextInputLayout>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnLogin"
|
||||||
|
style="?android:textAppearanceSmall"
|
||||||
|
android:background="@drawable/button_normal"
|
||||||
|
android:textColor="@color/colorAccent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="60dp"
|
||||||
|
android:text="@string/action.next"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:onClick="@{viewModel.onNamesNext()}"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</layout>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/nav_logout"
|
||||||
|
android:icon="@drawable/ic_menu_send"
|
||||||
|
android:title="Logout" />
|
||||||
|
|
||||||
|
</menu>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_settings"
|
||||||
|
android:orderInCategory="100"
|
||||||
|
android:title="@string/title.settings"
|
||||||
|
app:showAsAction="never" />
|
||||||
|
</menu>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_search"
|
||||||
|
android:title="@string/title.search"
|
||||||
|
app:title="@string/title.search"
|
||||||
|
android:icon="@android:drawable/ic_menu_search"
|
||||||
|
app:showAsAction="always"
|
||||||
|
app:actionViewClass="android.support.v7.widget.SearchView" />
|
||||||
|
</menu>
|
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
|
@ -0,0 +1,8 @@
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<style name="AppTheme.NoActionBar">
|
||||||
|
<item name="windowActionBar">false</item>
|
||||||
|
<item name="windowNoTitle">true</item>
|
||||||
|
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<resources>
|
||||||
|
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
|
||||||
|
(such as screen margins) for screens with more than 820dp of available width. This
|
||||||
|
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
|
||||||
|
<dimen name="activity_horizontal_margin">64dp</dimen>
|
||||||
|
</resources>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="colorPrimary">#303030</color>
|
||||||
|
<color name="colorPrimaryDark">#212121</color>
|
||||||
|
<color name="colorAccent">#80CBC4</color>
|
||||||
|
|
||||||
|
<!-- palette -->
|
||||||
|
<color name="white">#FFFFFF</color>
|
||||||
|
<color name="white.12">#1DFFFFFF</color>
|
||||||
|
<color name="white.50">#88FFFFFF</color>
|
||||||
|
|
||||||
|
<!-- text colors -->
|
||||||
|
<color name="text.hint">@color/white.50</color>
|
||||||
|
<color name="text">@color/white</color>
|
||||||
|
|
||||||
|
</resources>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<resources>
|
||||||
|
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||||
|
<dimen name="nav_header_vertical_spacing">16dp</dimen>
|
||||||
|
<dimen name="nav_header_height">160dp</dimen>
|
||||||
|
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||||
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
|
<dimen name="fab_margin">16dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="image.big">64dp</dimen>
|
||||||
|
<dimen name="image.small">32dp</dimen>
|
||||||
|
</resources>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item name="ic_menu_camera" type="drawable">@android:drawable/ic_menu_camera</item>
|
||||||
|
<item name="ic_menu_gallery" type="drawable">@android:drawable/ic_menu_gallery</item>
|
||||||
|
<item name="ic_menu_slideshow" type="drawable">@android:drawable/ic_menu_slideshow</item>
|
||||||
|
<item name="ic_menu_manage" type="drawable">@android:drawable/ic_menu_manage</item>
|
||||||
|
<item name="ic_menu_share" type="drawable">@android:drawable/ic_menu_share</item>
|
||||||
|
<item name="ic_menu_send" type="drawable">@android:drawable/ic_menu_send</item>
|
||||||
|
</resources>
|
|
@ -0,0 +1,48 @@
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Real Time Talk</string>
|
||||||
|
|
||||||
|
<string name="navigation_drawer_open">Open navigation drawer</string>
|
||||||
|
<string name="navigation_drawer_close">Close navigation drawer</string>
|
||||||
|
|
||||||
|
<string name="title.settings">Settings</string>
|
||||||
|
<string name="title.login">Sign in</string>
|
||||||
|
<string name="title.welcome">Welcome</string>
|
||||||
|
<string name="title.introduction">Tell us who you are</string>
|
||||||
|
<string name="title.credentials">Almost there</string>
|
||||||
|
<string name="title.search">Search</string>
|
||||||
|
|
||||||
|
<string name="subtitle.welcome">Input your login details</string>
|
||||||
|
<string name="subtitle.introduction">Input your full name</string>
|
||||||
|
<string name="subtitle.credentials">Choose your password</string>
|
||||||
|
|
||||||
|
<!-- Strings related to login -->
|
||||||
|
<string name="prompt.username">Username</string>
|
||||||
|
<string name="prompt.password">Password</string>
|
||||||
|
<string name="prompt.password_confirm">Confirm Password</string>
|
||||||
|
<string name="prompt.email">Email</string>
|
||||||
|
<string name="prompt.first_name">First Name</string>
|
||||||
|
<string name="prompt.last_name">Last Name</string>
|
||||||
|
|
||||||
|
<string name="action.sign_in_or_register">Sign in or register</string>
|
||||||
|
<string name="action.sign_in">Sign in</string>
|
||||||
|
<string name="action.login">Login</string>
|
||||||
|
<string name="action.register">No account yet? Create one</string>
|
||||||
|
<string name="action.forgot_password">Forgot username or password?</string>
|
||||||
|
<string name="action.next">Next</string>
|
||||||
|
<string name="action.create_account">Create Account</string>
|
||||||
|
|
||||||
|
<!-- Login errors -->
|
||||||
|
<string name="error.email.invalid">Email address is invalid</string>
|
||||||
|
<string name="error.email.incorrect">Email address doesn\'t exist</string>
|
||||||
|
<string name="error.password.short">Password should be at least 6 characters long</string>
|
||||||
|
<string name="error.password.invalid">Password should contain at least 1 letter and 1 number</string>
|
||||||
|
<string name="error.password.incorrect">This password is incorrect</string>
|
||||||
|
<string name="error.password.confirmation">Password does not match password confirmation</string>
|
||||||
|
<string name="error.required">This field is required</string>
|
||||||
|
<string name="error.no_internet">Check your internet connection!</string>
|
||||||
|
<string name="error.bad_request">Bad request, blame Dino Dizdarevic!</string>
|
||||||
|
<string name="error.user.not_found">User not found!</string>
|
||||||
|
<string name="error.user.bad_credentials">Please check your username and password!</string>
|
||||||
|
<string name="error.unknown">Unknown error!</string>
|
||||||
|
|
||||||
|
</resources>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
<item name="colorControlNormal">@color/white.12</item>
|
||||||
|
<item name="colorControlActivated">@color/colorAccent</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AppTheme.NoActionBar">
|
||||||
|
<item name="windowActionBar">false</item>
|
||||||
|
<item name="windowNoTitle">true</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||||
|
|
||||||
|
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||||
|
|
||||||
|
</resources>
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.smarthomies.realtimetalk;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
public class ExampleUnitTest {
|
||||||
|
@Test
|
||||||
|
public void addition_isCorrect() throws Exception {
|
||||||
|
assertEquals(4, 2 + 2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:2.2.0'
|
||||||
|
|
||||||
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
// in the individual module build.gradle files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task clean(type: Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Project-wide Gradle settings.
|
||||||
|
|
||||||
|
# IDE (e.g. Android Studio) users:
|
||||||
|
# Gradle settings configured through the IDE *will override*
|
||||||
|
# any settings specified in this file.
|
||||||
|
|
||||||
|
# For more details on how to configure your build environment visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
|
||||||
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
org.gradle.jvmargs=-Xmx1536m
|
||||||
|
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
|
# org.gradle.parallel=true
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue