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