mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Massive changes to account flow
This commit is contained in:
parent
8b73c35e43
commit
d5174ed2e9
15 changed files with 496 additions and 606 deletions
|
@ -1,110 +0,0 @@
|
|||
package com.lagradost.cloudstream3.ui
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.lagradost.cloudstream3.databinding.WhoIsWatchingAccountAddBinding
|
||||
import com.lagradost.cloudstream3.databinding.WhoIsWatchingAccountBinding
|
||||
import com.lagradost.cloudstream3.ui.result.setImage
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
|
||||
class WhoIsWatchingAdapter(
|
||||
private val selectCallBack: (DataStoreHelper.Account) -> Unit = { },
|
||||
private val editCallBack: (DataStoreHelper.Account) -> Unit = { },
|
||||
private val addAccountCallback: () -> Unit = {}
|
||||
) :
|
||||
ListAdapter<DataStoreHelper.Account, WhoIsWatchingAdapter.WhoIsWatchingHolder>(DiffCallback()) {
|
||||
|
||||
companion object {
|
||||
const val FOOTER = 1
|
||||
const val NORMAL = 0
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return currentList.size + 1
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int = when (position) {
|
||||
currentList.size -> FOOTER
|
||||
else -> NORMAL
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WhoIsWatchingHolder =
|
||||
WhoIsWatchingHolder(
|
||||
binding = when (viewType) {
|
||||
NORMAL -> WhoIsWatchingAccountBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
|
||||
FOOTER -> WhoIsWatchingAccountAddBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
|
||||
else -> throw NotImplementedError()
|
||||
},
|
||||
selectCallBack = selectCallBack,
|
||||
addAccountCallback = addAccountCallback,
|
||||
editCallBack = editCallBack,
|
||||
)
|
||||
|
||||
override fun onBindViewHolder(holder: WhoIsWatchingHolder, position: Int) =
|
||||
holder.bind(currentList.getOrNull(position))
|
||||
|
||||
class WhoIsWatchingHolder(
|
||||
val binding: ViewBinding,
|
||||
val selectCallBack: (DataStoreHelper.Account) -> Unit,
|
||||
val addAccountCallback: () -> Unit,
|
||||
val editCallBack: (DataStoreHelper.Account) -> Unit
|
||||
) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(card: DataStoreHelper.Account?) {
|
||||
when (binding) {
|
||||
is WhoIsWatchingAccountBinding -> binding.apply {
|
||||
if (card == null) return@apply
|
||||
outline.isVisible = card.keyIndex == DataStoreHelper.selectedKeyIndex
|
||||
profileText.text = card.name
|
||||
profileImageBackground.setImage(card.image)
|
||||
|
||||
// Handle the lock indicator
|
||||
val isLocked = card.lockPin != null
|
||||
lockIcon.isVisible = isLocked
|
||||
|
||||
root.setOnClickListener {
|
||||
selectCallBack(card)
|
||||
}
|
||||
root.setOnLongClickListener {
|
||||
editCallBack(card)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
}
|
||||
|
||||
is WhoIsWatchingAccountAddBinding -> binding.apply {
|
||||
root.setOnClickListener {
|
||||
addAccountCallback()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DiffCallback : DiffUtil.ItemCallback<DataStoreHelper.Account>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: DataStoreHelper.Account,
|
||||
newItem: DataStoreHelper.Account
|
||||
): Boolean = oldItem.keyIndex == newItem.keyIndex
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: DataStoreHelper.Account,
|
||||
newItem: DataStoreHelper.Account
|
||||
): Boolean = oldItem == newItem
|
||||
}
|
||||
}
|
|
@ -4,61 +4,153 @@ import android.view.LayoutInflater
|
|||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.AccountListItemAddBinding
|
||||
import com.lagradost.cloudstream3.databinding.AccountListItemBinding
|
||||
import com.lagradost.cloudstream3.databinding.AccountListItemEditingBinding
|
||||
import com.lagradost.cloudstream3.ui.account.AccountDialogs.showAccountEditDialog
|
||||
import com.lagradost.cloudstream3.ui.result.setImage
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
|
||||
class AccountAdapter(
|
||||
private val accounts: List<DataStoreHelper.Account>,
|
||||
private val onItemClick: (DataStoreHelper.Account) -> Unit
|
||||
private val accountSelectCallback: (DataStoreHelper.Account) -> Unit,
|
||||
private val accountCreateCallback: (DataStoreHelper.Account) -> Unit,
|
||||
private val accountEditCallback: (DataStoreHelper.Account) -> Unit
|
||||
) : RecyclerView.Adapter<AccountAdapter.AccountViewHolder>() {
|
||||
|
||||
inner class AccountViewHolder(private val binding: AccountListItemBinding) :
|
||||
companion object {
|
||||
private const val VIEW_TYPE_ACCOUNT = 0
|
||||
private const val VIEW_TYPE_ADD_ACCOUNT = 1
|
||||
const val VIEW_TYPE_EDIT_ACCOUNT = 2
|
||||
}
|
||||
|
||||
inner class AccountViewHolder(private val binding: ViewBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(account: DataStoreHelper.Account) {
|
||||
val isLastUsedAccount = account.keyIndex == DataStoreHelper.selectedKeyIndex
|
||||
fun bind(account: DataStoreHelper.Account?) {
|
||||
when (binding) {
|
||||
is AccountListItemBinding -> binding.apply {
|
||||
if (account == null) return@apply
|
||||
|
||||
binding.accountName.text = account.name
|
||||
binding.accountImage.setImage(account.image)
|
||||
binding.lockIcon.isVisible = account.lockPin != null
|
||||
binding.outline.isVisible = isLastUsedAccount
|
||||
val isLastUsedAccount = account.keyIndex == DataStoreHelper.selectedKeyIndex
|
||||
|
||||
if (isTvSettings()) {
|
||||
binding.root.isFocusableInTouchMode = true
|
||||
if (isLastUsedAccount) {
|
||||
binding.root.requestFocus()
|
||||
accountName.text = account.name
|
||||
accountImage.setImage(account.image)
|
||||
lockIcon.isVisible = account.lockPin != null
|
||||
outline.isVisible = isLastUsedAccount
|
||||
|
||||
if (isTvSettings()) {
|
||||
root.isFocusableInTouchMode = true
|
||||
if (isLastUsedAccount) {
|
||||
root.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
root.setOnClickListener {
|
||||
accountSelectCallback.invoke(account)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
is AccountListItemEditingBinding -> binding.apply {
|
||||
if (account == null) return@apply
|
||||
|
||||
val isLastUsedAccount = account.keyIndex == DataStoreHelper.selectedKeyIndex
|
||||
|
||||
accountName.text = account.name
|
||||
accountImage.setImage(account.image)
|
||||
lockIcon.isVisible = account.lockPin != null
|
||||
outline.isVisible = isLastUsedAccount
|
||||
|
||||
if (isTvSettings()) {
|
||||
root.isFocusableInTouchMode = true
|
||||
if (isLastUsedAccount) {
|
||||
root.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
root.setOnClickListener {
|
||||
showAccountEditDialog(root.context, account, isNewAccount = false) {
|
||||
accountEditCallback.invoke(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is AccountListItemAddBinding -> binding.apply {
|
||||
root.setOnClickListener {
|
||||
val remainingImages =
|
||||
DataStoreHelper.profileImages.toSet() - accounts.filter { it.customImage == null }
|
||||
.mapNotNull { DataStoreHelper.profileImages.getOrNull(it.defaultImageIndex) }.toSet()
|
||||
|
||||
val image =
|
||||
DataStoreHelper.profileImages.indexOf(remainingImages.randomOrNull() ?: DataStoreHelper.profileImages.random())
|
||||
val keyIndex = (accounts.maxOfOrNull { it.keyIndex } ?: 0) + 1
|
||||
|
||||
val accountName = root.context.getString(R.string.account)
|
||||
|
||||
showAccountEditDialog(root.context, DataStoreHelper.Account(
|
||||
keyIndex = keyIndex,
|
||||
name = "$accountName $keyIndex",
|
||||
customImage = null,
|
||||
defaultImageIndex = image
|
||||
), isNewAccount = true) {
|
||||
accountCreateCallback.invoke(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.root.setOnClickListener {
|
||||
onItemClick(account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AccountViewHolder {
|
||||
val binding = AccountListItemBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AccountViewHolder =
|
||||
AccountViewHolder(
|
||||
binding = when (viewType) {
|
||||
VIEW_TYPE_ACCOUNT -> {
|
||||
AccountListItemBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
}
|
||||
VIEW_TYPE_ADD_ACCOUNT -> {
|
||||
AccountListItemAddBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
}
|
||||
VIEW_TYPE_EDIT_ACCOUNT -> {
|
||||
AccountListItemEditingBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
}
|
||||
else -> throw IllegalArgumentException("Invalid view type")
|
||||
}
|
||||
)
|
||||
|
||||
if (isTvSettings()) {
|
||||
val layoutParams = binding.root.layoutParams as RecyclerView.LayoutParams
|
||||
val marginInDp = 5 // Set the margin to 5dp
|
||||
val marginInPixels = (marginInDp * parent.resources.displayMetrics.density).toInt()
|
||||
layoutParams.setMargins(marginInPixels, marginInPixels, marginInPixels, marginInPixels)
|
||||
binding.root.layoutParams = layoutParams
|
||||
}
|
||||
|
||||
return AccountViewHolder(binding)
|
||||
override fun onBindViewHolder(holder: AccountViewHolder, position: Int) {
|
||||
holder.bind(accounts.getOrNull(position))
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: AccountViewHolder, position: Int) {
|
||||
holder.bind(accounts[position])
|
||||
var viewType = 0
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
if (viewType != 0 && position != accounts.count()) {
|
||||
return viewType
|
||||
}
|
||||
|
||||
return when (position) {
|
||||
accounts.count() -> VIEW_TYPE_ADD_ACCOUNT
|
||||
else -> VIEW_TYPE_ACCOUNT
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return accounts.size
|
||||
return accounts.count() + 1
|
||||
}
|
||||
}
|
|
@ -1,115 +0,0 @@
|
|||
package com.lagradost.cloudstream3.ui.account
|
||||
|
||||
import android.content.Context
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.LockPinDialogBinding
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||
|
||||
object AccountDialog {
|
||||
// TODO add account creation dialog to allow creating accounts directly from AccountSelectActivity
|
||||
|
||||
fun showPinInputDialog(
|
||||
context: Context,
|
||||
currentPin: String?,
|
||||
editAccount: Boolean,
|
||||
callback: (String?) -> Unit
|
||||
) {
|
||||
fun TextView.visibleWithText(@StringRes textRes: Int) {
|
||||
visibility = View.VISIBLE
|
||||
setText(textRes)
|
||||
}
|
||||
|
||||
fun View.isVisible() = visibility == View.VISIBLE
|
||||
|
||||
val binding = LockPinDialogBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
val isPinSet = currentPin != null
|
||||
val isNewPin = editAccount && !isPinSet
|
||||
val isEditPin = editAccount && isPinSet
|
||||
|
||||
val titleRes = if (isEditPin) R.string.enter_current_pin else R.string.enter_pin
|
||||
|
||||
val dialog = AlertDialog.Builder(context, R.style.AlertDialogCustom)
|
||||
.setView(binding.root)
|
||||
.setTitle(titleRes)
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
callback.invoke(null)
|
||||
}
|
||||
.setOnCancelListener {
|
||||
callback.invoke(null)
|
||||
}
|
||||
.setOnDismissListener {
|
||||
if (binding.pinEditTextError.isVisible()) {
|
||||
callback.invoke(null)
|
||||
}
|
||||
}
|
||||
.create()
|
||||
|
||||
var isPinValid = false
|
||||
|
||||
binding.pinEditText.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
val enteredPin = s.toString()
|
||||
val isEnteredPinValid = enteredPin.length == 4
|
||||
|
||||
if (isEnteredPinValid) {
|
||||
if (isPinSet) {
|
||||
if (enteredPin != currentPin) {
|
||||
binding.pinEditTextError.visibleWithText(R.string.pin_error_incorrect)
|
||||
binding.pinEditText.text = null
|
||||
isPinValid = false
|
||||
} else {
|
||||
binding.pinEditTextError.visibility = View.GONE
|
||||
isPinValid = true
|
||||
|
||||
callback.invoke(enteredPin)
|
||||
dialog.dismissSafe()
|
||||
}
|
||||
} else {
|
||||
binding.pinEditTextError.visibility = View.GONE
|
||||
isPinValid = true
|
||||
}
|
||||
} else if (isNewPin) {
|
||||
binding.pinEditTextError.visibleWithText(R.string.pin_error_length)
|
||||
isPinValid = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {}
|
||||
})
|
||||
|
||||
// Detect IME_ACTION_DONE
|
||||
binding.pinEditText.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE && isPinValid) {
|
||||
val enteredPin = binding.pinEditText.text.toString()
|
||||
callback.invoke(enteredPin)
|
||||
dialog.dismissSafe()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
// We don't want to accidentally have the dialog dismiss when clicking outside of it.
|
||||
// That is what the cancel button is for.
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
|
||||
dialog.show()
|
||||
|
||||
// Auto focus on PIN input and show keyboard
|
||||
binding.pinEditText.requestFocus()
|
||||
binding.pinEditText.postDelayed({
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.showSoftInput(binding.pinEditText, InputMethodManager.SHOW_IMPLICIT)
|
||||
}, 200)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,276 @@
|
|||
package com.lagradost.cloudstream3.ui.account
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKeys
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.AccountEditDialogBinding
|
||||
import com.lagradost.cloudstream3.databinding.LockPinDialogBinding
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.result.setImage
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getDefaultAccount
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.setAccount
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||
|
||||
object AccountDialogs {
|
||||
fun showAccountEditDialog(
|
||||
context: Context,
|
||||
account: DataStoreHelper.Account,
|
||||
isNewAccount: Boolean,
|
||||
callback: (DataStoreHelper.Account) -> Unit
|
||||
) {
|
||||
val binding = AccountEditDialogBinding.inflate(LayoutInflater.from(context), null, false)
|
||||
val builder = AlertDialog.Builder(context, R.style.AlertDialogCustom)
|
||||
.setView(binding.root)
|
||||
|
||||
var currentEditAccount = account
|
||||
val dialog = builder.show()
|
||||
|
||||
// Set up the dialog content
|
||||
binding.accountName.text = Editable.Factory.getInstance()?.newEditable(account.name)
|
||||
binding.accountName.doOnTextChanged { text, _, _, _ ->
|
||||
currentEditAccount = currentEditAccount.copy(name = text?.toString() ?: "")
|
||||
}
|
||||
|
||||
binding.deleteBtt.isGone = isNewAccount
|
||||
binding.deleteBtt.setOnClickListener {
|
||||
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
|
||||
when (which) {
|
||||
DialogInterface.BUTTON_POSITIVE -> {
|
||||
// Remove the account
|
||||
removeKeys(account.keyIndex.toString())
|
||||
val currentAccounts = DataStoreHelper.accounts.toMutableList()
|
||||
currentAccounts.removeIf { it.keyIndex == account.keyIndex }
|
||||
DataStoreHelper.accounts = currentAccounts.toTypedArray()
|
||||
|
||||
// Update UI
|
||||
setAccount(getDefaultAccount(context), true)
|
||||
dialog?.dismissSafe()
|
||||
}
|
||||
|
||||
DialogInterface.BUTTON_NEGATIVE -> {
|
||||
dialog?.dismissSafe()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
AlertDialog.Builder(context).setTitle(R.string.delete).setMessage(
|
||||
context.getString(R.string.delete_message).format(
|
||||
currentEditAccount.name
|
||||
)
|
||||
)
|
||||
.setPositiveButton(R.string.delete, dialogClickListener)
|
||||
.setNegativeButton(R.string.cancel, dialogClickListener)
|
||||
.show().setDefaultFocus()
|
||||
} catch (t: Throwable) {
|
||||
logError(t)
|
||||
}
|
||||
}
|
||||
|
||||
binding.cancelBtt.setOnClickListener {
|
||||
dialog?.dismissSafe()
|
||||
}
|
||||
|
||||
// Handle the profile picture and its interactions
|
||||
binding.profilePic.setImage(account.image)
|
||||
binding.profilePic.setOnClickListener {
|
||||
// Roll the image forwards once
|
||||
currentEditAccount =
|
||||
currentEditAccount.copy(defaultImageIndex = (currentEditAccount.defaultImageIndex + 1) % DataStoreHelper.profileImages.size)
|
||||
binding.profilePic.setImage(currentEditAccount.image)
|
||||
}
|
||||
|
||||
// Handle applying changes
|
||||
binding.applyBtt.setOnClickListener {
|
||||
if (currentEditAccount.lockPin != null) {
|
||||
// Ask for the current PIN
|
||||
showPinInputDialog(context, currentEditAccount.lockPin, false) { pin ->
|
||||
if (pin == null) return@showPinInputDialog
|
||||
// PIN is correct, proceed to update the account
|
||||
callback.invoke(currentEditAccount)
|
||||
dialog.dismissSafe()
|
||||
}
|
||||
} else {
|
||||
// No lock PIN set, proceed to update the account
|
||||
callback.invoke(currentEditAccount)
|
||||
dialog.dismissSafe()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle setting or changing the PIN
|
||||
if (currentEditAccount.keyIndex == getDefaultAccount(context).keyIndex) {
|
||||
binding.lockProfileCheckbox.isVisible = false
|
||||
if (currentEditAccount.lockPin != null) {
|
||||
currentEditAccount = currentEditAccount.copy(lockPin = null)
|
||||
}
|
||||
}
|
||||
|
||||
var canSetPin = true
|
||||
|
||||
binding.lockProfileCheckbox.isChecked = currentEditAccount.lockPin != null
|
||||
|
||||
binding.lockProfileCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
if (canSetPin) {
|
||||
showPinInputDialog(context, null, true) { pin ->
|
||||
if (pin == null) {
|
||||
binding.lockProfileCheckbox.isChecked = false
|
||||
return@showPinInputDialog
|
||||
}
|
||||
|
||||
currentEditAccount = currentEditAccount.copy(lockPin = pin)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (currentEditAccount.lockPin != null) {
|
||||
// Ask for the current PIN
|
||||
showPinInputDialog(context, currentEditAccount.lockPin, true) { pin ->
|
||||
if (pin == null || pin != currentEditAccount.lockPin) {
|
||||
canSetPin = false
|
||||
binding.lockProfileCheckbox.isChecked = true
|
||||
} else {
|
||||
currentEditAccount = currentEditAccount.copy(lockPin = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
canSetPin = true
|
||||
}
|
||||
|
||||
fun showPinInputDialog(
|
||||
context: Context,
|
||||
currentPin: String?,
|
||||
editAccount: Boolean,
|
||||
errorText: String? = null,
|
||||
callback: (String?) -> Unit
|
||||
) {
|
||||
fun TextView.visibleWithText(@StringRes textRes: Int) {
|
||||
isVisible = true
|
||||
setText(textRes)
|
||||
}
|
||||
|
||||
fun TextView.visibleWithText(text: String?) {
|
||||
isVisible = true
|
||||
setText(text)
|
||||
}
|
||||
|
||||
val binding = LockPinDialogBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
val isPinSet = currentPin != null
|
||||
val isNewPin = editAccount && !isPinSet
|
||||
val isEditPin = editAccount && isPinSet
|
||||
|
||||
val titleRes = if (isEditPin) R.string.enter_current_pin else R.string.enter_pin
|
||||
|
||||
val builder = AlertDialog.Builder(context, R.style.AlertDialogCustom)
|
||||
.setView(binding.root)
|
||||
.setTitle(titleRes)
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
callback.invoke(null)
|
||||
}
|
||||
.setOnCancelListener {
|
||||
callback.invoke(null)
|
||||
}
|
||||
.setOnDismissListener {
|
||||
if (binding.pinEditTextError.isVisible) {
|
||||
callback.invoke(null)
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewPin) {
|
||||
if (errorText != null) binding.pinEditTextError.visibleWithText(errorText)
|
||||
builder.setPositiveButton(R.string.setup_done) { _, _ ->
|
||||
if (binding.pinEditTextError.isVisible) {
|
||||
// If the done button is pressed and there is a error,
|
||||
// ask again, and mention the error that caused this.
|
||||
showPinInputDialog(
|
||||
context = binding.root.context,
|
||||
currentPin = null,
|
||||
editAccount = true,
|
||||
errorText = binding.pinEditTextError.text.toString(),
|
||||
callback = callback
|
||||
)
|
||||
} else {
|
||||
val enteredPin = binding.pinEditText.text.toString()
|
||||
callback.invoke(enteredPin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val dialog = builder.create()
|
||||
|
||||
var isPinValid = false
|
||||
|
||||
binding.pinEditText.addTextChangedListener(object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
val enteredPin = s.toString()
|
||||
val isEnteredPinValid = enteredPin.length == 4
|
||||
|
||||
if (isEnteredPinValid) {
|
||||
if (isPinSet) {
|
||||
if (enteredPin != currentPin) {
|
||||
binding.pinEditTextError.visibleWithText(R.string.pin_error_incorrect)
|
||||
binding.pinEditText.text = null
|
||||
isPinValid = false
|
||||
} else {
|
||||
binding.pinEditTextError.isVisible = false
|
||||
isPinValid = true
|
||||
|
||||
callback.invoke(enteredPin)
|
||||
dialog.dismissSafe()
|
||||
}
|
||||
} else {
|
||||
binding.pinEditTextError.isVisible = false
|
||||
isPinValid = true
|
||||
}
|
||||
} else if (isNewPin) {
|
||||
binding.pinEditTextError.visibleWithText(R.string.pin_error_length)
|
||||
isPinValid = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {}
|
||||
})
|
||||
|
||||
// Detect IME_ACTION_DONE
|
||||
binding.pinEditText.setOnEditorActionListener { _, actionId, _ ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE && isPinValid) {
|
||||
val enteredPin = binding.pinEditText.text.toString()
|
||||
callback.invoke(enteredPin)
|
||||
dialog.dismissSafe()
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
// We don't want to accidentally have the dialog dismiss when clicking outside of it.
|
||||
// That is what the cancel button is for.
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
|
||||
dialog.show()
|
||||
|
||||
// Auto focus on PIN input and show keyboard
|
||||
binding.pinEditText.requestFocus()
|
||||
binding.pinEditText.postDelayed({
|
||||
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.showSoftInput(binding.pinEditText, InputMethodManager.SHOW_IMPLICIT)
|
||||
}, 200)
|
||||
}
|
||||
}
|
|
@ -4,15 +4,14 @@ import android.content.Intent
|
|||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.CommonActivity
|
||||
import com.lagradost.cloudstream3.CommonActivity.loadThemes
|
||||
import com.lagradost.cloudstream3.MainActivity
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.ActivityAccountSelectBinding
|
||||
import com.lagradost.cloudstream3.databinding.ActivityAccountSelectTvBinding
|
||||
import com.lagradost.cloudstream3.ui.account.AccountDialog.showPinInputDialog
|
||||
import com.lagradost.cloudstream3.ui.account.AccountAdapter.Companion.VIEW_TYPE_EDIT_ACCOUNT
|
||||
import com.lagradost.cloudstream3.ui.account.AccountDialogs.showPinInputDialog
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getAccounts
|
||||
|
@ -36,24 +35,34 @@ class AccountSelectActivity : AppCompatActivity() {
|
|||
|
||||
window.navigationBarColor = colorFromAttribute(R.attr.primaryBlackBackground)
|
||||
|
||||
val binding = if (isTvSettings()) {
|
||||
ActivityAccountSelectTvBinding.inflate(layoutInflater)
|
||||
} else ActivityAccountSelectBinding.inflate(layoutInflater)
|
||||
|
||||
val binding = ActivityAccountSelectBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
val recyclerView: RecyclerView = binding.root.findViewById(R.id.account_recycler_view)
|
||||
val recyclerView: RecyclerView = binding.accountRecyclerView
|
||||
|
||||
|
||||
val adapter = AccountAdapter(accounts) { selectedAccount ->
|
||||
val adapter = AccountAdapter(
|
||||
accounts,
|
||||
// Handle the selected account
|
||||
onAccountSelected(selectedAccount)
|
||||
}
|
||||
accountSelectCallback = { onAccountSelected(it) },
|
||||
// Handle the selected account
|
||||
accountCreateCallback = { onAccountUpdated(it) },
|
||||
accountEditCallback = { onAccountUpdated(it) }
|
||||
)
|
||||
|
||||
recyclerView.adapter = adapter
|
||||
|
||||
recyclerView.layoutManager = if (isTvSettings()) {
|
||||
LinearLayoutManager(this)
|
||||
} else GridLayoutManager(this, 2)
|
||||
binding.editAccountButton.setOnClickListener {
|
||||
adapter.viewType = VIEW_TYPE_EDIT_ACCOUNT
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
if (isTvSettings()) {
|
||||
val spanSize = if (accounts.count() <= 6) {
|
||||
accounts.count()
|
||||
} else 6
|
||||
|
||||
recyclerView.layoutManager = GridLayoutManager(this, spanSize)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onAccountSelected(selectedAccount: DataStoreHelper.Account) {
|
||||
|
@ -72,6 +81,23 @@ class AccountSelectActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun onAccountUpdated(account: DataStoreHelper.Account) {
|
||||
val currentAccounts = DataStoreHelper.accounts.toMutableList()
|
||||
|
||||
val overrideIndex = currentAccounts.indexOfFirst { it.keyIndex == account.keyIndex }
|
||||
if (overrideIndex != -1) {
|
||||
currentAccounts[overrideIndex] = account
|
||||
} else currentAccounts.add(account)
|
||||
|
||||
val currentHomePage = DataStoreHelper.currentHomePage
|
||||
setAccount(account)
|
||||
|
||||
DataStoreHelper.accounts = currentAccounts.toTypedArray()
|
||||
DataStoreHelper.currentHomePage = currentHomePage
|
||||
|
||||
this.recreate()
|
||||
}
|
||||
|
||||
private fun setAccount(account: DataStoreHelper.Account) {
|
||||
// Don't reload if it is the same account
|
||||
if (DataStoreHelper.selectedKeyIndex == account.keyIndex) {
|
||||
|
|
|
@ -38,6 +38,7 @@ import com.lagradost.cloudstream3.mvvm.observe
|
|||
import com.lagradost.cloudstream3.mvvm.observeNullable
|
||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi
|
||||
import com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi
|
||||
import com.lagradost.cloudstream3.ui.account.AccountSelectActivity
|
||||
import com.lagradost.cloudstream3.ui.result.txt
|
||||
import com.lagradost.cloudstream3.ui.search.*
|
||||
import com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallback
|
||||
|
@ -496,7 +497,8 @@ class HomeFragment : Fragment() {
|
|||
homeApiFab.setOnClickListener(apiChangeClickListener)
|
||||
homeChangeApi.setOnClickListener(apiChangeClickListener)
|
||||
homeSwitchAccount.setOnClickListener { v ->
|
||||
DataStoreHelper.showWhoIsWatching(v?.context ?: return@setOnClickListener)
|
||||
val accountSelectIntent = Intent(v.context, AccountSelectActivity::class.java)
|
||||
v.context.startActivity(accountSelectIntent)
|
||||
}
|
||||
homeRandom.setOnClickListener {
|
||||
if (listHomepageItems.isNotEmpty()) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.lagradost.cloudstream3.ui.home
|
||||
|
||||
import android.content.Intent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -27,6 +28,7 @@ import com.lagradost.cloudstream3.mvvm.Resource
|
|||
import com.lagradost.cloudstream3.mvvm.debugException
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.ui.WatchType
|
||||
import com.lagradost.cloudstream3.ui.account.AccountSelectActivity
|
||||
import com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.selectHomepage
|
||||
import com.lagradost.cloudstream3.ui.result.FOCUS_SELF
|
||||
import com.lagradost.cloudstream3.ui.result.ResultViewModel2
|
||||
|
@ -478,7 +480,8 @@ class HomeParentItemAdapterPreview(
|
|||
}
|
||||
|
||||
homeAccount?.setOnClickListener { v ->
|
||||
DataStoreHelper.showWhoIsWatching(v?.context ?: return@setOnClickListener)
|
||||
val accountSelectIntent = Intent(v.context, AccountSelectActivity::class.java)
|
||||
v.context.startActivity(accountSelectIntent)
|
||||
}
|
||||
|
||||
(binding as? FragmentHomeHeadTvBinding)?.apply {
|
||||
|
|
|
@ -1,15 +1,7 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.text.Editable
|
||||
import android.view.LayoutInflater
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.APIHolder.filterProviderByPreferredMedia
|
||||
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
||||
|
@ -20,21 +12,12 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
|||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKeys
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.databinding.WhoIsWatchingAccountEditBinding
|
||||
import com.lagradost.cloudstream3.databinding.WhoIsWatchingBinding
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.syncproviders.AccountManager
|
||||
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||
import com.lagradost.cloudstream3.ui.WatchType
|
||||
import com.lagradost.cloudstream3.ui.WhoIsWatchingAdapter
|
||||
import com.lagradost.cloudstream3.ui.account.AccountDialog.showPinInputDialog
|
||||
import com.lagradost.cloudstream3.ui.library.ListSorting
|
||||
import com.lagradost.cloudstream3.ui.result.UiImage
|
||||
import com.lagradost.cloudstream3.ui.result.VideoWatchState
|
||||
import com.lagradost.cloudstream3.ui.result.setImage
|
||||
import com.lagradost.cloudstream3.ui.result.setLinearListLayout
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.setDefaultFocus
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
|
@ -75,7 +58,7 @@ class UserPreferenceDelegate<T : Any>(
|
|||
|
||||
object DataStoreHelper {
|
||||
// be aware, don't change the index of these as Account uses the index for the art
|
||||
private val profileImages = arrayOf(
|
||||
val profileImages = arrayOf(
|
||||
R.drawable.profile_bg_dark_blue,
|
||||
R.drawable.profile_bg_blue,
|
||||
R.drawable.profile_bg_orange,
|
||||
|
@ -147,7 +130,7 @@ object DataStoreHelper {
|
|||
}
|
||||
|
||||
const val TAG = "data_store_helper"
|
||||
private var accounts by PreferenceDelegate("$TAG/account", arrayOf<Account>())
|
||||
var accounts by PreferenceDelegate("$TAG/account", arrayOf<Account>())
|
||||
var selectedKeyIndex by PreferenceDelegate("$TAG/account_key_index", 0)
|
||||
val currentAccount: String get() = selectedKeyIndex.toString()
|
||||
|
||||
|
@ -166,7 +149,7 @@ object DataStoreHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setAccount(account: Account, refreshHomePage: Boolean) {
|
||||
fun setAccount(account: Account, refreshHomePage: Boolean) {
|
||||
selectedKeyIndex = account.keyIndex
|
||||
showToast(account.name)
|
||||
MainActivity.bookmarksUpdatedEvent(true)
|
||||
|
@ -175,147 +158,7 @@ object DataStoreHelper {
|
|||
}
|
||||
}
|
||||
|
||||
private fun editAccount(context: Context, account: Account, isNewAccount: Boolean) {
|
||||
val binding =
|
||||
WhoIsWatchingAccountEditBinding.inflate(LayoutInflater.from(context), null, false)
|
||||
val builder =
|
||||
AlertDialog.Builder(context, R.style.AlertDialogCustom)
|
||||
.setView(binding.root)
|
||||
|
||||
var currentEditAccount = account
|
||||
val dialog = builder.show()
|
||||
binding.accountName.text = Editable.Factory.getInstance()?.newEditable(account.name)
|
||||
binding.accountName.doOnTextChanged { text, _, _, _ ->
|
||||
currentEditAccount = currentEditAccount.copy(name = text?.toString() ?: "")
|
||||
}
|
||||
|
||||
binding.deleteBtt.isGone = isNewAccount
|
||||
binding.deleteBtt.setOnClickListener {
|
||||
val dialogClickListener =
|
||||
DialogInterface.OnClickListener { _, which ->
|
||||
when (which) {
|
||||
DialogInterface.BUTTON_POSITIVE -> {
|
||||
// remove all keys as well as the account, note that default wont get
|
||||
// deleted from currentAccounts, as it is not part of "accounts",
|
||||
// but the watch keys will
|
||||
removeKeys(account.keyIndex.toString())
|
||||
val currentAccounts = accounts.toMutableList()
|
||||
currentAccounts.removeIf { it.keyIndex == account.keyIndex }
|
||||
accounts = currentAccounts.toTypedArray()
|
||||
|
||||
// update UI
|
||||
setAccount(getDefaultAccount(context), true)
|
||||
dialog?.dismissSafe()
|
||||
}
|
||||
|
||||
DialogInterface.BUTTON_NEGATIVE -> {}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
AlertDialog.Builder(context).setTitle(R.string.delete).setMessage(
|
||||
context.getString(R.string.delete_message).format(
|
||||
currentEditAccount.name
|
||||
)
|
||||
)
|
||||
.setPositiveButton(R.string.delete, dialogClickListener)
|
||||
.setNegativeButton(R.string.cancel, dialogClickListener)
|
||||
.show().setDefaultFocus()
|
||||
} catch (t: Throwable) {
|
||||
logError(t)
|
||||
// ye you somehow fucked up formatting did you?
|
||||
}
|
||||
}
|
||||
|
||||
binding.cancelBtt.setOnClickListener {
|
||||
dialog?.dismissSafe()
|
||||
}
|
||||
|
||||
binding.profilePic.setImage(account.image)
|
||||
binding.profilePic.setOnClickListener {
|
||||
// Roll the image forwards once
|
||||
currentEditAccount =
|
||||
currentEditAccount.copy(defaultImageIndex = (currentEditAccount.defaultImageIndex + 1) % profileImages.size)
|
||||
binding.profilePic.setImage(currentEditAccount.image)
|
||||
}
|
||||
|
||||
binding.applyBtt.setOnClickListener {
|
||||
if (currentEditAccount.lockPin != null) {
|
||||
// Ask for the current PIN
|
||||
showPinInputDialog(context, currentEditAccount.lockPin, false) { pin ->
|
||||
if (pin == null) return@showPinInputDialog
|
||||
// PIN is correct, proceed to update the account
|
||||
performAccountUpdate(currentEditAccount)
|
||||
dialog.dismissSafe()
|
||||
}
|
||||
} else {
|
||||
// No lock PIN set, proceed to update the account
|
||||
performAccountUpdate(currentEditAccount)
|
||||
dialog.dismissSafe()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle setting or changing the PIN
|
||||
|
||||
if (currentEditAccount.keyIndex == getDefaultAccount(context).keyIndex) {
|
||||
binding.lockProfileCheckbox.isVisible = false
|
||||
if (currentEditAccount.lockPin != null) {
|
||||
currentEditAccount = currentEditAccount.copy(lockPin = null)
|
||||
}
|
||||
}
|
||||
|
||||
var canSetPin = true
|
||||
|
||||
binding.lockProfileCheckbox.isChecked = currentEditAccount.lockPin != null
|
||||
|
||||
binding.lockProfileCheckbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
if (canSetPin) {
|
||||
showPinInputDialog(context, null, true) { pin ->
|
||||
if (pin == null) {
|
||||
binding.lockProfileCheckbox.isChecked = false
|
||||
return@showPinInputDialog
|
||||
}
|
||||
|
||||
currentEditAccount = currentEditAccount.copy(lockPin = pin)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (currentEditAccount.lockPin != null) {
|
||||
// Ask for the current PIN
|
||||
showPinInputDialog(context, currentEditAccount.lockPin, true) { pin ->
|
||||
if (pin == null || pin != currentEditAccount.lockPin) {
|
||||
canSetPin = false
|
||||
binding.lockProfileCheckbox.isChecked = true
|
||||
} else {
|
||||
currentEditAccount = currentEditAccount.copy(lockPin = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
canSetPin = true
|
||||
}
|
||||
|
||||
private fun performAccountUpdate(account: Account) {
|
||||
val currentAccounts = accounts.toMutableList()
|
||||
|
||||
val overrideIndex = currentAccounts.indexOfFirst { it.keyIndex == account.keyIndex }
|
||||
|
||||
if (overrideIndex != -1) {
|
||||
currentAccounts[overrideIndex] = account
|
||||
} else {
|
||||
currentAccounts.add(account)
|
||||
}
|
||||
|
||||
val currentHomePage = this.currentHomePage
|
||||
setAccount(account, false)
|
||||
this.currentHomePage = currentHomePage
|
||||
accounts = currentAccounts.toTypedArray()
|
||||
}
|
||||
|
||||
private fun getDefaultAccount(context: Context): Account {
|
||||
fun getDefaultAccount(context: Context): Account {
|
||||
return accounts.let { currentAccounts ->
|
||||
currentAccounts.getOrNull(currentAccounts.indexOfFirst { it.keyIndex == 0 }) ?: Account(
|
||||
keyIndex = 0,
|
||||
|
@ -333,71 +176,6 @@ object DataStoreHelper {
|
|||
}
|
||||
}
|
||||
|
||||
fun showWhoIsWatching(context: Context) {
|
||||
val binding: WhoIsWatchingBinding = WhoIsWatchingBinding.inflate(LayoutInflater.from(context))
|
||||
val builder = BottomSheetDialog(context)
|
||||
builder.setContentView(binding.root)
|
||||
|
||||
val showAccount = accounts.toMutableList().apply {
|
||||
val item = getDefaultAccount(context)
|
||||
remove(item)
|
||||
add(0, item)
|
||||
}
|
||||
|
||||
val accountName = context.getString(R.string.account)
|
||||
|
||||
binding.profilesRecyclerview.setLinearListLayout(isHorizontal = true)
|
||||
binding.profilesRecyclerview.adapter = WhoIsWatchingAdapter(
|
||||
selectCallBack = { account ->
|
||||
// Check if the selected account has a lock PIN set
|
||||
if (account.lockPin != null) {
|
||||
// Prompt for the lock pin
|
||||
showPinInputDialog(context, account.lockPin, false) { pin ->
|
||||
if (pin == null) return@showPinInputDialog
|
||||
// Pin is correct, unlock the profile
|
||||
setAccount(account, true)
|
||||
builder.dismissSafe()
|
||||
}
|
||||
} else {
|
||||
// No lock PIN set, directly set the account
|
||||
setAccount(account, true)
|
||||
builder.dismissSafe()
|
||||
}
|
||||
},
|
||||
addAccountCallback = {
|
||||
val currentAccounts = accounts
|
||||
val remainingImages =
|
||||
profileImages.toSet() - currentAccounts.filter { it.customImage == null }
|
||||
.mapNotNull { profileImages.getOrNull(it.defaultImageIndex) }.toSet()
|
||||
val image =
|
||||
profileImages.indexOf(remainingImages.randomOrNull() ?: profileImages.random())
|
||||
val keyIndex = (currentAccounts.maxOfOrNull { it.keyIndex } ?: 0) + 1
|
||||
|
||||
// create a new dummy account
|
||||
editAccount(
|
||||
context,
|
||||
Account(
|
||||
keyIndex = keyIndex,
|
||||
name = "$accountName $keyIndex",
|
||||
customImage = null,
|
||||
defaultImageIndex = image
|
||||
), isNewAccount = true
|
||||
)
|
||||
builder.dismissSafe()
|
||||
},
|
||||
editCallBack = { account ->
|
||||
editAccount(
|
||||
context, account, isNewAccount = false
|
||||
)
|
||||
builder.dismissSafe()
|
||||
}
|
||||
).apply {
|
||||
submitList(showAccount)
|
||||
}
|
||||
|
||||
builder.show()
|
||||
}
|
||||
|
||||
data class PosDur(
|
||||
@JsonProperty("position") val position: Long,
|
||||
@JsonProperty("duration") val duration: Long
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout 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"
|
||||
|
@ -28,15 +29,6 @@
|
|||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- <com.google.android.material.button.MaterialButton-->
|
||||
<!-- android:nextFocusDown="@id/repo_name_input"-->
|
||||
<!-- android:id="@+id/list_repositories"-->
|
||||
<!-- android:nextFocusLeft="@id/apply_btt"-->
|
||||
<!-- android:nextFocusRight="@id/cancel_btt"-->
|
||||
<!-- style="@style/WhiteButton"-->
|
||||
<!-- android:layout_width="wrap_content"-->
|
||||
<!-- android:layout_gravity="center_vertical"-->
|
||||
<!-- android:text="@string/view_public_repositories_button_short" />-->
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
|
@ -140,4 +132,5 @@
|
|||
android:nextFocusLeft="@id/apply_btt"
|
||||
android:text="@string/sort_cancel" />
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -44,6 +44,14 @@
|
|||
android:src="@drawable/video_locked"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pencil_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_baseline_add_24"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/account_name"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -2,15 +2,14 @@
|
|||
|
||||
<androidx.cardview.widget.CardView 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"
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_width="110dp"
|
||||
android:layout_height="110dp"
|
||||
android:animateLayoutChanges="true"
|
||||
android:backgroundTint="?attr/primaryGrayBackground"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardCornerRadius="@dimen/rounded_image_radius"
|
||||
android:layout_margin="5dp"
|
||||
android:layout_margin="10dp"
|
||||
android:focusable="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1"
|
||||
|
@ -27,4 +26,5 @@
|
|||
android:scaleType="centerCrop"
|
||||
android:contentDescription="@string/add_account" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
|
@ -4,13 +4,13 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_width="110dp"
|
||||
android:layout_height="110dp"
|
||||
android:animateLayoutChanges="true"
|
||||
android:backgroundTint="?attr/primaryGrayBackground"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:cardCornerRadius="@dimen/rounded_image_radius"
|
||||
android:layout_margin="5dp"
|
||||
android:layout_margin="10dp"
|
||||
android:focusable="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1"
|
||||
|
@ -20,10 +20,10 @@
|
|||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/profile_image_background"
|
||||
android:id="@+id/account_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:alpha="0.4"
|
||||
android:alpha="0.2"
|
||||
android:contentDescription="@string/profile_background_des"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
|
@ -44,9 +44,16 @@
|
|||
android:src="@drawable/video_locked"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pencil_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_outline_account_circle_24"
|
||||
android:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/profile_text"
|
||||
tools:text="@string/mobile_data"
|
||||
android:id="@+id/account_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
|
@ -1,6 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:background="?attr/primaryBlackBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -17,7 +18,7 @@
|
|||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
<com.lagradost.cloudstream3.ui.AutofitRecyclerView
|
||||
android:id="@+id/account_recycler_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -25,4 +26,15 @@
|
|||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp" />
|
||||
|
||||
</LinearLayout>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/edit_account_button"
|
||||
style="@style/RegularButtonTV"
|
||||
|
||||
android:layout_width="wrap_content"
|
||||
android:minWidth="150dp"
|
||||
|
||||
android:text="@string/edit"
|
||||
app:icon="@drawable/ic_baseline_add_24" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:background="?attr/primaryBlackBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="36dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:textAlignment="center"
|
||||
android:text="@string/select_an_account"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/account_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp" />
|
||||
|
||||
</LinearLayout>
|
|
@ -1,55 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<TextView
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:layout_marginTop="20dp"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/switch_account"
|
||||
android:textSize="20sp"
|
||||
android:textColor="?attr/textColor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:text="@string/history"
|
||||
android:textSize="15sp"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:text="@string/error_bookmarks_text"
|
||||
android:textSize="15sp"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_rowWeight="1"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:layout_marginTop="10dp"
|
||||
android:descendantFocusability="afterDescendants"
|
||||
android:id="@+id/profiles_recyclerview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:orientation="horizontal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:itemCount="4"
|
||||
tools:listitem="@layout/who_is_watching_account">
|
||||
|
||||
<requestFocus />
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
</LinearLayout>
|
Loading…
Add table
Add a link
Reference in a new issue