mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Endurain: Initial prefs and online auth implementation
This commit is contained in:
@@ -117,6 +117,10 @@ android {
|
|||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
buildConfigField "String", "GIT_HASH_SHORT", "\"${getGitHashShort()}\""
|
buildConfigField "String", "GIT_HASH_SHORT", "\"${getGitHashShort()}\""
|
||||||
buildConfigField "boolean", "INTERNET_ACCESS", "false"
|
buildConfigField "boolean", "INTERNET_ACCESS", "false"
|
||||||
|
|
||||||
|
manifestPlaceholders = [
|
||||||
|
appAuthRedirectScheme: "${applicationId}"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
@@ -286,6 +290,9 @@ dependencies {
|
|||||||
implementation libs.androidsvg
|
implementation libs.androidsvg
|
||||||
implementation libs.jsoup
|
implementation libs.jsoup
|
||||||
|
|
||||||
|
// AppAuth is used for OAuth/PKCE/OIDC functionality, like required by the Endurain integration
|
||||||
|
implementation 'net.openid:appauth:0.11.1'
|
||||||
|
|
||||||
// Bouncy Castle is included directly in GB, to avoid pulling the entire dependency
|
// Bouncy Castle is included directly in GB, to avoid pulling the entire dependency
|
||||||
// It's included in the org.bouncycastle.shaded package, to fix conflicts with roboelectric
|
// It's included in the org.bouncycastle.shaded package, to fix conflicts with roboelectric
|
||||||
//implementation 'org.bouncycastle:bcpkix-jdk18on:1.76'
|
//implementation 'org.bouncycastle:bcpkix-jdk18on:1.76'
|
||||||
|
|||||||
@@ -259,6 +259,10 @@
|
|||||||
android:name=".activities.preferences.HealthConnectPreferencesActivity"
|
android:name=".activities.preferences.HealthConnectPreferencesActivity"
|
||||||
android:label="@string/healthconnect_settings"
|
android:label="@string/healthconnect_settings"
|
||||||
android:parentActivityName=".activities.SettingsActivity" />
|
android:parentActivityName=".activities.SettingsActivity" />
|
||||||
|
<activity
|
||||||
|
android:name=".activities.EndurainPreferencesActivity"
|
||||||
|
android:label="Endurain"
|
||||||
|
android:parentActivityName=".activities.SettingsActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.AboutUserPreferencesActivity"
|
android:name=".activities.AboutUserPreferencesActivity"
|
||||||
android:label="@string/activity_prefs_about_you"
|
android:label="@string/activity_prefs_about_you"
|
||||||
|
|||||||
+136
@@ -0,0 +1,136 @@
|
|||||||
|
/* 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+9
@@ -414,6 +414,15 @@ public class SettingsActivity extends AbstractSettingsActivityV2 {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pref = findPreference("pref_category_endurain");
|
||||||
|
if (pref != null) {
|
||||||
|
pref.setOnPreferenceClickListener(preference -> {
|
||||||
|
Intent enableIntent = new Intent(requireContext(), EndurainPreferencesActivity.class);
|
||||||
|
startActivity(enableIntent);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pref = findPreference("pref_category_notifications");
|
pref = findPreference("pref_category_notifications");
|
||||||
if (pref != null) {
|
if (pref != null) {
|
||||||
pref.setOnPreferenceClickListener(preference -> {
|
pref.setOnPreferenceClickListener(preference -> {
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<Preference
|
||||||
|
android:icon="@drawable/ic_warning"
|
||||||
|
android:key="pref_key_network_required"
|
||||||
|
android:title="Network required"
|
||||||
|
android:summary="This integration requires network connectivity. Please install and enable the internet helper add-on app." />
|
||||||
|
<Preference
|
||||||
|
android:icon="@drawable/ic_info"
|
||||||
|
android:key="pref_key_status"
|
||||||
|
android:title="Endurain status"
|
||||||
|
android:summary="Logged in on endurain.example.com" />
|
||||||
|
<Preference
|
||||||
|
android:icon="@drawable/ic_language"
|
||||||
|
android:key="pref_key_log_in"
|
||||||
|
android:title="Log in to Endurain"
|
||||||
|
android:summary="Tap here to enter the Endurain server and log in" />
|
||||||
|
<Preference
|
||||||
|
android:icon="@drawable/ic_language"
|
||||||
|
android:key="pref_key_log_out"
|
||||||
|
android:title="Log out of Endurain"
|
||||||
|
android:summary="Tap here to log out, this disables the integration" />
|
||||||
|
</PreferenceScreen>
|
||||||
@@ -387,6 +387,13 @@
|
|||||||
android:key="pref_category_internethelper"
|
android:key="pref_category_internethelper"
|
||||||
android:title="@string/prefs_internet_helper_title"
|
android:title="@string/prefs_internet_helper_title"
|
||||||
android:summary="@string/prefs_internet_helper_summary" />
|
android:summary="@string/prefs_internet_helper_summary" />
|
||||||
|
|
||||||
|
<!-- FIXME: Use Endurain logo and translate strings -->
|
||||||
|
<PreferenceScreen
|
||||||
|
android:icon="@drawable/ic_shoe"
|
||||||
|
android:key="pref_category_endurain"
|
||||||
|
android:title="Endurain"
|
||||||
|
android:summary="Configure how to reach and use this self-hosted online fitness tracker" />
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
|||||||
Reference in New Issue
Block a user