diff --git a/app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt b/app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt index 8ce9f422454..212f416513c 100644 --- a/app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt @@ -12,11 +12,8 @@ package com.nextcloud.talk.profile import android.app.Activity import android.content.pm.PackageManager import android.os.Bundle -import android.text.Editable import android.text.TextUtils -import android.text.TextWatcher import android.util.Log -import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem import android.view.View @@ -24,6 +21,9 @@ import android.view.ViewGroup import androidx.activity.result.ActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.DrawableRes +import androidx.compose.material3.MaterialTheme +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.toDrawable import androidx.core.net.toFile @@ -34,14 +34,12 @@ import autodagger.AutoInjector import com.github.dhaval2404.imagepicker.ImagePicker import com.github.dhaval2404.imagepicker.ImagePicker.Companion.getError import com.google.android.material.snackbar.Snackbar -import com.nextcloud.android.common.ui.theme.utils.ColorRole import com.nextcloud.talk.R import com.nextcloud.talk.activities.BaseActivity import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.ActivityProfileBinding -import com.nextcloud.talk.databinding.UserInfoDetailsTableItemBinding import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.userprofile.Scope import com.nextcloud.talk.models.json.userprofile.UserProfileData @@ -433,7 +431,7 @@ class ProfileActivity : BaseActivity() { result.add( UserInfoDetailsItem( R.drawable.ic_web, - DisplayUtils.beautifyURL(userInfo.website), + userInfo.website, resources!!.getString(R.string.user_info_website), Field.WEBSITE, userInfo.websiteScope @@ -442,7 +440,7 @@ class ProfileActivity : BaseActivity() { result.add( UserInfoDetailsItem( R.drawable.ic_twitter, - DisplayUtils.beautifyTwitterHandle(userInfo.twitter), + userInfo.twitter, resources!!.getString(R.string.user_info_twitter), Field.TWITTER, userInfo.twitterScope @@ -587,7 +585,7 @@ class ProfileActivity : BaseActivity() { credentials, ApiUtils.getUrlForUserData(currentUser!!.baseUrl!!, currentUser!!.userId!!), item.field.scopeName, - item.scope!!.name + item.scope!!.id ) .retry(DEFAULT_RETRIES) .subscribeOn(Schedulers.io()) @@ -598,12 +596,12 @@ class ProfileActivity : BaseActivity() { } override fun onNext(userProfileOverall: GenericOverall) { - Log.d(TAG, "Successfully saved: " + item.scope + " as " + item.field) + Log.d(TAG, "Successfully saved: " + item.scope!!.id + " as " + item.field.scopeName) } override fun onError(e: Throwable) { item.scope = userInfo?.getScopeByField(item.field) - Log.e(TAG, "Failed to saved: " + item.scope + " as " + item.field, e) + Log.e(TAG, "Failed to saved: " + item.scope!!.id + " as " + item.field.scopeName, e) } override fun onComplete() { @@ -629,7 +627,7 @@ class ProfileActivity : BaseActivity() { var displayList: List? var filteredDisplayList: MutableList = LinkedList() - class ViewHolder(val binding: UserInfoDetailsTableItemBinding) : RecyclerView.ViewHolder(binding.root) + class ViewHolder(val composeView: ComposeView) : RecyclerView.ViewHolder(composeView) init { this.displayList = displayList ?: LinkedList() @@ -653,9 +651,12 @@ class ProfileActivity : BaseActivity() { } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - val itemBinding = - UserInfoDetailsTableItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) - return ViewHolder(itemBinding) + val composeView = ComposeView(parent.context).apply { + layoutParams = + ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnDetachedFromWindowOrReleasedFromPool) + } + return ViewHolder(composeView) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { @@ -664,87 +665,60 @@ class ProfileActivity : BaseActivity() { } else { filteredDisplayList[position] } - - initScopeElements(item, holder) - - holder.binding.icon.setImageResource(item.icon) - initUserInfoEditText(holder, item) - - holder.binding.icon.contentDescription = item.hint - viewThemeUtils.platform.colorImageView(holder.binding.icon, ColorRole.PRIMARY) - if (!TextUtils.isEmpty(item.text) || profileActivity.edit) { - holder.binding.userInfoDetailContainer.visibility = View.VISIBLE - profileActivity.viewThemeUtils.material.colorTextInputLayout(holder.binding.userInfoInputLayout) - if (profileActivity.edit && - profileActivity.editableFields.contains(item.field.toString().lowercase()) - ) { - holder.binding.userInfoEditTextEdit.isEnabled = true - holder.binding.userInfoEditTextEdit.isFocusableInTouchMode = true - holder.binding.userInfoEditTextEdit.isEnabled = true - holder.binding.userInfoEditTextEdit.isCursorVisible = true - holder.binding.scope.setOnClickListener { - ScopeDialog( - holder.binding.scope.context, - this, - item.field, - holder.adapterPosition - ).show() - } - holder.binding.scope.alpha = HIGH_EMPHASIS_ALPHA - } else { - holder.binding.userInfoEditTextEdit.isEnabled = false - holder.binding.userInfoEditTextEdit.isFocusableInTouchMode = false - holder.binding.userInfoEditTextEdit.isEnabled = false - holder.binding.userInfoEditTextEdit.isCursorVisible = false - holder.binding.scope.setOnClickListener(null) - holder.binding.scope.alpha = MEDIUM_EMPHASIS_ALPHA - } - } else { - holder.binding.userInfoDetailContainer.visibility = View.GONE + val colorScheme = viewThemeUtils.getColorScheme(profileActivity) + val itemPosition = when (position) { + 0 -> UserInfoDetailItemPosition.FIRST + filteredDisplayList.size - 1 -> UserInfoDetailItemPosition.LAST + else -> UserInfoDetailItemPosition.MIDDLE } - } - - private fun initUserInfoEditText(holder: ViewHolder, item: UserInfoDetailsItem) { - holder.binding.userInfoEditTextEdit.setText(item.text) - holder.binding.userInfoInputLayout.hint = item.hint - holder.binding.userInfoEditTextEdit.addTextChangedListener(object : TextWatcher { - override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { - // unused atm - } - override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { - if (profileActivity.edit) { - displayList!![holder.adapterPosition].text = holder.binding.userInfoEditTextEdit.text.toString() - } else { - filteredDisplayList[holder.adapterPosition].text = - holder.binding.userInfoEditTextEdit.text.toString() + if (profileActivity.edit) { + val itemData = UserInfoDetailItemData( + icon = item.icon, + text = item.text.orEmpty(), + hint = item.hint, + scope = item.scope + ) + val listeners = UserInfoDetailListeners( + onTextChange = { newText -> + if (profileActivity.edit) { + displayList!![position].text = newText + } else { + filteredDisplayList[position].text = newText + } + }, + onScopeClick = { ScopeDialog(profileActivity, this, item.field, position).show() } + ) + holder.composeView.setContent { + MaterialTheme(colorScheme = colorScheme) { + UserInfoDetailItemEditable( + data = itemData, + listeners = listeners, + position = itemPosition, + enabled = profileActivity.editableFields.contains(item.field.toString().lowercase()) + ) } } - - override fun afterTextChanged(s: Editable) { - // unused atm - } - }) - } - - private fun initScopeElements(item: UserInfoDetailsItem, holder: ViewHolder) { - if (item.scope == null) { - holder.binding.scope.visibility = View.GONE } else { - holder.binding.scope.visibility = View.VISIBLE - when (item.scope) { - Scope.PRIVATE -> holder.binding.scope.setImageResource(R.drawable.ic_cellphone) - Scope.LOCAL -> holder.binding.scope.setImageResource(R.drawable.ic_password) - Scope.FEDERATED -> holder.binding.scope.setImageResource(R.drawable.ic_contacts) - Scope.PUBLISHED -> holder.binding.scope.setImageResource(R.drawable.ic_link) - null -> { - // nothing + val displayText = when (item.field) { + Field.WEBSITE -> DisplayUtils.beautifyURL(item.text) + Field.TWITTER -> DisplayUtils.beautifyTwitterHandle(item.text) + else -> item.text.orEmpty() + } + holder.composeView.setContent { + MaterialTheme(colorScheme = colorScheme) { + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData( + icon = item.icon, + text = displayText, + hint = item.hint, + scope = item.scope + ), + position = itemPosition, + ellipsize = Field.EMAIL == item.field + ) } } - holder.binding.scope.contentDescription = holder.binding.scope.context.getString( - R.string.scope_toggle_description, - item.hint - ) } } @@ -774,7 +748,5 @@ class ProfileActivity : BaseActivity() { private val TAG = ProfileActivity::class.java.simpleName private const val DEFAULT_CACHE_SIZE: Int = 20 private const val DEFAULT_RETRIES: Long = 3 - private const val HIGH_EMPHASIS_ALPHA: Float = 0.87f - private const val MEDIUM_EMPHASIS_ALPHA: Float = 0.6f } } diff --git a/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItem.kt b/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItem.kt new file mode 100644 index 00000000000..e5923a23c34 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItem.kt @@ -0,0 +1,19 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.profile + +import androidx.annotation.DrawableRes +import com.nextcloud.talk.models.json.userprofile.Scope + +data class UserInfoDetailItemData( + @param:DrawableRes val icon: Int, + val text: String, + val hint: String, + val scope: Scope? +) + +data class UserInfoDetailListeners(val onTextChange: (String) -> Unit, val onScopeClick: (() -> Unit)?) diff --git a/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItemEditable.kt b/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItemEditable.kt new file mode 100644 index 00000000000..cb31de91ffd --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItemEditable.kt @@ -0,0 +1,218 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.profile + +import android.content.res.Configuration +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.OutlinedTextFieldDefaults +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.nextcloud.talk.R +import com.nextcloud.talk.models.json.userprofile.Scope + +private const val ENABLED_ALPHA = 1f +private const val DISABLED_ALPHA = 0.38f + +@Composable +fun UserInfoDetailItemEditable( + data: UserInfoDetailItemData, + listeners: UserInfoDetailListeners, + position: UserInfoDetailItemPosition, + enabled: Boolean = true +) { + val topPadding = if (position == UserInfoDetailItemPosition.FIRST) 0.dp else 8.dp + val bottomPadding = if (position == UserInfoDetailItemPosition.LAST) 16.dp else 8.dp + var textValue by remember(data.text) { mutableStateOf(data.text) } + Row( + modifier = Modifier + .fillMaxWidth() + .defaultMinSize(minHeight = 48.dp) + .padding(top = topPadding, bottom = bottomPadding), + verticalAlignment = Alignment.CenterVertically + ) { + Spacer(modifier = Modifier.width(16.dp)) + Icon( + painter = painterResource(id = data.icon), + contentDescription = data.hint, + modifier = Modifier + .padding(top = 8.dp) + .size(24.dp), + tint = MaterialTheme.colorScheme.primary + ) + Spacer(modifier = Modifier.width(16.dp)) + OutlinedTextField( + value = textValue, + onValueChange = { newText -> + textValue = newText + listeners.onTextChange(newText) + }, + modifier = Modifier.weight(1f), + label = { Text(data.hint) }, + singleLine = true, + enabled = enabled, + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), + colors = OutlinedTextFieldDefaults.colors( + focusedBorderColor = MaterialTheme.colorScheme.primary, + focusedLabelColor = MaterialTheme.colorScheme.primary, + cursorColor = MaterialTheme.colorScheme.primary + ) + ) + if (data.scope != null) { + ScopeIconButton(data.scope, data.hint, enabled, listeners.onScopeClick) + } + } +} + +@Composable +private fun ScopeIconButton(scope: Scope, hint: String, enabled: Boolean, onScopeClick: (() -> Unit)?) { + val scopeIconRes = when (scope) { + Scope.PRIVATE -> R.drawable.ic_cellphone + Scope.LOCAL -> R.drawable.ic_password + Scope.FEDERATED -> R.drawable.ic_contacts + Scope.PUBLISHED -> R.drawable.ic_link + } + IconButton( + onClick = { onScopeClick?.invoke() }, + modifier = Modifier + .size(48.dp) + .padding(top = 8.dp) + .alpha(if (enabled) ENABLED_ALPHA else DISABLED_ALPHA), + enabled = enabled + ) { + Icon( + painter = painterResource(id = scopeIconRes), + contentDescription = stringResource(R.string.scope_toggle_description, hint), + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} + +private val previewListeners = UserInfoDetailListeners(onTextChange = {}, onScopeClick = {}) + +@Preview(name = "Edit", showBackground = true) +@Preview(name = "Dark · Edit", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun PreviewEdit() { + val colorScheme = if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme() + MaterialTheme(colorScheme = colorScheme) { + Surface { + Column { + UserInfoDetailItemEditable( + data = UserInfoDetailItemData( + R.drawable.ic_user, + "John Doe", + stringResource(R.string.user_info_displayname), + Scope.PRIVATE + ), + listeners = previewListeners, + position = UserInfoDetailItemPosition.FIRST, + enabled = false + ) + UserInfoDetailItemEditable( + data = UserInfoDetailItemData( + R.drawable.ic_phone, + "+49 123 456 789 12", + stringResource(R.string.user_info_phone), + Scope.LOCAL + ), + listeners = previewListeners, + position = UserInfoDetailItemPosition.MIDDLE + ) + UserInfoDetailItemEditable( + data = UserInfoDetailItemData( + R.drawable.ic_email, + "john@example.com", + stringResource(R.string.user_info_email), + Scope.FEDERATED + ), + listeners = previewListeners, + position = UserInfoDetailItemPosition.MIDDLE + ) + } + } + } +} + +@Preview(name = "RTL · Arabic · Edit", showBackground = true, locale = "ar") +@Composable +private fun PreviewEditRtl() { + MaterialTheme(colorScheme = lightColorScheme()) { + Surface { + Column { + UserInfoDetailItemEditable( + data = UserInfoDetailItemData( + R.drawable.ic_user, + "جون دو", + stringResource(R.string.user_info_displayname), + Scope.PRIVATE + ), + listeners = previewListeners, + position = UserInfoDetailItemPosition.FIRST, + enabled = false + ) + UserInfoDetailItemEditable( + data = UserInfoDetailItemData( + R.drawable.ic_map_marker, + "برلين، ألمانيا", + stringResource(R.string.user_info_address), + Scope.PUBLISHED + ), + listeners = previewListeners, + position = UserInfoDetailItemPosition.MIDDLE + ) + UserInfoDetailItemEditable( + data = UserInfoDetailItemData( + R.drawable.ic_web, + "nextcloud.com", + stringResource(R.string.user_info_website), + Scope.PRIVATE + ), + listeners = previewListeners, + position = UserInfoDetailItemPosition.MIDDLE + ) + UserInfoDetailItemEditable( + data = UserInfoDetailItemData( + R.drawable.ic_twitter, + "@nextcloud", + stringResource(R.string.user_info_twitter), + Scope.LOCAL + ), + listeners = previewListeners, + position = UserInfoDetailItemPosition.LAST + ) + } + } + } +} diff --git a/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItemPosition.kt b/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItemPosition.kt new file mode 100644 index 00000000000..aeddde1d20e --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItemPosition.kt @@ -0,0 +1,9 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.profile + +enum class UserInfoDetailItemPosition { FIRST, MIDDLE, LAST } diff --git a/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItemReadOnly.kt b/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItemReadOnly.kt new file mode 100644 index 00000000000..2d670b5cf77 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/profile/UserInfoDetailItemReadOnly.kt @@ -0,0 +1,227 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.profile + +import android.content.res.Configuration +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.nextcloud.talk.R +import com.nextcloud.talk.models.json.userprofile.Scope + +private const val EDGE_RADIUS = 16 +private const val REGULAR_RADIUS = 4 + +@Composable +fun UserInfoDetailItemViewOnly( + userInfo: UserInfoDetailItemData, + position: UserInfoDetailItemPosition, + ellipsize: Boolean = false +) { + val cardShape = when (position) { + UserInfoDetailItemPosition.FIRST -> RoundedCornerShape( + topStart = EDGE_RADIUS.dp, + topEnd = EDGE_RADIUS.dp, + bottomStart = REGULAR_RADIUS.dp, + bottomEnd = REGULAR_RADIUS.dp + ) + UserInfoDetailItemPosition.MIDDLE -> RoundedCornerShape(REGULAR_RADIUS.dp) + UserInfoDetailItemPosition.LAST -> RoundedCornerShape( + topStart = REGULAR_RADIUS.dp, + topEnd = REGULAR_RADIUS.dp, + bottomStart = EDGE_RADIUS.dp, + bottomEnd = EDGE_RADIUS.dp + ) + } + val topPadding = if (position == UserInfoDetailItemPosition.FIRST) 0.dp else 2.dp + val bottomPadding = if (position == UserInfoDetailItemPosition.LAST) 16.dp else 0.dp + Card( + shape = cardShape, + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, top = topPadding, end = 16.dp, bottom = bottomPadding) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .defaultMinSize(minHeight = 48.dp) + .padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + painter = painterResource(id = userInfo.icon), + contentDescription = userInfo.hint, + modifier = Modifier.size(24.dp), + tint = MaterialTheme.colorScheme.primary + ) + Spacer(modifier = Modifier.width(16.dp)) + Column(modifier = Modifier.weight(1f)) { + Text(text = userInfo.hint, style = MaterialTheme.typography.titleMedium) + if (ellipsize) { + Text( + text = userInfo.text, + style = MaterialTheme.typography.bodyMedium, + overflow = TextOverflow.MiddleEllipsis, + maxLines = 1 + ) + } else { + Text(text = userInfo.text, style = MaterialTheme.typography.bodyMedium) + } + } + if (userInfo.scope != null) { + ScopeIcon(userInfo.scope, userInfo.hint) + } + } + } +} + +@Composable +private fun ScopeIcon(scope: Scope, hint: String) { + val scopeIconRes = when (scope) { + Scope.PRIVATE -> R.drawable.ic_cellphone + Scope.LOCAL -> R.drawable.ic_password + Scope.FEDERATED -> R.drawable.ic_contacts + Scope.PUBLISHED -> R.drawable.ic_link + } + Spacer(modifier = Modifier.width(16.dp)) + Icon( + painter = painterResource(id = scopeIconRes), + contentDescription = stringResource(R.string.scope_toggle_description, hint), + modifier = Modifier.size(24.dp) + ) +} + +@Preview(name = "Light · Read-only", showBackground = true) +@Preview(name = "Dark · Read-only", showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun PreviewViewOnly() { + val colorScheme = if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme() + MaterialTheme(colorScheme = colorScheme) { + Surface { + Column { + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData( + R.drawable.ic_user, + "John Doe", + stringResource(R.string.user_info_displayname), + Scope.PRIVATE + ), + position = UserInfoDetailItemPosition.FIRST + ) + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData( + R.drawable.ic_phone, + "+49 123 456 789 12", + stringResource(R.string.user_info_phone), + Scope.LOCAL + ), + position = UserInfoDetailItemPosition.MIDDLE + ) + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData( + R.drawable.ic_email, + "john@example.com", + stringResource(R.string.user_info_email), + Scope.FEDERATED + ), + position = UserInfoDetailItemPosition.MIDDLE + ) + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData( + R.drawable.ic_map_marker, + "Berlin, Germany", + stringResource(R.string.user_info_address), + Scope.PUBLISHED + ), + position = UserInfoDetailItemPosition.MIDDLE + ) + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData( + R.drawable.ic_web, + "nextcloud.com", + stringResource(R.string.user_info_website), + Scope.PRIVATE + ), + position = UserInfoDetailItemPosition.LAST + ) + } + } + } +} + +@Preview(name = "RTL · Arabic", showBackground = true, locale = "ar") +@Composable +private fun PreviewRtl() { + MaterialTheme { + Surface { + Column { + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData(R.drawable.ic_user, "جون دو", "الاسم الكامل", Scope.PRIVATE), + position = UserInfoDetailItemPosition.FIRST + ) + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData(R.drawable.ic_phone, "٠١٢٣ ٤٥٦ ٧٨٩", "هاتف", Scope.LOCAL), + position = UserInfoDetailItemPosition.MIDDLE + ) + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData( + R.drawable.ic_email, + "linda.de.long.family.name.to.render@example-length.com", + "بريد إلكتروني", + Scope.FEDERATED + ), + position = UserInfoDetailItemPosition.MIDDLE, + ellipsize = true + ) + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData( + R.drawable.ic_map_marker, + "برلين، ألمانيا", + "العنوان", + Scope.PUBLISHED + ), + position = UserInfoDetailItemPosition.MIDDLE + ) + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData( + R.drawable.ic_web, + "nextcloud.com", + "الموقع الإلكتروني", + Scope.PRIVATE + ), + position = UserInfoDetailItemPosition.MIDDLE + ) + UserInfoDetailItemViewOnly( + userInfo = UserInfoDetailItemData(R.drawable.ic_twitter, "@nextcloud", "تويتر", Scope.LOCAL), + position = UserInfoDetailItemPosition.LAST + ) + } + } + } +} diff --git a/app/src/main/res/drawable/ic_map_marker.xml b/app/src/main/res/drawable/ic_map_marker.xml index 9c7a82dd773..c2f205eb489 100644 --- a/app/src/main/res/drawable/ic_map_marker.xml +++ b/app/src/main/res/drawable/ic_map_marker.xml @@ -1,15 +1,16 @@ + android:fillColor="@android:color/white" + android:pathData="M536.5,456.5Q560,433 560,400Q560,367 536.5,343.5Q513,320 480,320Q447,320 423.5,343.5Q400,367 400,400Q400,433 423.5,456.5Q447,480 480,480Q513,480 536.5,456.5ZM480,774Q602,662 661,570.5Q720,479 720,408Q720,299 650.5,229.5Q581,160 480,160Q379,160 309.5,229.5Q240,299 240,408Q240,479 299,570.5Q358,662 480,774ZM480,880Q319,743 239.5,625.5Q160,508 160,408Q160,258 256.5,169Q353,80 480,80Q607,80 703.5,169Q800,258 800,408Q800,508 720.5,625.5Q641,743 480,880ZM480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Q480,400 480,400Z" /> diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index 311592d8ed8..fa369fd9a05 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -143,12 +143,12 @@ android:visibility="gone" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:itemCount="3" - tools:listitem="@layout/user_info_details_table_item" - tools:visibility="gone" /> + tools:visibility="visible" /> + layout="@layout/empty_list" + tools:visibility="gone" /> - - - - - - - - - - - - - - diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 2dee2f43490..6b4060bc874 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -70,7 +70,6 @@ 48dp 40dp 2dp - 12dp 18dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 86ca50a55e5..1c6dd2cc04d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -698,7 +698,6 @@ How to translate with transifex: Only synchronize to trusted servers Published Synchronize to trusted servers and the global and public address book - Scope toggle Change privacy level of %1$s