-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #21114 from wordpress-mobile/feature/feedback-form…
…-attachments Feature: Feedback form attachments
- Loading branch information
Showing
14 changed files
with
759 additions
and
59 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88 changes: 88 additions & 0 deletions
88
WordPress/src/main/java/org/wordpress/android/support/ZendeskUploadHelper.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package org.wordpress.android.support | ||
|
||
import com.zendesk.service.ErrorResponse | ||
import com.zendesk.service.ZendeskCallback | ||
import kotlinx.coroutines.suspendCancellableCoroutine | ||
import org.wordpress.android.util.AppLog | ||
import org.wordpress.android.util.AppLog.T | ||
import org.wordpress.android.util.extensions.mimeType | ||
import zendesk.support.Support | ||
import zendesk.support.UploadResponse | ||
import java.io.File | ||
import java.io.IOException | ||
import javax.inject.Inject | ||
import kotlin.coroutines.resume | ||
import kotlin.coroutines.resumeWithException | ||
|
||
/** | ||
* https://zendesk.github.io/mobile_sdk_javadocs/supportv2/v301/index.html?zendesk/support/UploadProvider.html | ||
*/ | ||
class ZendeskUploadHelper @Inject constructor() { | ||
/** | ||
* Uploads multiple file attachments to Zendesk and returns a list of their tokens when | ||
* all uploads have completed | ||
*/ | ||
suspend fun uploadFileAttachments( | ||
files: List<File> | ||
) = suspendCancellableCoroutine { continuation -> | ||
val uploadProvider = Support.INSTANCE.provider()?.uploadProvider() | ||
if (uploadProvider == null) { | ||
continuation.resumeWithException(IOException("Unable to upload attachments (null provider)")) | ||
return@suspendCancellableCoroutine | ||
} | ||
|
||
val tokens = ArrayList<String>() | ||
var numAttachments = files.size | ||
|
||
val callback = object : ZendeskCallback<UploadResponse>() { | ||
override fun onSuccess(result: UploadResponse) { | ||
if (continuation.isActive) { | ||
result.token?.let { | ||
tokens.add(it) | ||
} | ||
numAttachments-- | ||
if (numAttachments <= 0) { | ||
continuation.resume(tokens) | ||
} | ||
} | ||
} | ||
|
||
override fun onError(errorResponse: ErrorResponse?) { | ||
if (continuation.isActive) { | ||
continuation.resumeWithException( | ||
IOException("Uploading to Zendesk failed with ${errorResponse?.reason}") | ||
) | ||
} | ||
} | ||
} | ||
for (file in files) { | ||
uploadProvider.uploadAttachment( | ||
file.name, | ||
file, | ||
file.mimeType() ?: "", | ||
callback | ||
) | ||
} | ||
} | ||
|
||
/** | ||
* Deletes an attachment from Zendesk. This is currently used only during development. | ||
*/ | ||
@Suppress("unused") | ||
fun deleteAttachment(token: String) { | ||
val uploadProvider = Support.INSTANCE.provider()?.uploadProvider() | ||
if (uploadProvider == null) { | ||
AppLog.e(T.SUPPORT, "Upload provider is null") | ||
return | ||
} | ||
uploadProvider.deleteAttachment(token, object : ZendeskCallback<Void>() { | ||
override fun onSuccess(result: Void) { | ||
AppLog.i(T.SUPPORT, "Successfully deleted Zendesk attachment") | ||
} | ||
|
||
override fun onError(errorResponse: ErrorResponse?) { | ||
AppLog.e(T.SUPPORT, "Unable to delete Zendesk attachment: ${errorResponse?.reason}") | ||
} | ||
}) | ||
} | ||
} |
116 changes: 116 additions & 0 deletions
116
WordPress/src/main/java/org/wordpress/android/ui/compose/components/ProgressDialog.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package org.wordpress.android.ui.compose.components | ||
|
||
import android.content.res.Configuration | ||
import androidx.annotation.StringRes | ||
import androidx.compose.foundation.BorderStroke | ||
import androidx.compose.foundation.background | ||
import androidx.compose.foundation.layout.Arrangement | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.defaultMinSize | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.foundation.shape.RoundedCornerShape | ||
import androidx.compose.material3.CircularProgressIndicator | ||
import androidx.compose.material3.MaterialTheme | ||
import androidx.compose.material3.OutlinedButton | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.collectAsState | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.platform.LocalContext | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.dp | ||
import androidx.compose.ui.window.Dialog | ||
import androidx.compose.ui.window.DialogProperties | ||
import kotlinx.coroutines.flow.Flow | ||
import org.wordpress.android.R | ||
import org.wordpress.android.ui.compose.theme.M3Theme | ||
|
||
@Composable | ||
fun ProgressDialog(progressDialogState: Flow<ProgressDialogState?>) { | ||
progressDialogState.collectAsState(initial = null).value?.let { | ||
ProgressDialog(progressDialogState = it) | ||
} | ||
} | ||
|
||
@Composable | ||
fun ProgressDialog(progressDialogState: ProgressDialogState) { | ||
M3Theme { | ||
val dialogProps = DialogProperties( | ||
dismissOnBackPress = progressDialogState.dismissible, | ||
dismissOnClickOutside = progressDialogState.dismissible, | ||
usePlatformDefaultWidth = false | ||
) | ||
Dialog(onDismissRequest = progressDialogState.onDismiss, dialogProps) { | ||
Box( | ||
modifier = Modifier | ||
.background(MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(8.dp)) | ||
) { | ||
Column( | ||
verticalArrangement = Arrangement.Center, | ||
horizontalAlignment = Alignment.CenterHorizontally, | ||
modifier = Modifier.defaultMinSize(100.dp, 100.dp) | ||
) { | ||
if (progressDialogState.progress != null) { | ||
CircularProgressIndicator(progress = { | ||
progressDialogState.progress | ||
}, Modifier.padding(16.dp)) | ||
} else { | ||
CircularProgressIndicator(Modifier.padding(16.dp)) | ||
} | ||
if (progressDialogState.message != null) { | ||
Text( | ||
text = LocalContext.current.getString(progressDialogState.message), | ||
Modifier.padding(16.dp, 0.dp, 16.dp, 16.dp), | ||
color = MaterialTheme.colorScheme.onSurface | ||
) | ||
} | ||
if (progressDialogState.showCancel) { | ||
OutlinedButton( | ||
onClick = progressDialogState.onDismiss, | ||
shape = RoundedCornerShape(20.dp), | ||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f)), | ||
modifier = Modifier.padding(16.dp, 0.dp, 16.dp, 16.dp) | ||
) { | ||
Text( | ||
text = stringResource(id = R.string.cancel), | ||
Modifier.padding(2.dp), | ||
color = MaterialTheme.colorScheme.onSurface | ||
) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
data class ProgressDialogState( | ||
@StringRes val message: Int? = null, | ||
val progress: Float? = null, | ||
val showCancel: Boolean = false, | ||
val dismissible: Boolean = true, | ||
val onDismiss: () -> Unit = {} | ||
) | ||
|
||
@Preview( | ||
name = "Light Mode", | ||
showBackground = true | ||
) | ||
@Preview( | ||
name = "Dark Mode", | ||
showBackground = true, | ||
uiMode = Configuration.UI_MODE_NIGHT_YES, | ||
) | ||
@Composable | ||
fun ProgressDialogPreview() { | ||
ProgressDialog( | ||
progressDialogState = ProgressDialogState( | ||
message = R.string.uploading, | ||
showCancel = true, | ||
progress = 50f / 100f, | ||
) | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
WordPress/src/main/java/org/wordpress/android/ui/main/feedbackform/FeedbackFormAttachment.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package org.wordpress.android.ui.main.feedbackform | ||
|
||
import android.net.Uri | ||
import java.io.File | ||
|
||
data class FeedbackFormAttachment( | ||
val uri: Uri, | ||
val tempFile: File, | ||
val displayName: String, | ||
val mimeType: String, | ||
val attachmentType: FeedbackFormAttachmentType, | ||
val size: Long, | ||
) | ||
|
||
enum class FeedbackFormAttachmentType { | ||
IMAGE, | ||
VIDEO, | ||
} |
Oops, something went wrong.