Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.IdRes
import androidx.annotation.MainThread
import androidx.appcompat.app.AlertDialog
Expand Down Expand Up @@ -104,6 +105,7 @@ import com.lagradost.cloudstream3.ui.APIRepository
import com.lagradost.cloudstream3.ui.SyncWatchType
import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.account.AccountHelper.showAccountSelectLinear
import com.lagradost.cloudstream3.ui.account.ProfileImagePicker
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
import com.lagradost.cloudstream3.ui.home.HomeViewModel
import com.lagradost.cloudstream3.ui.library.LibraryViewModel
Expand Down Expand Up @@ -440,6 +442,15 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa
}
}

private val profileImagePicker = ProfileImagePicker(this)
private val profileImageLauncher = registerForActivityResult(
ActivityResultContracts.OpenDocument(),
profileImagePicker::onImagePicked,
)

internal fun pickProfileImage(callback: (String) -> Unit) {
profileImagePicker.launch(profileImageLauncher, callback)
}

var lastPopup: SearchResponse? = null
var lastPopupJob: Job? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class AccountAdapter(
private val accountSelectCallback: (DataStoreHelper.Account) -> Unit,
private val accountCreateCallback: (DataStoreHelper.Account) -> Unit,
private val accountEditCallback: (DataStoreHelper.Account) -> Unit,
private val accountDeleteCallback: (DataStoreHelper.Account) -> Unit
private val accountDeleteCallback: (DataStoreHelper.Account) -> Unit,
private val pickProfileImage: ((String) -> Unit) -> Unit,
) : NoStateAdapter<DataStoreHelper.Account>() {

companion object {
Expand Down Expand Up @@ -74,6 +75,7 @@ class AccountAdapter(
context = root.context,
account = item,
isNewAccount = false,
pickProfileImage = pickProfileImage,
accountEditCallback = { account ->
accountEditCallback.invoke(
account
Expand Down Expand Up @@ -127,6 +129,7 @@ class AccountAdapter(
context = root.context,
account = item,
isNewAccount = false,
pickProfileImage = pickProfileImage,
accountEditCallback = { account -> accountEditCallback.invoke(account) },
accountDeleteCallback = { account ->
accountDeleteCallback.invoke(
Expand Down Expand Up @@ -168,6 +171,7 @@ class AccountAdapter(
defaultImageIndex = image
),
isNewAccount = true,
pickProfileImage = pickProfileImage,
accountEditCallback = { account -> accountCreateCallback.invoke(account) },
accountDeleteCallback = {}
)
Expand Down Expand Up @@ -208,4 +212,4 @@ class AccountAdapter(
}
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ package com.lagradost.cloudstream3.ui.account
import android.app.Activity
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.text.Editable
import android.view.LayoutInflater
import android.view.inputmethod.EditorInfo
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isGone
Expand Down Expand Up @@ -42,11 +45,59 @@ import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.showInputMethod
import com.lagradost.cloudstream3.utils.UIHelper.showProgress

internal class ProfileImagePicker(private val context: Context) {
private var callback: ((String) -> Unit)? = null

fun launch(
launcher: ActivityResultLauncher<Array<String>>,
callback: (String) -> Unit,
) {
this.callback = callback
try {
launcher.launch(arrayOf("image/*"))
} catch (error: Exception) {
this.callback = null
logError(error)
showToast(R.string.edit_profile_image_error_invalid, Toast.LENGTH_SHORT)
}
}

fun onImagePicked(uri: Uri?) {
val callback = callback ?: return
this.callback = null
if (uri == null) return

try {
context.contentResolver.takePersistableUriPermission(
uri, Intent.FLAG_GRANT_READ_URI_PERMISSION
)
} catch (error: Exception) {
logError(error)
showToast(R.string.edit_profile_image_error_invalid)
return
}

ImageLoader(context).enqueue(
ImageRequest.Builder(context).data(uri)
.allowHardware(false).size(512, 512).listener(
onSuccess = { _, _ ->
callback(uri.toString())
showToast(R.string.edit_profile_image_success, Toast.LENGTH_SHORT)
},
onError = { _, _ ->
showToast(R.string.edit_profile_image_error_invalid)
}
).build()
)
}
}

object AccountHelper {
fun showAccountEditDialog(
context: Context,
account: DataStoreHelper.Account,
isNewAccount: Boolean,
pickProfileImage: ((String) -> Unit) -> Unit,
accountEditCallback: (DataStoreHelper.Account) -> Unit,
accountDeleteCallback: (DataStoreHelper.Account) -> Unit
) {
Expand Down Expand Up @@ -166,7 +217,7 @@ object AccountHelper {

canSetPin = true

binding.editProfilePhotoButton.setOnClickListener {
val showProfileImageUrlDialog = { callback: (String) -> Unit ->
val bottomSheetDialog = BottomSheetDialog(context)
val sheetBinding = BottomInputDialogBinding.inflate(LayoutInflater.from(context))
bottomSheetDialog.setContentView(sheetBinding.root)
Expand All @@ -189,8 +240,7 @@ object AccountHelper {
.allowHardware(false)
.listener(
onSuccess = { _, _ ->
currentEditAccount = currentEditAccount.copy(customImage = url)
binding.accountImage.loadImage(url)
callback(url)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Elegant solution, very nice!

showToast(
R.string.edit_profile_image_success,
Toast.LENGTH_SHORT
Expand All @@ -216,6 +266,29 @@ object AccountHelper {
}
}
}

binding.editProfilePhotoButton.setOnClickListener {
AlertDialog.Builder(context)
.setTitle(R.string.edit_profile_image_title)
.setItems(arrayOf(
context.getString(R.string.edit_profile_image_from_file),
context.getString(R.string.edit_profile_image_hint),
)) { _, selection ->
if (selection == 0) {
pickProfileImage { image ->
if (!dialog.isShowing) return@pickProfileImage
currentEditAccount = currentEditAccount.copy(customImage = image)
binding.accountImage.loadImage(image)
}
} else {
showProfileImageUrlDialog { image ->
currentEditAccount = currentEditAccount.copy(customImage = image)
binding.accountImage.loadImage(image)
}
}
}
.show()
}
}

fun showPinInputDialog(
Expand Down Expand Up @@ -404,7 +477,8 @@ object AccountHelper {
},
accountCreateCallback = { viewModel.handleAccountUpdate(it, activity) },
accountEditCallback = { viewModel.handleAccountUpdate(it, activity) },
accountDeleteCallback = { viewModel.handleAccountDelete(it, activity) }
accountDeleteCallback = { viewModel.handleAccountDelete(it, activity) },
pickProfileImage = activity::pickProfileImage,
).apply {
submitList(liveAccounts)
}
Expand All @@ -416,4 +490,4 @@ object AccountHelper {
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui.account
import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.FragmentActivity
import androidx.activity.viewModels
import androidx.preference.PreferenceManager
Expand Down Expand Up @@ -44,6 +45,16 @@ class AccountSelectActivity : FragmentActivity(), BiometricCallback {

val accountViewModel: AccountViewModel by viewModels()

private val profileImagePicker = ProfileImagePicker(this)
private val profileImageLauncher = registerForActivityResult(
ActivityResultContracts.OpenDocument(),
profileImagePicker::onImagePicked,
)

private fun pickProfileImage(callback: (String) -> Unit) {
profileImagePicker.launch(profileImageLauncher, callback)
}

@SuppressLint("NotifyDataSetChanged")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand Down Expand Up @@ -143,7 +154,8 @@ class AccountSelectActivity : FragmentActivity(), BiometricCallback {
navigateToMainActivity()
}
},
accountDeleteCallback = { accountViewModel.handleAccountDelete(it, this) }
accountDeleteCallback = { accountViewModel.handleAccountDelete(it, this) },
pickProfileImage = ::pickProfileImage,
).apply {
submitList(liveAccounts)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.AllLanguagesName
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.MainAPI
import com.lagradost.cloudstream3.MainActivity
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.TvType
Expand Down Expand Up @@ -658,7 +659,11 @@ class HomeFragment : BaseFragment<FragmentHomeBinding>(
}

homeMasterAdapter = HomeParentItemAdapterPreview(
homeViewModel, accountViewModel
homeViewModel,
accountViewModel,
pickProfileImage = { callback ->
(activity as? MainActivity)?.pickProfileImage(callback)
},
)
homeMasterRecycler.setRecycledViewPool(ParentItemAdapter.sharedPool)
homeMasterRecycler.adapter = homeMasterAdapter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ import com.lagradost.cloudstream3.ui.setRecycledViewPool

class HomeParentItemAdapterPreview(
private val viewModel: HomeViewModel,
private val accountViewModel: AccountViewModel
private val accountViewModel: AccountViewModel,
private val pickProfileImage: ((String) -> Unit) -> Unit,
) : ParentItemAdapter(
id = "HomeParentItemAdapterPreview".hashCode(),
clickCallback = {
Expand Down Expand Up @@ -104,7 +105,7 @@ class HomeParentItemAdapterPreview(
)
}

return HeaderViewHolder(binding, viewModel, accountViewModel)
return HeaderViewHolder(binding, viewModel, accountViewModel, pickProfileImage)
}

override fun onBindHeader(holder: ViewHolderState<Bundle>) {
Expand All @@ -131,6 +132,7 @@ class HomeParentItemAdapterPreview(
val binding: ViewBinding,
val viewModel: HomeViewModel,
accountViewModel: AccountViewModel,
private val pickProfileImage: ((String) -> Unit) -> Unit,
) :
ViewHolderState<Bundle>(binding) {

Expand Down Expand Up @@ -558,6 +560,7 @@ class HomeParentItemAdapterPreview(
context = context,
account = currentAccount,
isNewAccount = false,
pickProfileImage = pickProfileImage,
accountEditCallback = { accountViewModel.handleAccountUpdate(it, context) },
accountDeleteCallback = {
accountViewModel.handleAccountDelete(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,10 @@ object DataStoreHelper {
@JsonProperty("lockPin") @SerialName("lockPin") val lockPin: String? = null,
) {
@get:JsonIgnore
val image get() = customImage?.let { UiImage.Image(it) } ?:
val image get() = customImage?.takeUnless { image ->
image.startsWith("content://") && context?.contentResolver?.persistedUriPermissions
Comment thread
fire-light42 marked this conversation as resolved.
?.none { it.uri.toString() == image } != false
}?.let { UiImage.Image(it) } ?:
profileImages.getOrNull(defaultImageIndex)?.let {
UiImage.Drawable(it)
} ?: UiImage.Drawable(profileImages.first())
Expand Down
8 changes: 7 additions & 1 deletion app/src/main/res/layout/account_edit_dialog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
android:contentDescription="@string/preview_background_img_des"
android:focusable="true"
android:foreground="@drawable/outline_drawable_forced_round"
android:nextFocusRight="@id/edit_profile_photo_button"
android:scaleType="centerCrop"
android:src="@drawable/profile_bg_blue" />

Expand All @@ -60,6 +61,11 @@
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:background="@color/skipOpTransparent"
android:contentDescription="@string/edit_profile_image_title"
android:focusable="true"
android:foreground="@drawable/outline_drawable_forced_round"
android:nextFocusLeft="@id/account_image"
android:nextFocusDown="@id/account_name"
android:padding="5dp"
android:src="@drawable/ic_baseline_edit_24" />
</androidx.cardview.widget.CardView>
Expand Down Expand Up @@ -127,4 +133,4 @@
android:text="@string/sort_cancel" />

</RelativeLayout>
</LinearLayout>
</LinearLayout>
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,7 @@
<string name="speedup_title">LongPress Speed Toggle</string>
<string name="speedup_summary">Hold to get 2x speed</string>
<string name="edit_profile_image_title">Edit Profile Image</string>
<string name="edit_profile_image_from_file">@string/player_load_subtitles</string>
<string name="edit_profile_image_hint">Enter Profile Image URL</string>
<string name="edit_profile_image_error_empty">No URL Found</string>
<string name="edit_profile_image_error_invalid">Invalid URL or Image</string>
Expand Down