show bottom sheet when tapping avatar

This commit is contained in:
Phillip Thelen 2023-08-22 10:45:36 +02:00
parent 19bf9cf3d4
commit 42fdc2560e
9 changed files with 116 additions and 20 deletions

View file

@ -1405,6 +1405,9 @@
<string name="eggs_footer_description">Check out the [Market](/shops/market) to buy just the eggs you need!</string>
<string name="food_footer_description">Check out the [Market](/shops/market) to buy food or a Saddle to instantly raise your Pet!</string>
<string name="hatchingPotions_footer_description">Check out the [Market](/shops/market) to buy standard and seasonal Hatching Potions!</string>
<string name="open_profile">Open Profile</string>
<string name="customize_avatar">Customize Avatar</string>
<string name="share_avatar">Share Avatar</string>
<plurals name="you_x_others">
<item quantity="zero">You</item>

View file

@ -1,8 +1,6 @@
package com.habitrpg.android.habitica.interactors
import android.graphics.Bitmap
import android.view.ViewGroup
import androidx.core.graphics.scale
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.DialogLevelup10Binding
import com.habitrpg.android.habitica.helpers.SoundManager
@ -64,14 +62,6 @@ constructor(
dialogAvatarView.setAvatar(requestValues.user)
}
val message = requestValues.activity.getString(R.string.share_levelup, requestValues.newLevel)
val avatarView = AvatarView(requestValues.activity, showBackground = true, showMount = true, showPet = true)
avatarView.setAvatar(requestValues.user)
var sharedImage: Bitmap? = null
avatarView.onAvatarImageReady { image ->
sharedImage = image?.scale(image.width * 3, image.height * 3, false)
}
val alert = HabiticaAlertDialog(requestValues.activity)
alert.setTitle(requestValues.activity.getString(R.string.levelup_header, requestValues.newLevel))
alert.setAdditionalContentView(customView)
@ -81,7 +71,16 @@ constructor(
}
}
alert.addButton(R.string.share, false) { _, _ ->
requestValues.activity.shareContent("levelup", message, sharedImage)
MainScope().launchCatching {
val usecase = ShareAvatarUseCase()
usecase.callInteractor(ShareAvatarUseCase.RequestValues(
requestValues.activity,
requestValues.user,
requestValues.activity.getString(R.string.share_levelup, requestValues.newLevel),
"levelup"
))
}
}
alert.isCelebratory = true

View file

@ -0,0 +1,23 @@
package com.habitrpg.android.habitica.interactors
import android.graphics.Bitmap
import androidx.core.graphics.scale
import com.habitrpg.android.habitica.ui.activities.BaseActivity
import com.habitrpg.common.habitica.views.AvatarView
import com.habitrpg.shared.habitica.models.Avatar
import javax.inject.Inject
class ShareAvatarUseCase @Inject
constructor() : UseCase<ShareAvatarUseCase.RequestValues, Unit>() {
override suspend fun run(requestValues: RequestValues) {
val avatarView = AvatarView(requestValues.activity, showBackground = true, showMount = true, showPet = true)
avatarView.setAvatar(requestValues.avatar)
var sharedImage: Bitmap? = null
avatarView.onAvatarImageReady { image ->
sharedImage = image?.scale(image.width * 3, image.height * 3, false)
requestValues.activity.shareContent(requestValues.identifier, requestValues.message, sharedImage)
}
}
class RequestValues(val activity: BaseActivity, val avatar: Avatar, val message: String?, val identifier: String): UseCase.RequestValues
}

View file

@ -224,11 +224,13 @@ abstract class BaseActivity : AppCompatActivity() {
open fun hideConnectionProblem() {
}
fun shareContent(identifier: String, message: String, image: Bitmap? = null) {
fun shareContent(identifier: String, message: String?, image: Bitmap? = null) {
Analytics.sendEvent("shared", EventCategory.BEHAVIOUR, HitType.EVENT, mapOf("identifier" to identifier))
val sharingIntent = Intent(Intent.ACTION_SEND)
sharingIntent.type = "*/*"
sharingIntent.putExtra(Intent.EXTRA_TEXT, message)
if (message?.isNotBlank() == true) {
sharingIntent.putExtra(Intent.EXTRA_TEXT, message)
}
if (image != null) {
val path = MediaStore.Images.Media.insertImage(this.contentResolver, image, "${(Date())}", null)
if (path != null) {

View file

@ -17,9 +17,18 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.view.children
import androidx.core.view.setPadding
import androidx.drawerlayout.widget.DrawerLayout
@ -45,13 +54,13 @@ import com.habitrpg.android.habitica.helpers.Analytics
import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.EventCategory
import com.habitrpg.android.habitica.helpers.HitType
import com.habitrpg.common.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.helpers.NotificationOpenHandler
import com.habitrpg.android.habitica.helpers.SoundManager
import com.habitrpg.android.habitica.helpers.collectAsStateLifecycleAware
import com.habitrpg.android.habitica.interactors.CheckClassSelectionUseCase
import com.habitrpg.android.habitica.interactors.DisplayItemDropUseCase
import com.habitrpg.android.habitica.interactors.NotifyUserUseCase
import com.habitrpg.android.habitica.interactors.ShareAvatarUseCase
import com.habitrpg.android.habitica.models.TutorialStep
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.models.user.UserQuestStatus
@ -61,7 +70,9 @@ import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
import com.habitrpg.android.habitica.ui.viewmodels.MainActivityViewModel
import com.habitrpg.android.habitica.ui.viewmodels.NotificationsViewModel
import com.habitrpg.android.habitica.ui.views.AppHeaderView
import com.habitrpg.android.habitica.ui.views.ComposableAvatarView
import com.habitrpg.android.habitica.ui.views.GroupPlanMemberList
import com.habitrpg.android.habitica.ui.views.HabiticaButton
import com.habitrpg.android.habitica.ui.views.SnackbarActivity
import com.habitrpg.android.habitica.ui.views.dialogs.QuestCompletedDialog
import com.habitrpg.android.habitica.ui.views.showAsBottomSheet
@ -75,6 +86,7 @@ import com.habitrpg.common.habitica.extensions.dpToPx
import com.habitrpg.common.habitica.extensions.getThemeColor
import com.habitrpg.common.habitica.extensions.isUsingNightModeResources
import com.habitrpg.common.habitica.helpers.ExceptionHandler
import com.habitrpg.common.habitica.helpers.MainNavigationController
import com.habitrpg.common.habitica.helpers.launchCatching
import com.habitrpg.common.habitica.views.AvatarView
import com.habitrpg.shared.habitica.models.responses.MaintenanceResponse
@ -284,6 +296,63 @@ open class MainActivity : BaseActivity(), SnackbarActivity {
teamPlan = if (canShowTeamHeader) teamPlan else null,
teamPlanMembers = teamPlanMembers,
isMyProfile = true,
onAvatarClicked = {
showAsBottomSheet { dismiss ->
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(4.dp),
modifier = Modifier.padding(22.dp)
) {
ComposableAvatarView(avatar = user)
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(15.dp),
) {
HabiticaButton(
background = HabiticaTheme.colors.tintedUiSub,
color = Color.White,
onClick = {
dismiss()
MainNavigationController.navigate(R.id.openProfileActivity)
}) {
Text(stringResource(id = R.string.open_profile))
}
HabiticaButton(
background = HabiticaTheme.colors.tintedUiSub,
color = Color.White,
onClick = {
dismiss()
MainNavigationController.navigate(R.id.avatarOverviewFragment)
}) {
Text(stringResource(id = R.string.customize_avatar))
}
HabiticaButton(
background = HabiticaTheme.colors.tintedUiSub,
color = Color.White,
onClick = {
dismiss()
user?.let {
val usecase = ShareAvatarUseCase()
lifecycleScope.launchCatching {
usecase.callInteractor(
ShareAvatarUseCase.RequestValues(
this@MainActivity,
it,
null,
"avatar_bottomsheet"
)
)
}
}
}) {
Text(stringResource(id = R.string.share_avatar))
}
}
}
}
},
onMemberRowClicked = {
showAsBottomSheet { onClose ->
val group by viewModel.userViewModel.currentTeamPlanGroup.collectAsState(

View file

@ -106,6 +106,7 @@ fun AppHeaderView(
isMyProfile : Boolean = false,
teamPlan : TeamPlan? = null,
teamPlanMembers : List<Member>? = null,
onAvatarClicked: (() -> Unit)? = null,
onMemberRowClicked : () -> Unit,
onClassSelectionClicked: () -> Unit
) {
@ -117,7 +118,7 @@ fun AppHeaderView(
.size(110.dp, 100.dp)
.padding(end = 16.dp)
.clickable {
MainNavigationController.navigate(R.id.avatarOverviewFragment)
onAvatarClicked?.invoke()
}
)
val animationValue =

View file

@ -71,7 +71,7 @@ private fun BottomSheetWrapper(
content: @Composable (() -> Unit) -> Unit
) {
val coroutineScope = rememberCoroutineScope()
val modalBottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
val modalBottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden, skipHalfExpanded = true)
var isSheetOpened by remember { mutableStateOf(false) }
val systemUiController = rememberSystemUiController()

View file

@ -42,7 +42,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.1.0'
classpath 'com.android.tools.build:gradle:8.1.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.google.gms:google-services:4.3.15'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.8'

View file

@ -14,7 +14,6 @@ import android.text.TextUtils
import android.util.AttributeSet
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.core.graphics.drawable.toBitmap
import androidx.core.view.marginStart
import androidx.core.view.marginTop
import coil.dispose
@ -73,8 +72,8 @@ class AvatarView : FrameLayout {
if (BuildConfig.DEBUG && (avatar == null || avatarRectF == null)) {
error("Assertion failed")
}
val viewWidth = if (width > 0) width else layoutParams.width
val viewHeight = if (height > 0) height else layoutParams.height
val viewWidth = if (width > 0) width else (layoutParams?.width ?: 140)
val viewHeight = if (height > 0) height else (layoutParams?.height ?: 147)
val canvasRect = Rect(0, 0, if (viewWidth > 0) viewWidth else 140.dpToPx(context), if (viewHeight > 0) viewHeight else 147.dpToPx(context))
if (canvasRect.isEmpty) return null
avatarBitmap = Bitmap.createBitmap(