From 8bb563e4d0f0630ac02b707c3f5ec422bc075ab9 Mon Sep 17 00:00:00 2001 From: sneazy-ibo <41344259+sneazy-ibo@users.noreply.github.com> Date: Sun, 9 Jun 2024 20:13:15 +0200 Subject: [PATCH] feat: front end for images --- .../connections/anilist/AnilistMutations.kt | 31 +++++ .../ani/dantotsu/profile/ProfileActivity.kt | 108 +++++++++++++++++- .../ani/dantotsu/profile/ProfileFragment.kt | 2 +- app/src/main/res/layout/activity_profile.xml | 25 ++++ app/src/main/res/layout/fragment_profile.xml | 76 +++++++++++- .../main/res/layout/item_profile_app_bar.xml | 59 +++++++--- app/src/main/res/menu/menu_profile.xml | 5 + app/src/main/res/values/strings.xml | 1 + 8 files changed, 288 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt index 3d7ac85e..489f537e 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt @@ -1,5 +1,6 @@ package ani.dantotsu.connections.anilist +import android.net.Uri import ani.dantotsu.connections.anilist.Anilist.executeQuery import ani.dantotsu.connections.anilist.api.FuzzyDate import ani.dantotsu.connections.anilist.api.Query @@ -153,6 +154,36 @@ class AnilistMutations { return errors == null } + suspend fun uploadAvatar(avatarUri: Uri): Boolean { + val query = """ + mutation (${"$"}avatar: Upload) { + UpdateUser( + avatar: ${"$"}avatar + ) { + id + } + } + """ + val variables = mapOf("avatar" to avatarUri.toString()) + val result = executeQuery(query, variables.toString()) + return result?.get("errors") == null && result != null + } + + suspend fun uploadBanner(bannerUri: Uri): Boolean { + val query = """ + mutation (${"$"}banner: Upload) { + UpdateUser( + banner: ${"$"}banner + ) { + id + } + } + """ + val variables = mapOf("banner" to bannerUri.toString()) + val result = executeQuery(query, variables.toString()) + return result?.get("errors") == null && result != null + } + private fun String.stringSanitizer(): String { val sb = StringBuilder() diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt index 856dc0b8..eba50ce3 100644 --- a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt +++ b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt @@ -3,11 +3,13 @@ package ani.dantotsu.profile import android.animation.ObjectAnimator import android.content.Intent import android.content.res.Configuration +import android.net.Uri import android.os.Bundle import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.PopupMenu +import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.core.view.isGone @@ -21,6 +23,7 @@ import androidx.viewpager2.adapter.FragmentStateAdapter import ani.dantotsu.R import ani.dantotsu.blurImage import ani.dantotsu.connections.anilist.Anilist +import ani.dantotsu.connections.anilist.AnilistMutations import ani.dantotsu.connections.anilist.api.Query import ani.dantotsu.databinding.ActivityProfileBinding import ani.dantotsu.databinding.ItemProfileAppBarBinding @@ -80,6 +83,8 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene navBar.visibility = View.GONE binding.profileViewPager.isUserInputEnabled = false + bindingProfileAppBar = ItemProfileAppBarBinding.bind(binding.root) + lifecycleScope.launch(Dispatchers.IO) { val userid = intent.getIntExtra("userId", -1) val username = intent.getStringExtra("username") ?: "" @@ -117,6 +122,19 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene bindingProfileAppBar = ItemProfileAppBarBinding.bind(binding.root).apply { binding.profileProgressBar.visibility = View.GONE + editProfileAvatar.visibility = View.GONE + editProfileBanner.visibility = View.GONE + + bindingProfileAppBar.editProfileAvatar.setOnClickListener { + openMediaPickerForAvatar() + } + bindingProfileAppBar.editProfileBanner.setOnClickListener { + openMediaPickerForBanner() + } + binding.apply { + editProfileSave?.setOnClickListener { onSaveButtonClick() } + } + followButton.isGone = user.id == Anilist.userid || Anilist.userid == null @@ -149,14 +167,21 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene profileMenuButton.setOnClickListener { val popup = PopupMenu(context, profileMenuButton) popup.menuInflater.inflate(R.menu.menu_profile, popup.menu) + + if (user.id != Anilist.userid) { + popup.menu.findItem(R.id.action_edit_profile)?.isVisible = false + } + popup.setOnMenuItemClickListener { item -> when (item.itemId) { R.id.action_view_on_anilist -> { openLinkInBrowser("https://anilist.co/user/${user.name}") true } - - + R.id.action_edit_profile -> { + toggleEditProfile() + true + } else -> false } } @@ -247,7 +272,84 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene } } - //Collapsing UI Stuff + private fun toggleEditProfile() { + val viewIds = arrayOf( + R.id.profileNavBar, + R.id.profileButtonContainer, + R.id.userStatsContainer, + R.id.profileFavAnimeContainer, + R.id.profileFavMangaContainer, + R.id.profileFavCharactersContainer, + //R.id.profileFavStaffContainer + R.id.imageStatsContainer, + R.id.editProfileAvatar, + R.id.editProfileBanner, + R.id.editProfileSave, + ) + + viewIds.forEach { viewId -> + findViewById(viewId).apply { + visibility = if (visibility == View.VISIBLE) View.GONE else View.VISIBLE + } + } + } + + private var avatarUri: Uri? = null + private val avatarPicker = + registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> + uri?.let { avatarUri -> + uploadAvatar(avatarUri) + } + } + + private val bannerPicker = + registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> + uri?.let { bannerUri -> + uploadBanner(bannerUri) + } + } + + private fun openMediaPickerForAvatar() { + avatarPicker.launch("image/*") + } + + private fun openMediaPickerForBanner() { + bannerPicker.launch("image/*") + } + + private fun uploadAvatar(avatarUri: Uri) { + this.avatarUri = avatarUri + bindingProfileAppBar.profileUserAvatar.setImageURI(avatarUri) + + lifecycleScope.launch { + try { + val success = AnilistMutations().uploadAvatar(avatarUri) + if (success) { + toast("Avatar uploaded successfully") + } else { + toast("Failed to upload avatar") + } + } catch (e: Exception) { + toast("Error uploading avatar: ${e.message}") + } + } + } + + + private fun uploadBanner(bannerUri: Uri) { + // Logic incoming + bindingProfileAppBar.profileBannerImage.setImageURI(bannerUri) + } + + private fun onSaveButtonClick() { + val currentAvatarUri = avatarUri + if (currentAvatarUri != null) { + uploadAvatar(currentAvatarUri) + } + toast("Uploading avatar and banner images...") + } + + private var isCollapsed = false private val percent = 65 private var mMaxScrollSize = 0 diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt index 678d7f77..84556632 100644 --- a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt +++ b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt @@ -104,7 +104,7 @@ class ProfileFragment : Fragment() { } binding.userInfoContainer.isVisible = user.about != null - + binding.imageStatsContainer.visibility = View.GONE binding.statsEpisodesWatched.text = user.statistics.anime.episodesWatched.toString() binding.statsDaysWatched.text = diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index f97f8f4d..3e8e4db9 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -35,6 +35,31 @@ tools:ignore="SpeakableTextPresentCheck" /> + + + + + + + + + + + + + + + + + + + + + + + + - + - + android:backgroundTint="@color/transparent" + app:cardCornerRadius="64dp" + app:strokeColor="@color/transparent"> - + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3660dae9..b0e83676 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -796,6 +796,7 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc Blur Banners Blur Hide Scroll Bar + Edit Profile View on AniList Filter Notifications Anilist notifications update frequency : %1$s