diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainApiClient.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainApiClient.kt index 2f43382d38..d1269aca47 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainApiClient.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainApiClient.kt @@ -26,13 +26,13 @@ import org.json.JSONObject import org.slf4j.LoggerFactory import java.io.File -enum class AuthType { +enum class EndurainAuthType { NONE, AUTH_TOKEN, REFRESH_TOKEN } -data class LoginResponse( +data class EndurainLoginResponse( val session_id: String? = null, val access_token: String? = null, val refresh_token: String? = null, @@ -44,16 +44,16 @@ data class LoginResponse( val detail: String? = null ) -data class MfaVerifyRequest( +data class EndurainMfaVerifyRequest( val username: String, val mfa_code: String ) -data class TokenExchangeRequest( +data class EndurainTokenExchangeRequest( val code_verifier: String ) -data class IdentityProvider( +data class EndurainIdentityProvider( val id: String, val name: String, val slug: String @@ -69,16 +69,16 @@ class EndurainApiClient( /** * Build headers with authentication tokens */ - private fun buildHeaders(auth: AuthType): MutableMap { + private fun buildHeaders(auth: EndurainAuthType): MutableMap { val headers = mutableMapOf("X-Client-Type" to "mobile") when (auth) { - AuthType.AUTH_TOKEN -> { + EndurainAuthType.AUTH_TOKEN -> { tokenManager.getAccessToken()?.let { token -> headers["Authorization"] = "Bearer $token" } } - AuthType.REFRESH_TOKEN -> { + EndurainAuthType.REFRESH_TOKEN -> { tokenManager.getRefreshToken()?.let { token -> headers["Authorization"] = "Bearer $token" } @@ -92,14 +92,14 @@ class EndurainApiClient( /** * Username/Password Login */ - fun login(username: String, password: String): LoginResponse? { + fun login(username: String, password: String): EndurainLoginResponse? { try { val uri = "$baseUrl/api/v1/auth/login".toUri() // Form-encoded body val body = "username=${Uri.encode(username)}&password=${Uri.encode(password)}" - val headers = buildHeaders(AuthType.NONE) + val headers = buildHeaders(EndurainAuthType.NONE) headers["Content-Type"] = "application/x-www-form-urlencoded" val responseText = InternetUtils.doStringRequest( @@ -110,7 +110,7 @@ class EndurainApiClient( ) return if (responseText != null) { - gson.fromJson(responseText, LoginResponse::class.java) + gson.fromJson(responseText, EndurainLoginResponse::class.java) } else { LOG.error("Login failed: empty response") null @@ -124,14 +124,14 @@ class EndurainApiClient( /** * MFA Verification */ - fun verifyMfa(username: String, mfaCode: String): LoginResponse? { + fun verifyMfa(username: String, mfaCode: String): EndurainLoginResponse? { try { val uri = "$baseUrl/api/v1/auth/mfa/verify".toUri() - val request = MfaVerifyRequest(username, mfaCode) + val request = EndurainMfaVerifyRequest(username, mfaCode) val body = gson.toJson(request) - val headers = buildHeaders(AuthType.NONE) + val headers = buildHeaders(EndurainAuthType.NONE) headers["Content-Type"] = "application/json" val responseText = InternetUtils.doStringRequest( @@ -142,7 +142,7 @@ class EndurainApiClient( ) return if (responseText != null) { - gson.fromJson(responseText, LoginResponse::class.java) + gson.fromJson(responseText, EndurainLoginResponse::class.java) } else { LOG.error("MFA verification failed: empty response") null @@ -156,11 +156,11 @@ class EndurainApiClient( /** * Token Refresh */ - fun refreshToken(): LoginResponse? { + fun refreshToken(): EndurainLoginResponse? { try { val uri = "$baseUrl/api/v1/auth/refresh".toUri() - val headers = buildHeaders(AuthType.REFRESH_TOKEN) + val headers = buildHeaders(EndurainAuthType.REFRESH_TOKEN) headers["Content-Type"] = "application/json" val responseText = InternetUtils.doStringRequest( @@ -171,7 +171,7 @@ class EndurainApiClient( ) return if (responseText != null) { - gson.fromJson(responseText, LoginResponse::class.java) + gson.fromJson(responseText, EndurainLoginResponse::class.java) } else { LOG.error("Token refresh failed: empty response") null @@ -189,7 +189,7 @@ class EndurainApiClient( try { val uri = "$baseUrl/api/v1/auth/logout".toUri() - val headers = buildHeaders(AuthType.AUTH_TOKEN) + val headers = buildHeaders(EndurainAuthType.AUTH_TOKEN) headers["Content-Type"] = "application/json" InternetUtils.doStringRequest( @@ -210,11 +210,11 @@ class EndurainApiClient( /** * Get list of available identity providers */ - fun getIdentityProviders(): List? { + fun getIdentityProviders(): List? { try { val uri = "$baseUrl/api/v1/public/idp".toUri() - val headers = buildHeaders(AuthType.NONE) + val headers = buildHeaders(EndurainAuthType.NONE) headers["Content-Type"] = "application/json" val responseText = InternetUtils.doStringRequest( @@ -223,7 +223,7 @@ class EndurainApiClient( ) return if (responseText != null) { - val type = object : com.google.gson.reflect.TypeToken>() {}.type + val type = object : com.google.gson.reflect.TypeToken>() {}.type gson.fromJson(responseText, type) } else { LOG.error("Failed to fetch identity providers") @@ -238,14 +238,14 @@ class EndurainApiClient( /** * Exchange OAuth session for tokens (PKCE flow) */ - fun exchangeOAuthSession(sessionId: String, codeVerifier: String): LoginResponse? { + fun exchangeOAuthSession(sessionId: String, codeVerifier: String): EndurainLoginResponse? { try { val uri = "$baseUrl/api/v1/public/idp/session/$sessionId/tokens".toUri() - val request = TokenExchangeRequest(codeVerifier) + val request = EndurainTokenExchangeRequest(codeVerifier) val body = gson.toJson(request) - val headers = buildHeaders(AuthType.NONE) + val headers = buildHeaders(EndurainAuthType.NONE) headers["Content-Type"] = "application/json" val responseText = InternetUtils.doStringRequest( @@ -258,7 +258,7 @@ class EndurainApiClient( LOG.debug("OAuth token result: $responseText") return if (responseText != null) { - gson.fromJson(responseText, LoginResponse::class.java) + gson.fromJson(responseText, EndurainLoginResponse::class.java) } else { LOG.error("OAuth token exchange failed: empty response") null @@ -280,7 +280,7 @@ class EndurainApiClient( try { val uri = "$baseUrl$endpoint".toUri() - val headers = buildHeaders(AuthType.AUTH_TOKEN) + val headers = buildHeaders(EndurainAuthType.AUTH_TOKEN) headers["Content-Type"] = "application/json" return InternetUtils.doStringRequest( @@ -302,14 +302,15 @@ class EndurainApiClient( Thread { try { val uri = "$baseUrl/api/v1/activities/create/upload".toUri() - val headers = buildHeaders(AuthType.AUTH_TOKEN) + val headers = buildHeaders(EndurainAuthType.AUTH_TOKEN) InternetUtils.uploadBinaryFile( uri = uri, file = file, requestHeaders = headers - ) { success, responseText -> + ) { success, statusCode, responseText -> if (success && responseText != null) { + LOG.debug("Response $statusCode from Endurain: $responseText") val jsonArray = JSONArray(responseText) val firstObject = jsonArray.getJSONObject(0) val id = firstObject.getInt("id") @@ -332,7 +333,7 @@ class EndurainApiClient( fun editActivity(id: Int, activityKind: ActivityKind, name: String): Boolean { try { val uri = "$baseUrl/api/v1/activities/edit".toUri() - val headers = buildHeaders(AuthType.AUTH_TOKEN) + val headers = buildHeaders(EndurainAuthType.AUTH_TOKEN) headers["Content-Type"] = "application/json" var activityType = 10 // Generic workout @@ -367,7 +368,7 @@ class EndurainApiClient( try { val uri = "$baseUrl/api/v1/about".toUri() - val headers = buildHeaders(AuthType.NONE) + val headers = buildHeaders(EndurainAuthType.NONE) val result = InternetUtils.doJsonRequest( uri = uri, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSetupBottomSheet.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSetupBottomSheet.kt index a138d65da8..45ad89a84f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSetupBottomSheet.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSetupBottomSheet.kt @@ -175,7 +175,7 @@ class EndurainSetupBottomSheet : BottomSheetDialogFragment() { }.show() } - private fun launchSsoLogin(provider: IdentityProvider) { + private fun launchSsoLogin(provider: EndurainIdentityProvider) { val ssoUrl = vm.generateSsoUrl(provider.slug) LOG.info("Launching secure browser for SSO URL: $ssoUrl") diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSetupViewModel.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSetupViewModel.kt index 59b4bc1334..5cdf61721b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSetupViewModel.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSetupViewModel.kt @@ -40,14 +40,14 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic SSO_PROVIDERS } - val tokenManager = EndurainTokenManager(application) + val endurainTokenManager = EndurainTokenManager(application) var step = Step.SERVER var server = "" var localLoginEnabled = false var ssoEnabled = false var pendingMfaUsername: String? = null - var availableProviders: List = emptyList() - var serverVersion: String? = null + var availableProviders: List = emptyList() + var endurainServerVersion: String? = null /** * Fetch server version @@ -58,8 +58,8 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic ) { Thread { try { - apiClient = EndurainApiClient(serverUrl, tokenManager) - serverVersion = apiClient.fetchVersion() + apiClient = EndurainApiClient(serverUrl, endurainTokenManager) + endurainServerVersion = apiClient.fetchVersion() callback(true) } catch (e: Exception) { LOG.error("Fetching server version error", e) @@ -119,7 +119,7 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic fun fetchSsoProviders(callback: (Boolean) -> Unit) { Thread { try { - apiClient = EndurainApiClient(server, tokenManager) + apiClient = EndurainApiClient(server, endurainTokenManager) val providers = apiClient.getIdentityProviders() if (providers != null && providers.isNotEmpty()) { @@ -183,14 +183,14 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic prefs.edit { remove("code_verifier") } if (!::apiClient.isInitialized) { - apiClient = EndurainApiClient(server, tokenManager) + apiClient = EndurainApiClient(server, endurainTokenManager) } val response = apiClient.exchangeOAuthSession(sessionId, verifier) if (response?.access_token != null) { LOG.info("SSO login successful") - tokenManager.saveTokens( + endurainTokenManager.saveTokens( response.access_token, response.refresh_token!!, response.expires_in!!, @@ -219,7 +219,7 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic ) { Thread { try { - apiClient = EndurainApiClient(serverUrl, tokenManager) + apiClient = EndurainApiClient(serverUrl, endurainTokenManager) val response = apiClient.login(username, password) when { @@ -235,7 +235,7 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic } response.access_token != null -> { LOG.info("Login successful") - tokenManager.saveTokens( + endurainTokenManager.saveTokens( response.access_token, response.refresh_token!!, response.expires_in!!, @@ -274,7 +274,7 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic if (response?.access_token != null) { LOG.info("MFA verification successful") - tokenManager.saveTokens( + endurainTokenManager.saveTokens( response.access_token, response.refresh_token!!, response.expires_in!!, @@ -302,12 +302,12 @@ class EndurainSetupViewModel(application: Application) : AndroidViewModel(applic if (::apiClient.isInitialized) { apiClient.logout() } else { - tokenManager.clearTokens() + endurainTokenManager.clearTokens() } callback(true) } catch (e: Exception) { LOG.error("Logout error", e) - tokenManager.clearTokens() // Clear tokens anyway + endurainTokenManager.clearTokens() // Clear tokens anyway callback(true) } }.start() diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSsoProviderDialog.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSsoProviderDialog.kt index 2d81477e07..d7469a26a3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSsoProviderDialog.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/EndurainSsoProviderDialog.kt @@ -22,8 +22,8 @@ import nodomain.freeyourgadget.gadgetbridge.R class EndurainSsoProviderDialog( private val context: Context, - private val providers: List, - private val onProviderSelected: (IdentityProvider) -> Unit + private val providers: List, + private val onProviderSelected: (EndurainIdentityProvider) -> Unit ) { fun show() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/OnlineFitnessTrackersPreferencesActivity.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/OnlineFitnessTrackersPreferencesActivity.kt index 3229de3150..ac71994afd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/OnlineFitnessTrackersPreferencesActivity.kt +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/OnlineFitnessTrackersPreferencesActivity.kt @@ -40,8 +40,8 @@ class OnlineFitnessTrackersPreferencesActivity : AbstractSettingsActivityV2() { setPreferencesFromResource(R.xml.online_fitness_trackers_preferences, rootKey) updateNetworkWarning() - wireLoginPreference() - wireLogoutPreference() + wireLoginPreferences() + wireLogoutPreferences() updateStatus() updateLogoutPreferenceVisibility() setupLoginResultListener() @@ -50,8 +50,8 @@ class OnlineFitnessTrackersPreferencesActivity : AbstractSettingsActivityV2() { val vm: EndurainSetupViewModel by viewModels() val server = GBApplication.getPrefs().preferences.getString("endurain_server", null) if (server != null) { - if (vm.tokenManager.isAccessTokenExpired()) { - vm.tokenManager.performTokenRefresh(server) { + if (vm.endurainTokenManager.isAccessTokenExpired()) { + vm.endurainTokenManager.performTokenRefresh(server) { activity?.runOnUiThread { updateStatus() updateLogoutPreferenceVisibility() @@ -77,6 +77,16 @@ class OnlineFitnessTrackersPreferencesActivity : AbstractSettingsActivityV2() { updateLogoutPreferenceVisibility() } } + parentFragmentManager.setFragmentResultListener( + "wanderer_login_result", + this + ) { _, bundle -> + val success = bundle.getBoolean("success", false) + if (success) { + updateStatus() + updateLogoutPreferenceVisibility() + } + } } override fun onResume() { @@ -90,54 +100,79 @@ class OnlineFitnessTrackersPreferencesActivity : AbstractSettingsActivityV2() { !GBApplication.hasInternetAccess() } - private fun wireLoginPreference() { - findPreference("pref_key_log_in")?.setOnPreferenceClickListener { + private fun wireLoginPreferences() { + findPreference("pref_key_endurain_log_in")?.setOnPreferenceClickListener { EndurainSetupBottomSheet() .show(parentFragmentManager, "endurain_setup") true } - } - - private fun wireLogoutPreference() { - findPreference("pref_key_log_out")?.setOnPreferenceClickListener { - performLogout() + findPreference("pref_key_wanderer_log_in")?.setOnPreferenceClickListener { + WandererSetupBottomSheet() + .show(parentFragmentManager, "wanderer_setup") true } } - private fun performLogout() { - vm.logout { success -> - activity?.runOnUiThread { - if (success) { - GB.toast(getString(R.string.endurain_logged_out_successfully), Toast.LENGTH_SHORT, GB.INFO) - updateStatus() - updateLogoutPreferenceVisibility() - } else { - GB.toast(getString(R.string.endurain_logout_failed), Toast.LENGTH_SHORT, GB.WARN) + private fun wireLogoutPreferences() { + findPreference("pref_key_endurain_log_out")?.setOnPreferenceClickListener { + vm.logout { success -> + activity?.runOnUiThread { + if (success) { + GB.toast(getString(R.string.endurain_logged_out_successfully), Toast.LENGTH_SHORT, GB.INFO) + updateStatus() + updateLogoutPreferenceVisibility() + } else { + GB.toast(getString(R.string.endurain_logout_failed), Toast.LENGTH_SHORT, GB.WARN) + } } } + true + } + findPreference("pref_key_wanderer_log_out")?.setOnPreferenceClickListener { + WandererTokenManager(requireContext()).clearTokens() + activity?.runOnUiThread { + GB.toast(getString(R.string.endurain_logged_out_successfully), Toast.LENGTH_SHORT, GB.INFO) + updateStatus() + updateLogoutPreferenceVisibility() + } + + true } } private fun updateLogoutPreferenceVisibility() { - findPreference("pref_key_log_out")?.isVisible = vm.tokenManager.isLoggedIn() - findPreference("pref_key_log_in")?.isVisible = !vm.tokenManager.isLoggedIn() + findPreference("pref_key_endurain_log_out")?.isVisible = vm.endurainTokenManager.isLoggedIn() + findPreference("pref_key_endurain_log_in")?.isVisible = !vm.endurainTokenManager.isLoggedIn() + findPreference("pref_key_wanderer_log_out")?.isVisible = WandererTokenManager(requireContext()).isLoggedIn() + findPreference("pref_key_wanderer_log_in")?.isVisible = !WandererTokenManager(requireContext()).isLoggedIn() } private fun updateStatus() { - val statusPref = findPreference("pref_key_status") - val server = GBApplication.getPrefs().preferences.getString("endurain_server", null) - val tokenExpiresAt = DateTimeUtils.parseTimeStamp(vm.tokenManager.getRefreshTokenExpiresAt()) + val endurainStatusPref = findPreference("pref_key_endurain_status") + val endurainServer = GBApplication.getPrefs().preferences.getString("endurain_server", null) + val endurainTokenExpiresAt = DateTimeUtils.parseTimeStamp(vm.endurainTokenManager.getRefreshTokenExpiresAt()) + val wandererStatusPref = findPreference("pref_key_wanderer_status") + val wandererServer = GBApplication.getPrefs().preferences.getString("wanderer_server", null) + val wandererAPITokenAvailable = WandererTokenManager(requireContext()).isLoggedIn() + // Update Endurain preferences var summaryText = getString(R.string.endurain_not_logged_in_integration_disabled) - if (vm.tokenManager.isLoggedIn() && server != null) { + if (vm.endurainTokenManager.isLoggedIn() && endurainServer != null) { summaryText = - getString(R.string.endurain_logged_in_refresh_token, server, tokenExpiresAt) + getString(R.string.endurain_logged_in_refresh_token, endurainServer, endurainTokenExpiresAt) } - if (vm.serverVersion != null) { - summaryText += getString(R.string.endurain_server_version, vm.serverVersion) + if (vm.endurainServerVersion != null) { + summaryText += getString(R.string.endurain_server_version, vm.endurainServerVersion) } - statusPref?.summary = summaryText + endurainStatusPref?.summary = summaryText + + // Update Wanderer preferences + summaryText = getString(R.string.endurain_not_logged_in_integration_disabled) + if (wandererAPITokenAvailable) { + summaryText = + getString(R.string.wanderer_logged_in).format(wandererServer) + } + wandererStatusPref?.summary = summaryText } } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/WandererApiClient.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/WandererApiClient.kt new file mode 100644 index 0000000000..00302cf45b --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/WandererApiClient.kt @@ -0,0 +1,81 @@ +/* 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 . */ +package nodomain.freeyourgadget.gadgetbridge.activities.endurain + +import androidx.core.net.toUri +import nodomain.freeyourgadget.gadgetbridge.util.InternetUtils +import org.json.JSONObject +import org.slf4j.LoggerFactory +import java.io.File + +class WandererApiClient( + private val baseUrl: String, + private val tokenManager: WandererTokenManager +) { + private val LOG = LoggerFactory.getLogger(WandererApiClient::class.java) + + /** + * Build headers with authentication tokens + */ + private fun buildHeaders(): MutableMap { + val headers: MutableMap = mutableMapOf() + + tokenManager.getAPIToken()?.let { token -> + headers["Authorization"] = "Bearer $token" + } + + return headers + } + + /** + * Upload activity file (GPX) + */ + fun uploadActivity(file: File, callback: (String?, String?) -> Unit) { + Thread { + try { + val uri = "$baseUrl/api/v1/trail/upload".toUri() + val headers = buildHeaders() + + InternetUtils.uploadBinaryFile( + uri = uri, + file = file, + requestHeaders = headers, + method = "PUT" + ) { success, statusCode, responseText -> + if (success && statusCode != null && statusCode >= 200 && statusCode < 300 && responseText != null) { + LOG.debug("Response $statusCode from Wanderer: $responseText") + val jsonObject = JSONObject(responseText) + callback(jsonObject.getString("id"), null) + } else { + if (responseText != null) { + val jsonObject = JSONObject(responseText) + val message = jsonObject.getString("message") + LOG.error("Activity upload failed: $message") + callback(null, message) + } else { + LOG.error("Activity upload failed") + callback(null, null) + } + } + } + } catch (e: Exception) { + LOG.error("Activity upload error", e) + callback(null, null) + } + }.start() + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/WandererSetupBottomSheet.kt b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/WandererSetupBottomSheet.kt new file mode 100644 index 0000000000..1f25dd5de9 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/endurain/WandererSetupBottomSheet.kt @@ -0,0 +1,76 @@ +/* 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 . */ +package nodomain.freeyourgadget.gadgetbridge.activities.endurain + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.EditText +import android.widget.Toast +import androidx.core.content.edit +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import nodomain.freeyourgadget.gadgetbridge.GBApplication +import nodomain.freeyourgadget.gadgetbridge.R +import nodomain.freeyourgadget.gadgetbridge.util.GB +import org.slf4j.LoggerFactory + +class WandererSetupBottomSheet : BottomSheetDialogFragment() { + private val LOG = LoggerFactory.getLogger(WandererSetupBottomSheet::class.java) + private val prefs get() = GBApplication.getPrefs().preferences + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View = inflater.inflate( + R.layout.wanderer_bottomsheet_setup_wizard, + container, + false + ) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val serverNameInput = view.findViewById(R.id.wanderer_server_name) + val apiTokenInput = view.findViewById(R.id.wanderer_api_token) + val saveButton = view.findViewById