mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Endurain: Upload FIT file if available
This commit is contained in:
committed by
Arjan Schrijver
parent
d6f6287919
commit
cc529b40e2
+9
-4
@@ -750,10 +750,15 @@ class WorkoutDetailsFragment : Fragment(), MenuProvider {
|
|||||||
val workoutName = currentWorkout!!.summary.name
|
val workoutName = currentWorkout!!.summary.name
|
||||||
val activityKind = ActivityKind.fromCode(currentWorkout!!.summary.activityKind)
|
val activityKind = ActivityKind.fromCode(currentWorkout!!.summary.activityKind)
|
||||||
val activityTrackProvider = gbDevice.deviceCoordinator.getActivityTrackProvider(gbDevice, requireContext())
|
val activityTrackProvider = gbDevice.deviceCoordinator.getActivityTrackProvider(gbDevice, requireContext())
|
||||||
val gpxFile = ActivitySummaryUtils.getShareableGpxFile(activityTrackProvider, workout.summary)
|
|
||||||
|
|
||||||
if (gpxFile == null) {
|
val activityFile = if (workout.summary.rawDetailsPath?.endsWith(".fit") == true) {
|
||||||
GB.toast(getString(R.string.no_gpx_track_in_activity_toast), Toast.LENGTH_LONG, GB.INFO)
|
FileUtils.tryFixPath(workout.summary.rawDetailsPath)
|
||||||
|
} else {
|
||||||
|
ActivitySummaryUtils.getShareableGpxFile(activityTrackProvider, workout.summary)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activityFile == null) {
|
||||||
|
GB.toast(getString(R.string.no_activity_track_in_activity_toast), Toast.LENGTH_LONG, GB.INFO)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,7 +768,7 @@ class WorkoutDetailsFragment : Fragment(), MenuProvider {
|
|||||||
val apiClient = EndurainApiClient(serverUrl!!, endurainVm.tokenManager)
|
val apiClient = EndurainApiClient(serverUrl!!, endurainVm.tokenManager)
|
||||||
endurainVm.tokenManager.performTokenRefresh(serverUrl) {
|
endurainVm.tokenManager.performTokenRefresh(serverUrl) {
|
||||||
LOG.info("Uploading workout '{}' (type {}) to Endurain", workoutName, activityKind)
|
LOG.info("Uploading workout '{}' (type {}) to Endurain", workoutName, activityKind)
|
||||||
apiClient.uploadActivity(gpxFile) { newId ->
|
apiClient.uploadActivity(activityFile) { newId ->
|
||||||
if (newId != null) {
|
if (newId != null) {
|
||||||
// Update activity type on the server
|
// Update activity type on the server
|
||||||
apiClient.editActivity(newId, activityKind, workoutName)
|
apiClient.editActivity(newId, activityKind, workoutName)
|
||||||
|
|||||||
@@ -171,17 +171,17 @@ class InternetUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val boundary = "----GadgetbridgeFormBoundary${System.currentTimeMillis()}"
|
val boundary = "----GadgetbridgeFormBoundary${System.currentTimeMillis()}"
|
||||||
val multipartBody = buildMultipartBody(file, fileName, mimeType, boundary)
|
val multipartBodyBytes = buildMultipartBody(file, fileName, mimeType, boundary)
|
||||||
|
|
||||||
val headers = requestHeaders.toMutableMap()
|
val headers = requestHeaders.toMutableMap()
|
||||||
headers["Content-Type"] = "multipart/form-data; boundary=$boundary"
|
headers["Content-Type"] = "multipart/form-data; boundary=$boundary"
|
||||||
|
|
||||||
val response = if (GBApplication.hasDirectInternetAccess()) {
|
val response = if (GBApplication.hasDirectInternetAccess()) {
|
||||||
directRequest(
|
directBinaryRequest(
|
||||||
uri = uri,
|
uri = uri,
|
||||||
method = "POST",
|
method = "POST",
|
||||||
requestHeaders = headers,
|
requestHeaders = headers,
|
||||||
body = multipartBody,
|
body = multipartBodyBytes,
|
||||||
allowInsecure = allowInsecure
|
allowInsecure = allowInsecure
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@@ -189,7 +189,7 @@ class InternetUtils {
|
|||||||
uri,
|
uri,
|
||||||
HttpRequest.Method.POST,
|
HttpRequest.Method.POST,
|
||||||
headers,
|
headers,
|
||||||
multipartBody.toByteArray(),
|
multipartBodyBytes,
|
||||||
allowInsecure
|
allowInsecure
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -207,24 +207,57 @@ class InternetUtils {
|
|||||||
fileName: String,
|
fileName: String,
|
||||||
mimeType: String,
|
mimeType: String,
|
||||||
boundary: String
|
boundary: String
|
||||||
): String {
|
): ByteArray {
|
||||||
val fileBytes = file.readBytes()
|
val fileBytes = file.readBytes()
|
||||||
val output = ByteArrayOutputStream()
|
val output = ByteArrayOutputStream()
|
||||||
val writer = output.bufferedWriter()
|
|
||||||
|
|
||||||
writer.write("--$boundary\r\n")
|
|
||||||
writer.write("Content-Disposition: form-data; name=\"file\"; filename=\"$fileName\"\r\n")
|
|
||||||
writer.write("Content-Type: $mimeType\r\n")
|
|
||||||
writer.write("\r\n")
|
|
||||||
writer.flush()
|
|
||||||
|
|
||||||
|
val header = "--$boundary\r\n" +
|
||||||
|
"Content-Disposition: form-data; name=\"file\"; filename=\"$fileName\"\r\n" +
|
||||||
|
"Content-Type: $mimeType\r\n" +
|
||||||
|
"\r\n"
|
||||||
|
output.write(header.toByteArray(Charsets.US_ASCII))
|
||||||
output.write(fileBytes)
|
output.write(fileBytes)
|
||||||
|
output.write("\r\n--$boundary--\r\n".toByteArray(Charsets.US_ASCII))
|
||||||
|
|
||||||
writer.write("\r\n")
|
return output.toByteArray()
|
||||||
writer.write("--$boundary--\r\n")
|
}
|
||||||
writer.flush()
|
|
||||||
|
|
||||||
return output.toString("UTF-8")
|
/**
|
||||||
|
* Direct HTTP request using OkHttp with a binary body.
|
||||||
|
*/
|
||||||
|
private fun directBinaryRequest(
|
||||||
|
uri: Uri,
|
||||||
|
method: String,
|
||||||
|
requestHeaders: Map<String, String>,
|
||||||
|
body: ByteArray,
|
||||||
|
allowInsecure: Boolean
|
||||||
|
): WebResourceResponse {
|
||||||
|
val client = if (allowInsecure) createInsecureClient() else defaultClient
|
||||||
|
val builder = Request.Builder().url(uri.toString())
|
||||||
|
|
||||||
|
for ((key, value) in headersWithUserAgent(requestHeaders)) {
|
||||||
|
builder.addHeader(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
val contentType = getHeader(requestHeaders, "content-type") ?: "application/octet-stream"
|
||||||
|
val requestBody = body.toRequestBody(contentType.toMediaType())
|
||||||
|
builder.method(method.uppercase(), requestBody)
|
||||||
|
|
||||||
|
client.newCall(builder.build()).execute().use { response ->
|
||||||
|
val statusCode = response.code
|
||||||
|
val message = if (!response.message.isEmpty()) response.message else "OK"
|
||||||
|
val headers = response.headers.toMap()
|
||||||
|
val respContentType = response.header("content-type") ?: "application/octet-stream"
|
||||||
|
val encoding = response.header("content-encoding") ?: "UTF-8"
|
||||||
|
return WebResourceResponse(
|
||||||
|
respContentType,
|
||||||
|
encoding,
|
||||||
|
statusCode,
|
||||||
|
message,
|
||||||
|
headers,
|
||||||
|
ByteArrayInputStream(response.body.bytes())
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -4970,6 +4970,7 @@
|
|||||||
<string name="pref_endurain_log_out_title">Log out of Endurain</string>
|
<string name="pref_endurain_log_out_title">Log out of Endurain</string>
|
||||||
<string name="pref_endurain_log_out_summary">Tap here to log out, this disables the integration</string>
|
<string name="pref_endurain_log_out_summary">Tap here to log out, this disables the integration</string>
|
||||||
<string name="no_gpx_track_in_activity_toast">No GPX track in this activity</string>
|
<string name="no_gpx_track_in_activity_toast">No GPX track in this activity</string>
|
||||||
|
<string name="no_activity_track_in_activity_toast">No activity track in this activity</string>
|
||||||
<string name="unable_to_display_gpx_track_toast">Unable to display GPX track: %1$s</string>
|
<string name="unable_to_display_gpx_track_toast">Unable to display GPX track: %1$s</string>
|
||||||
<string name="unable_to_share_gpx_track_toast">Unable to share GPX track: %1$s</string>
|
<string name="unable_to_share_gpx_track_toast">Unable to share GPX track: %1$s</string>
|
||||||
<string name="endurain_successfully_uploaded_toast">Successfully uploaded to Endurain</string>
|
<string name="endurain_successfully_uploaded_toast">Successfully uploaded to Endurain</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user