mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Endurain: First try with bottomsheet instead of dialogs
This commit is contained in:
@@ -260,7 +260,7 @@
|
|||||||
android:label="@string/healthconnect_settings"
|
android:label="@string/healthconnect_settings"
|
||||||
android:parentActivityName=".activities.SettingsActivity" />
|
android:parentActivityName=".activities.SettingsActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.EndurainPreferencesActivity"
|
android:name=".activities.endurain.EndurainPreferencesActivity"
|
||||||
android:label="Endurain"
|
android:label="Endurain"
|
||||||
android:parentActivityName=".activities.SettingsActivity" />
|
android:parentActivityName=".activities.SettingsActivity" />
|
||||||
<activity
|
<activity
|
||||||
|
|||||||
-136
@@ -1,136 +0,0 @@
|
|||||||
/* Copyright (C) 2025 Arjan Schrijver
|
|
||||||
|
|
||||||
This file is part of Gadgetbridge.
|
|
||||||
|
|
||||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as published
|
|
||||||
by the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
Gadgetbridge 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
||||||
package nodomain.freeyourgadget.gadgetbridge.activities
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
import androidx.core.content.edit
|
|
||||||
import androidx.core.net.toUri
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.preference.Preference
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.InternetUtils
|
|
||||||
|
|
||||||
class EndurainPreferencesActivity : AbstractSettingsActivityV2() {
|
|
||||||
override fun newFragment(): PreferenceFragmentCompat {
|
|
||||||
return EndurainPreferencesFragment()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
class EndurainPreferencesFragment : AbstractPreferenceFragment() {
|
|
||||||
override fun onCreatePreferences(
|
|
||||||
savedInstanceState: Bundle?,
|
|
||||||
rootKey: String?
|
|
||||||
) {
|
|
||||||
setPreferencesFromResource(R.xml.endurain_preferences, rootKey)
|
|
||||||
val prefs = GBApplication.getPrefs().preferences
|
|
||||||
|
|
||||||
// Hide network required warning when network is available
|
|
||||||
val networkWarning = findPreference<Preference>("pref_key_network_required")
|
|
||||||
networkWarning?.isVisible = !GBApplication.hasInternetAccess()
|
|
||||||
|
|
||||||
// Wire up the login button
|
|
||||||
val loginPref = findPreference<Preference>("pref_key_log_in")
|
|
||||||
loginPref?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
||||||
val currentServer = prefs.getString("endurain_server", "https://")
|
|
||||||
val input = TextInputEditText(requireContext()).apply {
|
|
||||||
setText(currentServer)
|
|
||||||
layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val layout = TextInputLayout(requireContext()).apply {
|
|
||||||
hint = "Example: https://endurain.example.com"
|
|
||||||
addView(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
val dialog = MaterialAlertDialogBuilder(requireContext())
|
|
||||||
.setTitle("Endurain server")
|
|
||||||
.setView(layout)
|
|
||||||
.setNegativeButton(R.string.Cancel, null)
|
|
||||||
.setPositiveButton(R.string.ok, null) // ← no listener yet
|
|
||||||
.create()
|
|
||||||
|
|
||||||
dialog.setOnShowListener {
|
|
||||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
|
||||||
val newUrl = input.text.toString().toUri()
|
|
||||||
val newServer =
|
|
||||||
if (newUrl.scheme == null || newUrl.host == null) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
"${newUrl.scheme}://${newUrl.host}"
|
|
||||||
}
|
|
||||||
|
|
||||||
prefs.edit {
|
|
||||||
putString("endurain_server", newServer)
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog.dismiss()
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
doLogin()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dialog.show()
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Wire up the logoff button
|
|
||||||
val logoffPref = findPreference<Preference>("pref_key_log_out")
|
|
||||||
logoffPref?.isVisible = false
|
|
||||||
|
|
||||||
// TODO: Fill the status preference text
|
|
||||||
val statusPref = findPreference<Preference>("pref_key_status")
|
|
||||||
statusPref?.summary = "Not logged in, integration is disabled"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun doLogin() {
|
|
||||||
val prefs = GBApplication.getPrefs().preferences
|
|
||||||
val server = prefs.getString("endurain_server", "").orEmpty()
|
|
||||||
if (server.isBlank()) return
|
|
||||||
|
|
||||||
val settingsUri = "${server}/api/v1/public/server_settings".toUri()
|
|
||||||
val serverSettings = InternetUtils.doJsonRequest(settingsUri)
|
|
||||||
|
|
||||||
if (serverSettings == null) {
|
|
||||||
GB.toast("Endurain server is offline", Toast.LENGTH_LONG, GB.ERROR)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val localLogin = serverSettings.optBoolean("local_login_enabled")
|
|
||||||
val ssoLogin = serverSettings.optBoolean("sso_enabled")
|
|
||||||
|
|
||||||
GB.toast("Endurain local=$localLogin sso=$ssoLogin", Toast.LENGTH_LONG, GB.INFO)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
@@ -66,6 +66,7 @@ import nodomain.freeyourgadget.gadgetbridge.R;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.activities.automations.AutomationsSettingsActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.automations.AutomationsSettingsActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsPreferencesActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsPreferencesActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.discovery.DiscoveryPairingPreferenceActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.discovery.DiscoveryPairingPreferenceActivity;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.endurain.EndurainPreferencesActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.maps.MapsSettingsActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.maps.MapsSettingsActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.preferences.HealthConnectPreferencesActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.preferences.HealthConnectPreferencesActivity;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.externalevents.TimeChangeReceiver;
|
import nodomain.freeyourgadget.gadgetbridge.externalevents.TimeChangeReceiver;
|
||||||
|
|||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
/* Copyright (C) 2026 Arjan Schrijver
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.activities.endurain
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.preference.Preference
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractPreferenceFragment
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivityV2
|
||||||
|
|
||||||
|
class EndurainPreferencesActivity : AbstractSettingsActivityV2() {
|
||||||
|
|
||||||
|
override fun newFragment(): PreferenceFragmentCompat =
|
||||||
|
EndurainPreferencesFragment()
|
||||||
|
|
||||||
|
class EndurainPreferencesFragment : AbstractPreferenceFragment() {
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.endurain_preferences, rootKey)
|
||||||
|
|
||||||
|
updateNetworkWarning()
|
||||||
|
wireLoginPreference()
|
||||||
|
hideLogoffPreference()
|
||||||
|
updateStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateNetworkWarning() {
|
||||||
|
findPreference<Preference>("pref_key_network_required")?.isVisible =
|
||||||
|
!GBApplication.hasInternetAccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun wireLoginPreference() {
|
||||||
|
findPreference<Preference>("pref_key_log_in")?.setOnPreferenceClickListener {
|
||||||
|
EndurainSetupBottomSheet()
|
||||||
|
.show(parentFragmentManager, "endurain_setup")
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hideLogoffPreference() {
|
||||||
|
findPreference<Preference>("pref_key_log_out")?.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateStatus() {
|
||||||
|
findPreference<Preference>("pref_key_status")?.summary =
|
||||||
|
"Not logged in, integration is disabled"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
/* Copyright (C) 2026 Arjan Schrijver
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.activities.endurain
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.R
|
||||||
|
|
||||||
|
class EndurainSetupBottomSheet : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
private val prefs get() = GBApplication.getPrefs().preferences
|
||||||
|
private val vm: EndurainSetupViewModel by viewModels()
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View = inflater.inflate(
|
||||||
|
R.layout.endurain_bottomsheet_setup_wizard,
|
||||||
|
container,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
val serverLayout = view.findViewById<TextInputLayout>(R.id.server_layout)
|
||||||
|
val serverInput = view.findViewById<TextInputEditText>(R.id.server_input)
|
||||||
|
|
||||||
|
val loginTypeGroup =
|
||||||
|
view.findViewById<MaterialButtonToggleGroup>(R.id.login_type_group)
|
||||||
|
val localButton = view.findViewById<MaterialButton>(R.id.local_login_button)
|
||||||
|
val ssoButton = view.findViewById<MaterialButton>(R.id.sso_login_button)
|
||||||
|
|
||||||
|
val userLayout = view.findViewById<TextInputLayout>(R.id.user_layout)
|
||||||
|
val passLayout = view.findViewById<TextInputLayout>(R.id.password_layout)
|
||||||
|
val userInput = view.findViewById<TextInputEditText>(R.id.user_input)
|
||||||
|
val passInput = view.findViewById<TextInputEditText>(R.id.password_input)
|
||||||
|
|
||||||
|
val progress = view.findViewById<View>(R.id.progress)
|
||||||
|
val next = view.findViewById<MaterialButton>(R.id.next_button)
|
||||||
|
|
||||||
|
serverInput.setText(prefs.getString("endurain_server", ""))
|
||||||
|
|
||||||
|
fun showProgress(show: Boolean) {
|
||||||
|
progress.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
|
next.isEnabled = !show
|
||||||
|
}
|
||||||
|
|
||||||
|
next.setOnClickListener {
|
||||||
|
when (vm.step) {
|
||||||
|
EndurainSetupViewModel.Step.SERVER -> {
|
||||||
|
val uri = serverInput.text.toString().toUri()
|
||||||
|
if (uri.scheme == null || uri.host == null) {
|
||||||
|
serverLayout.error = "Invalid server URL"
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
serverLayout.error = null
|
||||||
|
val server = "${uri.scheme}://${uri.host}"
|
||||||
|
vm.server = server
|
||||||
|
prefs.edit { putString("endurain_server", server) }
|
||||||
|
|
||||||
|
showProgress(true)
|
||||||
|
vm.fetchServerCapabilities(server) { ok ->
|
||||||
|
showProgress(false)
|
||||||
|
if (!ok) return@fetchServerCapabilities
|
||||||
|
vm.step = EndurainSetupViewModel.Step.LOGIN_TYPE
|
||||||
|
loginTypeGroup.visibility = View.VISIBLE
|
||||||
|
localButton.visibility =
|
||||||
|
if (vm.localLoginEnabled) View.VISIBLE else View.GONE
|
||||||
|
ssoButton.visibility =
|
||||||
|
if (vm.ssoEnabled) View.VISIBLE else View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EndurainSetupViewModel.Step.LOCAL_LOGIN -> {
|
||||||
|
val user = userInput.text.toString()
|
||||||
|
val pass = passInput.text.toString()
|
||||||
|
if (user.isBlank()) {
|
||||||
|
userLayout.error = "Required"
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
if (pass.isBlank()) {
|
||||||
|
passLayout.error = "Required"
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
userLayout.error = null
|
||||||
|
passLayout.error = null
|
||||||
|
|
||||||
|
showProgress(true)
|
||||||
|
vm.performLocalLogin(vm.server, user, pass) { success ->
|
||||||
|
showProgress(false)
|
||||||
|
if (success) {
|
||||||
|
prefs.edit {
|
||||||
|
putString("endurain_user", user)
|
||||||
|
putString("endurain_password", pass)
|
||||||
|
}
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loginTypeGroup.addOnButtonCheckedListener { _, checkedId, isChecked ->
|
||||||
|
if (!isChecked) return@addOnButtonCheckedListener
|
||||||
|
when (checkedId) {
|
||||||
|
R.id.local_login_button -> {
|
||||||
|
vm.step = EndurainSetupViewModel.Step.LOCAL_LOGIN
|
||||||
|
userLayout.visibility = View.VISIBLE
|
||||||
|
passLayout.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
R.id.sso_login_button -> {
|
||||||
|
vm.step = EndurainSetupViewModel.Step.SSO_LOGIN
|
||||||
|
// TODO launch SSO flow
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
/* Copyright (C) 2026 Arjan Schrijver
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge 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 Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.activities.endurain
|
||||||
|
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.InternetUtils
|
||||||
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
class EndurainSetupViewModel : ViewModel() {
|
||||||
|
|
||||||
|
enum class Step { SERVER, LOGIN_TYPE, LOCAL_LOGIN, SSO_LOGIN, DONE }
|
||||||
|
|
||||||
|
var step: Step = Step.SERVER
|
||||||
|
var server: String = ""
|
||||||
|
var localLoginEnabled: Boolean = false
|
||||||
|
var ssoEnabled: Boolean = false
|
||||||
|
|
||||||
|
fun fetchServerCapabilities(
|
||||||
|
server: String,
|
||||||
|
onResult: (Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val ok = withContext(Dispatchers.IO) {
|
||||||
|
val uri = "$server/api/v1/public/server_settings"
|
||||||
|
val json: JSONObject? =
|
||||||
|
InternetUtils.doJsonRequest(uri.toUri())
|
||||||
|
if (json == null) return@withContext false
|
||||||
|
localLoginEnabled = json.optBoolean("local_login_enabled")
|
||||||
|
ssoEnabled = json.optBoolean("sso_enabled")
|
||||||
|
true
|
||||||
|
}
|
||||||
|
onResult(ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun performLocalLogin(
|
||||||
|
server: String,
|
||||||
|
user: String,
|
||||||
|
pass: String,
|
||||||
|
onResult: (Boolean) -> Unit
|
||||||
|
) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val success = withContext(Dispatchers.IO) {
|
||||||
|
// TODO real API call
|
||||||
|
user.isNotBlank() && pass.isNotBlank()
|
||||||
|
}
|
||||||
|
onResult(success)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Endurain setup"
|
||||||
|
android:textAppearance="?attr/textAppearanceHeadlineSmall" />
|
||||||
|
|
||||||
|
<!-- SERVER -->
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/server_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Endurain server">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/server_input"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textUri" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<!-- LOGIN TYPE -->
|
||||||
|
<com.google.android.material.button.MaterialButtonToggleGroup
|
||||||
|
android:id="@+id/login_type_group"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:singleSelection="true">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/local_login_button"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="Local" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/sso_login_button"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="SSO" />
|
||||||
|
</com.google.android.material.button.MaterialButtonToggleGroup>
|
||||||
|
|
||||||
|
<!-- LOCAL LOGIN -->
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/user_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/username"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/user_input"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/password_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/prefs_password"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/password_input"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textPassword" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="end"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingTop="12dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/next_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Next" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user