feat: front end for images

This commit is contained in:
sneazy-ibo
2024-06-09 20:13:15 +02:00
parent 6f685a4388
commit 8bb563e4d0
8 changed files with 288 additions and 19 deletions

View File

@@ -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<JsonObject>(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<JsonObject>(query, variables.toString())
return result?.get("errors") == null && result != null
}
private fun String.stringSanitizer(): String {
val sb = StringBuilder()

View File

@@ -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<View>(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

View File

@@ -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 =

View File

@@ -35,6 +35,31 @@
tools:ignore="SpeakableTextPresentCheck" />
</LinearLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/editProfileSave"
android:layout_width="122dp"
android:layout_height="46dp"
android:layout_gravity="bottom|end"
android:layout_marginStart="12dp"
android:layout_marginEnd="26dp"
android:layout_marginBottom="46dp"
android:backgroundTint="?attr/colorPrimary"
android:baselineAligned="false"
android:visibility="gone"
app:cardCornerRadius="24dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/publish"
android:layout_gravity="center_horizontal|center_vertical"
android:fontFamily="@font/poppins_semi_bold"
android:textColor="?android:colorBackground"
android:textSize="16sp">
</TextView>
</com.google.android.material.card.MaterialCardView>
<nl.joery.animatedbottombar.AnimatedBottomBar
android:id="@+id/profileNavBar"

View File

@@ -12,6 +12,69 @@
android:nestedScrollingEnabled="true"
android:orientation="vertical">
<LinearLayout
android:id="@+id/imageStatsContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:visibility="gone">
<TextView
android:id="@+id/avatarStatsTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:fontFamily="@font/poppins_bold"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:text="Avatar"
android:textSize="16sp"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/avatarStats"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="32dp"
android:fontFamily="@font/poppins_bold"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:text="Allowed Formats: JPEG, PNG. Max size: 3mb. Optimal dimensions: 230x230"
android:alpha="0.58"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/bannerStatsTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="32dp"
android:fontFamily="@font/poppins_bold"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:text="Banner"
android:textSize="16sp"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/BannerStats"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="32dp"
android:fontFamily="@font/poppins_bold"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:text="Allowed Formats: JPEG, PNG. Max size: 6mb. Optimal dimensions: 1700x330"
android:alpha="0.58"
android:textStyle="bold"
tools:ignore="HardcodedText" />
</LinearLayout>
<LinearLayout
android:id="@+id/userStatsContainer"
@@ -195,13 +258,24 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:nestedScrollingEnabled="true"
android:padding="16dp"
android:textAlignment="textStart"
tools:text="@string/slogan" />
<EditText
android:id="@+id/profileUserBioEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:textSize="16sp"
android:background="@null"
android:inputType="textMultiLine"
android:minLines="5"
android:maxLines="10"
android:visibility="gone"/>
</LinearLayout>
<LinearLayout

View File

@@ -45,6 +45,20 @@
android:src="@drawable/linear_gradient_bg"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/editProfileBanner"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_gravity="end|bottom"
android:layout_marginEnd="12dp"
android:layout_marginBottom="12dp"
android:contentDescription="@string/edit_profile"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:tint="@color/transparent"
android:visibility="visible">
</ImageView>
<LinearLayout
android:id="@+id/profileUserDataContainer"
android:layout_width="wrap_content"
@@ -53,25 +67,42 @@
android:layout_marginBottom="8dp"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:id="@+id/profileUserAvatarContainer"
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_gravity="center"
android:backgroundTint="@color/transparent"
app:cardCornerRadius="64dp"
app:strokeColor="@color/transparent">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profileUserAvatar"
<com.google.android.material.card.MaterialCardView
android:id="@+id/profileUserAvatarContainer"
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:ignore="ContentDescription,ImageContrastCheck"
tools:tint="@color/transparent" />
android:backgroundTint="@color/transparent"
app:cardCornerRadius="64dp"
app:strokeColor="@color/transparent">
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profileUserAvatar"
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:ignore="ContentDescription,ImageContrastCheck"
tools:tint="@color/transparent" />
</com.google.android.material.card.MaterialCardView>
<ImageView
android:id="@+id/editProfileAvatar"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_gravity="end|bottom"
android:contentDescription="@string/edit_profile"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:tint="@color/transparent"
android:visibility="visible">
</ImageView>
</FrameLayout>
<TextView
android:id="@+id/profileUserName"

View File

@@ -7,4 +7,9 @@
android:title="@string/view_on_anilist"
app:showAsAction="never" />
<item
android:id="@+id/action_edit_profile"
android:title="@string/edit_profile"
app:showAsAction="never" />
</menu>

View File

@@ -796,6 +796,7 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
<string name="blur_banners">Blur Banners</string>
<string name="blur">Blur</string>
<string name="hide_scroll_bar">Hide Scroll Bar</string>
<string name="edit_profile" translatable="false">Edit Profile</string>
<string name="view_on_anilist" translatable="false">View on AniList</string>
<string name="anilist_notification_filters">Filter Notifications</string>
<string name="anilist_notifications_checking_time">Anilist notifications update frequency : %1$s</string>