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

add role badges #4029

Merged
merged 2 commits into from
Sep 25, 2023
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,25 @@ import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.Typeface
import android.graphics.drawable.LayerDrawable
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.text.TextWatcher
import android.text.style.StyleSpan
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.activity.viewModels
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.annotation.Px
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.app.ActivityOptionsCompat
import androidx.core.graphics.ColorUtils
import androidx.core.view.MenuProvider
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
Expand All @@ -48,6 +53,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.viewpager2.widget.MarginPageTransformer
import com.bumptech.glide.Glide
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.chip.Chip
import com.google.android.material.color.MaterialColors
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.shape.MaterialShapeDrawable
Expand Down Expand Up @@ -475,10 +481,10 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide
accountFieldAdapter.notifyDataSetChanged()

binding.accountLockedImageView.visible(account.locked)
binding.accountBadgeTextView.visible(account.bot)

updateAccountAvatar()
updateToolbar()
updateBadges()
updateMovedAccount()
updateRemoteAccount()
updateAccountJoinedDate()
Expand All @@ -491,6 +497,33 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide
}
}

private fun updateBadges() {
binding.accountBadgeContainer.removeAllViews()

val isLight = resources.getBoolean(R.bool.lightNavigationBar)

if (loadedAccount?.bot == true) {
val badgeView = getBadge(getColor(R.color.tusky_grey_50), R.drawable.ic_bot_24dp, getString(R.string.profile_badge_bot_text), isLight)
binding.accountBadgeContainer.addView(badgeView)
}

loadedAccount?.roles?.forEach { role ->
val badgeColor = if (role.color.isNotBlank()) {
Color.parseColor(role.color)
} else {
// sometimes the color is not set for a role, in this case fall back to our default blue
getColor(R.color.tusky_blue)
}

val sb = SpannableStringBuilder("${role.name} ${viewModel.domain}")
Lakoja marked this conversation as resolved.
Show resolved Hide resolved
sb.setSpan(StyleSpan(Typeface.BOLD), 0, role.name.length, 0)

val badgeView = getBadge(badgeColor, R.drawable.profile_badge_person_24dp, sb, isLight)

binding.accountBadgeContainer.addView(badgeView)
}
}

private fun updateAccountJoinedDate() {
loadedAccount?.let { account ->
try {
Expand Down Expand Up @@ -1003,6 +1036,46 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide
}
}

private fun getBadge(
@ColorInt baseColor: Int,
@DrawableRes icon: Int,
text: CharSequence,
isLight: Boolean
): Chip {
val badge = Chip(this)

// text color with maximum contrast
val textColor = if (isLight) Color.BLACK else Color.WHITE
// badge color with 50% transparency so it blends in with the theme background
val backgroundColor = Color.argb(128, Color.red(baseColor), Color.green(baseColor), Color.blue(baseColor))
// a color between the text color and the badge color
val outlineColor = ColorUtils.blendARGB(textColor, baseColor, 0.7f)

// configure the badge
badge.text = text
badge.setTextColor(textColor)
badge.chipStrokeWidth = resources.getDimension(R.dimen.profile_badge_stroke_width)
badge.chipStrokeColor = ColorStateList.valueOf(outlineColor)
badge.setChipIconResource(icon)
badge.isChipIconVisible = true
badge.chipIconSize = resources.getDimension(R.dimen.profile_badge_icon_size)
badge.chipIconTint = ColorStateList.valueOf(outlineColor)
badge.chipBackgroundColor = ColorStateList.valueOf(backgroundColor)

// badge isn't clickable, so disable all related behavior
badge.isClickable = false
badge.isFocusable = false
badge.setEnsureMinTouchTargetSize(false)

// reset some chip defaults so it looks better for our badge usecase
badge.iconStartPadding = resources.getDimension(R.dimen.profile_badge_icon_start_padding)
badge.iconEndPadding = resources.getDimension(R.dimen.profile_badge_icon_end_padding)
badge.minHeight = resources.getDimensionPixelSize(R.dimen.profile_badge_min_height)
badge.chipMinHeight = resources.getDimension(R.dimen.profile_badge_min_height)
badge.updatePadding(top = 0, bottom = 0)
return badge
}

override fun androidInjector() = dispatchingAndroidInjector

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ class AccountViewModel @Inject constructor(
lateinit var accountId: String
var isSelf = false

/** the domain of the viewed account **/
var domain = ""

/** True if the viewed account has the same domain as the active account */
var isFromOwnDomain = false

Expand All @@ -68,11 +71,12 @@ class AccountViewModel @Inject constructor(
mastodonApi.account(accountId)
.fold(
{ account ->
domain = getDomain(account.url)
isFromOwnDomain = domain == activeAccount.domain

accountData.postValue(Success(account))
isDataLoading = false
isRefreshing.postValue(false)

isFromOwnDomain = getDomain(account.url) == activeAccount.domain
},
{ t ->
Log.w(TAG, "failed obtaining account", t)
Expand Down
9 changes: 7 additions & 2 deletions app/src/main/java/com/keylesspalace/tusky/entity/Account.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ data class Account(
val bot: Boolean = false,
val emojis: List<Emoji>? = emptyList(), // nullable for backward compatibility
val fields: List<Field>? = emptyList(), // nullable for backward compatibility
val moved: Account? = null

val moved: Account? = null,
val roles: List<Role>? = emptyList()
Lakoja marked this conversation as resolved.
Show resolved Hide resolved
) {

val name: String
Expand Down Expand Up @@ -68,3 +68,8 @@ data class StringField(
val name: String,
val value: String
)

data class Role(
val name: String,
val color: String
)
6 changes: 0 additions & 6 deletions app/src/main/res/drawable/profile_badge_background.xml

This file was deleted.

10 changes: 10 additions & 0 deletions app/src/main/res/drawable/profile_badge_person_24dp.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="m12,12c2.688,0 4.864,-2.177 4.864,-4.864 0,-2.688 -2.177,-4.864 -4.864,-4.864 -2.688,0 -4.864,2.177 -4.864,4.864C7.136,9.823 9.312,12 12,12ZM12,14.432c-3.247,0 -9.729,1.63 -9.729,4.864v2.432L21.729,21.729L21.729,19.297c0,-3.235 -6.482,-4.864 -9.729,-4.864z"
android:strokeWidth="1.2161"
android:fillColor="#000000"/>
</vector>
53 changes: 28 additions & 25 deletions app/src/main/res/layout/activity_account.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
android:layout_height="180dp"
android:layout_alignTop="@+id/account_header_info"
android:background="?attr/colorPrimaryDark"
android:scaleType="centerCrop"
android:contentDescription="@string/label_header"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
Expand Down Expand Up @@ -154,40 +154,42 @@
app:tint="?android:textColorSecondary"
tools:visibility="visible" />

<TextView
<com.google.android.material.chip.Chip
android:id="@+id/accountFollowsYouTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:background="@drawable/profile_badge_background"
android:clickable="false"
android:focusable="false"
android:minHeight="@dimen/profile_badge_min_height"
android:text="@string/follows_you"
android:textSize="?attr/status_text_small"
android:visibility="gone"
app:chipBackgroundColor="#0000"
app:chipMinHeight="@dimen/profile_badge_min_height"
app:chipStrokeColor="?android:attr/textColorTertiary"
app:chipStrokeWidth="@dimen/profile_badge_stroke_width"
app:ensureMinTouchTargetSize="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/accountUsernameTextView"
tools:visibility="visible" />

<TextView
android:id="@+id/accountBadgeTextView"
android:layout_width="wrap_content"
<com.google.android.material.chip.ChipGroup
android:id="@+id/accountBadgeContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="6dp"
android:background="@drawable/profile_badge_background"
android:text="@string/profile_badge_bot_text"
android:textSize="?attr/status_text_small"
android:visibility="gone"
app:layout_constraintStart_toEndOf="@id/accountFollowsYouTextView"
app:layout_constraintTop_toBottomOf="@id/accountUsernameTextView"
app:layout_goneMarginStart="0dp"
tools:visibility="visible" />
app:chipSpacingVertical="4dp"
app:layout_constraintStart_toEndOf="@id/accountUsernameTextView"
app:layout_constraintTop_toBottomOf="@id/accountFollowsYouTextView"
app:layout_goneMarginStart="0dp" />

<androidx.constraintlayout.widget.Barrier
android:id="@+id/labelBarrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="accountFollowsYouTextView,accountBadgeTextView" />
app:constraint_referenced_ids="accountFollowsYouTextView,accountBadgeContainer" />

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/accountNoteTextInputLayout"
Expand Down Expand Up @@ -225,10 +227,11 @@
android:lineSpacingMultiplier="1.1"
android:paddingTop="2dp"
android:textColor="?android:textColorTertiary"
android:textDirection="firstStrong"
android:textIsSelectable="true"
android:textSize="?attr/status_text_medium"
android:textDirection="firstStrong"
app:layout_constraintTop_toBottomOf="@id/saveNoteInfo"
app:layout_goneMarginTop="8dp"
tools:text="This is a test description. Descriptions can be quite looooong." />

<androidx.recyclerview.widget.RecyclerView
Expand All @@ -245,12 +248,12 @@
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
tools:text="April, 1971"
android:textColor="@color/textColorSecondary"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/accountRemoveView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/accountFieldList"
app:layout_constraintBottom_toTopOf="@id/accountRemoveView"/>
tools:text="April, 1971" />

<TextView
android:id="@+id/accountRemoveView"
Expand All @@ -269,8 +272,8 @@
android:id="@+id/accountMovedView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_marginTop="4dp"
android:visibility="gone"
app:layout_constraintTop_toBottomOf="@id/accountRemoveView"
tools:visibility="visible">

Expand All @@ -287,16 +290,16 @@
tools:text="Account has moved" />

<ImageView
android:importantForAccessibility="no"
android:id="@+id/accountMovedAvatar"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_centerVertical="true"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="24dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginBottom="8dp"
android:importantForAccessibility="no"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/accountMovedText"
tools:src="@drawable/avatar_default" />

Expand Down Expand Up @@ -471,8 +474,8 @@
android:layout_width="@dimen/account_activity_avatar_size"
android:layout_height="@dimen/account_activity_avatar_size"
android:layout_marginStart="16dp"
android:padding="3dp"
android:contentDescription="@string/label_avatar"
android:padding="3dp"
app:layout_anchor="@+id/accountHeaderInfoContainer"
app:layout_anchorGravity="top"
app:layout_scrollFlags="scroll"
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,11 @@

<dimen name="timeline_status_avatar_height">48dp</dimen>
<dimen name="timeline_status_avatar_width">48dp</dimen>

<dimen name="profile_badge_stroke_width">1dp</dimen>
<dimen name="profile_badge_min_height">24dp</dimen>
<dimen name="profile_badge_icon_size">16dp</dimen>
<dimen name="profile_badge_icon_start_padding">8dp</dimen>
<dimen name="profile_badge_icon_end_padding">0dp</dimen>

</resources>