Explorar el Código

Do bunch of work on settings

Signed-off-by: Mario Danic <mario@lovelyhq.com>
Mario Danic hace 7 años
padre
commit
2199dfc088
Se han modificado 21 ficheros con 785 adiciones y 145 borrados
  1. 27 20
      app/build.gradle
  2. 2 0
      app/src/main/AndroidManifest.xml
  3. 1 1
      app/src/main/java/com/nextcloud/talk/adapters/items/RoomItem.java
  4. 1 1
      app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java
  5. 9 5
      app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.java
  6. 271 0
      app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java
  7. 15 4
      app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java
  8. 14 12
      app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java
  9. 18 20
      app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalJob.java
  10. 3 0
      app/src/main/java/com/nextcloud/talk/jobs/creator/MagicJobCreator.java
  11. 2 0
      app/src/main/java/com/nextcloud/talk/persistence/entities/User.java
  12. 3 2
      app/src/main/java/com/nextcloud/talk/utils/PushUtils.java
  13. 26 3
      app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java
  14. 74 11
      app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferences.java
  15. 81 0
      app/src/main/java/com/nextcloud/talk/utils/preferences/MagicUserInputModule.java
  16. 0 61
      app/src/main/java/com/nextcloud/talk/utils/preferences/json/ProxyTypeAdapter.java
  17. 178 3
      app/src/main/res/layout/controller_settings.xml
  18. 29 0
      app/src/main/res/values/arrays.xml
  19. 1 0
      app/src/main/res/values/dimens.xml
  20. 5 2
      app/src/main/res/values/setup.xml
  21. 25 0
      app/src/main/res/values/strings.xml

+ 27 - 20
app/build.gradle

@@ -8,7 +8,6 @@ versioning {
     //preRelease "rc1"
 }
 
-// For maven repository
 version = versioning.name
 
 android {
@@ -16,10 +15,9 @@ android {
     buildToolsVersion '26.0.2'
     defaultConfig {
         applicationId "com.nextcloud.talk"
+        versionName version
         minSdkVersion 21
         targetSdkVersion 26
-        versionCode 1
-        versionName "1.0"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
 
         // Enabling multidex support.
@@ -58,14 +56,22 @@ ext {
     googleLibraryVersion = '11.4.2'
 }
 
+
+configurations.all {
+    resolutionStrategy {
+        force "com.android.support:cardview-v7:${supportLibraryVersion}"
+        force "com.android.support:preference-v7:${supportLibraryVersion}"
+    }
+}
+
 dependencies {
     implementation fileTree(dir: 'libs', include: ['*.jar'])
     implementation "com.android.support:appcompat-v7:${supportLibraryVersion}"
     implementation "com.android.support:design:${supportLibraryVersion}"
     implementation 'com.android.support:multidex:1.0.2'
 
-    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
-    compile "io.reactivex.rxjava2:rxjava:2.1.4"
+    implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
+    implementation "io.reactivex.rxjava2:rxjava:2.1.4"
 
     implementation 'com.bluelinelabs:conductor:2.1.4'
     implementation 'com.bluelinelabs:conductor-support:2.1.4'
@@ -78,7 +84,7 @@ dependencies {
     annotationProcessor 'com.bluelinelabs:logansquare-compiler:1.3.7'
 
     implementation 'com.squareup.retrofit2:retrofit:2.3.0'
-    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
+    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
     implementation 'com.github.aurae.retrofit2:converter-logansquare:1.4.1'
 
     implementation 'com.google.dagger:dagger:2.8'
@@ -88,37 +94,36 @@ dependencies {
 
     implementation 'org.greenrobot:eventbus:3.0.0'
 
-    compile 'io.requery:requery:1.4.0'
-    compile 'io.requery:requery-android:1.4.0'
-    compile 'net.zetetic:android-database-sqlcipher:3.5.7'
-    annotationProcessor 'io.requery:requery-processor:1.4.0'
+    implementation 'io.requery:requery:1.4.1'
+    implementation 'io.requery:requery-android:1.4.1'
+    implementation 'net.zetetic:android-database-sqlcipher:3.5.7'
+    annotationProcessor 'io.requery:requery-processor:1.4.1'
 
     compile 'org.parceler:parceler-api:1.1.9'
     annotationProcessor 'org.parceler:parceler:1.1.9'
 
-    compile 'net.orange-box.storebox:storebox-lib:1.4.0'
+    implementation 'net.orange-box.storebox:storebox-lib:1.4.0'
 
     compileOnly "org.projectlombok:lombok:1.16.18"
     annotationProcessor "org.projectlombok:lombok:1.16.18"
 
-    compile 'com.jakewharton:butterknife:8.8.1'
+    implementation 'com.jakewharton:butterknife:8.8.1'
     annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
 
     debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
     releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
 
-    compile "javax.transaction:transaction-api:1.1-rev-1"
-
-    compile 'com.github.HITGIF:TextFieldBoxes:1.3.4'
+    implementation "javax.transaction:transaction-api:1.1-rev-1"
 
-    compile 'eu.davidea:flexible-adapter:5.0.0-rc2'
+    implementation 'com.github.HITGIF:TextFieldBoxes:1.3.4'
 
-    compile 'cn.carbs.android:AvatarImageView:1.0.4'
+    implementation 'eu.davidea:flexible-adapter:5.0.0-rc2'
 
-    compile 'com.github.bumptech.glide:glide:4.2.0'
-    annotationProcessor 'com.github.bumptech.glide:compiler:4.2.0'
-    compile 'com.github.bumptech.glide:okhttp3-integration:4.2.0@aar'
+    implementation 'cn.carbs.android:AvatarImageView:1.0.4'
 
+    implementation 'com.github.bumptech.glide:glide:4.3.0'
+    annotationProcessor 'com.github.bumptech.glide:compiler:4.3.0'
+    implementation 'com.github.bumptech.glide:okhttp3-integration:4.3.0@aar'
     implementation 'org.webrtc:google-webrtc:1.0.+'
     implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}"
 
@@ -130,6 +135,8 @@ dependencies {
     implementation "com.google.firebase:firebase-core:${googleLibraryVersion}"
 
     implementation 'com.yarolegovich:lovely-dialog:1.0.7'
+    implementation 'com.yarolegovich:lovelyinput:1.0.2'
+    implementation 'com.yarolegovich:mp:1.0.8'
 
     testImplementation 'junit:junit:4.12'
     androidTestImplementation ('com.android.support.test.espresso:espresso-core:3.0.1', {

+ 2 - 0
app/src/main/AndroidManifest.xml

@@ -1,4 +1,5 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
           package="com.nextcloud.talk">
 
     <uses-feature android:name="android.hardware.camera.any"/>
@@ -17,6 +18,7 @@
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 
     <application
+        tools:replace="label, icon, theme, roundIcon, name, allowBackup"
         android:name=".application.NextcloudTalkApplication"
         android:allowBackup="true"
         android:fullBackupContent="@xml/backup_config"

+ 1 - 1
app/src/main/java/com/nextcloud/talk/adapters/items/RoomItem.java

@@ -115,7 +115,7 @@ public class RoomItem extends AbstractFlexibleItem<RoomItem.RoomItemViewHolder>
                 if (!TextUtils.isEmpty(room.getName())) {
                     GlideUrl glideUrl = new GlideUrl(ApiHelper.getUrlForAvatarWithName(userEntity.getBaseUrl(),
                             room.getName()), new LazyHeaders.Builder()
-                            .setHeader("Accept", "*/*")
+                            .setHeader("Accept", "image/*")
                             .setHeader("User-Agent", ApiHelper.getUserAgent())
                             .build());
 

+ 1 - 1
app/src/main/java/com/nextcloud/talk/adapters/items/UserItem.java

@@ -101,7 +101,7 @@ public class UserItem extends AbstractFlexibleItem<UserItem.UserItemViewHolder>
 
         GlideUrl glideUrl = new GlideUrl(ApiHelper.getUrlForAvatarWithName(userEntity.getBaseUrl(),
                 user.getUserId()), new LazyHeaders.Builder()
-                .setHeader("Accept", "*/*")
+                .setHeader("Accept", "image/*")
                 .setHeader("User-Agent", ApiHelper.getUserAgent())
                 .build());
 

+ 9 - 5
app/src/main/java/com/nextcloud/talk/controllers/AccountVerificationController.java

@@ -134,7 +134,7 @@ public class AccountVerificationController extends BaseController {
 
                                 if (!TextUtils.isEmpty(displayName)) {
                                     dbQueryDisposable = userUtils.createOrUpdateUser(username, token,
-                                            baseUrl, displayName, null)
+                                            baseUrl, displayName, null, true)
                                             .subscribeOn(Schedulers.newThread())
                                             .observeOn(AndroidSchedulers.mainThread())
                                             .subscribe(userEntity -> {
@@ -146,10 +146,14 @@ public class AccountVerificationController extends BaseController {
                                                         new JobRequest.Builder(PushRegistrationJob.TAG).
                                                                 setUpdateCurrent(true).startNow().build().schedule();
 
-                                                        getRouter().setRoot(RouterTransaction.with(new
-                                                                BottomNavigationController(R.menu.menu_navigation))
-                                                                .pushChangeHandler(new HorizontalChangeHandler())
-                                                                .popChangeHandler(new HorizontalChangeHandler()));
+                                                        if (userUtils.getUsers().size() == 1) {
+                                                            getRouter().setRoot(RouterTransaction.with(new
+                                                                    BottomNavigationController(R.menu.menu_navigation))
+                                                                    .pushChangeHandler(new HorizontalChangeHandler())
+                                                                    .popChangeHandler(new HorizontalChangeHandler()));
+                                                        } else {
+                                                            getRouter().popToRoot();
+                                                        }
                                                     },
                                                     throwable -> {
                                                         progressText.setText(progressText.getText().toString() +

+ 271 - 0
app/src/main/java/com/nextcloud/talk/controllers/SettingsController.java

@@ -20,24 +20,295 @@
 
 package com.nextcloud.talk.controllers;
 
+import android.content.Intent;
+import android.net.Uri;
 import android.support.annotation.NonNull;
+import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.TextView;
 
+import com.bluelinelabs.conductor.RouterTransaction;
+import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler;
+import com.bumptech.glide.load.model.GlideUrl;
+import com.bumptech.glide.load.model.LazyHeaders;
+import com.nextcloud.talk.BuildConfig;
 import com.nextcloud.talk.R;
+import com.nextcloud.talk.api.helpers.api.ApiHelper;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.controllers.base.BaseController;
+import com.nextcloud.talk.persistence.entities.UserEntity;
+import com.nextcloud.talk.utils.ColorUtils;
+import com.nextcloud.talk.utils.database.user.UserUtils;
+import com.nextcloud.talk.utils.glide.GlideApp;
+import com.nextcloud.talk.utils.preferences.AppPreferences;
+import com.nextcloud.talk.utils.preferences.MagicUserInputModule;
+import com.yarolegovich.mp.MaterialChoicePreference;
+import com.yarolegovich.mp.MaterialEditTextPreference;
+import com.yarolegovich.mp.MaterialPreferenceScreen;
+import com.yarolegovich.mp.MaterialStandardPreference;
+
+import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.inject.Inject;
 
 import autodagger.AutoInjector;
+import butterknife.BindView;
+import cn.carbs.android.avatarimageview.library.AvatarImageView;
 
 @AutoInjector(NextcloudTalkApplication.class)
 public class SettingsController extends BaseController {
 
     public static final String TAG = "SettingsController";
 
+    @BindView(R.id.settings_screen)
+    MaterialPreferenceScreen settingsScreen;
+
+    @BindView(R.id.settings_proxy_choice)
+    MaterialChoicePreference proxyChoice;
+
+    @BindView(R.id.settings_proxy_port_edit)
+    MaterialEditTextPreference proxyPortEditText;
+
+    @BindView(R.id.settings_licence)
+    MaterialStandardPreference licenceButton;
+
+    @BindView(R.id.settings_privacy)
+    MaterialStandardPreference privacyButton;
+
+    @BindView(R.id.settings_source_code)
+    MaterialStandardPreference sourceCodeButton;
+
+    @BindView(R.id.settings_version)
+    MaterialStandardPreference versionInfo;
+
+    @BindView(R.id.avatar_image)
+    AvatarImageView avatarImageView;
+
+    @BindView(R.id.avatar_image_invisible)
+    AvatarImageView avatarImageViewInvisible;
+
+    @BindView(R.id.display_name_text)
+    TextView displayName;
+
+    @BindView(R.id.settings_remove_account)
+    MaterialStandardPreference removeAccountButton;
+
+    @BindView(R.id.settings_switch)
+    MaterialStandardPreference switchAccountButton;
+
+    @BindView(R.id.settings_reauthorize)
+    MaterialStandardPreference reauthorizeButton;
+
+    @BindView(R.id.settings_add_account)
+    MaterialStandardPreference addAccountButton;
+
+    @Inject
+    AppPreferences appPreferences;
+
+    @Inject
+    UserUtils userUtils;
+
+    private OnPreferenceValueChangedListener<String> proxyTypeChangeListener;
+    private OnPreferenceValueChangedListener<Boolean> proxyCredentialsChangeListener;
+
     @Override
     protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
         return inflater.inflate(R.layout.controller_settings, container, false);
     }
+
+    @Override
+    protected void onViewBound(@NonNull View view) {
+        super.onViewBound(view);
+        NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
+    }
+
+    @Override
+    protected void onAttach(@NonNull View view) {
+        super.onAttach(view);
+
+        if ("No proxy".equals(appPreferences.getProxyType()) || appPreferences.getProxyType() == null) {
+            hideProxySettings();
+        } else {
+            showProxySettings();
+        }
+
+        if (appPreferences.getProxyCredentials()) {
+            showProxyCredentials();
+        } else {
+            hideProxyCredentials();
+        }
+
+        appPreferences.registerProxyTypeListener(proxyTypeChangeListener = new ProxyTypeChangeListener());
+        appPreferences.registerProxyCredentialsListener(proxyCredentialsChangeListener = new
+                ProxyCredentialsChangeListener());
+
+        List<String> listWithIntFields = new ArrayList<>();
+        listWithIntFields.add("proxy_port");
+
+        settingsScreen.setUserInputModule(new MagicUserInputModule(getActivity(), listWithIntFields));
+        settingsScreen.setVisibilityController(R.id.settings_proxy_use_credentials,
+                Arrays.asList(R.id.settings_proxy_username_edit, R.id.settings_proxy_password_edit),
+                true);
+
+        if (!TextUtils.isEmpty(getResources().getString(R.string.nc_gpl3_url))) {
+            licenceButton.setOnClickListener(view1 -> {
+                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getResources().
+                        getString(R.string.nc_gpl3_url)));
+                startActivity(browserIntent);
+            });
+        } else {
+            licenceButton.setVisibility(View.GONE);
+        }
+
+        if (!TextUtils.isEmpty(getResources().getString(R.string.nc_privacy_url))) {
+            privacyButton.setOnClickListener(view12 -> {
+                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getResources().
+                        getString(R.string.nc_privacy_url)));
+                startActivity(browserIntent);
+            });
+        } else {
+            privacyButton.setVisibility(View.GONE);
+        }
+
+        if (!TextUtils.isEmpty(getResources().getString(R.string.nc_source_code_url))) {
+            sourceCodeButton.setOnClickListener(view13 -> {
+                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getResources().
+                        getString(R.string.nc_source_code_url)));
+                startActivity(browserIntent);
+            });
+        } else {
+            sourceCodeButton.setVisibility(View.GONE);
+        }
+
+        versionInfo.setSummary("v" + BuildConfig.VERSION_NAME);
+
+        UserEntity userEntity = userUtils.getCurrentUser();
+        if (userEntity != null) {
+            // Awful hack
+            avatarImageViewInvisible.setTextAndColorSeed(String.valueOf(userEntity.getDisplayName().
+                    toUpperCase().charAt(0)), ColorUtils.colorSeed);
+
+            GlideUrl glideUrl = new GlideUrl(ApiHelper.getUrlForAvatarWithName(userEntity.getBaseUrl(),
+                    userEntity.getUsername()), new LazyHeaders.Builder()
+                    .setHeader("Accept", "image/*")
+                    .setHeader("User-Agent", ApiHelper.getUserAgent())
+                    .build());
+
+            GlideApp.with(NextcloudTalkApplication.getSharedApplication().getApplicationContext())
+                    .load(glideUrl)
+                    .circleCrop()
+                    .centerInside()
+                    .into(avatarImageView)
+                    .onLoadFailed(avatarImageViewInvisible.getDrawable());
+
+            displayName.setText(userEntity.getDisplayName());
+        }
+
+        if (userUtils.getUsers().size() <= 1) {
+            switchAccountButton.setVisibility(View.GONE);
+        }
+
+
+        reauthorizeButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                getParentController().getRouter().pushController(RouterTransaction.with(
+                        new WebViewLoginController(userEntity.getBaseUrl(),
+                                true)).pushChangeHandler(new VerticalChangeHandler())
+                        .popChangeHandler(new VerticalChangeHandler()));
+            }
+        });
+
+        addAccountButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                getParentController().getRouter().pushController(RouterTransaction.with(new
+                        ServerSelectionController()).pushChangeHandler(new VerticalChangeHandler())
+                        .popChangeHandler(new VerticalChangeHandler()));
+            }
+        });
+    }
+
+    @Override
+    public void onDestroy() {
+        appPreferences.unregisterProxyTypeListener(proxyTypeChangeListener);
+        appPreferences.unregisterProxyCredentialsListener(proxyCredentialsChangeListener);
+        super.onDestroy();
+    }
+
+
+    private void hideProxySettings() {
+        appPreferences.removeProxyHost();
+        appPreferences.removeProxyPort();
+        appPreferences.removeProxyCredentials();
+        appPreferences.removeProxyUsername();
+        appPreferences.removeProxyPassword();
+        settingsScreen.findViewById(R.id.settings_proxy_host_edit).setVisibility(View.GONE);
+        settingsScreen.findViewById(R.id.settings_proxy_port_edit).setVisibility(View.GONE);
+        settingsScreen.findViewById(R.id.settings_proxy_use_credentials).setVisibility(View.GONE);
+        settingsScreen.findViewById(R.id.settings_proxy_username_edit).setVisibility(View.GONE);
+        settingsScreen.findViewById(R.id.settings_proxy_password_edit).setVisibility(View.GONE);
+    }
+
+    private void showProxySettings() {
+        settingsScreen.findViewById(R.id.settings_proxy_host_edit).setVisibility(View.VISIBLE);
+        settingsScreen.findViewById(R.id.settings_proxy_port_edit).setVisibility(View.VISIBLE);
+        settingsScreen.findViewById(R.id.settings_proxy_use_credentials).setVisibility(View.VISIBLE);
+    }
+
+    private void showProxyCredentials() {
+        settingsScreen.findViewById(R.id.settings_proxy_username_edit).setVisibility(View.VISIBLE);
+        settingsScreen.findViewById(R.id.settings_proxy_password_edit).setVisibility(View.VISIBLE);
+    }
+
+    private void hideProxyCredentials() {
+        appPreferences.removeProxyUsername();
+        appPreferences.removeProxyPassword();
+        settingsScreen.findViewById(R.id.settings_proxy_username_edit).setVisibility(View.GONE);
+        settingsScreen.findViewById(R.id.settings_proxy_password_edit).setVisibility(View.GONE);
+    }
+
+    private class ProxyCredentialsChangeListener implements OnPreferenceValueChangedListener<Boolean> {
+
+        @Override
+        public void onChanged(Boolean newValue) {
+            if (newValue) {
+                showProxyCredentials();
+            } else {
+                hideProxyCredentials();
+            }
+        }
+    }
+
+    private class ProxyTypeChangeListener implements OnPreferenceValueChangedListener<String> {
+
+        @Override
+        public void onChanged(String newValue) {
+            if ("No proxy".equals(newValue)) {
+                hideProxySettings();
+            } else {
+                switch (newValue) {
+                    case "HTTP":
+                        proxyPortEditText.setValue("3128");
+                        break;
+                    case "DIRECT":
+                        proxyPortEditText.setValue("8080");
+                        break;
+                    case "SOCKS":
+                        proxyPortEditText.setValue("1080");
+                        break;
+                    default:
+                        break;
+                }
+
+                showProxySettings();
+            }
+        }
+    }
 }

+ 15 - 4
app/src/main/java/com/nextcloud/talk/controllers/WebViewLoginController.java

@@ -29,6 +29,8 @@ import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.webkit.CookieManager;
+import android.webkit.CookieSyncManager;
 import android.webkit.SslErrorHandler;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
@@ -132,6 +134,10 @@ public class WebViewLoginController extends BaseController {
         webView.getSettings().setSavePassword(false);
         webView.clearCache(true);
         webView.clearFormData();
+        webView.clearHistory();
+
+        CookieSyncManager.createInstance(getActivity());
+        CookieManager.getInstance().removeAllCookies(null);
 
         Map<String, String> headers = new HashMap<>();
         headers.put("OCS-APIRequest", "true");
@@ -219,7 +225,7 @@ public class WebViewLoginController extends BaseController {
 
             // We use the URL user entered because one provided by the server is NOT reliable
             userQueryDisposable = userUtils.createOrUpdateUser(loginData.getUsername(), loginData.getToken(),
-                    baseUrl, displayName, pushConfiguration).
+                    baseUrl, displayName, pushConfiguration, true).
                     subscribe(userEntity -> {
                                 if (!isPasswordUpdate) {
                                     BundleBuilder bundleBuilder = new BundleBuilder(new Bundle());
@@ -230,9 +236,14 @@ public class WebViewLoginController extends BaseController {
                                             (bundleBuilder.build())).pushChangeHandler(new HorizontalChangeHandler())
                                             .popChangeHandler(new HorizontalChangeHandler()));
                                 } else {
-                                    getRouter().setRoot(RouterTransaction.with(new BottomNavigationController(R.menu.menu_navigation))
-                                            .pushChangeHandler(new HorizontalChangeHandler())
-                                            .popChangeHandler(new HorizontalChangeHandler()));
+                                    if (getRouter().hasRootController()) {
+                                        getRouter().popToRoot();
+                                    } else {
+                                        getRouter().setRoot(RouterTransaction.with(
+                                                new BottomNavigationController(R.menu.menu_navigation)
+                                        ).pushChangeHandler(new HorizontalChangeHandler())
+                                                .popChangeHandler(new HorizontalChangeHandler()));
+                                    }
                                 }
                             }, throwable -> dispose(),
                             this::dispose);

+ 14 - 12
app/src/main/java/com/nextcloud/talk/dagger/modules/RestModule.java

@@ -30,7 +30,6 @@ import com.nextcloud.talk.api.NcApi;
 import com.nextcloud.talk.api.helpers.api.ApiHelper;
 import com.nextcloud.talk.application.NextcloudTalkApplication;
 import com.nextcloud.talk.utils.preferences.AppPreferences;
-import com.nextcloud.talk.utils.preferences.json.ProxyPrefs;
 import com.nextcloud.talk.utils.ssl.MagicTrustManager;
 import com.nextcloud.talk.utils.ssl.SSLSocketFactoryCompat;
 
@@ -71,14 +70,16 @@ public class RestModule {
     @Provides
     @Singleton
     Proxy provideProxy(AppPreferences appPreferences) {
-        ProxyPrefs proxyPrefs = appPreferences.getProxyServer();
-        if (!TextUtils.isEmpty(proxyPrefs.getProxyHost())) {
-            if (Proxy.Type.SOCKS.equals(Proxy.Type.valueOf(proxyPrefs.getProxyType()))) {
-                return (new Proxy(Proxy.Type.valueOf(proxyPrefs.getProxyType()),
-                        InetSocketAddress.createUnresolved(proxyPrefs.getProxyHost(), proxyPrefs.getProxyPort())));
+        if (!TextUtils.isEmpty(appPreferences.getProxyType()) && !"No proxy".equals(appPreferences.getProxyType())
+                && !TextUtils.isEmpty(appPreferences.getProxyHost())) {
+            if (Proxy.Type.SOCKS.equals(Proxy.Type.valueOf(appPreferences.getProxyType()))) {
+                return (new Proxy(Proxy.Type.valueOf(appPreferences.getProxyType()),
+                        InetSocketAddress.createUnresolved(appPreferences.getProxyHost(), Integer.parseInt(
+                                appPreferences.getProxyPort()))));
             } else {
-                return (new Proxy(Proxy.Type.valueOf(proxyPrefs.getProxyType()),
-                        new InetSocketAddress(proxyPrefs.getProxyHost(), proxyPrefs.getProxyPort())));
+                return (new Proxy(Proxy.Type.valueOf(appPreferences.getProxyType()),
+                        new InetSocketAddress(appPreferences.getProxyHost(),
+                                Integer.parseInt(appPreferences.getProxyPort()))));
             }
         } else {
             return Proxy.NO_PROXY;
@@ -138,11 +139,12 @@ public class RestModule {
         if (!Proxy.NO_PROXY.equals(proxy)) {
             httpClient.proxy(proxy);
 
-            if (!TextUtils.isEmpty(appPreferences.getProxyServer().getUsername()) &&
-                    !TextUtils.isEmpty(appPreferences.getProxyServer().getPassword())) {
+            if (appPreferences.getProxyCredentials() &&
+                    !TextUtils.isEmpty(appPreferences.getProxyUsername()) &&
+                    !TextUtils.isEmpty(appPreferences.getProxyPassword())) {
                 httpClient.proxyAuthenticator(new ProxyAuthenticator(Credentials.basic(
-                        appPreferences.getProxyServer().getUsername(),
-                        appPreferences.getProxyServer().getPassword())));
+                        appPreferences.getProxyUsername(),
+                        appPreferences.getProxyPassword())));
             }
         }
 

+ 18 - 20
app/src/main/java/com/nextcloud/talk/utils/preferences/json/ProxyPrefs.java → app/src/main/java/com/nextcloud/talk/jobs/AccountRemovalJob.java

@@ -18,32 +18,30 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-package com.nextcloud.talk.utils.preferences.json;
+package com.nextcloud.talk.jobs;
 
-import com.bluelinelabs.logansquare.annotation.JsonField;
-import com.bluelinelabs.logansquare.annotation.JsonObject;
 
-import org.parceler.Parcel;
+import android.support.annotation.NonNull;
 
-import lombok.Data;
+import com.evernote.android.job.Job;
+import com.nextcloud.talk.application.NextcloudTalkApplication;
+import com.nextcloud.talk.utils.database.user.UserUtils;
 
+import javax.inject.Inject;
 
-@Data
-@Parcel
-@JsonObject
-public class ProxyPrefs {
-    @JsonField(name = "proxy_host")
-    String proxyHost;
+import autodagger.AutoInjector;
 
-    @JsonField(name = "proxy_port")
-    int proxyPort;
+@AutoInjector(NextcloudTalkApplication.class)
+public class AccountRemovalJob extends Job {
+    public static final String TAG = "AccountRemovalJob";
 
-    @JsonField(name = "proxy_type")
-    String proxyType;
+    @Inject
+    UserUtils userUtils;
 
-    @JsonField(name = "username")
-    String username;
-
-    @JsonField(name = "password")
-    String password;
+    @NonNull
+    @Override
+    protected Result onRunJob(Params params) {
+        NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
+        return Result.SUCCESS;
+    }
 }

+ 3 - 0
app/src/main/java/com/nextcloud/talk/jobs/creator/MagicJobCreator.java

@@ -25,6 +25,7 @@ import android.support.annotation.Nullable;
 
 import com.evernote.android.job.Job;
 import com.evernote.android.job.JobCreator;
+import com.nextcloud.talk.jobs.AccountRemovalJob;
 import com.nextcloud.talk.jobs.PushRegistrationJob;
 
 public class MagicJobCreator implements JobCreator {
@@ -36,6 +37,8 @@ public class MagicJobCreator implements JobCreator {
         switch (tag) {
             case PushRegistrationJob.TAG:
                 return new PushRegistrationJob();
+            case AccountRemovalJob.TAG:
+                return new AccountRemovalJob();
             default:
                 return null;
         }

+ 2 - 0
app/src/main/java/com/nextcloud/talk/persistence/entities/User.java

@@ -44,4 +44,6 @@ public interface User extends Parcelable, Persistable, Serializable {
     String getDisplayName();
 
     String getPushConfigurationState();
+
+    boolean getCurrent();
 }

+ 3 - 2
app/src/main/java/com/nextcloud/talk/utils/PushUtils.java

@@ -231,7 +231,8 @@ public class PushUtils {
                 if (userUtils.anyUserExists()) {
                     String providerValue;
                     PushConfigurationState accountPushData = null;
-                    for (UserEntity userEntity : userUtils.getUsers()) {
+                    for (Object userEntityObject : userUtils.getUsers()) {
+                        UserEntity userEntity = (UserEntity) userEntityObject;
                         providerValue = userEntity.getPushConfigurationState();
                         if (!TextUtils.isEmpty(providerValue)) {
                             try {
@@ -296,7 +297,7 @@ public class PushUtils {
                                                         userUtils.createOrUpdateUser(userEntity.getUsername(),
                                                                 userEntity.getToken(), userEntity.getBaseUrl(),
                                                                 userEntity.getDisplayName(),
-                                                                LoganSquare.serialize(pushConfigurationState))
+                                                                LoganSquare.serialize(pushConfigurationState), null)
                                                                 .subscribe(new Consumer<UserEntity>() {
                                                                     @Override
                                                                     public void accept(UserEntity userEntity) throws Exception {

+ 26 - 3
app/src/main/java/com/nextcloud/talk/utils/database/user/UserUtils.java

@@ -49,7 +49,7 @@ public class UserUtils {
         return (dataStore.count(User.class).limit(1).get().value() > 0);
     }
 
-    public List<UserEntity> getUsers() {
+    public List getUsers() {
         Result findUsersQueryResult = dataStore.select(User.class).get();
 
         return findUsersQueryResult.toList();
@@ -57,7 +57,8 @@ public class UserUtils {
 
     // temporary method while we only support 1 user
     public UserEntity getCurrentUser() {
-        Result findUserQueryResult = dataStore.select(User.class).limit(1).get();
+        Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.CURRENT.eq(true))
+                .limit(1).get();
 
         return (UserEntity) findUserQueryResult.firstOrNull();
     }
@@ -74,9 +75,21 @@ public class UserUtils {
 
     }
 
+    private void disableAllUsersWithoutId(long userId) {
+        Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.ID.notEqual(userId))
+                .and(UserEntity.CURRENT.eq(true)).get();
+
+        for (Object object : findUserQueryResult) {
+            UserEntity userEntity = (UserEntity) object;
+            userEntity.setCurrent(false);
+            dataStore.update(userEntity).blockingGet();
+        }
+    }
+
     public Observable<UserEntity> createOrUpdateUser(String username, String token, String serverUrl,
                                                      @Nullable String displayName,
-                                                     @Nullable String pushConfigurationState) {
+                                                     @Nullable String pushConfigurationState,
+                                                     @Nullable Boolean currentUser) {
         Result findUserQueryResult = dataStore.select(User.class).where(UserEntity.USERNAME.eq(username).
                 and(UserEntity.BASE_URL.eq(serverUrl.toLowerCase()))).limit(1).get();
 
@@ -96,6 +109,8 @@ public class UserUtils {
                 user.setPushConfigurationState(pushConfigurationState);
             }
 
+            user.setCurrent(true);
+
         } else {
             if (!token.equals(user.getToken())) {
                 user.setToken(token);
@@ -108,6 +123,14 @@ public class UserUtils {
             if (pushConfigurationState != null && !pushConfigurationState.equals(user.getPushConfigurationState())) {
                 user.setPushConfigurationState(pushConfigurationState);
             }
+
+            if (currentUser != null) {
+                user.setCurrent(currentUser);
+
+                if (currentUser) {
+                    disableAllUsersWithoutId(user.getId());
+                }
+            }
         }
 
         return dataStore.upsert(user)

+ 74 - 11
app/src/main/java/com/nextcloud/talk/utils/preferences/AppPreferences.java

@@ -20,30 +20,93 @@
 
 package com.nextcloud.talk.utils.preferences;
 
-import com.nextcloud.talk.utils.preferences.json.ProxyPrefs;
-import com.nextcloud.talk.utils.preferences.json.ProxyTypeAdapter;
-
 import net.orange_box.storebox.annotations.method.ClearMethod;
 import net.orange_box.storebox.annotations.method.KeyByString;
+import net.orange_box.storebox.annotations.method.RegisterChangeListenerMethod;
 import net.orange_box.storebox.annotations.method.RemoveMethod;
-import net.orange_box.storebox.annotations.method.TypeAdapter;
+import net.orange_box.storebox.annotations.method.UnregisterChangeListenerMethod;
 import net.orange_box.storebox.annotations.option.SaveOption;
 import net.orange_box.storebox.enums.SaveMode;
+import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener;
 
 @SaveOption(SaveMode.APPLY)
 public interface AppPreferences {
 
-    @KeyByString("proxy_server")
-    @TypeAdapter(ProxyTypeAdapter.class)
-    ProxyPrefs getProxyServer();
+    @KeyByString("proxy_type")
+    @RegisterChangeListenerMethod
+    void registerProxyTypeListener(OnPreferenceValueChangedListener<String> listener);
 
-    @KeyByString("proxy_server")
-    @TypeAdapter(ProxyTypeAdapter.class)
-    void setProxyServer(ProxyPrefs proxyPrefsServer);
+    @KeyByString("proxy_type")
+    @UnregisterChangeListenerMethod
+    void unregisterProxyTypeListener(OnPreferenceValueChangedListener<String> listener);
+
+    @KeyByString("proxy_type")
+    String getProxyType();
+
+    @KeyByString("proxy_type")
+    void setProxyType(String proxyType);
 
     @KeyByString("proxy_server")
     @RemoveMethod
-    void removeProxyServer();
+    void removeProxyType();
+
+    @KeyByString("proxy_host")
+    String getProxyHost();
+
+    @KeyByString("proxy_host")
+    void setProxyHost(String proxyHost);
+
+    @KeyByString("proxy_host")
+    @RemoveMethod
+    void removeProxyHost();
+
+    @KeyByString("proxy_port")
+    String getProxyPort();
+
+    @KeyByString("proxy_port")
+    void setProxyPort(String proxyPort);
+
+    @KeyByString("proxy_port")
+    @RemoveMethod
+    void removeProxyPort();
+
+    @KeyByString("proxy_credentials")
+    @RegisterChangeListenerMethod
+    void registerProxyCredentialsListener(OnPreferenceValueChangedListener<Boolean> listener);
+
+    @KeyByString("proxy_credentials")
+    @UnregisterChangeListenerMethod
+    void unregisterProxyCredentialsListener(OnPreferenceValueChangedListener<Boolean> listener);
+
+    @KeyByString("proxy_credentials")
+    boolean getProxyCredentials();
+
+    @KeyByString("proxy_credentials")
+    void setProxyNeedsCredentials(boolean proxyNeedsCredentials);
+
+    @KeyByString("proxy_credentials")
+    @RemoveMethod
+    void removeProxyCredentials();
+
+    @KeyByString("proxy_username")
+    String getProxyUsername();
+
+    @KeyByString("proxy_username")
+    void setProxyUsername(String proxyUsername);
+
+    @KeyByString("proxy_username")
+    @RemoveMethod
+    void removeProxyUsername();
+
+    @KeyByString("proxy_password")
+    String getProxyPassword();
+
+    @KeyByString("proxy_password")
+    void setProxyPassword(String proxyPassword);
+
+    @KeyByString("proxy_password")
+    @RemoveMethod
+    void removeProxyPassword();
 
     @KeyByString("push_token")
     String getPushToken();

+ 81 - 0
app/src/main/java/com/nextcloud/talk/utils/preferences/MagicUserInputModule.java

@@ -0,0 +1,81 @@
+/*
+ * Nextcloud Talk application
+ *
+ * @author Mario Danic
+ * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.nextcloud.talk.utils.preferences;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.support.v7.app.AlertDialog;
+import android.text.InputType;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+
+import com.nextcloud.talk.R;
+import com.yarolegovich.mp.io.StandardUserInputModule;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MagicUserInputModule extends StandardUserInputModule {
+
+    private List<String> keysWithIntegerInput = new ArrayList<>();
+
+    public MagicUserInputModule(Context context) {
+        super(context);
+    }
+
+    public MagicUserInputModule(Context context, List<String> keysWithIntegerInput) {
+        super(context);
+        this.keysWithIntegerInput = keysWithIntegerInput;
+    }
+
+    @Override
+    public void showEditTextInput(
+            String key,
+            CharSequence title,
+            CharSequence defaultValue,
+            final Listener<String> listener) {
+        final View view = LayoutInflater.from(context).inflate(R.layout.dialog_edittext, null);
+        final EditText inputField = (EditText) view.findViewById(R.id.mp_text_input);
+
+        if (defaultValue != null) {
+            inputField.setText(defaultValue);
+            inputField.setSelection(defaultValue.length());
+        }
+
+        if (keysWithIntegerInput.contains(key)) {
+            inputField.setInputType(InputType.TYPE_CLASS_NUMBER);
+        }
+
+        final Dialog dialog = new AlertDialog.Builder(context)
+                .setTitle(title)
+                .setView(view)
+                .show();
+        view.findViewById(R.id.mp_btn_confirm).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                listener.onInput(inputField.getText().toString());
+                dialog.dismiss();
+            }
+        });
+    }
+
+}

+ 0 - 61
app/src/main/java/com/nextcloud/talk/utils/preferences/json/ProxyTypeAdapter.java

@@ -1,61 +0,0 @@
-/*
- * Nextcloud Talk application
- *
- * @author Mario Danic
- * Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.nextcloud.talk.utils.preferences.json;
-
-import android.support.annotation.Nullable;
-import android.util.Log;
-
-import com.bluelinelabs.logansquare.LoganSquare;
-
-import net.orange_box.storebox.adapters.base.BaseStringTypeAdapter;
-
-import java.io.IOException;
-
-public class ProxyTypeAdapter extends BaseStringTypeAdapter<ProxyPrefs> {
-
-    private static final String TAG = "ProxyTypeAdapter";
-
-    @Nullable
-    @Override
-    public String adaptForPreferences(@Nullable ProxyPrefs value) {
-        if (value != null) {
-            try {
-                return LoganSquare.serialize(value);
-            } catch (IOException e) {
-                Log.d(TAG, "Failed to serialize proxy from preferences");
-            }
-        }
-        return "";
-    }
-
-    @Nullable
-    @Override
-    public ProxyPrefs adaptFromPreferences(@Nullable String value) {
-        if (value != null) {
-            try {
-                return LoganSquare.parse(value, ProxyPrefs.class);
-            } catch (IOException e) {
-                Log.d(TAG, "Failed to parse proxy from preferences");
-            }
-        }
-        return new ProxyPrefs();
-    }
-}

+ 178 - 3
app/src/main/res/layout/controller_settings.xml

@@ -19,8 +19,183 @@
   ~ along with this program.  If not, see <http://www.gnu.org/licenses/>.
   -->
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.yarolegovich.mp.MaterialPreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+                                              xmlns:apc="http://schemas.android.com/apk/res-auto"
+                                              android:id="@+id/settings_screen"
+                                              android:layout_width="match_parent"
+                                              android:layout_height="match_parent">
+
+    <com.yarolegovich.mp.MaterialPreferenceCategory
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:animateLayoutChanges="true">
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+            <cn.carbs.android.avatarimageview.library.AvatarImageView
+                android:id="@+id/avatar_image_invisible"
+                android:layout_width="@dimen/avatar_size_big"
+                android:layout_height="@dimen/avatar_size_big"
+                android:layout_centerHorizontal="true"
+                android:scaleType="centerInside"
+                android:visibility="invisible"
+                apc:aiv_CornerRadius="@dimen/avatar_corner_radius"
+                apc:aiv_ShowBoarder="false"
+                apc:aiv_TextSizeRatio="0.5"/>
+
+            <cn.carbs.android.avatarimageview.library.AvatarImageView
+                android:id="@+id/avatar_image"
+                android:layout_width="@dimen/avatar_size_big"
+                android:layout_height="@dimen/avatar_size_big"
+                android:layout_centerHorizontal="true"
+                android:scaleType="centerInside"
+                apc:aiv_CornerRadius="@dimen/avatar_corner_radius"
+                apc:aiv_ShowBoarder="false"
+                apc:aiv_TextSizeRatio="0.5"/>
+
+            <TextView
+                android:id="@+id/display_name_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/avatar_image"
+                android:layout_centerHorizontal="true"
+                android:layout_margin="@dimen/margin_between_elements"/>
+
+            <com.yarolegovich.mp.MaterialStandardPreference
+                android:id="@+id/settings_switch"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                apc:mp_title="@string/nc_settings_switch_account"
+                android:layout_below="@id/display_name_text"
+                android:tag="switchAccountButton"/>
+
+            <com.yarolegovich.mp.MaterialStandardPreference
+                android:id="@+id/settings_reauthorize"
                 android:layout_width="match_parent"
-                android:layout_height="match_parent">
+                android:layout_height="wrap_content"
+                apc:mp_title="@string/nc_settings_reauthorize"
+                android:layout_below="@id/settings_switch"/>
+
+            <com.yarolegovich.mp.MaterialStandardPreference
+                android:id="@+id/settings_remove_account"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                apc:mp_title="@string/nc_settings_remove_account"
+                android:layout_below="@id/settings_reauthorize"/>
+
+            <com.yarolegovich.mp.MaterialStandardPreference
+                android:id="@+id/settings_add_account"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                apc:mp_title="@string/nc_settings_add_account"
+                android:layout_below="@id/settings_remove_account"/>
+
+        </RelativeLayout>
+
+    </com.yarolegovich.mp.MaterialPreferenceCategory>
+
+    <com.yarolegovich.mp.MaterialPreferenceCategory
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:animateLayoutChanges="true"
+        apc:mpc_title="@string/nc_settings_proxy_title"
+        apc:mpc_title_color="@color/colorPrimary">
+
+        <com.yarolegovich.mp.MaterialChoicePreference
+            android:id="@+id/settings_proxy_choice"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            apc:mp_default_value="@string/nc_no_proxy"
+            apc:mp_entry_descriptions="@array/proxy_type_descriptions"
+            apc:mp_key="@string/nc_settings_proxy_type_key"
+            apc:mp_show_value="onRight"
+            apc:mp_title="@string/nc_settings_proxy_type_title">
+        </com.yarolegovich.mp.MaterialChoicePreference>
+
+        <com.yarolegovich.mp.MaterialEditTextPreference
+            android:id="@+id/settings_proxy_host_edit"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            apc:mp_key="@string/nc_settings_proxy_host_key"
+            apc:mp_show_value="onRight"
+            apc:mp_title="@string/nc_settings_proxy_host_title"/>
+
+        <com.yarolegovich.mp.MaterialEditTextPreference
+            android:id="@+id/settings_proxy_port_edit"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            apc:mp_key="@string/nc_settings_proxy_port_key"
+            apc:mp_show_value="onRight"
+            apc:mp_title="@string/nc_settings_proxy_port_title"/>
+
+        <com.yarolegovich.mp.MaterialSwitchPreference
+            android:id="@+id/settings_proxy_use_credentials"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            apc:mp_default_value="false"
+            apc:mp_key="@string/nc_settings_use_credentials_key"
+            apc:mp_show_value="onRight"
+            apc:mp_title="@string/nc_settings_use_credentials_title">
+
+        </com.yarolegovich.mp.MaterialSwitchPreference>
+
+        <com.yarolegovich.mp.MaterialEditTextPreference
+            android:id="@+id/settings_proxy_username_edit"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            apc:mp_key="@string/nc_settings_proxy_username_key"
+            apc:mp_show_value="onRight"
+            apc:mp_title="@string/nc_username"/>
+
+        <com.yarolegovich.mp.MaterialEditTextPreference
+            android:id="@+id/settings_proxy_password_edit"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            apc:mp_key="@string/nc_settings_proxy_password_key"
+            apc:mp_show_value="onRight"
+            apc:mp_title="@string/nc_password"/>
+
+    </com.yarolegovich.mp.MaterialPreferenceCategory>
+
+    <com.yarolegovich.mp.MaterialPreferenceCategory
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/padding_between_elements"
+        android:animateLayoutChanges="true"
+        apc:mpc_title="@string/nc_about"
+        apc:mpc_title_color="@color/colorPrimary">
+
+        <com.yarolegovich.mp.MaterialStandardPreference
+            android:id="@+id/settings_privacy"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            apc:mp_title="@string/nc_privacy"/>
+
+        <com.yarolegovich.mp.MaterialStandardPreference
+            android:id="@+id/settings_source_code"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            apc:mp_title="@string/nc_get_source_code">
+        </com.yarolegovich.mp.MaterialStandardPreference>
+
+        <com.yarolegovich.mp.MaterialStandardPreference
+            android:id="@+id/settings_licence"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            apc:mp_summary="@string/nc_license_summary"
+            apc:mp_title="@string/nc_license_title">
+        </com.yarolegovich.mp.MaterialStandardPreference>
+
+        <com.yarolegovich.mp.MaterialStandardPreference
+            android:id="@+id/settings_version"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            apc:mp_summary="v0.1"
+            apc:mp_title="@string/nc_app_name">
+        </com.yarolegovich.mp.MaterialStandardPreference>
+
+    </com.yarolegovich.mp.MaterialPreferenceCategory>
 
-</RelativeLayout>
+</com.yarolegovich.mp.MaterialPreferenceScreen>

+ 29 - 0
app/src/main/res/values/arrays.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Nextcloud Talk application
+  ~
+  ~ @author Mario Danic
+  ~ Copyright (C) 2017 Mario Danic <mario@lovelyhq.com>
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU General Public License as published by
+  ~ the Free Software Foundation, either version 3 of the License, or
+  ~ at your option) any later version.
+  ~
+  ~ This program is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  ~ GNU General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU General Public License
+  ~ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+  -->
+
+<resources>
+    <array name="proxy_type_descriptions">
+        <item>No proxy</item>
+        <item>HTTP</item>
+        <item>DIRECT</item>
+        <item>SOCKS</item>
+    </array>
+</resources>

+ 1 - 0
app/src/main/res/values/dimens.xml

@@ -15,6 +15,7 @@
     <dimen name="padding_between_elements">8dp</dimen>
     <dimen name="margin_between_elements">8dp</dimen>
     <dimen name="avatar_size">40dp</dimen>
+    <dimen name="avatar_size_big">80dp</dimen>
     <dimen name="avatar_corner_radius">20dp</dimen>
 
 </resources>

+ 5 - 2
app/src/main/res/values/setup.xml

@@ -8,7 +8,10 @@
     <string name="nc_server_product_name">Nextcloud</string>
 
     <color name="nc_background_color">@color/per70white</color>
-
     <string name="nc_push_server_url">https://push-notifications.nextcloud.com</string>
 
-</resources>
+    <!-- Will not be shown if empty -->
+    <string name="nc_privacy_url">https://nextcloud.com/privacy/</string>
+    <string name="nc_gpl3_url">https://www.gnu.org/licenses/gpl-3.0.en.html</string>
+    <string name="nc_source_code_url">https://github.com/nextcloud/talk-android</string>
+</resources>

+ 25 - 0
app/src/main/res/values/strings.xml

@@ -31,4 +31,29 @@
     <string name="nc_details">Details</string>
     <string name="nc_certificate_error">Your SSL setup prevented us from connecting</string>
 
+    <!-- Settings -->
+    <string name="nc_settings_proxy_title">Proxy</string>
+    <string name="nc_settings_proxy_type_key">proxy_type</string>
+    <string name="nc_settings_proxy_type_title">Proxy type</string>
+    <string name="nc_settings_proxy_host_key">proxy_host</string>
+    <string name="nc_settings_proxy_host_title">Proxy host</string>
+    <string name="nc_settings_proxy_port_key">proxy_port</string>
+    <string name="nc_settings_proxy_port_title">Proxy port</string>
+    <string name="nc_settings_proxy_username_key">proxy_username</string>
+    <string name="nc_settings_proxy_password_key">proxy_password</string>
+    <string name="nc_settings_use_credentials_title">Use credentials</string>
+    <string name="nc_settings_use_credentials_key">proxy_credentials</string>
+    <string name="nc_settings_switch_account">Switch between accounts</string>
+    <string name="nc_settings_reauthorize">Reauthorize</string>
+    <string name="nc_settings_remove_account">Remove account</string>
+    <string name="nc_settings_add_account">Add a new account</string>
+
+    <string name="nc_no_proxy">No proxy</string>
+    <string name="nc_username">Username</string>
+    <string name="nc_password">Password</string>
+    <string name="nc_about">About</string>
+    <string name="nc_privacy">Privacy</string>
+    <string name="nc_get_source_code">Get source code</string>
+    <string name="nc_license_title">License</string>
+    <string name="nc_license_summary">GNU General Public License, Version 3</string>
 </resources>