Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Gravatar QuickEditor #21312

Draft
wants to merge 5 commits into
base: adam/gravatar_2.0.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion WordPress/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ repositories {
includeGroupByRegex "org.wordpress.react-native-libraries.*"
includeGroup "com.automattic"
includeGroup "com.automattic.tracks"
includeGroup "com.automattic.ucrop"
includeGroup "com.gravatar"
includeGroup "rs.wordpress.api"
}
Expand Down Expand Up @@ -203,6 +204,7 @@ android {
buildConfigField "boolean", "VOICE_TO_CONTENT", "false"
buildConfigField "boolean", "READER_FLOATING_BUTTON", "false"
buildConfigField "boolean", "ENABLE_SELF_HOSTED_USERS", "false"
buildConfigField "boolean", "GRAVATAR_QUICK_EDITOR", "true"

// Override these constants in jetpack product flavor to enable/ disable features
buildConfigField "boolean", "ENABLE_SITE_CREATION", "true"
Expand Down Expand Up @@ -440,6 +442,7 @@ dependencies {
}
implementation(libs.wordpress.persistent.edittext)
implementation("$gradle.ext.gravatarBinaryPath:${libs.versions.gravatar.get()}")
implementation("$gradle.ext.gravatarQuickEditorBinaryPath:${libs.versions.gravatar.get()}")

implementation(libs.google.play.app.update)

Expand Down Expand Up @@ -488,7 +491,7 @@ dependencies {
implementation(libs.apache.commons.text)
implementation(libs.airbnb.lottie.main)
implementation(libs.facebook.shimmer)
implementation(libs.yalantis.ucrop) {
implementation(libs.automattic.ucrop) {
exclude group: 'androidx.core', module: 'core'
exclude group: 'androidx.constraintlayout', module: 'constraintlayout'
exclude group: 'androidx.appcompat', module: 'appcompat'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import androidx.lifecycle.compose.LocalLifecycleOwner
import org.wordpress.android.ui.compose.theme.AppTheme
import androidx.camera.core.Preview as CameraPreview

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,13 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.gravatar.quickeditor.GravatarQuickEditor
import com.gravatar.quickeditor.ui.editor.AuthenticationMethod
import com.gravatar.quickeditor.ui.editor.AvatarPickerContentLayout
import com.gravatar.quickeditor.ui.editor.GravatarQuickEditorParams
import com.gravatar.services.AvatarService
import com.gravatar.services.GravatarResult
import com.gravatar.types.Email
import com.yalantis.ucrop.UCrop
import com.yalantis.ucrop.UCrop.Options
import com.yalantis.ucrop.UCropActivity
Expand Down Expand Up @@ -81,6 +86,7 @@ import org.wordpress.android.util.ToastUtils
import org.wordpress.android.util.ToastUtils.Duration.SHORT
import org.wordpress.android.util.WPMediaUtils
import org.wordpress.android.util.config.DomainManagementFeatureConfig
import org.wordpress.android.util.config.GravatarQuickEditorFeatureConfig
import org.wordpress.android.util.config.QRCodeAuthFlowFeatureConfig
import org.wordpress.android.util.config.RecommendTheAppFeatureConfig
import org.wordpress.android.util.extensions.getColorFromAttribute
Expand Down Expand Up @@ -130,6 +136,9 @@ class MeFragment : Fragment(R.layout.me_fragment), OnScrollToTopListener {
@Inject
lateinit var qrCodeAuthFlowFeatureConfig: QRCodeAuthFlowFeatureConfig

@Inject
lateinit var gravatarQuickEditorFeatureConfig: GravatarQuickEditorFeatureConfig

@Inject
lateinit var jetpackBrandingUtils: JetpackBrandingUtils

Expand All @@ -155,6 +164,7 @@ class MeFragment : Fragment(R.layout.me_fragment), OnScrollToTopListener {

private val shouldShowDomainButton
get() = BuildConfig.IS_JETPACK_APP && domainManagementFeatureConfig.isEnabled() && accountStore.hasAccessToken()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
(requireActivity().application as WordPress).component().inject(this)
Expand Down Expand Up @@ -191,7 +201,21 @@ class MeFragment : Fragment(R.layout.me_fragment), OnScrollToTopListener {

val showPickerListener = OnClickListener {
AnalyticsTracker.track(ME_GRAVATAR_TAPPED)
showPhotoPickerForGravatar()
if (gravatarQuickEditorFeatureConfig.isEnabled()) {
GravatarQuickEditor.show(
fragment = this@MeFragment,
gravatarQuickEditorParams = GravatarQuickEditorParams {
email = Email(accountStore.account.email)
avatarPickerContentLayout = AvatarPickerContentLayout.Horizontal
},
authenticationMethod = AuthenticationMethod.Bearer(accountStore.accessToken.orEmpty()),
onAvatarSelected = {
loadAvatar(null, true)
},
)
} else {
showPhotoPickerForGravatar()
}
}
avatarContainer.setOnClickListener(showPickerListener)
rowMyProfile.setOnClickListener {
Expand Down Expand Up @@ -472,9 +496,9 @@ class MeFragment : Fragment(R.layout.me_fragment), OnScrollToTopListener {
isUpdatingGravatar = isUpdating
}

private fun MeFragmentBinding.loadAvatar(injectFilePath: String?) {
private fun MeFragmentBinding.loadAvatar(injectFilePath: String?, forceRefresh: Boolean = false) {
val newAvatarUploaded = !injectFilePath.isNullOrEmpty()
val avatarUrl = meGravatarLoader.constructGravatarUrl(accountStore.account.avatarUrl)
val avatarUrl = meGravatarLoader.constructGravatarUrl(accountStore.account.avatarUrl, forceRefresh)
meGravatarLoader.load(
newAvatarUploaded,
avatarUrl,
Expand Down Expand Up @@ -687,7 +711,10 @@ class MeFragment : Fragment(R.layout.me_fragment), OnScrollToTopListener {
avatarService.uploadCatching(file, accountStore.accessToken.orEmpty())
when (result) {
is GravatarResult.Failure -> {
AnalyticsTracker.track(ME_GRAVATAR_UPLOAD_EXCEPTION, mapOf("error_type" to result.error.javaClass.name))
AnalyticsTracker.track(
ME_GRAVATAR_UPLOAD_EXCEPTION,
mapOf("error_type" to result.error.javaClass.name)
)
EventBus.getDefault().post(GravatarUploadFinished(filePath, false))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ class MeGravatarLoader @Inject constructor(
}
}

fun constructGravatarUrl(rawAvatarUrl: String): String {
fun constructGravatarUrl(rawAvatarUrl: String, forceRefresh: Boolean = false): String {
val avatarSz = resourseProvider.getDimensionPixelSize(R.dimen.avatar_sz_extra_small)
return WPAvatarUtils.rewriteAvatarUrl(rawAvatarUrl, avatarSz)
val cacheBuster = if (forceRefresh) System.currentTimeMillis().toString() else null
return WPAvatarUtils.rewriteAvatarUrl(rawAvatarUrl, avatarSz, cacheBuster)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
Expand All @@ -37,6 +36,7 @@ import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
Expand Down Expand Up @@ -283,27 +283,22 @@ private fun ReadingPreferencesPreviewFeedback(
end = endIndex,
)

addStringAnnotation(
tag = "url",
annotation = "feedback",
addLink(
clickable = LinkAnnotation.Clickable(
tag = "url",
linkInteractionListener = {
onSendFeedbackClick()
}
),
start = startIndex,
end = endIndex,
)
}

val buttonLabel = stringResource(R.string.reader_preferences_screen_preview_text_feedback_label)
ClickableText(
Text(
text = annotatedString,
style = textStyle,
onClick = { offset ->
annotatedString.getStringAnnotations(tag = "url", start = offset, end = offset)
.firstOrNull()
?.let { annotation ->
if (annotation.item == "feedback") {
onSendFeedbackClick()
}
}
},
modifier = Modifier.semantics {
onClick(
label = buttonLabel,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.wordpress.android.ui.reader.views.compose.tagsfeed

import android.content.res.Configuration
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
Expand Down Expand Up @@ -91,7 +90,7 @@ fun ReaderTagsFeed(uiState: UiState) {
}
}

@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun Loaded(uiState: UiState.Loaded) {
val pullRefreshState = rememberPullRefreshState(
Expand Down Expand Up @@ -138,7 +137,7 @@ private fun Loaded(uiState: UiState.Loaded) {

Column(
modifier = Modifier
.animateItemPlacement()
.animateItem()
.fillMaxWidth()
.padding(
top = Margin.Large.value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class WPAvatarUtils {
private WPAvatarUtils() {
throw new IllegalStateException("Utility class");
}

public static final DefaultAvatarOption DEFAULT_AVATAR = MysteryPerson.INSTANCE;

/**
Expand All @@ -35,7 +36,8 @@ private WPAvatarUtils() {
* @return the fixed url
*/
public static String rewriteAvatarUrl(@NonNull final String imageUrl, int avatarSz,
@Nullable DefaultAvatarOption defaultImage) {
@Nullable DefaultAvatarOption defaultImage,
@Nullable String cacheBuster) {
if (TextUtils.isEmpty(imageUrl)) {
return "";
}
Expand All @@ -47,17 +49,27 @@ public static String rewriteAvatarUrl(@NonNull final String imageUrl, int avatar
try {
return new AvatarUrl(new URL(imageUrl),
new AvatarQueryOptions.Builder()
.setPreferredSize(avatarSz)
.setDefaultAvatarOption(defaultImage)
.build()
).url(null).toString();
.setPreferredSize(avatarSz)
.setDefaultAvatarOption(defaultImage)
.build()
).url(cacheBuster).toString();
} catch (MalformedURLException | IllegalArgumentException e) {
return "";
}
}
}

public static String rewriteAvatarUrl(@NonNull final String imageUrl, int avatarSz) {
return rewriteAvatarUrl(imageUrl, avatarSz, DEFAULT_AVATAR);
return rewriteAvatarUrl(imageUrl, avatarSz, DEFAULT_AVATAR, null);
}

public static String rewriteAvatarUrl(@NonNull final String imageUrl, int avatarSz,
@Nullable DefaultAvatarOption defaultImage) {
return rewriteAvatarUrl(imageUrl, avatarSz, defaultImage, null);
}

public static String rewriteAvatarUrl(@NonNull final String imageUrl, int avatarSz,
@Nullable String cacheBuster) {
return rewriteAvatarUrl(imageUrl, avatarSz, DEFAULT_AVATAR, cacheBuster);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.wordpress.android.util.config

import org.wordpress.android.BuildConfig
import org.wordpress.android.annotation.Feature
import javax.inject.Inject

@Feature(GravatarQuickEditorFeatureConfig.GRAVATAR_QUICK_EDITOR_REMOTE_FIELD, true)
class GravatarQuickEditorFeatureConfig @Inject constructor(appConfig: AppConfig) : FeatureConfig(
appConfig,
BuildConfig.GRAVATAR_QUICK_EDITOR,
GRAVATAR_QUICK_EDITOR_REMOTE_FIELD
) {
override fun isEnabled(): Boolean {
return super.isEnabled() && BuildConfig.GRAVATAR_QUICK_EDITOR
}

companion object {
const val GRAVATAR_QUICK_EDITOR_REMOTE_FIELD = "gravatar_quick_editor"
}
}
1 change: 1 addition & 0 deletions config/gradle/included_builds.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ gradle.ext.aztecAndroidGlideLoaderPath = "org.wordpress.aztec:glide-loader"
gradle.ext.aztecAndroidPicassoLoaderPath = "org.wordpress.aztec:picasso-loader"
gradle.ext.aboutAutomatticBinaryPath = "com.automattic:about"
gradle.ext.gravatarBinaryPath = "com.gravatar:gravatar"
gradle.ext.gravatarQuickEditorBinaryPath = "com.gravatar:gravatar-quickeditor"

def localBuilds = new File("${rootDir}/local-builds.gradle")
if (localBuilds.exists()) {
Expand Down
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ wordpress-login = '155-de03d4d605843dd2f37b46430523d92e22c47432'
wordpress-persistent-edittext = '1.0.2'
wordpress-rs = 'trunk-50f703a7f677084157d02f05d4d477d7eaf960b1'
wordpress-utils = '3.14.0'
yalantis-ucrop = '2.2.9'
automattic-ucrop = '2.2.10'
zendesk = '5.1.2'

[libraries]
Expand Down Expand Up @@ -227,7 +227,7 @@ wordpress-lint = { group = "org.wordpress", name = "lint", version.ref = "wordpr
wordpress-persistent-edittext = { group = "org.wordpress", name = "persistentedittext", version.ref = "wordpress-persistent-edittext" }
wordpress-rs-android = { group = "rs.wordpress.api", name = "android", version.ref = "wordpress-rs" }
wordpress-utils = { group = "org.wordpress", name = "utils", version.ref = "wordpress-utils" }
yalantis-ucrop = { group = "com.github.yalantis", name = "ucrop", version.ref = "yalantis-ucrop" }
automattic-ucrop = { group = "com.automattic", name = "ucrop", version.ref = "automattic-ucrop" }
zendesk-support = { group = "com.zendesk", name = "support", version.ref = "zendesk" }

[plugins]
Expand Down
10 changes: 8 additions & 2 deletions libs/image-editor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ android {
}

repositories {
maven { url "https://www.jitpack.io" }
maven {
url 'https://a8c-libs.s3.amazonaws.com/android'
content {
includeGroup "com.automattic"
includeGroup "com.automattic.ucrop"
}
}
}

dependencies {
Expand All @@ -57,7 +63,7 @@ dependencies {
implementation(libs.androidx.lifecycle.viewmodel.main)
implementation(libs.androidx.lifecycle.viewmodel.savedstate)
implementation(libs.androidx.lifecycle.livedata.core)
implementation(libs.yalantis.ucrop) {
implementation(libs.automattic.ucrop) {
exclude group: 'com.squareup.okhttp3'
exclude group: 'androidx.core', module: 'core'
exclude group: 'androidx.constraintlayout', module: 'constraintlayout'
Expand Down
Loading