Display public users on login fragment (#142)
* Add public users to login fragment * Display user image and hide recyclerview if no public users
This commit is contained in:
parent
37c8247231
commit
5d2409c93e
13 changed files with 316 additions and 13 deletions
|
@ -12,6 +12,7 @@ import dev.jdtech.jellyfin.adapters.ServerGridAdapter
|
||||||
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
||||||
import dev.jdtech.jellyfin.api.JellyfinApi
|
import dev.jdtech.jellyfin.api.JellyfinApi
|
||||||
import dev.jdtech.jellyfin.database.Server
|
import dev.jdtech.jellyfin.database.Server
|
||||||
|
import dev.jdtech.jellyfin.models.User
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||||
import org.jellyfin.sdk.model.api.BaseItemPerson
|
import org.jellyfin.sdk.model.api.BaseItemPerson
|
||||||
|
@ -57,7 +58,7 @@ fun bindItemBackdropById(imageView: ImageView, itemId: UUID) {
|
||||||
@BindingAdapter("personImage")
|
@BindingAdapter("personImage")
|
||||||
fun bindPersonImage(imageView: ImageView, person: BaseItemPerson) {
|
fun bindPersonImage(imageView: ImageView, person: BaseItemPerson) {
|
||||||
imageView
|
imageView
|
||||||
.loadImage("/items/${person.id}/Images/${ImageType.PRIMARY}", R.drawable.person_placeholder)
|
.loadImage("/items/${person.id}/Images/${ImageType.PRIMARY}", placeholderId = R.drawable.person_placeholder)
|
||||||
.posterDescription(person.name)
|
.posterDescription(person.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,14 +105,21 @@ fun bindSeasonPoster(imageView: ImageView, seasonId: UUID) {
|
||||||
imageView.loadImage("/items/${seasonId}/Images/${ImageType.PRIMARY}")
|
imageView.loadImage("/items/${seasonId}/Images/${ImageType.PRIMARY}")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ImageView.loadImage(url: String, @DrawableRes errorPlaceHolderId: Int? = null): View {
|
@BindingAdapter("userImage")
|
||||||
|
fun bindUserImage(imageView: ImageView, user: User) {
|
||||||
|
imageView
|
||||||
|
.loadImage("/users/${user.id}/Images/${ImageType.PRIMARY}", placeholderId = R.drawable.user_placeholder)
|
||||||
|
.posterDescription(user.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ImageView.loadImage(url: String, @DrawableRes placeholderId: Int = R.color.neutral_800, @DrawableRes errorPlaceHolderId: Int? = null): View {
|
||||||
val api = JellyfinApi.getInstance(context.applicationContext)
|
val api = JellyfinApi.getInstance(context.applicationContext)
|
||||||
|
|
||||||
Glide
|
Glide
|
||||||
.with(context)
|
.with(context)
|
||||||
.load("${api.api.baseUrl}$url")
|
.load("${api.api.baseUrl}$url")
|
||||||
.transition(DrawableTransitionOptions.withCrossFade())
|
.transition(DrawableTransitionOptions.withCrossFade())
|
||||||
.placeholder(R.color.neutral_800)
|
.placeholder(placeholderId)
|
||||||
.error(errorPlaceHolderId)
|
.error(errorPlaceHolderId)
|
||||||
.into(this)
|
.into(this)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
package dev.jdtech.jellyfin.adapters
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import dev.jdtech.jellyfin.databinding.UserItemBinding
|
||||||
|
import dev.jdtech.jellyfin.models.User
|
||||||
|
|
||||||
|
class UserListAdapter(
|
||||||
|
private val clickListener: (user: User) -> Unit
|
||||||
|
) : ListAdapter<User, UserListAdapter.UserViewHolder>(DiffCallback) {
|
||||||
|
class UserViewHolder(private var binding: UserItemBinding) :
|
||||||
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(user: User) {
|
||||||
|
binding.user = user
|
||||||
|
binding.executePendingBindings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object DiffCallback : DiffUtil.ItemCallback<User>() {
|
||||||
|
override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
|
||||||
|
return oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
|
||||||
|
return oldItem == newItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(
|
||||||
|
parent: ViewGroup,
|
||||||
|
viewType: Int
|
||||||
|
): UserViewHolder {
|
||||||
|
return UserViewHolder(
|
||||||
|
UserItemBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
|
||||||
|
val user = getItem(position)
|
||||||
|
holder.itemView.setOnClickListener { clickListener(user) }
|
||||||
|
holder.bind(user)
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import dev.jdtech.jellyfin.adapters.UserListAdapter
|
||||||
import dev.jdtech.jellyfin.databinding.FragmentLoginBinding
|
import dev.jdtech.jellyfin.databinding.FragmentLoginBinding
|
||||||
import dev.jdtech.jellyfin.viewmodels.LoginViewModel
|
import dev.jdtech.jellyfin.viewmodels.LoginViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
@ -51,6 +52,11 @@ class LoginFragment : Fragment() {
|
||||||
login()
|
login()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.usersRecyclerView.adapter = UserListAdapter { user ->
|
||||||
|
(binding.editTextUsername as AppCompatEditText).setText(user.name)
|
||||||
|
(binding.editTextPassword as AppCompatEditText).requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
viewModel.uiState.collect { uiState ->
|
viewModel.uiState.collect { uiState ->
|
||||||
|
@ -64,6 +70,17 @@ class LoginFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
|
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
|
viewModel.usersState.collect { usersState ->
|
||||||
|
when (usersState) {
|
||||||
|
is LoginViewModel.UsersState.Loading -> Unit
|
||||||
|
is LoginViewModel.UsersState.Users -> bindUsersStateUsers(usersState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||||
viewModel.navigateToMain.collect {
|
viewModel.navigateToMain.collect {
|
||||||
|
@ -102,6 +119,16 @@ class LoginFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun bindUsersStateUsers(usersState: LoginViewModel.UsersState.Users) {
|
||||||
|
val users = usersState.users
|
||||||
|
if (users.isEmpty()) {
|
||||||
|
binding.usersRecyclerView.isVisible = false
|
||||||
|
} else {
|
||||||
|
binding.usersRecyclerView.isVisible = true
|
||||||
|
(binding.usersRecyclerView.adapter as UserListAdapter).submitList(users)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun login() {
|
private fun login() {
|
||||||
val username = (binding.editTextUsername as AppCompatEditText).text.toString()
|
val username = (binding.editTextUsername as AppCompatEditText).text.toString()
|
||||||
val password = (binding.editTextPassword as AppCompatEditText).text.toString()
|
val password = (binding.editTextPassword as AppCompatEditText).text.toString()
|
||||||
|
|
8
app/src/main/java/dev/jdtech/jellyfin/models/User.kt
Normal file
8
app/src/main/java/dev/jdtech/jellyfin/models/User.kt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
package dev.jdtech.jellyfin.models
|
||||||
|
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
data class User(
|
||||||
|
val id: UUID,
|
||||||
|
val name: String
|
||||||
|
)
|
|
@ -9,6 +9,7 @@ import dev.jdtech.jellyfin.R
|
||||||
import dev.jdtech.jellyfin.api.JellyfinApi
|
import dev.jdtech.jellyfin.api.JellyfinApi
|
||||||
import dev.jdtech.jellyfin.database.Server
|
import dev.jdtech.jellyfin.database.Server
|
||||||
import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
||||||
|
import dev.jdtech.jellyfin.models.User
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
@ -18,8 +19,8 @@ import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.jellyfin.sdk.model.api.AuthenticateUserByName
|
import org.jellyfin.sdk.model.api.AuthenticateUserByName
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.lang.Exception
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlin.Exception
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class LoginViewModel
|
class LoginViewModel
|
||||||
|
@ -34,6 +35,8 @@ constructor(
|
||||||
|
|
||||||
private val _uiState = MutableStateFlow<UiState>(UiState.Normal)
|
private val _uiState = MutableStateFlow<UiState>(UiState.Normal)
|
||||||
val uiState = _uiState.asStateFlow()
|
val uiState = _uiState.asStateFlow()
|
||||||
|
private val _usersState = MutableStateFlow<UsersState>(UsersState.Loading)
|
||||||
|
val usersState = _usersState.asStateFlow()
|
||||||
private val _navigateToMain = MutableSharedFlow<Boolean>()
|
private val _navigateToMain = MutableSharedFlow<Boolean>()
|
||||||
val navigateToMain = _navigateToMain.asSharedFlow()
|
val navigateToMain = _navigateToMain.asSharedFlow()
|
||||||
|
|
||||||
|
@ -43,6 +46,28 @@ constructor(
|
||||||
data class Error(val message: String) : UiState()
|
data class Error(val message: String) : UiState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed class UsersState {
|
||||||
|
object Loading : UsersState()
|
||||||
|
data class Users(val users: List<User>) : UsersState()
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
loadPublicUsers()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadPublicUsers() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
_usersState.emit(UsersState.Loading)
|
||||||
|
try {
|
||||||
|
val publicUsers by jellyfinApi.userApi.getPublicUsers()
|
||||||
|
val users = publicUsers.map { User(it.id, it.name.orEmpty()) }
|
||||||
|
_usersState.emit(UsersState.Users(users))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
_usersState.emit(UsersState.Users(emptyList()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a authentication request to the Jellyfin server
|
* Send a authentication request to the Jellyfin server
|
||||||
*
|
*
|
||||||
|
|
15
app/src/main/res/drawable-television/user_placeholder.xml
Normal file
15
app/src/main/res/drawable-television/user_placeholder.xml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="?attr/colorPrimary" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:bottom="18dp"
|
||||||
|
android:drawable="@drawable/ic_user"
|
||||||
|
android:end="18dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:start="18dp"
|
||||||
|
android:top="18dp" />
|
||||||
|
</layer-list>
|
21
app/src/main/res/drawable/ic_user_color_on_primary.xml
Normal file
21
app/src/main/res/drawable/ic_user_color_on_primary.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorOnPrimary"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M20,21v-2a4,4 0,0 0,-4 -4H8a4,4 0,0 0,-4 4v2"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeColor="@android:color/white"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="round" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M12,7m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeColor="@android:color/white"
|
||||||
|
android:strokeLineCap="round"
|
||||||
|
android:strokeLineJoin="round" />
|
||||||
|
</vector>
|
15
app/src/main/res/drawable/user_placeholder.xml
Normal file
15
app/src/main/res/drawable/user_placeholder.xml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="?attr/colorPrimary" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:bottom="18dp"
|
||||||
|
android:drawable="@drawable/ic_user_color_on_primary"
|
||||||
|
android:end="18dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:start="18dp"
|
||||||
|
android:top="18dp" />
|
||||||
|
</layer-list>
|
|
@ -26,8 +26,6 @@
|
||||||
android:id="@+id/linearLayout"
|
android:id="@+id/linearLayout"
|
||||||
android:layout_width="@dimen/setup_container_width"
|
android:layout_width="@dimen/setup_container_width"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:layout_marginEnd="24dp"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -39,15 +37,31 @@
|
||||||
android:id="@+id/text_login"
|
android:id="@+id/text_login"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
android:layout_marginBottom="32dp"
|
android:layout_marginBottom="32dp"
|
||||||
android:text="@string/login"
|
android:text="@string/login"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
||||||
android:textColor="?android:textColorPrimary" />
|
android:textColor="?android:textColorPrimary" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/users_recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="12dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:itemCount="2"
|
||||||
|
tools:listitem="@layout/user_item"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/edit_text_username"
|
android:id="@+id/edit_text_username"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
android:autofillHints="username"
|
android:autofillHints="username"
|
||||||
android:hint="@string/edit_text_username_hint"
|
android:hint="@string/edit_text_username_hint"
|
||||||
|
@ -57,6 +71,7 @@
|
||||||
android:id="@+id/edit_text_password"
|
android:id="@+id/edit_text_password"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
android:autofillHints="password"
|
android:autofillHints="password"
|
||||||
android:hint="@string/edit_text_password_hint"
|
android:hint="@string/edit_text_password_hint"
|
||||||
|
@ -66,7 +81,8 @@
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/button_login"
|
android:id="@+id/button_login"
|
||||||
|
|
53
app/src/main/res/layout-television/user_item.xml
Normal file
53
app/src/main/res/layout-television/user_item.xml
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="user"
|
||||||
|
type="dev.jdtech.jellyfin.models.User" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="64dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="12dp"
|
||||||
|
android:background="@drawable/focus_border"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:focusableInTouchMode="true">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/user_image"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
app:layout_constraintDimensionRatio="w,1:1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Findroid.Image"
|
||||||
|
app:userImage="@{user}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/user_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="@{user.name}"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/user_image"
|
||||||
|
tools:text="username" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</layout>
|
|
@ -26,8 +26,6 @@
|
||||||
android:id="@+id/linearLayout"
|
android:id="@+id/linearLayout"
|
||||||
android:layout_width="@dimen/setup_container_width"
|
android:layout_width="@dimen/setup_container_width"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="24dp"
|
|
||||||
android:layout_marginEnd="24dp"
|
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
@ -39,16 +37,32 @@
|
||||||
android:id="@+id/text_login"
|
android:id="@+id/text_login"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
android:layout_marginBottom="32dp"
|
android:layout_marginBottom="32dp"
|
||||||
android:text="@string/login"
|
android:text="@string/login"
|
||||||
android:textAppearance="@style/TextAppearance.Material3.HeadlineMedium"
|
android:textAppearance="@style/TextAppearance.Material3.HeadlineMedium"
|
||||||
android:textColor="?android:textColorPrimary" />
|
android:textColor="?android:textColorPrimary" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/users_recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="12dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:itemCount="2"
|
||||||
|
tools:listitem="@layout/user_item"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/edit_text_username_layout"
|
android:id="@+id/edit_text_username_layout"
|
||||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
android:hint="@string/edit_text_username_hint"
|
android:hint="@string/edit_text_username_hint"
|
||||||
app:startIconDrawable="@drawable/ic_user">
|
app:startIconDrawable="@drawable/ic_user">
|
||||||
|
@ -67,6 +81,7 @@
|
||||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
android:hint="@string/edit_text_password_hint"
|
android:hint="@string/edit_text_password_hint"
|
||||||
app:passwordToggleEnabled="true"
|
app:passwordToggleEnabled="true"
|
||||||
|
@ -84,7 +99,8 @@
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/button_login"
|
android:id="@+id/button_login"
|
||||||
|
|
|
@ -16,8 +16,7 @@
|
||||||
android:layout_marginHorizontal="12dp"
|
android:layout_marginHorizontal="12dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:foreground="@drawable/ripple_background"
|
android:foreground="@drawable/ripple_background">
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<com.google.android.material.imageview.ShapeableImageView
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
android:id="@+id/episode_image"
|
android:id="@+id/episode_image"
|
||||||
|
|
50
app/src/main/res/layout/user_item.xml
Normal file
50
app/src/main/res/layout/user_item.xml
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<data>
|
||||||
|
|
||||||
|
<variable
|
||||||
|
name="user"
|
||||||
|
type="dev.jdtech.jellyfin.models.User" />
|
||||||
|
</data>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="64dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="12dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="@drawable/ripple_background">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:id="@+id/user_image"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
app:layout_constraintDimensionRatio="w,1:1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Findroid.Image"
|
||||||
|
app:userImage="@{user}" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/user_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="@{user.name}"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/user_image"
|
||||||
|
tools:text="username" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</layout>
|
Loading…
Reference in a new issue