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

Gravatar native Quick Editor #3055

Draft
wants to merge 16 commits into
base: main
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
6 changes: 2 additions & 4 deletions .configure
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"project_name": "pocketcasts-android",
"branch": "trunk",
"pinned_hash": "21f42df268ccea3b3d0f258e6e8e8d0b09a32545",
"pinned_hash": "b2e97535bbca2c7f16164b0fe4aed3f4ebe04584",
"files_to_copy": [
{
"file": "android/pocket-casts/secret.properties",
Expand Down Expand Up @@ -44,7 +44,5 @@
"encrypt": true
}
],
"file_dependencies": [

]
"file_dependencies": []
}
Binary file modified .configure-files/secret.properties.enc
Binary file not shown.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
* Bug Fixes
* Fix global auto download setting was incorrectly overriding the podcast auto download setting
([#3342](https://github.com/Automattic/pocket-casts-android/pull/3342))
* New Features
* Modify avatar will use Gravatar native Quick Editor
([#3055](https://github.com/Automattic/pocket-casts-android/pull/3055))

7.79
-----
Expand Down
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ dependencies {
implementation(projects.modules.services.ui)
implementation(projects.modules.services.utils)
implementation(projects.modules.services.views)
implementation(projects.modules.services.gravatar)

debugImplementation(libs.compose.ui.tooling)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package au.com.shiftyjelly.pocketcasts.ui

import android.Manifest
import android.os.SystemClock
import android.view.InputDevice
import android.view.MotionEvent
Expand Down Expand Up @@ -29,7 +28,6 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.rule.GrantPermissionRule
import androidx.test.uiautomator.UiDevice
import au.com.shiftyjelly.pocketcasts.ui.theme.Theme
import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
Expand Down Expand Up @@ -57,9 +55,8 @@ class MainActivityTest {

@get:Rule var activityRule: ActivityScenarioRule<MainActivity> = ActivityScenarioRule(MainActivity::class.java)

@get:Rule val composeTestRule = createAndroidComposeRule<MainActivity>()

@get:Rule var permissionRule = GrantPermissionRule.grant(Manifest.permission.WRITE_EXTERNAL_STORAGE)
@get:Rule
val composeTestRule = createAndroidComposeRule<MainActivity>()

lateinit var device: UiDevice

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package au.com.shiftyjelly.pocketcasts.di
import android.content.Context
import android.net.ConnectivityManager
import androidx.core.content.getSystemService
import au.com.shiftyjelly.pocketcasts.GravatarSdkService
import au.com.shiftyjelly.pocketcasts.servers.di.Downloads
import au.com.shiftyjelly.pocketcasts.utils.gravatar.GravatarService
import dagger.Binds
import dagger.Module
import dagger.Provides
Expand All @@ -29,6 +31,9 @@ abstract class AppModule {
fun downloadRequestBuilder(): Request.Builder = Request.Builder()
}

@Binds
abstract fun gravatarService(factory: GravatarSdkService.Factory): GravatarService.Factory

@Binds
@Downloads
abstract fun downloadsCallFactory(@Downloads client: OkHttpClient): Call.Factory
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,7 @@ class MainActivity :
return binding.snackbarFragment
}

@SuppressLint("PrivateResource")
override fun onMiniPlayerHidden() {
updateSnackbarPosition(miniPlayerOpen = false)
settings.updateBottomInset(0)
Expand All @@ -997,6 +998,7 @@ class MainActivity :
}
}

@SuppressLint("PrivateResource")
override fun onMiniPlayerVisible() {
updateSnackbarPosition(miniPlayerOpen = true)

Expand Down
4 changes: 3 additions & 1 deletion app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root">

<androidx.coordinatorlayout.widget.CoordinatorLayout
Expand All @@ -14,7 +15,8 @@
android:id="@+id/mainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false" />
android:clipToPadding="false"
tools:ignore="PrivateResource" />

<au.com.shiftyjelly.pocketcasts.player.view.PlayerBottomSheet
android:id="@+id/playerBottomSheet"
Expand Down
1 change: 1 addition & 0 deletions automotive/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ dependencies {
implementation(projects.modules.services.analytics)
implementation(projects.modules.services.compose)
implementation(projects.modules.services.crashlogging)
implementation(projects.modules.services.gravatarNoop)
implementation(projects.modules.services.localization)
implementation(projects.modules.services.mediaNoop)
implementation(projects.modules.services.model)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package au.com.shiftyjelly.pocketcasts.di

import au.com.shiftyjelly.pocketcasts.NoOpGravatarSdkService
import au.com.shiftyjelly.pocketcasts.servers.di.Downloads
import au.com.shiftyjelly.pocketcasts.utils.gravatar.GravatarService
import dagger.Binds
import dagger.Module
import dagger.Provides
Expand All @@ -23,4 +25,7 @@ abstract class AutomotiveAppModule {
@Binds
@Downloads
abstract fun downloadsCallFactory(@Downloads client: OkHttpClient): Call.Factory

@Binds
abstract fun gravatarService(factory: NoOpGravatarSdkService.Factory): GravatarService.Factory
}
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ subprojects {
buildConfigField("String", "ENCRYPTION_KEY", "\"${project.property("encryptionKey")}\"")
buildConfigField("String", "APP_SECRET", "\"${project.property("appSecret")}\"")
buildConfigField("String", "META_APP_ID", "\"${project.property("metaAppId")}\"")
buildConfigField("String", "GRAVATAR_APP_ID", "\"${project.property("gravatarAppId")}\"")

testInstrumentationRunner = project.property("testInstrumentationRunner") as String
testApplicationId = "au.com.shiftyjelly.pocketcasts.test${project.name.replace("-", "_")}"
Expand Down
1 change: 1 addition & 0 deletions dependencies.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,6 @@ project.apply {
set("encryptionKey", secretProperties.getProperty("encryption_key", ""))
set("appSecret", secretProperties.getProperty("app_secret", ""))
set("metaAppId", secretProperties.getProperty("metaAppId", ""))
set("gravatarAppId", secretProperties.getProperty("gravatarAppId", ""))
}
}
5 changes: 5 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ espresso = "3.6.1"
firebase = "33.6.0"
fragment = "1.8.5"
glance = "1.0.0"
gravatar = "2.2.0"
google-services = "4.4.2"
hilt = "2.53"
hilt-compiler = "1.2.0"
Expand Down Expand Up @@ -124,6 +125,10 @@ fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragm
glance-appwidget = { module = "androidx.glance:glance-appwidget", version.ref = "glance" }
glance-material3 = { module = "androidx.glance:glance-material3", version.ref = "glance" }

# Gravatar
gravatar = { module = "com.gravatar:gravatar", version.ref = "gravatar" }
gravatar-quickeditor = { module = "com.gravatar:gravatar-quickeditor", version.ref = "gravatar" }

# Horologist
horologist-audio-ui = { module = "com.google.android.horologist:horologist-audio-ui", version.ref = "horologist" }
horologist-audio = { module = "com.google.android.horologist:horologist-audio", version.ref = "horologist" }
Expand Down
3 changes: 2 additions & 1 deletion modules/features/profile/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application>
<activity android:name=".cloud.AddFileActivity"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ import au.com.shiftyjelly.pocketcasts.settings.onboarding.OnboardingFlow
import au.com.shiftyjelly.pocketcasts.settings.onboarding.OnboardingLauncher
import au.com.shiftyjelly.pocketcasts.settings.onboarding.OnboardingUpgradeSource
import au.com.shiftyjelly.pocketcasts.ui.helper.FragmentHostListener
import au.com.shiftyjelly.pocketcasts.utils.Gravatar
import au.com.shiftyjelly.pocketcasts.utils.Util
import au.com.shiftyjelly.pocketcasts.utils.extensions.pxToDp
import au.com.shiftyjelly.pocketcasts.utils.featureflag.Feature
import au.com.shiftyjelly.pocketcasts.utils.featureflag.FeatureFlag
import au.com.shiftyjelly.pocketcasts.utils.gravatar.GravatarService
import au.com.shiftyjelly.pocketcasts.utils.log.LogBuffer
import au.com.shiftyjelly.pocketcasts.views.dialog.ConfirmationDialog
import au.com.shiftyjelly.pocketcasts.views.fragments.BaseFragment
Expand Down Expand Up @@ -86,9 +88,19 @@ class AccountDetailsFragment : BaseFragment() {

@Inject lateinit var syncManager: SyncManager

@Inject lateinit var gravatarServiceFactory: GravatarService.Factory

private val accountViewModel by viewModels<AccountDetailsViewModel>()
private val upgradeBannerViewModel by viewModels<ProfileUpgradeBannerViewModel>()

private lateinit var gravatarService: GravatarService

override fun onCreate(savedInstanceState: Bundle?) {
gravatarService = gravatarServiceFactory.create(this) { accountViewModel.gravatarUpdated() }

super.onCreate(savedInstanceState)
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
Expand Down Expand Up @@ -130,9 +142,7 @@ class AccountDetailsFragment : BaseFragment() {
upgradeBannerViewModel.onFeatureCardChanged(featureCard)
},
onChangeAvatar = { email ->
analyticsTracker.track(AnalyticsEvent.ACCOUNT_DETAILS_CHANGE_AVATAR)
Gravatar.refreshGravatarTimestamp()
requireActivity().startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(Gravatar.getGravatarChangeAvatarUrl(email))))
openGravatarQuickEditor(email)
},
onChangeEmail = {
(requireActivity() as FragmentHostListener).addFragment(ChangeEmailFragment.newInstance())
Expand Down Expand Up @@ -277,6 +287,15 @@ class AccountDetailsFragment : BaseFragment() {
activity?.finish()
}

private fun openGravatarQuickEditor(email: String) {
analyticsTracker.track(AnalyticsEvent.ACCOUNT_DETAILS_CHANGE_AVATAR)
if (FeatureFlag.isEnabled(Feature.GRAVATAR_NATIVE_QUICK_EDITOR)) {
gravatarService.launchQuickEditor(theme.isLightTheme, email)
} else {
gravatarService.launchExternalQuickEditor(email)
}
}

private fun performSignOut() {
LogBuffer.i(LogBuffer.TAG_BACKGROUND_TASKS, "User requested to sign out")
userManager.signOut(playbackManager, wasInitiatedByUser = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.reactive.asFlow
Expand Down Expand Up @@ -65,7 +64,7 @@ class AccountDetailsViewModel
}
}

internal val headerState = signInState.asFlow().map { state ->
internal val headerState = combine(signInState.asFlow(), Gravatar.lastTimeStamp) { state, _ ->
when (state) {
is SignInState.SignedOut -> AccountHeaderState.empty()
is SignInState.SignedIn -> {
Expand Down Expand Up @@ -187,6 +186,10 @@ class AccountDetailsViewModel
settings.marketingOptIn.set(isChecked, updateModifiedAt = true)
}

fun gravatarUpdated() {
Gravatar.refreshGravatarTimestamp()
}

companion object {
private const val SOURCE_KEY = "source"
private const val ENABLED_KEY = "enabled"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class ProfileViewModel @Inject constructor(

internal val isSignedIn get() = signInState.value.isSignedIn

internal val profileHeaderState = signInState.map { state ->
internal val profileHeaderState = combine(signInState, Gravatar.lastTimeStamp) { state, _ ->
when (state) {
is SignInState.SignedIn -> ProfileHeaderState(
imageUrl = Gravatar.getUrl(state.email),
Expand Down
24 changes: 24 additions & 0 deletions modules/services/gravatar-noop/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.ksp)
alias(libs.plugins.hilt)
}

android {
namespace = "au.com.shiftyjelly.pocketcasts.gravatar"
buildFeatures {
buildConfig = true
viewBinding = false
compose = false
}
}

dependencies {
ksp(libs.dagger.hilt.compiler)
ksp(libs.hilt.compiler)

api(libs.dagger.hilt.android)

implementation(projects.modules.services.utils)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package au.com.shiftyjelly.pocketcasts

import androidx.fragment.app.Fragment
import au.com.shiftyjelly.pocketcasts.utils.gravatar.GravatarService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.FragmentComponent

@Module
@InstallIn(FragmentComponent::class)
object GravatarModule {
@Provides
fun provideGravatarService(
fragment: Fragment,
onAvatarSelected: () -> Unit,
): GravatarService = NoOpGravatarSdkService(fragment, onAvatarSelected)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package au.com.shiftyjelly.pocketcasts

import androidx.fragment.app.Fragment
import au.com.shiftyjelly.pocketcasts.utils.gravatar.GravatarService
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject

class NoOpGravatarSdkService @AssistedInject constructor(@Assisted fragment: Fragment?, @Assisted onAvatarSelected: (() -> Unit)?) :
GravatarService {

override fun launchExternalQuickEditor(email: String) {
error("Operation not supported")
}

override fun launchQuickEditor(isLightTheme: Boolean, email: String) {
error("Operation not supported")
}

override suspend fun logout(email: String) {
error("Operation not supported")
}

@AssistedFactory
interface Factory : GravatarService.Factory {
override fun create(fragment: Fragment?, onAvatarSelected: (() -> Unit)?): NoOpGravatarSdkService
}
}
27 changes: 27 additions & 0 deletions modules/services/gravatar/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.ksp)
alias(libs.plugins.hilt)
}

android {
namespace = "au.com.shiftyjelly.pocketcasts.gravatar"
buildFeatures {
buildConfig = true
viewBinding = false
compose = false
}
}

dependencies {
ksp(libs.dagger.hilt.compiler)
ksp(libs.hilt.compiler)

api(libs.dagger.hilt.android)

implementation(projects.modules.services.utils)

implementation(libs.gravatar)
implementation(libs.gravatar.quickeditor)
}
Loading