Selaa lähdekoodia

user container-styling for text field on login screen

* utilize endIcon capabilities
* move to native view binding

Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Andy Scherzinger 4 vuotta sitten
vanhempi
commit
c8144a08d5

+ 2 - 1
src/androidTest/java/com/owncloud/android/ui/LoginIT.java

@@ -47,6 +47,7 @@ import androidx.test.rule.GrantPermissionRule;
 import static androidx.test.espresso.Espresso.onView;
 import static androidx.test.espresso.action.ViewActions.click;
 import static androidx.test.espresso.action.ViewActions.typeText;
+import static androidx.test.espresso.action.ViewActions.typeTextIntoFocusedView;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 import static androidx.test.espresso.web.sugar.Web.onWebView;
 import static androidx.test.espresso.web.webdriver.DriverAtoms.findElement;
@@ -86,7 +87,7 @@ public class LoginIT extends AbstractIT {
 
         onView(withId(R.id.login)).perform(click());
         onView(withId(R.id.host_url_input)).perform(typeText(baseUrl));
-        onView(withId(R.id.test_server_button)).perform(click());
+        onView(withId(R.id.host_url_input)).perform(typeTextIntoFocusedView("\n"));
 
         Thread.sleep(3000);
 

+ 83 - 88
src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -73,7 +73,6 @@ import android.webkit.WebResourceRequest;
 import android.webkit.WebResourceResponse;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
-import android.widget.EditText;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
 import android.widget.TextView;
@@ -91,6 +90,8 @@ import com.nextcloud.client.onboarding.OnboardingService;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
+import com.owncloud.android.databinding.AccountSetupBinding;
+import com.owncloud.android.databinding.AccountSetupWebviewBinding;
 import com.owncloud.android.lib.common.OwnCloudAccount;
 import com.owncloud.android.lib.common.OwnCloudClient;
 import com.owncloud.android.lib.common.OwnCloudClientFactory;
@@ -198,7 +199,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
     private static final int REQUEST_CODE_QR_SCAN = 101;
     public static final int REQUEST_CODE_FIRST_RUN = 102;
 
-
     /// parameters from EXTRAs in starter Intent
     private byte mAction;
     private Account mAccount;
@@ -210,8 +210,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
     private AccountManager mAccountMgr;
 
     /// Server PRE-Fragment elements
-    private EditText mHostUrlInput;
-    private TextView mServerStatusView;
+    private AccountSetupBinding accountSetupBinding;
+    private AccountSetupWebviewBinding accountSetupWebviewBinding;
 
     private String mServerStatusText = EMPTY_STRING;
     private int mServerStatusIcon;
@@ -219,9 +219,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
     private GetServerInfoOperation.ServerInfo mServerInfo = new GetServerInfoOperation.ServerInfo();
 
     /// Authentication PRE-Fragment elements
-    private TextView mAuthStatusView;
-    private WebView mLoginWebView;
-
     private WebViewFidoBridge webViewFidoU2fBridge;
     private WebViewWebauthnBridge webViewWebauthnBridge;
 
@@ -308,11 +305,12 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
         /// load user interface
         if (webViewLoginMethod) {
             setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
-            setContentView(R.layout.account_setup_webview);
-            mLoginWebView = findViewById(R.id.login_webview);
+            accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater());
+            setContentView(accountSetupWebviewBinding.getRoot());
             initWebViewLogin(webloginUrl, false);
         } else {
-            setContentView(R.layout.account_setup);
+            accountSetupBinding = AccountSetupBinding.inflate(getLayoutInflater());
+            setContentView(accountSetupBinding.getRoot());
 
             /// initialize general UI elements
             initOverallUi();
@@ -321,7 +319,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
 
             /// initialize block to be moved to single Fragment to retrieve and validate credentials
             initAuthorizationPreFragment(savedInstanceState);
-
         }
 
         initServerPreFragment(savedInstanceState);
@@ -344,32 +341,32 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
     @SuppressFBWarnings("ANDROID_WEB_VIEW_JAVASCRIPT")
     @SuppressLint("SetJavaScriptEnabled")
     private void initWebViewLogin(String baseURL, boolean useGenericUserAgent) {
-        mLoginWebView.setVisibility(View.GONE);
+        accountSetupWebviewBinding.loginWebview.setVisibility(View.GONE);
 
-        final ProgressBar progressBar = findViewById(R.id.login_webview_progress_bar);
-
-        mLoginWebView.getSettings().setAllowFileAccess(false);
-        mLoginWebView.getSettings().setJavaScriptEnabled(true);
-        mLoginWebView.getSettings().setDomStorageEnabled(true);
+        accountSetupWebviewBinding.loginWebview.getSettings().setAllowFileAccess(false);
+        accountSetupWebviewBinding.loginWebview.getSettings().setJavaScriptEnabled(true);
+        accountSetupWebviewBinding.loginWebview.getSettings().setDomStorageEnabled(true);
 
         if (useGenericUserAgent) {
-            mLoginWebView.getSettings().setUserAgentString(MainApp.getUserAgent());
+            accountSetupWebviewBinding.loginWebview.getSettings().setUserAgentString(MainApp.getUserAgent());
         } else {
-            mLoginWebView.getSettings().setUserAgentString(getWebLoginUserAgent());
+            accountSetupWebviewBinding.loginWebview.getSettings().setUserAgentString(getWebLoginUserAgent());
         }
-        mLoginWebView.getSettings().setSaveFormData(false);
-        mLoginWebView.getSettings().setSavePassword(false);
+        accountSetupWebviewBinding.loginWebview.getSettings().setSaveFormData(false);
+        accountSetupWebviewBinding.loginWebview.getSettings().setSavePassword(false);
 
         FidoDialogOptions.Builder dialogOptionsBuilder = FidoDialogOptions.builder();
         dialogOptionsBuilder.setShowSdkLogo(true);
         dialogOptionsBuilder.setTheme(R.style.FidoDialog);
-        webViewFidoU2fBridge = WebViewFidoBridge.createInstanceForWebView(this, mLoginWebView, dialogOptionsBuilder);
+        webViewFidoU2fBridge = WebViewFidoBridge.createInstanceForWebView(
+            this, accountSetupWebviewBinding.loginWebview, dialogOptionsBuilder);
 
         WebauthnDialogOptions.Builder webauthnOptionsBuilder = WebauthnDialogOptions.builder();
         webauthnOptionsBuilder.setShowSdkLogo(true);
         webauthnOptionsBuilder.setAllowSkipPin(true);
         webauthnOptionsBuilder.setTheme(R.style.FidoDialog);
-        webViewWebauthnBridge = WebViewWebauthnBridge.createInstanceForWebView(this, mLoginWebView, webauthnOptionsBuilder);
+        webViewWebauthnBridge = WebViewWebauthnBridge.createInstanceForWebView(
+            this, accountSetupWebviewBinding.loginWebview, webauthnOptionsBuilder);
 
         Map<String, String> headers = new HashMap<>();
         headers.put(RemoteOperation.OCS_API_HEADER, RemoteOperation.OCS_API_HEADER_VALUE);
@@ -381,17 +378,17 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             url = getResources().getString(R.string.webview_login_url);
         }
 
-        mLoginWebView.loadUrl(url, headers);
+        accountSetupWebviewBinding.loginWebview.loadUrl(url, headers);
 
-        setClient(progressBar);
+        setClient(accountSetupWebviewBinding.loginWebviewProgressBar);
     }
 
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (mLoginWebView != null && event.getAction() == KeyEvent.ACTION_DOWN &&
+        if (accountSetupWebviewBinding != null && event.getAction() == KeyEvent.ACTION_DOWN &&
             keyCode == KeyEvent.KEYCODE_BACK) {
-            if (mLoginWebView.canGoBack()) {
-                mLoginWebView.goBack();
+            if (accountSetupWebviewBinding.loginWebview.canGoBack()) {
+                accountSetupWebviewBinding.loginWebview.goBack();
             } else {
                 finish();
             }
@@ -401,7 +398,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
     }
 
     private void setClient(ProgressBar progressBar) {
-        mLoginWebView.setWebViewClient(new WebViewClient() {
+        accountSetupWebviewBinding.loginWebview.setWebViewClient(new WebViewClient() {
             @Override
             public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
                 webViewFidoU2fBridge.delegateShouldInterceptRequest(view, request);
@@ -429,8 +426,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             public void onPageFinished(WebView view, String url) {
                 super.onPageFinished(view, url);
 
-                progressBar.setVisibility(View.GONE);
-                mLoginWebView.setVisibility(View.VISIBLE);
+                accountSetupWebviewBinding.loginWebviewProgressBar.setVisibility(View.GONE);
+                accountSetupWebviewBinding.loginWebview.setVisibility(View.VISIBLE);
 
                 ThemeUtils.colorStatusBar(AuthenticatorActivity.this, primaryColor);
                 getWindow().setNavigationBarColor(primaryColor);
@@ -452,14 +449,14 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             }
 
             public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
-                progressBar.setVisibility(View.GONE);
-                mLoginWebView.setVisibility(View.VISIBLE);
+                accountSetupWebviewBinding.loginWebviewProgressBar.setVisibility(View.GONE);
+                accountSetupWebviewBinding.loginWebview.setVisibility(View.VISIBLE);
 
                 InputStream resources = getResources().openRawResource(R.raw.custom_error);
                 String customError = DisplayUtils.getData(resources);
 
                 if (!customError.isEmpty()) {
-                    mLoginWebView.loadData(customError, "text/html; charset=UTF-8", null);
+                    accountSetupWebviewBinding.loginWebview.loadData(customError, "text/html; charset=UTF-8", null);
                 }
             }
         });
@@ -470,8 +467,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             String prefix = getString(R.string.login_data_own_scheme) + PROTOCOL_SUFFIX + "login/";
             LoginUrlInfo loginUrlInfo = parseLoginDataUrl(prefix, dataString);
 
-            if (mHostUrlInput != null) {
-                mHostUrlInput.setText("");
+            if (accountSetupBinding != null) {
+                accountSetupBinding.hostUrlInput.setText("");
             }
             mServerInfo.mBaseUrl = AuthenticatorUrlUtils.normalizeUrlSuffix(loginUrlInfo.serverAddress);
             webViewUser = loginUrlInfo.username;
@@ -530,23 +527,17 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
      * Configures elements in the user interface under direct control of the Activity.
      */
     private void initOverallUi() {
-        mHostUrlInput = findViewById(R.id.host_url_input);
-        mAuthStatusView = findViewById(R.id.auth_status_text);
-        mServerStatusView = findViewById(R.id.server_status_text);
+        accountSetupBinding.hostUrlContainer.setEndIconOnClickListener(v -> checkOcServer());
 
-        ImageView scanQR = findViewById(R.id.scan_qr);
         if (deviceInfo.hasCamera(this)) {
-            scanQR.setOnClickListener(v -> onScan());
-            ThemeUtils.tintDrawable(scanQR.getDrawable(), getResources().getColor(R.color.login_text_color));
+            accountSetupBinding.scanQr.setOnClickListener(v -> onScan());
+            ThemeUtils.tintDrawable(accountSetupBinding.scanQr.getDrawable(),
+                                    getResources().getColor(R.color.login_text_color));
         } else {
-            scanQR.setVisibility(View.GONE);
+            accountSetupBinding.scanQr.setVisibility(View.GONE);
         }
     }
 
-    public void onTestServerConnectionClick(View v) {
-        checkOcServer();
-    }
-
     /**
      * @param savedInstanceState Saved activity state, as in {{@link #onCreate(Bundle)}
      */
@@ -588,10 +579,6 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
      * @param savedInstanceState Saved activity state, as in {{@link #onCreate(Bundle)}
      */
     private void initAuthorizationPreFragment(Bundle savedInstanceState) {
-
-        /// step 0 - get UI elements in layout
-        mAuthStatusView = findViewById(R.id.auth_status_text);
-
         /// step 1 - load and process relevant inputs (resources, intent, savedInstanceState)
         if (savedInstanceState != null) {
             mAuthStatusText = savedInstanceState.getString(KEY_AUTH_STATUS_TEXT);
@@ -601,8 +588,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
         /// step 2 - set properties of UI elements (text, visibility, enabled...)
         showAuthStatus();
 
-        mHostUrlInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
-        mHostUrlInput.setOnEditorActionListener(this);
+        accountSetupBinding.hostUrlInput.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+        accountSetupBinding.hostUrlInput.setOnEditorActionListener(this);
     }
 
     /**
@@ -689,8 +676,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
         }
 
         if (intent.getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, false)) {
-            setContentView(R.layout.account_setup_webview);
-            mLoginWebView = findViewById(R.id.login_webview);
+            accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater());
+            setContentView(accountSetupWebviewBinding.getRoot());
             initWebViewLogin(getString(R.string.provider_registration_server), true);
         }
     }
@@ -719,7 +706,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
         if (!bindService(new Intent(this, OperationsService.class),
                          mOperationsServiceConnection,
                          Context.BIND_AUTO_CREATE)) {
-            DisplayUtils.showSnackMessage(findViewById(R.id.scroll), R.string.error_cant_bind_to_operations_service);
+            DisplayUtils.showSnackMessage(accountSetupBinding.scroll, R.string.error_cant_bind_to_operations_service);
             finish();
         }
 
@@ -753,8 +740,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
 
     private void checkOcServer() {
         String uri;
-        if (mHostUrlInput != null && !mHostUrlInput.getText().toString().isEmpty()) {
-            uri = mHostUrlInput.getText().toString().trim();
+        if (accountSetupBinding != null && !accountSetupBinding.hostUrlInput.getText().toString().isEmpty()) {
+            uri = accountSetupBinding.hostUrlInput.getText().toString().trim();
         } else {
             uri = mServerInfo.mBaseUrl;
         }
@@ -762,9 +749,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
         mServerInfo = new GetServerInfoOperation.ServerInfo();
 
         if (uri.length() != 0) {
-            if (mHostUrlInput != null) {
+            if (accountSetupBinding != null) {
                 uri = AuthenticatorUrlUtils.stripIndexPhpOrAppsFiles(uri);
-                mHostUrlInput.setText(uri);
+                accountSetupBinding.hostUrlInput.setText(uri);
             }
 
             // Handle internationalized domain names
@@ -775,7 +762,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
                 Log_OC.e(TAG, "Error converting internationalized domain name " + uri, ex);
             }
 
-            if (mHostUrlInput != null) {
+            if (accountSetupBinding != null) {
                 mServerStatusText = getResources().getString(R.string.auth_testing_connection);
                 mServerStatusIcon = R.drawable.progress_small;
                 showServerStatus();
@@ -852,7 +839,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
 
                 } catch (AccountNotFoundException e) {
                     Log_OC.e(TAG, "Account " + mAccount + " was removed!", e);
-                    DisplayUtils.showSnackMessage(findViewById(R.id.scroll), R.string.auth_account_does_not_exist);
+                    DisplayUtils.showSnackMessage(accountSetupBinding.scroll, R.string.auth_account_does_not_exist);
                     finish();
                 }
             }
@@ -915,8 +902,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
                     }
                 }).start();
 
-                setContentView(R.layout.account_setup_webview);
-                mLoginWebView = findViewById(R.id.login_webview);
+                accountSetupWebviewBinding = AccountSetupWebviewBinding.inflate(getLayoutInflater());
+                setContentView(accountSetupWebviewBinding.getRoot());
                 initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false);
             }
         } else {
@@ -946,7 +933,12 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
 
             case OK_NO_SSL:
             case OK:
-                if (mHostUrlInput.getText().toString().trim().toLowerCase(Locale.ROOT).startsWith(HTTP_PROTOCOL)) {
+                if (accountSetupBinding.hostUrlInput
+                    .getText()
+                    .toString()
+                    .trim()
+                    .toLowerCase(Locale.ROOT)
+                    .startsWith(HTTP_PROTOCOL)) {
                     mServerStatusText = getResources().getString(R.string.auth_connection_established);
                     mServerStatusIcon = R.drawable.ic_ok;
                 } else {
@@ -1044,7 +1036,12 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             case OK_NO_SSL:
             case OK:
                 if (showWebViewLoginUrl) {
-                    if (mHostUrlInput.getText().toString().trim().toLowerCase(Locale.ROOT).startsWith(HTTP_PROTOCOL)) {
+                    if (accountSetupBinding.hostUrlInput
+                        .getText()
+                        .toString()
+                        .trim()
+                        .toLowerCase(Locale.ROOT)
+                        .startsWith(HTTP_PROTOCOL)) {
                         mAuthStatusText = getResources().getString(R.string.auth_connection_established);
                         mAuthStatusIcon = R.drawable.ic_ok;
                     } else {
@@ -1115,7 +1112,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
 
                 } catch (AccountNotFoundException e) {
                     Log_OC.e(TAG, "Account " + mAccount + " was removed!", e);
-                    DisplayUtils.showSnackMessage(findViewById(R.id.scroll), R.string.auth_account_does_not_exist);
+                    DisplayUtils.showSnackMessage(accountSetupBinding.scroll, R.string.auth_account_does_not_exist);
                     finish();
                 }
             }
@@ -1137,15 +1134,15 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
                 }
             } else {
                 // init webView again
-                if (mLoginWebView != null) {
-                    mLoginWebView.setVisibility(View.GONE);
+                if (accountSetupWebviewBinding != null) {
+                    accountSetupWebviewBinding.loginWebview.setVisibility(View.GONE);
                 }
-                setContentView(R.layout.account_setup);
+                accountSetupBinding = AccountSetupBinding.inflate(getLayoutInflater());
+                setContentView(accountSetupBinding.getRoot());
                 initOverallUi();
 
-                mAuthStatusView = findViewById(R.id.auth_status_text);
-                mHostUrlInput.setText(mServerInfo.mBaseUrl);
-                mServerStatusView.setVisibility(View.GONE);
+                accountSetupBinding.hostUrlInput.setText(mServerInfo.mBaseUrl);
+                accountSetupBinding.serverStatusText.setVisibility(View.GONE);
                 showAuthStatus();
             }
 
@@ -1165,17 +1162,15 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             }
 
         } else {    // authorization fail due to client side - probably wrong credentials
-            mLoginWebView = findViewById(R.id.login_webview);
-
-            if (mLoginWebView != null) {
+            if (accountSetupWebviewBinding != null) {
                 initWebViewLogin(mServerInfo.mBaseUrl + WEB_LOGIN, false);
-                DisplayUtils.showSnackMessage(this, mLoginWebView, R.string.auth_access_failed,
+                DisplayUtils.showSnackMessage(this,
+                                              accountSetupWebviewBinding.loginWebview, R.string.auth_access_failed,
                                               result.getLogMessage());
             } else {
                 DisplayUtils.showSnackMessage(this, R.string.auth_access_failed, result.getLogMessage());
 
                 // init webView again
-                mLoginWebView.setVisibility(View.GONE);
                 updateAuthStatusIconAndText(result);
             }
 
@@ -1331,11 +1326,11 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
      */
     private void showServerStatus() {
         if (mServerStatusIcon == NO_ICON && EMPTY_STRING.equals(mServerStatusText)) {
-            mServerStatusView.setVisibility(View.INVISIBLE);
+            accountSetupBinding.serverStatusText.setVisibility(View.INVISIBLE);
         } else {
-            mServerStatusView.setText(mServerStatusText);
-            mServerStatusView.setCompoundDrawablesWithIntrinsicBounds(mServerStatusIcon, 0, 0, 0);
-            mServerStatusView.setVisibility(View.VISIBLE);
+            accountSetupBinding.serverStatusText.setText(mServerStatusText);
+            accountSetupBinding.serverStatusText.setCompoundDrawablesWithIntrinsicBounds(mServerStatusIcon, 0, 0, 0);
+            accountSetupBinding.serverStatusText.setVisibility(View.VISIBLE);
         }
     }
 
@@ -1344,13 +1339,13 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
      * authorization server.
      */
     private void showAuthStatus() {
-        if (mAuthStatusView != null) {
+        if (accountSetupBinding != null) {
             if (mAuthStatusIcon == NO_ICON && EMPTY_STRING.equals(mAuthStatusText)) {
-                mAuthStatusView.setVisibility(View.INVISIBLE);
+                accountSetupBinding.authStatusText.setVisibility(View.INVISIBLE);
             } else {
-                mAuthStatusView.setText(mAuthStatusText);
-                mAuthStatusView.setCompoundDrawablesWithIntrinsicBounds(mAuthStatusIcon, 0, 0, 0);
-                mAuthStatusView.setVisibility(View.VISIBLE);
+                accountSetupBinding.authStatusText.setText(mAuthStatusText);
+                accountSetupBinding.authStatusText.setCompoundDrawablesWithIntrinsicBounds(mAuthStatusIcon, 0, 0, 0);
+                accountSetupBinding.authStatusText.setVisibility(View.VISIBLE);
             }
         }
     }
@@ -1364,7 +1359,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
     @Override
     public boolean onEditorAction(TextView inputField, int actionId, KeyEvent event) {
         if ((actionId == EditorInfo.IME_ACTION_NEXT || actionId == EditorInfo.IME_NULL)
-            && inputField != null && inputField.equals(mHostUrlInput)) {
+            && inputField != null && inputField.equals(accountSetupBinding.hostUrlInput)) {
             checkOcServer();
         }
         return false;   // always return false to grant that the software keyboard is hidden anyway

+ 19 - 38
src/main/res/layout-land/account_setup.xml

@@ -55,57 +55,38 @@
             <FrameLayout
                 android:id="@+id/host_url_frame"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginBottom="@dimen/zero"
-                android:background="@color/primary">
+                android:layout_height="wrap_content">
 
-                <LinearLayout
+                <com.google.android.material.textfield.TextInputLayout
+                    android:id="@+id/host_url_container"
+                    style="@style/Widget.App.Login.TextInputLayout"
                     android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:orientation="vertical">
-
-                    <TextView
-                        android:id="@+id/edit_text"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:ems="10"
-                        android:text="@string/auth_host_url"
-                        android:labelFor="@+id/host_url_input"
-                        android:textColor="@color/login_text_color" />
+                    android:layout_height="wrap_content"
+                    android:hint="@string/auth_host_url"
+                    android:theme="@style/TextInputLayoutLogin"
+                    app:endIconContentDescription="@string/test_server_button"
+                    app:endIconDrawable="@drawable/arrow_right"
+                    app:endIconMode="custom"
+                    app:endIconTint="@color/login_text_color">
 
                     <com.google.android.material.textfield.TextInputEditText
                         android:id="@+id/host_url_input"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
-                        android:minHeight="@dimen/minimum_size_for_touchable_area"
-                        android:layout_gravity="bottom"
-                        android:drawablePadding="@dimen/alternate_half_padding"
-                        android:inputType="textUri"
-                        android:paddingStart="@dimen/zero"
+                        android:gravity="top"
+                        android:importantForAutofill="no"
+                        android:inputType="textCapSentences|textMultiLine|textNoSuggestions"
+                        android:lines="1"
+                        android:minLines="1"
+                        android:paddingStart="@dimen/standard_padding"
                         android:paddingEnd="@dimen/alternate_padding_right"
-                        android:textColor="@color/login_text_color"
-                        android:textColorHint="@color/login_text_hint_color">
+                        android:scrollbars="vertical">
 
                         <requestFocus />
 
                     </com.google.android.material.textfield.TextInputEditText>
 
-                </LinearLayout>
-
-                <ImageButton
-                    android:id="@+id/test_server_button"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center_vertical|end"
-                    android:layout_marginEnd="@dimen/alternate_half_padding"
-                    android:background="@android:color/transparent"
-                    android:contentDescription="@string/test_server_button"
-                    android:onClick="onTestServerConnectionClick"
-                    android:padding="@dimen/zero"
-                    android:scaleType="fitCenter"
-                    android:src="@drawable/arrow_right"
-                    android:tint="@color/login_btn_tint" />
-
+                </com.google.android.material.textfield.TextInputLayout>
             </FrameLayout>
 
             <TextView

+ 19 - 38
src/main/res/layout/account_setup.xml

@@ -54,57 +54,38 @@
             <FrameLayout
                 android:id="@+id/host_url_frame"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginBottom="@dimen/zero"
-                android:background="@color/primary">
+                android:layout_height="wrap_content">
 
-                <LinearLayout
+                <com.google.android.material.textfield.TextInputLayout
+                    android:id="@+id/host_url_container"
+                    style="@style/Widget.App.Login.TextInputLayout"
                     android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:orientation="vertical">
-
-                    <TextView
-                        android:id="@+id/edit_text"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:ems="10"
-                        android:text="@string/auth_host_url"
-                        android:labelFor="@+id/host_url_input"
-                        android:textColor="@color/login_text_color" />
+                    android:layout_height="wrap_content"
+                    android:hint="@string/auth_host_url"
+                    android:theme="@style/TextInputLayoutLogin"
+                    app:endIconContentDescription="@string/test_server_button"
+                    app:endIconDrawable="@drawable/arrow_right"
+                    app:endIconMode="custom"
+                    app:endIconTint="@color/login_text_color">
 
                     <com.google.android.material.textfield.TextInputEditText
                         android:id="@+id/host_url_input"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
-                        android:minHeight="@dimen/minimum_size_for_touchable_area"
-                        android:layout_gravity="bottom"
-                        android:drawablePadding="@dimen/alternate_half_padding"
-                        android:inputType="textUri"
-                        android:paddingStart="@dimen/zero"
+                        android:gravity="top"
+                        android:importantForAutofill="no"
+                        android:inputType="textCapSentences|textMultiLine|textNoSuggestions"
+                        android:lines="1"
+                        android:minLines="1"
+                        android:paddingStart="@dimen/standard_padding"
                         android:paddingEnd="@dimen/alternate_padding_right"
-                        android:textColor="@color/login_text_color"
-                        android:textColorHint="@color/login_text_color">
+                        android:scrollbars="vertical">
 
                         <requestFocus />
 
                     </com.google.android.material.textfield.TextInputEditText>
 
-                </LinearLayout>
-
-                <ImageButton
-                    android:id="@+id/test_server_button"
-                    android:layout_width="@dimen/minimum_size_for_touchable_area"
-                    android:layout_height="@dimen/minimum_size_for_touchable_area"
-                    android:layout_gravity="center_vertical|end"
-                    android:layout_marginEnd="@dimen/alternate_half_padding"
-                    android:background="@android:color/transparent"
-                    android:contentDescription="@string/test_server_button"
-                    android:onClick="onTestServerConnectionClick"
-                    android:padding="12dp"
-                    android:scaleType="fitCenter"
-                    android:src="@drawable/arrow_right"
-                    android:tint="@color/login_text_color" />
-
+                </com.google.android.material.textfield.TextInputLayout>
             </FrameLayout>
 
             <TextView

+ 31 - 0
src/main/res/values/styles.xml

@@ -313,9 +313,40 @@
 	<style name="NextcloudTextAppearanceMedium" parent="@style/TextAppearance.AppCompat.Medium">
 	</style>
 
+    <style name="Widget.App.Login.TextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
+        <item name="materialThemeOverlay">@style/ThemeOverlay.App.Login.TextInputLayout</item>
+        <item name="shapeAppearance">@style/ShapeAppearance.MaterialComponents.SmallComponent</item>
+        <item name="hintTextColor">?attr/colorOnSurface</item>
+    </style>
+
+    <style name="ThemeOverlay.App.Login.TextInputLayout" parent="">
+        <item name="colorPrimary">@color/white</item>
+        <item name="colorOnSurface">@color/white</item>
+        <item name="colorError">@color/hwSecurityRed</item>
+        <item name="textAppearanceSubtitle1">@style/TextAppearance.MaterialComponents.Subtitle1</item>
+        <item name="textAppearanceCaption">@style/TextAppearance.MaterialComponents.Caption</item>
+        <item name="editTextStyle">@style/Widget.MaterialComponents.TextInputEditText.OutlinedBox</item>
+    </style>
+
 	<style name="TextInputLayout" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
     </style>
 
+    <style name="TextInputLayoutLogin" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox">
+        <item name="boxStrokeColor">@color/white</item>
+        <item name="boxStrokeErrorColor">@color/white</item>
+        <item name="hintTextAppearance">@style/HintTextLogin</item>
+        <item name="errorTextAppearance">@style/HintTextLogin</item>
+        <item name="android:colorPrimary">@color/white</item>
+        <!-- Theme attributes -->
+        <item name="android:textColorHint">#80FFFFFF</item>
+        <item name="colorControlNormal">@color/white</item>
+        <item name="colorControlActivated">@color/white</item>
+    </style>
+
+    <style name="HintTextLogin" parent="TextAppearance.AppCompat">
+        <item name="android:textColor">@color/white</item>
+    </style>
+
 	<style name="AppTabTextAppearance" parent="@style/TextAppearance.Design.Tab">
 		<item name="android:textSize">16sp</item>
 		<item name="textAllCaps">false</item>