added local accounts

This commit is contained in:
LagradOst 2023-08-02 05:30:50 +02:00
parent b06f098447
commit 180987e2d0
17 changed files with 693 additions and 29 deletions

View file

@ -148,6 +148,14 @@ class AcraApplication : Application() {
_context = WeakReference(value)
}
fun <T : Any> getKeyClass(path: String, valueType: Class<T>): T? {
return context?.getKey(path, valueType)
}
fun <T : Any> setKeyClass(path: String, value: T) {
context?.setKey(path, value)
}
fun removeKeys(folder: String): Int? {
return context?.removeKeys(folder)
}

View file

@ -0,0 +1,106 @@
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)
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
}
}

View file

@ -40,6 +40,7 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showOptionSelectStringRes
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbarMargin
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbarView
import com.lagradost.cloudstream3.utils.UIHelper.setImage
@ -250,6 +251,11 @@ class HomeParentItemAdapterPreview(
private var bookmarkRecyclerView: RecyclerView =
itemView.findViewById(R.id.home_bookmarked_child_recyclerview)
private var homeAccount: View? =
itemView.findViewById(R.id.home_switch_account)
private var topPadding : View? = itemView.findViewById(R.id.home_padding)
private val homeNonePadding: View = itemView.findViewById(R.id.home_none_padding)
private val previewCallback: ViewPager2.OnPageChangeCallback =
@ -432,6 +438,8 @@ class HomeParentItemAdapterPreview(
resumeRecyclerView.setLinearListLayout()
bookmarkRecyclerView.setLinearListLayout()
fixPaddingStatusbarMargin(topPadding)
for ((chip, watch) in toggleList) {
chip.isChecked = false
chip.setOnCheckedChangeListener { _, isChecked ->
@ -445,6 +453,10 @@ class HomeParentItemAdapterPreview(
}
}
homeAccount?.setOnClickListener { v ->
DataStoreHelper.showWhoIsWatching(v?.context ?: return@setOnClickListener)
}
(binding as? FragmentHomeHeadTvBinding)?.apply {
homePreviewChangeApi.setOnClickListener { view ->
view.context.selectHomepage(viewModel.repo?.name) { api ->
@ -485,8 +497,6 @@ class HomeParentItemAdapterPreview(
}
(binding as? FragmentHomeHeadBinding)?.apply {
fixPaddingStatusbar(binding.homeSearch)
homeSearch.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
viewModel.queryTextSubmit(query)

View file

@ -96,8 +96,8 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
// protected var currentPrefQuality =
// Qualities.P2160.value // preferred maximum quality, used for ppl w bad internet or on cell
protected var fastForwardTime = 10000L
protected var androidTVInterfaceOffSeekTime = 10000L;
protected var androidTVInterfaceOnSeekTime = 30000L;
protected var androidTVInterfaceOffSeekTime = 10000L
protected var androidTVInterfaceOnSeekTime = 30000L
protected var swipeHorizontalEnabled = false
protected var swipeVerticalEnabled = false
protected var playBackSpeedEnabled = false

View file

@ -1252,7 +1252,6 @@ class GeneratorPlayer : FullScreenPlayer() {
private fun displayTimeStamp(show: Boolean) {
if (timestampShowState == show) return
skipIndex++
println("displayTimeStamp = $show")
timestampShowState = show
playerBinding?.skipChapterButton?.apply {
val showWidth = 170.toPx
@ -1294,7 +1293,6 @@ class GeneratorPlayer : FullScreenPlayer() {
override fun onTimestamp(timestamp: EpisodeSkip.SkipStamp?) {
if (timestamp != null) {
println("timestamp: $timestamp")
playerBinding?.skipChapterButton?.setText(timestamp.uiText)
displayTimeStamp(true)
val currentIndex = skipIndex

View file

@ -6,7 +6,12 @@ import androidx.preference.PreferenceManager
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.lagradost.cloudstream3.AcraApplication.Companion.getKeyClass
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKeyClass
import com.lagradost.cloudstream3.mvvm.logError
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
const val DOWNLOAD_HEADER_CACHE = "download_header_cache"
@ -20,6 +25,31 @@ const val PREFERENCES_NAME = "rebuild_preference"
// TODO degelgate by value for get & set
class PreferenceDelegate<T : Any>(
val key: String, val default: T //, private val klass: KClass<T>
) {
private val klass: KClass<out T> = default::class
// simple cache to make it not get the key every time it is accessed, however this requires
// that ONLY this changes the key
private var cache: T? = null
operator fun getValue(self: Any?, property: KProperty<*>) =
cache ?: getKeyClass(key, klass.java).also { newCache -> cache = newCache } ?: default
operator fun setValue(
self: Any?,
property: KProperty<*>,
t: T?
) {
cache = t
if (t == null) {
removeKey(key)
} else {
setKeyClass(key, t)
}
}
}
object DataStore {
val mapper: JsonMapper = JsonMapper.builder().addModule(KotlinModule())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()
@ -89,7 +119,7 @@ object DataStore {
}
fun Context.removeKeys(folder: String): Int {
val keys = getKeys(folder)
val keys = getKeys("$folder/")
keys.forEach { value ->
removeKey(value)
}
@ -106,6 +136,15 @@ object DataStore {
}
}
fun <T> Context.getKey(path: String, valueType: Class<T>): T? {
try {
val json: String = getSharedPrefs().getString(path, null) ?: return null
return json.toKotlinObject(valueType)
} catch (e: Exception) {
return null
}
}
fun <T> Context.setKey(folder: String, path: String, value: T) {
setKey(getFolderName(folder, path), value)
}
@ -114,6 +153,10 @@ object DataStore {
return mapper.readValue(this, T::class.java)
}
fun <T> String.toKotlinObject(valueType: Class<T>): T {
return mapper.readValue(this, valueType)
}
// GET KEY GIVEN PATH AND DEFAULT VALUE, NULL IF ERROR
inline fun <reified T : Any> Context.getKey(path: String, defVal: T?): T? {
try {

View file

@ -1,6 +1,14 @@
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.widget.doOnTextChanged
import com.fasterxml.jackson.annotation.JsonProperty
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
@ -8,10 +16,20 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys
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.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
const val VIDEO_POS_DUR = "video_pos_dur"
const val VIDEO_WATCH_STATE = "video_watch_state"
@ -26,6 +44,197 @@ const val RESULT_SEASON = "result_season"
const val RESULT_DUB = "result_dub"
object DataStoreHelper {
// be aware, don't change the index of these as Account uses the index for the art
private val profileImages = arrayOf(
R.drawable.profile_bg_dark_blue,
R.drawable.profile_bg_blue,
R.drawable.profile_bg_orange,
R.drawable.profile_bg_pink,
R.drawable.profile_bg_purple,
R.drawable.profile_bg_red,
R.drawable.profile_bg_teal
)
data class Account(
@JsonProperty("keyIndex")
val keyIndex: Int,
@JsonProperty("name")
val name: String,
@JsonProperty("customImage")
val customImage: String? = null,
@JsonProperty("defaultImageIndex")
val defaultImageIndex: Int,
) {
val image: UiImage
get() = customImage?.let { UiImage.Image(it) } ?: UiImage.Drawable(
profileImages.getOrNull(defaultImageIndex) ?: profileImages.first()
)
}
const val TAG = "data_store_helper"
private var accounts by PreferenceDelegate("$TAG/account", arrayOf<Account>())
var selectedKeyIndex by PreferenceDelegate("$TAG/account_key_index", 0)
val currentAccount: String get() = selectedKeyIndex.toString()
private fun setAccount(account: Account) {
selectedKeyIndex = account.keyIndex
showToast(account.name)
MainActivity.bookmarksUpdatedEvent(true)
}
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))
MainActivity.bookmarksUpdatedEvent(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 {
// rolls the image forwards once
currentEditAccount =
currentEditAccount.copy(defaultImageIndex = (currentEditAccount.defaultImageIndex + 1) % profileImages.size)
binding.profilePic.setImage(currentEditAccount.image)
}
binding.applyBtt.setOnClickListener {
val currentAccounts = accounts.toMutableList()
val overrideIndex =
currentAccounts.indexOfFirst { it.keyIndex == currentEditAccount.keyIndex }
// if an account is found that has the same keyIndex then override that one, if not then append it
if (overrideIndex != -1) {
currentAccounts[overrideIndex] = currentEditAccount
} else {
currentAccounts.add(currentEditAccount)
}
// set the new default account as well as add the key for the new account
setAccount(currentEditAccount)
accounts = currentAccounts.toTypedArray()
dialog.dismissSafe()
}
}
private fun getDefaultAccount(context: Context): Account {
return accounts.let { currentAccounts ->
currentAccounts.getOrNull(currentAccounts.indexOfFirst { it.keyIndex == 0 }) ?: Account(
keyIndex = 0,
name = context.getString(R.string.default_account),
defaultImageIndex = 0
)
}
}
fun showWhoIsWatching(context: Context) {
val binding: WhoIsWatchingBinding = WhoIsWatchingBinding.inflate(
LayoutInflater.from(context)
)
val showAccount = accounts.toMutableList().apply {
val item = getDefaultAccount(context)
remove(item)
add(0, item)
}
val builder =
BottomSheetDialog(context)
builder.setContentView(binding.root)
val accountName = context.getString(R.string.account)
binding.profilesRecyclerview.setLinearListLayout(isHorizontal = true)
binding.profilesRecyclerview.adapter = WhoIsWatchingAdapter(
selectCallBack = { account ->
setAccount(account)
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
@ -117,7 +326,6 @@ object DataStoreHelper {
/**
* A datastore wide account for future implementations of a multiple account system
**/
var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION
fun getAllWatchStateIds(): List<Int>? {
val folder = "$currentAccount/$RESULT_WATCH_STATE"

View file

@ -15,6 +15,7 @@ import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.view.*
import android.view.ViewGroup.MarginLayoutParams
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import android.widget.ListAdapter
@ -33,6 +34,10 @@ import androidx.core.graphics.blue
import androidx.core.graphics.drawable.toBitmapOrNull
import androidx.core.graphics.green
import androidx.core.graphics.red
import androidx.core.view.marginBottom
import androidx.core.view.marginLeft
import androidx.core.view.marginRight
import androidx.core.view.marginTop
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.navigation.fragment.NavHostFragment
@ -55,7 +60,6 @@ import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.result.UiImage
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isEmulatorSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import jp.wasabeef.glide.transformations.BlurTransformation
import kotlin.math.roundToInt
@ -77,8 +81,8 @@ object UIHelper {
|| Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)
}
fun populateChips(view: ChipGroup?, tags : List<String>) {
if(view == null) return
fun populateChips(view: ChipGroup?, tags: List<String>) {
if (view == null) return
view.removeAllViews()
val context = view.context ?: return
@ -304,7 +308,7 @@ object UIHelper {
else req
}
if(radius > 0) {
if (radius > 0) {
builder = builder.apply(bitmapTransform(BlurTransformation(radius, sample)))
}
@ -496,6 +500,22 @@ object UIHelper {
)
}
fun fixPaddingStatusbarMargin(v: View?) {
if (v == null) return
val ctx = v.context ?: return
v.layoutParams = v.layoutParams.apply {
if (this is MarginLayoutParams) {
setMargins(
v.marginLeft,
v.marginTop + ctx.getStatusBarHeight(),
v.marginRight,
v.marginBottom
)
}
}
}
fun fixPaddingStatusbarView(v: View?) {
if (v == null) return
val ctx = v.context ?: return

View file

@ -1,6 +1,13 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM7.35,18.5C8.66,17.56 10.26,17 12,17s3.34,0.56 4.65,1.5C15.34,19.44 13.74,20 12,20S8.66,19.44 7.35,18.5zM18.14,17.12L18.14,17.12C16.45,15.8 14.32,15 12,15s-4.45,0.8 -6.14,2.12l0,0C4.7,15.73 4,13.95 4,12c0,-4.42 3.58,-8 8,-8s8,3.58 8,8C20,13.95 19.3,15.73 18.14,17.12z"/>
<path android:fillColor="@android:color/white" android:pathData="M12,6c-1.93,0 -3.5,1.57 -3.5,3.5S10.07,13 12,13s3.5,-1.57 3.5,-3.5S13.93,6 12,6zM12,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S11.17,8 12,8s1.5,0.67 1.5,1.5S12.83,11 12,11z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/white"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM7.35,18.5C8.66,17.56 10.26,17 12,17s3.34,0.56 4.65,1.5C15.34,19.44 13.74,20 12,20S8.66,19.44 7.35,18.5zM18.14,17.12L18.14,17.12C16.45,15.8 14.32,15 12,15s-4.45,0.8 -6.14,2.12l0,0C4.7,15.73 4,13.95 4,12c0,-4.42 3.58,-8 8,-8s8,3.58 8,8C20,13.95 19.3,15.73 18.14,17.12z" />
<path
android:fillColor="@android:color/white"
android:pathData="M12,6c-1.93,0 -3.5,1.57 -3.5,3.5S10.07,13 12,13s3.5,-1.57 3.5,-3.5S13.93,6 12,6zM12,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S11.17,8 12,8s1.5,0.67 1.5,1.5S12.83,11 12,11z" />
</vector>

View file

@ -7,15 +7,14 @@
<stroke
android:width="2dp"
android:color="@android:color/white" />
<corners android:radius="2dp" />
<corners android:radius="@dimen/rounded_image_radius" />
</shape>
</item>
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<corners android:radius="2dp" />
<corners android:radius="@dimen/rounded_image_radius" />
<solid android:color="?attr/iconGrayBackground" />
</shape>
</item>
</ripple>

View file

@ -38,16 +38,21 @@
<LinearLayout
android:id="@+id/home_padding"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:layout_height="50dp"
android:gravity="center"
android:orientation="horizontal">
<androidx.appcompat.widget.SearchView
android:id="@+id/home_search"
android:nextFocusRight="@id/home_switch_account"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_gravity="start"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:padding="0dp"
android:layout_marginEnd="50dp"
android:editTextColor="@color/white"
android:gravity="start"
android:gravity="center_vertical"
android:iconifiedByDefault="true"
android:textColor="@color/white"
android:textColorHint="@color/white"
@ -57,6 +62,19 @@
app:queryHint="@string/search_hint"
app:searchIcon="@drawable/search_icon"
tools:ignore="RtlSymmetry" />
<ImageView
android:background="?android:attr/selectableItemBackgroundBorderless"
android:nextFocusLeft="@id/home_search"
android:id="@+id/home_switch_account"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginStart="-50dp"
android:contentDescription="@string/account"
android:padding="10dp"
android:src="@drawable/ic_outline_account_circle_24" />
</LinearLayout>
<!--

View file

@ -34,7 +34,7 @@
android:id="@+id/outline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/outline"
android:background="@drawable/outline_card"
android:visibility="gone"
tools:visibility="visible" />

View file

@ -0,0 +1,35 @@
<?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:layout_marginBottom="10dp"
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" />
<androidx.recyclerview.widget.RecyclerView
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>

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<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:animateLayoutChanges="true"
android:backgroundTint="?attr/primaryGrayBackground"
android:foreground="?attr/selectableItemBackgroundBorderless"
app:cardCornerRadius="@dimen/rounded_image_radius"
android:layout_margin="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.4"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/profile_image_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.4"
android:contentDescription="@string/profile_background_des"
android:scaleType="centerCrop" />
<View
android:id="@+id/outline"
tools:visibility="visible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/outline_card"
android:visibility="gone" />
<TextView
android:id="@+id/profile_text"
tools:text="@string/mobile_data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:padding="10dp"
android:textSize="16sp" />
</androidx.cardview.widget.CardView>

View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<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:animateLayoutChanges="true"
android:backgroundTint="?attr/primaryGrayBackground"
android:foreground="?attr/selectableItemBackgroundBorderless"
app:cardCornerRadius="@dimen/rounded_image_radius"
android:layout_margin="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.4"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:layout_gravity="center"
android:src="@drawable/ic_baseline_add_24"
android:layout_width="40dp"
android:layout_height="40dp"
android:scaleType="centerCrop"
android:contentDescription="@string/add_account" />
</androidx.cardview.widget.CardView>

View file

@ -0,0 +1,135 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/text1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_rowWeight="1"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:text="@string/create_account"
android:textColor="?attr/textColor"
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
android:id="@+id/text2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_rowWeight="1"
android:layout_gravity="center_vertical"
android:layout_marginBottom="10dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:textColor="?attr/grayTextColor"
android:textSize="15sp"
android:visibility="gone"
tools:text="Gogoanime" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:layout_marginBottom="60dp"
android:orientation="vertical">
<EditText
android:id="@+id/account_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autofillHints="username"
android:hint="@string/default_account"
android:inputType="text"
android:nextFocusLeft="@id/apply_btt"
android:nextFocusRight="@id/cancel_btt"
android:nextFocusDown="@id/site_url_input"
android:requiresFadingEdge="vertical"
android:textColorHint="?attr/grayTextColor"
tools:ignore="LabelFor" />
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="@dimen/rounded_image_radius">
<ImageView
android:id="@+id/profile_pic"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_gravity="center"
android:contentDescription="@string/preview_background_img_des"
android:scaleType="centerCrop"
android:src="@drawable/profile_bg_blue" />
</androidx.cardview.widget.CardView>
</LinearLayout>
<RelativeLayout
android:id="@+id/apply_btt_holder"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_gravity="bottom"
android:layout_marginTop="-60dp"
android:orientation="horizontal"
android:padding="10dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/delete_btt"
style="@style/BlackButton"
android:layout_width="wrap_content"
android:layout_alignParentStart="true"
android:layout_gravity="center_vertical"
android:nextFocusRight="@id/apply_btt"
android:text="@string/delete" />
<com.google.android.material.button.MaterialButton
android:id="@+id/apply_btt"
style="@style/WhiteButton"
android:layout_width="wrap_content"
android:layout_gravity="center_vertical|end"
android:layout_toStartOf="@+id/cancel_btt"
android:nextFocusLeft="@id/delete_btt"
android:nextFocusRight="@id/cancel_btt"
android:text="@string/sort_apply" />
<com.google.android.material.button.MaterialButton
android:id="@+id/cancel_btt"
style="@style/BlackButton"
android:layout_width="wrap_content"
android:layout_alignParentEnd="true"
android:layout_gravity="center_vertical|end"
android:nextFocusLeft="@id/apply_btt"
android:text="@string/sort_cancel" />
</RelativeLayout>
</LinearLayout>

View file

@ -307,6 +307,7 @@
<string name="queued">queued</string>
<string name="no_subtitles">No Subtitles</string>
<string name="default_subtitles">Default</string>
<string name="default_account">@string/default_subtitles</string>
<string name="free_storage">Free</string>
<string name="used_storage">Used</string>
<string name="app_storage">App</string>