From 36320550812a6fdec4c0ae90f49aa753158f54a1 Mon Sep 17 00:00:00 2001 From: rebelonion <87634197+rebelonion@users.noreply.github.com> Date: Tue, 5 Mar 2024 23:53:38 -0600 Subject: [PATCH 1/9] fix: correctly set banner --- app/src/main/java/ani/dantotsu/profile/FollowerItem.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/ani/dantotsu/profile/FollowerItem.kt b/app/src/main/java/ani/dantotsu/profile/FollowerItem.kt index ca419759..518e6164 100644 --- a/app/src/main/java/ani/dantotsu/profile/FollowerItem.kt +++ b/app/src/main/java/ani/dantotsu/profile/FollowerItem.kt @@ -19,7 +19,11 @@ class FollowerItem( binding = viewBinding binding.profileUserName.text = name avatar?.let { binding.profileUserAvatar.loadImage(it) } - banner?.let { binding.profileBannerImage.loadImage(it) } + if (banner != null) { + binding.profileBannerImage.loadImage(banner) + } else { + binding.profileBannerImage.setImageResource(R.drawable.linear_gradient_bg) + } binding.root.setOnClickListener { clickCallback(id) } } From c862c072b52aad33d8e4d4fc9649f6801c53f180 Mon Sep 17 00:00:00 2001 From: aayush262 Date: Wed, 6 Mar 2024 13:43:37 +0530 Subject: [PATCH 2/9] feat: author and staff stuff --- .../connections/anilist/AnilistQueries.kt | 37 ++++++++++-- .../dantotsu/connections/anilist/api/Staff.kt | 9 ++- .../main/java/ani/dantotsu/media/Author.kt | 6 +- .../java/ani/dantotsu/media/AuthorAdapter.kt | 60 +++++++++++++++++++ app/src/main/java/ani/dantotsu/media/Media.kt | 1 + .../ani/dantotsu/media/MediaInfoFragment.kt | 50 ++++++++++------ .../ani/dantotsu/profile/ProfileFragment.kt | 8 ++- app/src/main/res/values/strings.xml | 1 + 8 files changed, 143 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/ani/dantotsu/media/AuthorAdapter.kt diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt index 86d2a6a9..98e48cda 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt @@ -65,7 +65,7 @@ class AnilistQueries { media.cameFromContinue = false val query = - """{Media(id:${media.id}){id mediaListEntry{id status score(format:POINT_100) progress private notes repeat customLists updatedAt startedAt{year month day}completedAt{year month day}}isFavourite siteUrl idMal nextAiringEpisode{episode airingAt}source countryOfOrigin format duration season seasonYear startDate{year month day}endDate{year month day}genres studios(isMain:true){nodes{id name siteUrl}}description trailer { site id } synonyms tags { name rank isMediaSpoiler } characters(sort:[ROLE,FAVOURITES_DESC],perPage:25,page:1){edges{role node{id image{medium}name{userPreferred}}}}relations{edges{relationType(version:2)node{id idMal mediaListEntry{progress private score(format:POINT_100) status} episodes chapters nextAiringEpisode{episode} popularity meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}staffPreview: staff(perPage: 8, sort: [RELEVANCE, ID]) {edges{role node{id name{userPreferred}}}}recommendations(sort:RATING_DESC){nodes{mediaRecommendation{id idMal mediaListEntry{progress private score(format:POINT_100) status} episodes chapters nextAiringEpisode{episode}meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}externalLinks{url site}}}""" + """{Media(id:${media.id}){id mediaListEntry{id status score(format:POINT_100) progress private notes repeat customLists updatedAt startedAt{year month day}completedAt{year month day}}isFavourite siteUrl idMal nextAiringEpisode{episode airingAt}source countryOfOrigin format duration season seasonYear startDate{year month day}endDate{year month day}genres studios(isMain:true){nodes{id name siteUrl}}description trailer { site id } synonyms tags { name rank isMediaSpoiler } characters(sort:[ROLE,FAVOURITES_DESC],perPage:25,page:1){edges{role node{id image{medium}name{userPreferred}}}}relations{edges{relationType(version:2)node{id idMal mediaListEntry{progress private score(format:POINT_100) status} episodes chapters nextAiringEpisode{episode} popularity meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}staffPreview: staff(perPage: 8, sort: [RELEVANCE, ID]) {edges{role node{id image{large,medium} name{userPreferred}}}}recommendations(sort:RATING_DESC){nodes{mediaRecommendation{id idMal mediaListEntry{progress private score(format:POINT_100) status} episodes chapters nextAiringEpisode{episode}meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}externalLinks{url site}}}""" runBlocking { val anilist = async { var response = executeQuery(query, force = true, show = true) @@ -136,6 +136,29 @@ class AnilistQueries { } } } + if (fetchedMedia.staff != null) { + media.staff = arrayListOf() + fetchedMedia.staff?.edges?.forEach { i -> + i.node?.apply { + media.staff?.add( + Author( + id = id, + name = i.node?.name?.userPreferred, + image = i.node?.image?.medium, + role = when (i.role.toString()) { + "MAIN" -> currContext()?.getString(R.string.main_role) + ?: "MAIN" + + "SUPPORTING" -> currContext()?.getString(R.string.supporting_role) + ?: "SUPPORTING" + + else -> i.role.toString() + } + ) + ) + } + } + } if (fetchedMedia.relations != null) { media.relations = arrayListOf() fetchedMedia.relations?.edges?.forEach { mediaEdge -> @@ -212,8 +235,10 @@ class AnilistQueries { fetchedMedia.staff?.edges?.find { authorRoles.contains(it.role?.trim()) }?.node?.let { media.anime.author = Author( - it.id.toString(), - it.name?.userPreferred ?: "N/A" + it.id, + it.name?.userPreferred ?: "N/A", + it.image?.medium, + "AUTHOR" ) } @@ -232,8 +257,10 @@ class AnilistQueries { } else if (media.manga != null) { fetchedMedia.staff?.edges?.find { authorRoles.contains(it.role?.trim()) }?.node?.let { media.manga.author = Author( - it.id.toString(), - it.name?.userPreferred ?: "N/A" + it.id, + it.name?.userPreferred ?: "N/A", + it.image?.medium, + "AUTHOR" ) } } diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/api/Staff.kt b/app/src/main/java/ani/dantotsu/connections/anilist/api/Staff.kt index b4742e5b..7b56f693 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/api/Staff.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/api/Staff.kt @@ -15,7 +15,7 @@ data class Staff( @SerialName("languageV2") var languageV2: String?, // The staff images - // @SerialName("image") var image: StaffImage?, + @SerialName("image") var image: StaffImage?, // A general description of the staff member @SerialName("description") var description: String?, @@ -93,7 +93,14 @@ data class StaffConnection( // The pagination information // @SerialName("pageInfo") var pageInfo: PageInfo?, ) +@Serializable +data class StaffImage( + // The character's image of media at its largest size + @SerialName("large") var large: String?, + // The character's image of media at medium size + @SerialName("medium") var medium: String?, +) : java.io.Serializable @Serializable data class StaffEdge( var role: String?, diff --git a/app/src/main/java/ani/dantotsu/media/Author.kt b/app/src/main/java/ani/dantotsu/media/Author.kt index 4c99f710..9ab3c169 100644 --- a/app/src/main/java/ani/dantotsu/media/Author.kt +++ b/app/src/main/java/ani/dantotsu/media/Author.kt @@ -3,7 +3,9 @@ package ani.dantotsu.media import java.io.Serializable data class Author( - val id: String, - val name: String, + val id: Int, + val name: String?, + val image: String?, + val role: String?, var yearMedia: MutableMap>? = null ) : Serializable diff --git a/app/src/main/java/ani/dantotsu/media/AuthorAdapter.kt b/app/src/main/java/ani/dantotsu/media/AuthorAdapter.kt new file mode 100644 index 00000000..35195960 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/media/AuthorAdapter.kt @@ -0,0 +1,60 @@ +package ani.dantotsu.media + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Intent +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.core.app.ActivityOptionsCompat +import androidx.core.content.ContextCompat +import androidx.core.util.Pair +import androidx.core.view.ViewCompat +import androidx.recyclerview.widget.RecyclerView +import ani.dantotsu.databinding.ItemCharacterBinding +import ani.dantotsu.loadImage +import ani.dantotsu.setAnimation +import java.io.Serializable + +class AuthorAdapter( + private val authorList: ArrayList +) : RecyclerView.Adapter() { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AuthorViewHolder { + val binding = + ItemCharacterBinding.inflate(LayoutInflater.from(parent.context), parent, false) + return AuthorViewHolder(binding) + } + + @SuppressLint("SetTextI18n") + override fun onBindViewHolder(holder:AuthorViewHolder, position: Int) { + val binding = holder.binding + setAnimation(binding.root.context, holder.binding.root) + val author = authorList[position] + binding.itemCompactRelation.text = author.role + binding.itemCompactImage.loadImage(author.image) + binding.itemCompactTitle.text = author.name + } + + override fun getItemCount(): Int = authorList.size + inner class AuthorViewHolder(val binding: ItemCharacterBinding) : + RecyclerView.ViewHolder(binding.root) { + init { + itemView.setOnClickListener { + val author = authorList[bindingAdapterPosition] + ContextCompat.startActivity( + itemView.context, + Intent( + itemView.context, + AuthorActivity::class.java + ).putExtra("author", author as Serializable), + ActivityOptionsCompat.makeSceneTransitionAnimation( + itemView.context as Activity, + Pair.create( + binding.itemCompactImage, + ViewCompat.getTransitionName(binding.itemCompactImage)!! + ), + ).toBundle() + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/media/Media.kt b/app/src/main/java/ani/dantotsu/media/Media.kt index ebc4d4f7..ea8273ec 100644 --- a/app/src/main/java/ani/dantotsu/media/Media.kt +++ b/app/src/main/java/ani/dantotsu/media/Media.kt @@ -58,6 +58,7 @@ data class Media( var endDate: FuzzyDate? = null, var characters: ArrayList? = null, + var staff: ArrayList? = null, var prequel: Media? = null, var sequel: Media? = null, var relations: ArrayList? = null, diff --git a/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt b/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt index cafdb4ff..06fb3aa9 100644 --- a/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt +++ b/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt @@ -411,23 +411,6 @@ class MediaInfoFragment : Fragment() { parent.addView(bind.root) } - if (!media.characters.isNullOrEmpty() && !offline) { - val bind = ItemTitleRecyclerBinding.inflate( - LayoutInflater.from(context), - parent, - false - ) - bind.itemTitle.setText(R.string.characters) - bind.itemRecycler.adapter = - CharacterAdapter(media.characters!!) - bind.itemRecycler.layoutManager = LinearLayoutManager( - requireContext(), - LinearLayoutManager.HORIZONTAL, - false - ) - parent.addView(bind.root) - } - if (!media.relations.isNullOrEmpty() && !offline) { if (media.sequel != null || media.prequel != null) { val bind = ItemQuelsBinding.inflate( @@ -490,7 +473,38 @@ class MediaInfoFragment : Fragment() { ) parent.addView(bindi.root) } - + if (!media.characters.isNullOrEmpty() && !offline) { + val bind = ItemTitleRecyclerBinding.inflate( + LayoutInflater.from(context), + parent, + false + ) + bind.itemTitle.setText(R.string.characters) + bind.itemRecycler.adapter = + CharacterAdapter(media.characters!!) + bind.itemRecycler.layoutManager = LinearLayoutManager( + requireContext(), + LinearLayoutManager.HORIZONTAL, + false + ) + parent.addView(bind.root) + } + if (!media.staff.isNullOrEmpty() && !offline) { + val bind = ItemTitleRecyclerBinding.inflate( + LayoutInflater.from(context), + parent, + false + ) + bind.itemTitle.setText(R.string.staff) + bind.itemRecycler.adapter = + AuthorAdapter(media.staff!!) + bind.itemRecycler.layoutManager = LinearLayoutManager( + requireContext(), + LinearLayoutManager.HORIZONTAL, + false + ) + parent.addView(bind.root) + } if (!media.recommendations.isNullOrEmpty() && !offline) { val bind = ItemTitleRecyclerBinding.inflate( LayoutInflater.from(context), diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt index 50daccab..f7f4f853 100644 --- a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt +++ b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt @@ -18,6 +18,8 @@ import ani.dantotsu.connections.anilist.ProfileViewModel import ani.dantotsu.connections.anilist.api.Query import ani.dantotsu.databinding.FragmentProfileBinding import ani.dantotsu.loadImage +import ani.dantotsu.media.Author +import ani.dantotsu.media.AuthorAdapter import ani.dantotsu.media.Character import ani.dantotsu.media.CharacterAdapter import ani.dantotsu.media.Media @@ -145,14 +147,14 @@ class ProfileFragment() : Fragment() { false ) - val favStaff = arrayListOf() + val favStaff = arrayListOf() user.favourites?.staff?.nodes?.forEach { i -> - favStaff.add(Character(i.id, i.name.full, i.image.large, i.image.large, "")) + favStaff.add(Author(i.id, i.name.full, i.image.large , "" )) } if (favStaff.isEmpty()) { binding.profileFavStaffContainer.visibility = View.GONE } - binding.profileFavStaffRecycler.adapter = CharacterAdapter(favStaff) + binding.profileFavStaffRecycler.adapter = AuthorAdapter(favStaff) binding.profileFavStaffRecycler.layoutManager = LinearLayoutManager( requireContext(), LinearLayoutManager.HORIZONTAL, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a9c86ec6..a2014d2c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -123,6 +123,7 @@ Synopsis Characters Relations + Staff Roles Details From 18778f3c5af3d1da841c577491bcbd538d532ec5 Mon Sep 17 00:00:00 2001 From: aayush262 Date: Wed, 6 Mar 2024 15:58:55 +0530 Subject: [PATCH 3/9] fix(profile): remove progress in fav media --- .../java/ani/dantotsu/media/MediaAdaptor.kt | 2 + .../ani/dantotsu/profile/ProfileFragment.kt | 9 +- app/src/main/res/layout/fragment_profile.xml | 85 +++---------------- app/src/main/res/layout/item_character.xml | 4 +- .../main/res/layout/item_media_compact.xml | 1 + 5 files changed, 21 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/ani/dantotsu/media/MediaAdaptor.kt b/app/src/main/java/ani/dantotsu/media/MediaAdaptor.kt index c17a5ec1..7d96e95b 100644 --- a/app/src/main/java/ani/dantotsu/media/MediaAdaptor.kt +++ b/app/src/main/java/ani/dantotsu/media/MediaAdaptor.kt @@ -43,6 +43,7 @@ class MediaAdaptor( private val activity: FragmentActivity, private val matchParent: Boolean = false, private val viewPager: ViewPager2? = null, + private val fav: Boolean = false, ) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { @@ -128,6 +129,7 @@ class MediaAdaptor( ) b.itemCompactTotal.text = " | ${media.manga.totalChapters ?: "~"}" } + b.itemCompactProgressContainer.visibility = if (fav) View.GONE else View.VISIBLE } } diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt index f7f4f853..408b7833 100644 --- a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt +++ b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt @@ -120,7 +120,6 @@ class ProfileFragment() : Fragment() { binding.profileFavAnimeContainer, binding.profileFavAnimeRecyclerView, binding.profileFavAnimeProgressBar, - binding.profileFavAnimeEmpty, binding.profileFavAnime ) @@ -129,7 +128,6 @@ class ProfileFragment() : Fragment() { binding.profileFavMangaContainer, binding.profileFavMangaRecyclerView, binding.profileFavMangaProgressBar, - binding.profileFavMangaEmpty, binding.profileFavManga ) @@ -186,21 +184,18 @@ class ProfileFragment() : Fragment() { container: View, recyclerView: RecyclerView, progress: View, - empty: View, title: View ) { container.visibility = View.VISIBLE progress.visibility = View.VISIBLE recyclerView.visibility = View.GONE - empty.visibility = View.GONE title.visibility = View.INVISIBLE mode.observe(viewLifecycleOwner) { recyclerView.visibility = View.GONE - empty.visibility = View.GONE if (it != null) { if (it.isNotEmpty()) { - recyclerView.adapter = MediaAdaptor(0, it, requireActivity()) + recyclerView.adapter = MediaAdaptor(0, it, requireActivity(), fav=true) recyclerView.layoutManager = LinearLayoutManager( requireContext(), LinearLayoutManager.HORIZONTAL, @@ -211,7 +206,7 @@ class ProfileFragment() : Fragment() { LayoutAnimationController(setSlideIn(), 0.25f) } else { - empty.visibility = View.VISIBLE + container.visibility = View.GONE } title.visibility = View.VISIBLE title.startAnimation(setSlideUp()) diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 0ff67438..592378b4 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -144,8 +144,8 @@ android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:layout_marginEnd="32dp" - android:padding="8dp" android:fontFamily="@font/poppins_bold" + android:padding="8dp" android:text="Stats" android:textSize="18sp" tools:ignore="HardcodedText" /> @@ -335,8 +335,8 @@ android:id="@+id/userInfoContainer" android:layout_width="match_parent" android:layout_height="match_parent" - tools:layout_height="wrap_content" - android:orientation="vertical"> + android:orientation="vertical" + tools:layout_height="wrap_content"> @@ -355,12 +355,12 @@ android:id="@+id/profileUserBio" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="16dp" android:layout_marginStart="16dp" + android:layout_marginTop="16dp" android:layout_marginEnd="16dp" - android:textAlignment="textStart" android:ellipsize="end" android:padding="16dp" + android:textAlignment="textStart" tools:text="@string/slogan" /> @@ -369,8 +369,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:visibility="gone" - tools:visibility="visible"> + android:visibility="gone"> - - - - - - - - + android:layout_height="wrap_content"> - - - - - - - - - + android:layout_height="wrap_content"> + + @@ -550,14 +492,15 @@ android:layout_height="wrap_content" android:orientation="vertical" tools:visibility="gone"> + diff --git a/app/src/main/res/layout/item_character.xml b/app/src/main/res/layout/item_character.xml index 1aa042f2..caf96e66 100644 --- a/app/src/main/res/layout/item_character.xml +++ b/app/src/main/res/layout/item_character.xml @@ -64,7 +64,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:alpha="0.58" - android:ellipsize="marquee" + android:ellipsize="end" android:includeFontPadding="false" android:singleLine="true" android:textAlignment="textEnd" @@ -73,7 +73,7 @@ android:textStyle="italic" android:transitionName="mediaTitle" tools:ignore="TextContrastCheck" - tools:text="SOURCE " /> + tools:text="SOURCE" /> diff --git a/app/src/main/res/layout/item_media_compact.xml b/app/src/main/res/layout/item_media_compact.xml index 389b0ae9..a3bae4b1 100644 --- a/app/src/main/res/layout/item_media_compact.xml +++ b/app/src/main/res/layout/item_media_compact.xml @@ -149,6 +149,7 @@ tools:text="@string/get_recommendations" /> From acef7c3d5e4fc5264732490908a6dab713fccc5b Mon Sep 17 00:00:00 2001 From: Finnley Somdahl <87634197+rebelonion@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:11:13 -0600 Subject: [PATCH 4/9] fix: headerAdaptor crash --- app/src/main/java/ani/dantotsu/media/SearchActivity.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/ani/dantotsu/media/SearchActivity.kt b/app/src/main/java/ani/dantotsu/media/SearchActivity.kt index 2962a527..33403915 100644 --- a/app/src/main/java/ani/dantotsu/media/SearchActivity.kt +++ b/app/src/main/java/ani/dantotsu/media/SearchActivity.kt @@ -199,7 +199,9 @@ class SearchActivity : AppCompatActivity() { var state: Parcelable? = null override fun onPause() { - headerAdaptor.addHistory() + if (this::headerAdaptor.isInitialized) { + headerAdaptor.addHistory() + } super.onPause() state = binding.searchRecyclerView.layoutManager?.onSaveInstanceState() } From e50a65571f687db5cbb38e9458b3c2acf1e31c99 Mon Sep 17 00:00:00 2001 From: rebelonion <87634197+rebelonion@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:38:55 -0600 Subject: [PATCH 5/9] fix: follow activity crash --- .../main/java/ani/dantotsu/profile/FollowActivity.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt b/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt index 4d05174c..0c528118 100644 --- a/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt +++ b/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt @@ -36,20 +36,22 @@ class FollowActivity : AppCompatActivity(){ private lateinit var selected: ImageButton override fun onCreate(savedInstanceState: Bundle?) { + val immersiveMode = PrefManager.getVal(PrefName.ImmersiveMode) + if (immersiveMode) { + requestWindowFeature(Window.FEATURE_NO_TITLE) + } super.onCreate(savedInstanceState) ThemeManager(this).applyTheme() initActivity(this) binding = ActivityFollowBinding.inflate(layoutInflater) - setContentView(binding.root) - if (!PrefManager.getVal(PrefName.ImmersiveMode)) { + if (!immersiveMode) { this.window.statusBarColor = ContextCompat.getColor(this, R.color.nav_bg_inv) binding.root.fitsSystemWindows = true } else { binding.root.fitsSystemWindows = false - requestWindowFeature(Window.FEATURE_NO_TITLE) window.setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN @@ -58,6 +60,8 @@ class FollowActivity : AppCompatActivity(){ topMargin = statusBarHeight } } + + setContentView(binding.root) val layoutType = PrefManager.getVal(PrefName.FollowerLayout) selected = getSelected(layoutType) binding.followerGrid.alpha = 0.33f From 2855093f5ff2cffadcc34de2a1503c80ebc9abf9 Mon Sep 17 00:00:00 2001 From: ibo <41344259+sneazy-ibo@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:06:56 +0100 Subject: [PATCH 6/9] feat: Inbox WIP(#222) --- app/src/main/AndroidManifest.xml | 4 ++ .../java/ani/dantotsu/home/HomeFragment.kt | 9 +++ .../java/ani/dantotsu/inbox/FeedFragment.kt | 8 +++ .../java/ani/dantotsu/inbox/InboxActivity.kt | 60 +++++++++++++++++++ .../java/ani/dantotsu/inbox/NotifsFragment.kt | 8 +++ app/src/main/res/drawable/inbox_empty.xml | 5 ++ app/src/main/res/drawable/inbox_filled.xml | 5 ++ app/src/main/res/layout/activity_inbox.xml | 48 +++++++++++++++ app/src/main/res/layout/fragment_feed.xml | 6 ++ app/src/main/res/layout/fragment_home.xml | 12 ++++ app/src/main/res/layout/fragment_notifs.xml | 6 ++ 11 files changed, 171 insertions(+) create mode 100644 app/src/main/java/ani/dantotsu/inbox/FeedFragment.kt create mode 100644 app/src/main/java/ani/dantotsu/inbox/InboxActivity.kt create mode 100644 app/src/main/java/ani/dantotsu/inbox/NotifsFragment.kt create mode 100644 app/src/main/res/drawable/inbox_empty.xml create mode 100644 app/src/main/res/drawable/inbox_filled.xml create mode 100644 app/src/main/res/layout/activity_inbox.xml create mode 100644 app/src/main/res/layout/fragment_feed.xml create mode 100644 app/src/main/res/layout/fragment_notifs.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7a22ab3d..3a72b824 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -221,6 +221,10 @@ + + (R.id.imageButton) + + navBar = binding.inboxNavBar + navBar.updateLayoutParams { bottomMargin = navBarHeight } + + val activityTab = navBar.createTab(R.drawable.inbox_filled, "Activity") + val notificationTab = + navBar.createTab(R.drawable.ic_round_notifications_active_24, "Notification") + navBar.addTab(activityTab) + navBar.addTab(notificationTab) + + navBar.visibility = View.GONE + + navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener { + override fun onTabSelected( + lastIndex: Int, + lastTab: AnimatedBottomBar.Tab?, + newIndex: Int, + newTab: AnimatedBottomBar.Tab + ) { + selected = newIndex + + val fragmentTransaction = supportFragmentManager.beginTransaction() + when (newIndex) { + 0 -> fragmentTransaction.replace(R.id.container, FeedFragment()) + 1 -> fragmentTransaction.replace(R.id.container, NotifsFragment()) + } + fragmentTransaction.commit() + } + }) + + navBar.selectTabAt(selected) + navBar.visibility = View.VISIBLE + } + } diff --git a/app/src/main/java/ani/dantotsu/inbox/NotifsFragment.kt b/app/src/main/java/ani/dantotsu/inbox/NotifsFragment.kt new file mode 100644 index 00000000..d6e256c9 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/inbox/NotifsFragment.kt @@ -0,0 +1,8 @@ +package ani.dantotsu.inbox + +import androidx.fragment.app.Fragment +import ani.dantotsu.R + +class NotifsFragment : Fragment(R.layout.fragment_notifs) { + // testing rn +} \ No newline at end of file diff --git a/app/src/main/res/drawable/inbox_empty.xml b/app/src/main/res/drawable/inbox_empty.xml new file mode 100644 index 00000000..bb6540aa --- /dev/null +++ b/app/src/main/res/drawable/inbox_empty.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/inbox_filled.xml b/app/src/main/res/drawable/inbox_filled.xml new file mode 100644 index 00000000..08ad4bf1 --- /dev/null +++ b/app/src/main/res/drawable/inbox_filled.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/layout/activity_inbox.xml b/app/src/main/res/layout/activity_inbox.xml new file mode 100644 index 00000000..1677b0d3 --- /dev/null +++ b/app/src/main/res/layout/activity_inbox.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_feed.xml b/app/src/main/res/layout/fragment_feed.xml new file mode 100644 index 00000000..77d9ef65 --- /dev/null +++ b/app/src/main/res/layout/fragment_feed.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index f8279ae2..a2eea4d8 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -135,6 +135,18 @@ + + + + + \ No newline at end of file From e2eae6250baf2d8a8bfa29b3fb480a257302514b Mon Sep 17 00:00:00 2001 From: aayush262 Date: Thu, 7 Mar 2024 01:02:27 +0530 Subject: [PATCH 7/9] feat: WIP activity and notification page --- app/src/main/AndroidManifest.xml | 15 +- .../java/ani/dantotsu/home/HomeFragment.kt | 8 - .../java/ani/dantotsu/inbox/FeedFragment.kt | 8 - .../java/ani/dantotsu/inbox/InboxActivity.kt | 60 ------- .../java/ani/dantotsu/inbox/NotifsFragment.kt | 8 - .../notifications/NotificationActivity.kt | 47 ++++++ .../ani/dantotsu/profile/ActivityActivity.kt | 48 ++++++ .../ani/dantotsu/profile/ProfileActivity.kt | 15 +- .../settings/SettingsDialogFragment.kt | 9 +- app/src/main/res/layout/activity_activity.xml | 55 +++++++ app/src/main/res/layout/activity_follow.xml | 9 +- app/src/main/res/layout/activity_inbox.xml | 48 ------ .../main/res/layout/activity_notification.xml | 55 +++++++ app/src/main/res/layout/activity_profile.xml | 34 ++-- .../main/res/layout/bottom_sheet_settings.xml | 18 ++ app/src/main/res/layout/fragment_home.xml | 12 -- app/src/main/res/layout/item_activity.xml | 154 ++++++++++++++++++ app/src/main/res/layout/item_follower.xml | 13 +- app/src/main/res/layout/item_notification.xml | 78 +++++++++ 19 files changed, 518 insertions(+), 176 deletions(-) delete mode 100644 app/src/main/java/ani/dantotsu/inbox/FeedFragment.kt delete mode 100644 app/src/main/java/ani/dantotsu/inbox/InboxActivity.kt delete mode 100644 app/src/main/java/ani/dantotsu/inbox/NotifsFragment.kt create mode 100644 app/src/main/java/ani/dantotsu/notifications/NotificationActivity.kt create mode 100644 app/src/main/java/ani/dantotsu/profile/ActivityActivity.kt create mode 100644 app/src/main/res/layout/activity_activity.xml delete mode 100644 app/src/main/res/layout/activity_inbox.xml create mode 100644 app/src/main/res/layout/activity_notification.xml create mode 100644 app/src/main/res/layout/item_activity.xml create mode 100644 app/src/main/res/layout/item_notification.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3a72b824..fc0721be 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -114,6 +114,16 @@ android:name=".profile.FollowActivity" android:windowSoftInputMode="adjustResize|stateHidden" android:parentActivityName=".MainActivity" /> + + + + @@ -221,10 +231,7 @@ - - + (R.id.imageButton) - - navBar = binding.inboxNavBar - navBar.updateLayoutParams { bottomMargin = navBarHeight } - - val activityTab = navBar.createTab(R.drawable.inbox_filled, "Activity") - val notificationTab = - navBar.createTab(R.drawable.ic_round_notifications_active_24, "Notification") - navBar.addTab(activityTab) - navBar.addTab(notificationTab) - - navBar.visibility = View.GONE - - navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener { - override fun onTabSelected( - lastIndex: Int, - lastTab: AnimatedBottomBar.Tab?, - newIndex: Int, - newTab: AnimatedBottomBar.Tab - ) { - selected = newIndex - - val fragmentTransaction = supportFragmentManager.beginTransaction() - when (newIndex) { - 0 -> fragmentTransaction.replace(R.id.container, FeedFragment()) - 1 -> fragmentTransaction.replace(R.id.container, NotifsFragment()) - } - fragmentTransaction.commit() - } - }) - - navBar.selectTabAt(selected) - navBar.visibility = View.VISIBLE - } - } diff --git a/app/src/main/java/ani/dantotsu/inbox/NotifsFragment.kt b/app/src/main/java/ani/dantotsu/inbox/NotifsFragment.kt deleted file mode 100644 index d6e256c9..00000000 --- a/app/src/main/java/ani/dantotsu/inbox/NotifsFragment.kt +++ /dev/null @@ -1,8 +0,0 @@ -package ani.dantotsu.inbox - -import androidx.fragment.app.Fragment -import ani.dantotsu.R - -class NotifsFragment : Fragment(R.layout.fragment_notifs) { - // testing rn -} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/notifications/NotificationActivity.kt b/app/src/main/java/ani/dantotsu/notifications/NotificationActivity.kt new file mode 100644 index 00000000..da536d5f --- /dev/null +++ b/app/src/main/java/ani/dantotsu/notifications/NotificationActivity.kt @@ -0,0 +1,47 @@ +package ani.dantotsu.notifications + +import android.os.Bundle +import android.view.ViewGroup +import android.view.Window +import android.view.WindowManager +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import androidx.core.view.updateLayoutParams +import ani.dantotsu.R +import ani.dantotsu.databinding.ActivityNotificationBinding +import ani.dantotsu.initActivity +import ani.dantotsu.settings.saving.PrefManager +import ani.dantotsu.settings.saving.PrefName +import ani.dantotsu.statusBarHeight +import ani.dantotsu.themes.ThemeManager + +class NotificationActivity : AppCompatActivity() { + private lateinit var binding: ActivityNotificationBinding + + override fun onCreate(savedInstanceState: Bundle?) { + val immersiveMode = PrefManager.getVal(PrefName.ImmersiveMode) + if (immersiveMode) { + requestWindowFeature(Window.FEATURE_NO_TITLE) + } + super.onCreate(savedInstanceState) + ThemeManager(this).applyTheme() + initActivity(this) + binding = ActivityNotificationBinding.inflate(layoutInflater) + if (!immersiveMode) { + this.window.statusBarColor = + ContextCompat.getColor(this, R.color.nav_bg_inv) + binding.root.fitsSystemWindows = true + + } else { + binding.root.fitsSystemWindows = false + window.setFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN + ) + binding.listTitle.updateLayoutParams { + topMargin = statusBarHeight + } + } + setContentView(binding.root) + } +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/profile/ActivityActivity.kt b/app/src/main/java/ani/dantotsu/profile/ActivityActivity.kt new file mode 100644 index 00000000..30b2f685 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/profile/ActivityActivity.kt @@ -0,0 +1,48 @@ +package ani.dantotsu.profile + +import android.os.Bundle +import android.view.ViewGroup +import android.view.Window +import android.view.WindowManager +import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat +import androidx.core.view.updateLayoutParams +import ani.dantotsu.R +import ani.dantotsu.databinding.ActivityActivityBinding +import ani.dantotsu.initActivity +import ani.dantotsu.settings.saving.PrefManager +import ani.dantotsu.settings.saving.PrefName +import ani.dantotsu.statusBarHeight +import ani.dantotsu.themes.ThemeManager + + +class ActivityActivity : AppCompatActivity() { + private lateinit var binding: ActivityActivityBinding + + override fun onCreate(savedInstanceState: Bundle?) { + val immersiveMode = PrefManager.getVal(PrefName.ImmersiveMode) + if (immersiveMode) { + requestWindowFeature(Window.FEATURE_NO_TITLE) + } + super.onCreate(savedInstanceState) + ThemeManager(this).applyTheme() + initActivity(this) + binding = ActivityActivityBinding.inflate(layoutInflater) + if (!immersiveMode) { + this.window.statusBarColor = + ContextCompat.getColor(this, R.color.nav_bg_inv) + binding.root.fitsSystemWindows = true + + } else { + binding.root.fitsSystemWindows = false + window.setFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN + ) + binding.listTitle.updateLayoutParams { + topMargin = statusBarHeight + } + } + setContentView(binding.root) + } +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt index 9006afcd..a7afa0f5 100644 --- a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt +++ b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt @@ -105,7 +105,15 @@ class ProfileActivity : AppCompatActivity() { } binding.profileProgressBar.visibility = View.GONE binding.profileTopContainer.visibility = View.VISIBLE - + binding.profileActivityButton.setOnClickListener { + ContextCompat.startActivity( + this@ProfileActivity, + Intent(this@ProfileActivity, ActivityActivity::class.java) + .putExtra("userId", user.id) + .putExtra("username", user.name), + null + ) + } binding.profileMenuButton.setOnClickListener { val popup = PopupMenu(this@ProfileActivity, binding.profileMenuButton) popup.menuInflater.inflate(R.menu.menu_profile, popup.menu) @@ -151,9 +159,8 @@ class ProfileActivity : AppCompatActivity() { binding.profileBannerImage.loadImage(user.bannerImage) binding.profileBannerImage.updateLayoutParams { height += statusBarHeight } binding.profileBannerGradient.updateLayoutParams { height += statusBarHeight } - binding.profileMenuButton.updateLayoutParams { - topMargin += statusBarHeight - } + binding.profileMenuButton.updateLayoutParams { topMargin += statusBarHeight } + binding.profileActivityButton.updateLayoutParams { topMargin += statusBarHeight } binding.profileBannerImage.setOnLongClickListener { ImageViewDialog.newInstance( this@ProfileActivity, diff --git a/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt b/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt index dfbe5be6..5692e047 100644 --- a/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt +++ b/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt @@ -13,7 +13,6 @@ import ani.dantotsu.MainActivity import ani.dantotsu.profile.ProfileActivity import ani.dantotsu.R import ani.dantotsu.connections.anilist.Anilist -import ani.dantotsu.currContext import ani.dantotsu.databinding.BottomSheetSettingsBinding import ani.dantotsu.download.anime.OfflineAnimeFragment import ani.dantotsu.download.manga.OfflineMangaFragment @@ -24,6 +23,7 @@ import ani.dantotsu.home.MangaFragment import ani.dantotsu.home.NoInternet import ani.dantotsu.incognitoNotification import ani.dantotsu.loadImage +import ani.dantotsu.notifications.NotificationActivity import ani.dantotsu.offline.OfflineFragment import ani.dantotsu.openLinkInBrowser import ani.dantotsu.others.imagesearch.ImageSearchActivity @@ -81,7 +81,7 @@ class SettingsDialogFragment : BottomSheetDialogFragment() { } binding.settingsUserAvatar.setOnClickListener{ ContextCompat.startActivity( - currContext()!!, Intent(currContext()!!, ProfileActivity::class.java) + requireContext(), Intent(requireContext(), ProfileActivity::class.java) .putExtra("userId", Anilist.userid), null ) } @@ -104,7 +104,10 @@ class SettingsDialogFragment : BottomSheetDialogFragment() { openLinkInBrowser("https://anilist.co/settings/lists") dismiss() } - + binding.settingsNotification.setOnClickListener { + startActivity(Intent(activity, NotificationActivity::class.java)) + dismiss() + } binding.settingsDownloads.isChecked = PrefManager.getVal(PrefName.OfflineMode) binding.settingsDownloads.setOnCheckedChangeListener { _, isChecked -> Timer().schedule(300) { diff --git a/app/src/main/res/layout/activity_activity.xml b/app/src/main/res/layout/activity_activity.xml new file mode 100644 index 00000000..584c5588 --- /dev/null +++ b/app/src/main/res/layout/activity_activity.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_follow.xml b/app/src/main/res/layout/activity_follow.xml index 7cd44c3f..60df0bc2 100644 --- a/app/src/main/res/layout/activity_follow.xml +++ b/app/src/main/res/layout/activity_follow.xml @@ -33,11 +33,11 @@ android:id="@+id/listTitle" android:layout_width="wrap_content" android:layout_height="48dp" - android:layout_marginStart="44dp" android:layout_gravity="center_vertical" - android:gravity="center|start" + android:layout_marginStart="44dp" android:ellipsize="end" android:fontFamily="@font/poppins_bold" + android:gravity="center|start" android:singleLine="true" android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title" android:textColor="?attr/colorOnBackground" @@ -87,12 +87,11 @@ - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_inbox.xml b/app/src/main/res/layout/activity_inbox.xml deleted file mode 100644 index 1677b0d3..00000000 --- a/app/src/main/res/layout/activity_inbox.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_notification.xml b/app/src/main/res/layout/activity_notification.xml new file mode 100644 index 00000000..7383dbd7 --- /dev/null +++ b/app/src/main/res/layout/activity_notification.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index 021128d1..c91792c8 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -58,8 +58,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal|bottom" - android:orientation="vertical" - tools:visibility="visible"> + android:orientation="vertical"> + app:strokeColor="?attr/colorOnSecondary" + tools:ignore="HardcodedText,SpeakableTextPresentCheck" /> - - + android:orientation="horizontal"> + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_follower.xml b/app/src/main/res/layout/item_follower.xml index 3c56e72f..68b354c8 100644 --- a/app/src/main/res/layout/item_follower.xml +++ b/app/src/main/res/layout/item_follower.xml @@ -1,18 +1,19 @@ + + app:cardCornerRadius="16dp"> + + tools:ignore="ContentDescription,ImageContrastCheck" + tools:tint="@color/transparent" /> diff --git a/app/src/main/res/layout/item_notification.xml b/app/src/main/res/layout/item_notification.xml new file mode 100644 index 00000000..c0ffdc79 --- /dev/null +++ b/app/src/main/res/layout/item_notification.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 7ac679f9278dad2abafef164c6e3a97af53da272 Mon Sep 17 00:00:00 2001 From: rebelonion <87634197+rebelonion@users.noreply.github.com> Date: Thu, 7 Mar 2024 02:51:04 -0600 Subject: [PATCH 8/9] feat: anilist notifications --- .../dantotsu/connections/anilist/Anilist.kt | 1 + .../connections/anilist/AnilistQueries.kt | 13 +- .../connections/anilist/api/Notification.kt | 118 ++++++++++++++ .../dantotsu/connections/anilist/api/User.kt | 2 +- .../java/ani/dantotsu/home/HomeFragment.kt | 4 + .../notifications/NotificationActivity.kt | 53 +++++++ .../ani/dantotsu/profile/ProfileFragment.kt | 34 +++- .../dantotsu/profile/activity/ActivityItem.kt | 22 +++ .../profile/activity/NotificationItem.kt | 144 +++++++++++++++++ .../activity/NotificationItemBuilder.kt | 148 ++++++++++++++++++ .../main/res/drawable/notification_circle.xml | 8 + .../main/res/layout/activity_notification.xml | 2 +- app/src/main/res/layout/activity_profile.xml | 5 +- app/src/main/res/layout/fragment_home.xml | 38 +++-- app/src/main/res/layout/item_notification.xml | 8 +- 15 files changed, 572 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/ani/dantotsu/connections/anilist/api/Notification.kt create mode 100644 app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt create mode 100644 app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt create mode 100644 app/src/main/java/ani/dantotsu/profile/activity/NotificationItemBuilder.kt create mode 100644 app/src/main/res/drawable/notification_circle.xml diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/Anilist.kt b/app/src/main/java/ani/dantotsu/connections/anilist/Anilist.kt index 76f30db2..55b1098c 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/Anilist.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/Anilist.kt @@ -28,6 +28,7 @@ object Anilist { var bg: String? = null var episodesWatched: Int? = null var chapterRead: Int? = null + var unreadNotificationCount: Int = 0 var genres: ArrayList? = null var tags: Map>? = null diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt index 98e48cda..070146c4 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt @@ -7,6 +7,8 @@ import ani.dantotsu.checkId import ani.dantotsu.connections.anilist.Anilist.authorRoles import ani.dantotsu.connections.anilist.Anilist.executeQuery import ani.dantotsu.connections.anilist.api.FuzzyDate +import ani.dantotsu.connections.anilist.api.Notification +import ani.dantotsu.connections.anilist.api.NotificationResponse import ani.dantotsu.connections.anilist.api.Page import ani.dantotsu.connections.anilist.api.Query import ani.dantotsu.currContext @@ -36,7 +38,7 @@ class AnilistQueries { val response: Query.Viewer? measureTimeMillis { response = - executeQuery("""{Viewer{name options{displayAdultContent}avatar{medium}bannerImage id mediaListOptions{rowOrder animeList{sectionOrder customLists}mangaList{sectionOrder customLists}}statistics{anime{episodesWatched}manga{chaptersRead}}}}""") + executeQuery("""{Viewer{name options{displayAdultContent}avatar{medium}bannerImage id mediaListOptions{rowOrder animeList{sectionOrder customLists}mangaList{sectionOrder customLists}}statistics{anime{episodesWatched}manga{chaptersRead}}unreadNotificationCount}}""") }.also { println("time : $it") } val user = response?.data?.user ?: return false @@ -49,6 +51,7 @@ class AnilistQueries { Anilist.episodesWatched = user.statistics?.anime?.episodesWatched Anilist.chapterRead = user.statistics?.manga?.chaptersRead Anilist.adult = user.options?.displayAdultContent ?: false + Anilist.unreadNotificationCount = user.unreadNotificationCount?:0 return true } @@ -1337,4 +1340,12 @@ Page(page:$page,perPage:50) { default[1] = userBannerImage("MANGA",id) return default } + + suspend fun getNotifications(id: Int): NotificationResponse? { + val res = executeQuery("""{User(id:$id){unreadNotificationCount}Page{notifications(resetNotificationCount:true){__typename...on AiringNotification{id,type,animeId,episode,contexts,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}},}...on FollowingNotification{id,userId,type,context,createdAt,user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMessageNotification{id,userId,type,activityId,context,createdAt,message{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMentionNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplySubscribedNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentMentionNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentReplyNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentSubscribedNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentLikeNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadLikeNotification{id,userId,type,threadId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on RelatedMediaAdditionNotification{id,type,context,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDataChangeNotification{id,type,mediaId,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaMergeNotification{id,type,mediaId,deletedMediaTitles,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDeletionNotification{id,type,deletedMediaTitle,context,reason,createdAt,}}}}""", force = true) + if (res != null) { + Anilist.unreadNotificationCount = 0 + } + return res + } } \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/api/Notification.kt b/app/src/main/java/ani/dantotsu/connections/anilist/api/Notification.kt new file mode 100644 index 00000000..073fadc1 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/connections/anilist/api/Notification.kt @@ -0,0 +1,118 @@ +package ani.dantotsu.connections.anilist.api + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +enum class NotificationType(val value: String) { + ACTIVITY_MESSAGE("ACTIVITY_MESSAGE"), + ACTIVITY_REPLY("ACTIVITY_REPLY"), + FOLLOWING("FOLLOWING"), + ACTIVITY_MENTION("ACTIVITY_MENTION"), + THREAD_COMMENT_MENTION("THREAD_COMMENT_MENTION"), + THREAD_SUBSCRIBED("THREAD_SUBSCRIBED"), + THREAD_COMMENT_REPLY("THREAD_COMMENT_REPLY"), + AIRING("AIRING"), + ACTIVITY_LIKE("ACTIVITY_LIKE"), + ACTIVITY_REPLY_LIKE("ACTIVITY_REPLY_LIKE"), + THREAD_LIKE("THREAD_LIKE"), + THREAD_COMMENT_LIKE("THREAD_COMMENT_LIKE"), + ACTIVITY_REPLY_SUBSCRIBED("ACTIVITY_REPLY_SUBSCRIBED"), + RELATED_MEDIA_ADDITION("RELATED_MEDIA_ADDITION"), + MEDIA_DATA_CHANGE("MEDIA_DATA_CHANGE"), + MEDIA_MERGE("MEDIA_MERGE"), + MEDIA_DELETION("MEDIA_DELETION") +} + +@Serializable +data class NotificationResponse( + @SerialName("data") + val data: Data, +) : java.io.Serializable { + @Serializable + data class Data( + @SerialName("User") + val user: NotificationUser, + @SerialName("Page") + val page: NotificationPage, + ) : java.io.Serializable +} + +@Serializable +data class NotificationUser( + @SerialName("unreadNotificationCount") + val unreadNotificationCount: Int, +) : java.io.Serializable + +@Serializable +data class NotificationPage( + @SerialName("notifications") + val notifications: List, +) : java.io.Serializable + +@Serializable +data class Notification( + @SerialName("__typename") + val typename: String, + @SerialName("id") + val id: Int, + @SerialName("userId") + val userId: Int?, + @SerialName("CommentId") + val commentId: Int?, + @SerialName("type") + val notificationType: String, + @SerialName("activityId") + val activityId: Int?, + @SerialName("animeId") + val mediaId: Int?, + @SerialName("episode") + val episode: Int?, + @SerialName("contexts") + val contexts: List?, + @SerialName("context") + val context: String?, + @SerialName("reason") + val reason: String?, + @SerialName("deletedMediaTitle") + val deletedMediaTitle: String?, + @SerialName("deletedMediaTitles") + val deletedMediaTitles: List?, + @SerialName("createdAt") + val createdAt: Int, + @SerialName("media") + val media: ani.dantotsu.connections.anilist.api.Media?, + @SerialName("user") + val user: ani.dantotsu.connections.anilist.api.User?, + @SerialName("message") + val message: MessageActivity?, + @SerialName("activity") + val activity: ActivityUnion?, + @SerialName("Thread") + val thread: Thread?, + @SerialName("comment") + val comment: ThreadComment?, +) : java.io.Serializable + +@Serializable +data class MessageActivity( + @SerialName("id") + val id: Int?, +) : java.io.Serializable + +@Serializable +data class ActivityUnion( + @SerialName("id") + val id: Int?, +) : java.io.Serializable + +@Serializable +data class Thread( + @SerialName("id") + val id: Int?, +) : java.io.Serializable + +@Serializable +data class ThreadComment( + @SerialName("id") + val id: Int?, +) : java.io.Serializable diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt b/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt index c74ef85b..b1ec8862 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/api/User.kt @@ -46,7 +46,7 @@ data class User( @SerialName("statistics") var statistics: UserStatisticTypes?, // The number of unread notifications the user has - // @SerialName("unreadNotificationCount") var unreadNotificationCount: Int?, + @SerialName("unreadNotificationCount") var unreadNotificationCount: Int?, // The url for the user page on the AniList website // @SerialName("siteUrl") var siteUrl: String?, diff --git a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt index 881cb199..775f436e 100644 --- a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt +++ b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt @@ -80,6 +80,8 @@ class HomeFragment : Fragment() { binding.homeUserBg.loadImage(Anilist.bg) binding.homeUserDataProgressBar.visibility = View.GONE + binding.homeNotificationDot.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE + binding.homeAnimeList.setOnClickListener { ContextCompat.startActivity( requireActivity(), Intent(requireActivity(), ListActivity::class.java) @@ -361,6 +363,8 @@ class HomeFragment : Fragment() { override fun onResume() { if (!model.loaded) Refresh.activity[1]!!.postValue(true) + if (_binding != null) + binding.homeNotificationDot.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE super.onResume() } } \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/notifications/NotificationActivity.kt b/app/src/main/java/ani/dantotsu/notifications/NotificationActivity.kt index da536d5f..2c4f5e60 100644 --- a/app/src/main/java/ani/dantotsu/notifications/NotificationActivity.kt +++ b/app/src/main/java/ani/dantotsu/notifications/NotificationActivity.kt @@ -1,5 +1,6 @@ package ani.dantotsu.notifications +import android.content.Intent import android.os.Bundle import android.view.ViewGroup import android.view.Window @@ -7,16 +8,27 @@ import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.core.view.updateLayoutParams +import androidx.lifecycle.lifecycleScope +import androidx.recyclerview.widget.LinearLayoutManager import ani.dantotsu.R +import ani.dantotsu.connections.anilist.Anilist +import ani.dantotsu.connections.anilist.api.Notification import ani.dantotsu.databinding.ActivityNotificationBinding import ani.dantotsu.initActivity +import ani.dantotsu.media.MediaDetailsActivity +import ani.dantotsu.profile.ProfileActivity +import ani.dantotsu.profile.activity.NotificationItem import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.statusBarHeight import ani.dantotsu.themes.ThemeManager +import com.xwray.groupie.GroupieAdapter +import kotlinx.coroutines.launch class NotificationActivity : AppCompatActivity() { private lateinit var binding: ActivityNotificationBinding + private var adapter: GroupieAdapter = GroupieAdapter() + private var notificationList: List = emptyList() override fun onCreate(savedInstanceState: Bundle?) { val immersiveMode = PrefManager.getVal(PrefName.ImmersiveMode) @@ -43,5 +55,46 @@ class NotificationActivity : AppCompatActivity() { } } setContentView(binding.root) + + binding.notificationList.adapter = adapter + binding.notificationList.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) + + binding.listBack.setOnClickListener { + onBackPressed() + } + + lifecycleScope.launch { + val res = Anilist.query.getNotifications(Anilist.userid?:0) + res?.data?.page?.notifications?.let { notifications -> + notificationList = notifications + adapter.update(notificationList.map { NotificationItem(it, ::onNotificationClick) }) + } + } + } + + private fun onNotificationClick(id: Int, type: NotificationClickType) { + when (type) { + NotificationClickType.USER -> { + ContextCompat.startActivity( + this, Intent(this, ProfileActivity::class.java) + .putExtra("userId", id), null + ) + } + NotificationClickType.MEDIA -> { + ContextCompat.startActivity( + this, Intent(this, MediaDetailsActivity::class.java) + .putExtra("mediaId", id), null + ) + } + NotificationClickType.UNDEFINED -> { + // Do nothing + } + } + } + + companion object { + enum class NotificationClickType { + USER, MEDIA, UNDEFINED + } } } \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt index 408b7833..00135292 100644 --- a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt +++ b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt @@ -70,13 +70,14 @@ class ProfileFragment() : Fragment() { binding.profileUserBio.settings.loadWithOverviewMode = true binding.profileUserBio.settings.useWideViewPort = true binding.profileUserBio.setInitialScale(1) + val styledHtml = styled( + convertMarkdownToHtml(user.about ?: ""), + backGroundColorTypedValue.data, + textColorTypedValue.data + ) binding.profileUserBio.loadDataWithBaseURL( null, - styled( - convertMarkdownToHtml(user.about ?: ""), - backGroundColorTypedValue.data, - textColorTypedValue.data - ), + styledHtml, "text/html; charset=utf-8", "UTF-8", null @@ -215,7 +216,22 @@ class ProfileFragment() : Fragment() { } } - private fun styled(html: String, backGroundColor: Int, textColor: Int): String { + private fun styled(html: String, backGroundColor: Int, textColor: Int): String { //istg anilist has the worst api + //remove some of the html entities + val step1 = html.replace(" ", " ") + .replace("&", "&") + .replace("<", "<") + .replace(">", ">") + .replace(""", "\"") + .replace("'", "'") + .replace("
", "")
+            .replace("`", "")
+            .replace("~", "")
+
+        val step2 = step1.replace("(?s)___(.*?)___".toRegex(), "
$1
") + val step3 = step2.replace("(?s)__(.*?)__".toRegex(), "
$1
") + + return """ @@ -233,6 +249,10 @@ class ProfileFragment() : Fragment() { max-width: 100%; height: auto; /* Maintain aspect ratio */ } + video { + max-width: 100%; + height: auto; /* Maintain aspect ratio */ + } a { color: ${textColor.toCssColor()}; } @@ -240,7 +260,7 @@ class ProfileFragment() : Fragment() { - $html + $step3 """.trimIndent() diff --git a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt new file mode 100644 index 00000000..f1ced201 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt @@ -0,0 +1,22 @@ +package ani.dantotsu.profile.activity + +import android.view.View +import ani.dantotsu.R +import ani.dantotsu.databinding.ItemNotificationBinding +import com.xwray.groupie.viewbinding.BindableItem + +class ActivityItem( +): BindableItem() { + private lateinit var binding: ItemNotificationBinding + override fun bind(viewBinding: ItemNotificationBinding, position: Int) { + binding = viewBinding + } + + override fun getLayout(): Int { + return R.layout.item_notification + } + + override fun initializeViewBinding(view: View): ItemNotificationBinding { + return ItemNotificationBinding.bind(view) + } +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt b/app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt new file mode 100644 index 00000000..1559be45 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt @@ -0,0 +1,144 @@ +package ani.dantotsu.profile.activity + +import android.view.View +import ani.dantotsu.R +import ani.dantotsu.connections.anilist.api.Notification +import ani.dantotsu.connections.anilist.api.NotificationType +import ani.dantotsu.databinding.ItemNotificationBinding +import ani.dantotsu.loadImage +import ani.dantotsu.notifications.NotificationActivity +import com.xwray.groupie.viewbinding.BindableItem + +class NotificationItem( + private val notification: Notification, + val clickCallback: (Int, NotificationActivity.Companion.NotificationClickType) -> Unit +): BindableItem() { + private lateinit var binding: ItemNotificationBinding + private lateinit var clickType: NotificationActivity.Companion.NotificationClickType + private var id = 0 + override fun bind(viewBinding: ItemNotificationBinding, position: Int) { + binding = viewBinding + setBinding() + } + + override fun getLayout(): Int { + return R.layout.item_notification + } + + override fun initializeViewBinding(view: View): ItemNotificationBinding { + return ItemNotificationBinding.bind(view) + } + + private fun setBinding() { + val notificationType: NotificationType = + NotificationType.valueOf(notification.notificationType) + binding.notificationText.text = NotificationItemBuilder.getContent(notification) + binding.notificationDate.text = NotificationItemBuilder.getDateTime(notification.createdAt) + binding.root.setOnClickListener { clickCallback(id, clickType) } + + when (notificationType) { + NotificationType.ACTIVITY_MESSAGE -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.ACTIVITY_REPLY -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.FOLLOWING -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.ACTIVITY_MENTION -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.THREAD_COMMENT_MENTION -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.THREAD_SUBSCRIBED -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.THREAD_COMMENT_REPLY -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.AIRING -> { + binding.notificationCover.loadImage(notification.media?.coverImage?.large) + binding.notificationBannerImage.loadImage(notification.media?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.MEDIA + id = notification.media?.id ?: 0 + } + NotificationType.ACTIVITY_LIKE -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.ACTIVITY_REPLY_LIKE -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.THREAD_LIKE -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.THREAD_COMMENT_LIKE -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.ACTIVITY_REPLY_SUBSCRIBED -> { + binding.notificationCover.loadImage(notification.user?.avatar?.large) + binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.USER + id = notification.user?.id ?: 0 + } + NotificationType.RELATED_MEDIA_ADDITION -> { + binding.notificationCover.loadImage(notification.media?.coverImage?.large) + binding.notificationBannerImage.loadImage(notification.media?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.MEDIA + id = notification.media?.id ?: 0 + } + NotificationType.MEDIA_DATA_CHANGE -> { + binding.notificationCover.loadImage(notification.media?.coverImage?.large) + binding.notificationBannerImage.loadImage(notification.media?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.MEDIA + id = notification.media?.id ?: 0 + } + NotificationType.MEDIA_MERGE -> { + binding.notificationCover.loadImage(notification.media?.coverImage?.large) + binding.notificationBannerImage.loadImage(notification.media?.bannerImage) + clickType = NotificationActivity.Companion.NotificationClickType.MEDIA + id = notification.media?.id ?: 0 + } + NotificationType.MEDIA_DELETION -> { + binding.notificationCover.visibility = View.GONE + clickType = NotificationActivity.Companion.NotificationClickType.UNDEFINED + id = 0 + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/profile/activity/NotificationItemBuilder.kt b/app/src/main/java/ani/dantotsu/profile/activity/NotificationItemBuilder.kt new file mode 100644 index 00000000..84911091 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/profile/activity/NotificationItemBuilder.kt @@ -0,0 +1,148 @@ +package ani.dantotsu.profile.activity + +import ani.dantotsu.connections.anilist.api.Notification +import ani.dantotsu.connections.anilist.api.NotificationType +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale + +/* +* ACTIVITY_MESSAGE + +A user has sent you message +ACTIVITY_REPLY + +A user has replied to your activity +FOLLOWING + +A user has followed you +ACTIVITY_MENTION + +A user has mentioned you in their activity +THREAD_COMMENT_MENTION + +A user has mentioned you in a forum comment +THREAD_SUBSCRIBED + +A user has commented in one of your subscribed forum threads +THREAD_COMMENT_REPLY + +A user has replied to your forum comment +AIRING + +An anime you are currently watching has aired +ACTIVITY_LIKE + +A user has liked your activity +ACTIVITY_REPLY_LIKE + +A user has liked your activity reply +THREAD_LIKE + +A user has liked your forum thread +THREAD_COMMENT_LIKE + +A user has liked your forum comment +ACTIVITY_REPLY_SUBSCRIBED + +A user has replied to activity you have also replied to +RELATED_MEDIA_ADDITION + +A new anime or manga has been added to the site where its related media is on the user's list +MEDIA_DATA_CHANGE + +An anime or manga has had a data change that affects how a user may track it in their lists +MEDIA_MERGE + +Anime or manga entries on the user's list have been merged into a single entry +MEDIA_DELETION + +An anime or manga on the user's list has been deleted from the site + +* */ + +interface NotificationItemBuilder { + + companion object { + fun getContent(notification: Notification): String { + val notificationType: NotificationType = + NotificationType.valueOf(notification.notificationType) + return when (notificationType) { + NotificationType.ACTIVITY_MESSAGE -> { + "${notification.user?.name} sent you a message" + } + + NotificationType.ACTIVITY_REPLY -> { + "${notification.user?.name} replied to your activity" + } + + NotificationType.FOLLOWING -> { + "${notification.user?.name} followed you" + } + + NotificationType.ACTIVITY_MENTION -> { + "${notification.user?.name} mentioned you in their activity" + } + + NotificationType.THREAD_COMMENT_MENTION -> { + "${notification.user?.name} mentioned you in a forum comment" + } + + NotificationType.THREAD_SUBSCRIBED -> { + "${notification.user?.name} commented in one of your subscribed forum threads" + } + + NotificationType.THREAD_COMMENT_REPLY -> { + "${notification.user?.name} replied to your forum comment" + } + + NotificationType.AIRING -> { + "Episode ${notification.episode} of ${notification.media?.title?.english ?: notification.media?.title?.romaji} has aired" + } + + NotificationType.ACTIVITY_LIKE -> { + "${notification.user?.name} liked your activity" + } + + NotificationType.ACTIVITY_REPLY_LIKE -> { + "${notification.user?.name} liked your reply" + } + + NotificationType.THREAD_LIKE -> { + "${notification.user?.name} liked your forum thread" + } + + NotificationType.THREAD_COMMENT_LIKE -> { + "${notification.user?.name} liked your forum comment" + } + + NotificationType.ACTIVITY_REPLY_SUBSCRIBED -> { + "${notification.user?.name} replied to activity you have also replied to" + } + + NotificationType.RELATED_MEDIA_ADDITION -> { + "${notification.media?.title?.english ?: notification.media?.title?.romaji} has been added to the site" + } + + NotificationType.MEDIA_DATA_CHANGE -> { + "${notification.media?.title?.english ?: notification.media?.title?.romaji} has had a data change: ${notification.reason}" + } + + NotificationType.MEDIA_MERGE -> { + "${notification.deletedMediaTitles?.joinToString(", ")} have been merged into ${notification.media?.title?.english ?: notification.media?.title?.romaji}" + } + + NotificationType.MEDIA_DELETION -> { + "${notification.deletedMediaTitle} has been deleted from the site" + } + } + } + + fun getDateTime(time: Int): String { + val date = Date(time * 1000L) + val sdf = SimpleDateFormat("dd/MM/yyyy hh:mm a", Locale.getDefault()) + return sdf.format(date) + } + + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/notification_circle.xml b/app/src/main/res/drawable/notification_circle.xml new file mode 100644 index 00000000..fe33dad2 --- /dev/null +++ b/app/src/main/res/drawable/notification_circle.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/src/main/res/layout/activity_notification.xml b/app/src/main/res/layout/activity_notification.xml index 7383dbd7..047efd00 100644 --- a/app/src/main/res/layout/activity_notification.xml +++ b/app/src/main/res/layout/activity_notification.xml @@ -46,7 +46,7 @@ diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index f8279ae2..a26958f0 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -135,23 +135,35 @@ - + - + android:layout_marginTop="4dp" + android:backgroundTint="@color/nav_bg_inv" + app:cardCornerRadius="26dp"> - + + + + + + + diff --git a/app/src/main/res/layout/item_notification.xml b/app/src/main/res/layout/item_notification.xml index c0ffdc79..004eb600 100644 --- a/app/src/main/res/layout/item_notification.xml +++ b/app/src/main/res/layout/item_notification.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="180dp" + android:layout_height="170dp" android:layout_marginTop="16dp" android:orientation="horizontal"> @@ -39,9 +39,10 @@ @@ -63,6 +64,7 @@ tools:ignore="HardcodedText" /> Date: Fri, 8 Mar 2024 00:45:13 +0530 Subject: [PATCH 9/9] fix: some UI changes (for better or worse) --- app/src/main/AndroidManifest.xml | 2 +- .../java/ani/dantotsu/home/AnimeFragment.kt | 1 - .../ani/dantotsu/home/AnimePageAdapter.kt | 2 + .../java/ani/dantotsu/home/HomeFragment.kt | 11 +- .../ani/dantotsu/home/MangaPageAdapter.kt | 3 +- .../media/manga/MangaChapterAdapter.kt | 2 +- .../ani/dantotsu/profile/ActivityActivity.kt | 39 +- .../ani/dantotsu/profile/FollowActivity.kt | 28 +- .../java/ani/dantotsu/profile/FollowerItem.kt | 14 + .../activity}/NotificationActivity.kt | 45 +-- .../profile/activity/NotificationItem.kt | 78 +++- .../activity/NotificationItemBuilder.kt | 32 +- .../settings/SettingsDialogFragment.kt | 16 +- .../main/res/drawable/notification_circle.xml | 2 +- app/src/main/res/layout/activity_follow.xml | 1 + .../main/res/layout/activity_notification.xml | 55 --- app/src/main/res/layout/activity_profile.xml | 1 + .../main/res/layout/bottom_sheet_settings.xml | 376 +++++++++--------- app/src/main/res/layout/fragment_home.xml | 20 +- app/src/main/res/layout/item_activity.xml | 12 +- app/src/main/res/layout/item_anime_page.xml | 47 ++- app/src/main/res/layout/item_follower.xml | 25 +- app/src/main/res/layout/item_manga_page.xml | 48 ++- .../main/res/layout/item_media_compact.xml | 8 +- app/src/main/res/layout/item_media_large.xml | 1 - app/src/main/res/layout/item_notification.xml | 68 +++- 26 files changed, 493 insertions(+), 444 deletions(-) rename app/src/main/java/ani/dantotsu/{notifications => profile/activity}/NotificationActivity.kt (64%) delete mode 100644 app/src/main/res/layout/activity_notification.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fc0721be..8408d9ff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -120,7 +120,7 @@ android:parentActivityName=".MainActivity" > diff --git a/app/src/main/java/ani/dantotsu/home/AnimeFragment.kt b/app/src/main/java/ani/dantotsu/home/AnimeFragment.kt index f3baeb3f..2e110541 100644 --- a/app/src/main/java/ani/dantotsu/home/AnimeFragment.kt +++ b/app/src/main/java/ani/dantotsu/home/AnimeFragment.kt @@ -283,7 +283,6 @@ class AnimeFragment : Fragment() { binding.root.requestApplyInsets() binding.root.requestLayout() } - super.onResume() } } \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt b/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt index 295b49b2..fc480ae3 100644 --- a/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt +++ b/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt @@ -94,6 +94,8 @@ class AnimePageAdapter : RecyclerView.Adapter 0) View.VISIBLE else View.GONE + binding.animeNotificationCount.text = Anilist.unreadNotificationCount.toString() listOf( binding.animePreviousSeason, diff --git a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt index 775f436e..e0a2dc14 100644 --- a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt +++ b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt @@ -79,8 +79,8 @@ class HomeFragment : Fragment() { if (!(PrefManager.getVal(PrefName.BannerAnimations) as Boolean)) binding.homeUserBg.pause() binding.homeUserBg.loadImage(Anilist.bg) binding.homeUserDataProgressBar.visibility = View.GONE - - binding.homeNotificationDot.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE + binding.homeNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE + binding.homeNotificationCount.text = Anilist.unreadNotificationCount.toString() binding.homeAnimeList.setOnClickListener { ContextCompat.startActivity( @@ -360,11 +360,12 @@ class HomeFragment : Fragment() { } } } - override fun onResume() { if (!model.loaded) Refresh.activity[1]!!.postValue(true) - if (_binding != null) - binding.homeNotificationDot.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE + if (_binding != null) { + binding.homeNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE + binding.homeNotificationCount.text = Anilist.unreadNotificationCount.toString() + } super.onResume() } } \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt b/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt index 6cedbb80..1f714260 100644 --- a/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt +++ b/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt @@ -74,7 +74,8 @@ class MangaPageAdapter : RecyclerView.Adapter 0) View.VISIBLE else View.GONE + binding.mangaNotificationCount.text = Anilist.unreadNotificationCount.toString() binding.mangaSearchBar.hint = "MANGA" binding.mangaSearchBarText.setOnClickListener { ContextCompat.startActivity( diff --git a/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt b/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt index a2cf40b7..d19aa011 100644 --- a/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt +++ b/app/src/main/java/ani/dantotsu/media/manga/MangaChapterAdapter.kt @@ -369,7 +369,7 @@ class MangaChapterAdapter( } 1L -> "1 day ago" in 2..6 -> "$daysDifference days ago" - else -> SimpleDateFormat("dd MMM yyyy", Locale.ENGLISH).format(targetDate) + else -> SimpleDateFormat("dd MMM yyyy", Locale.getDefault()).format(targetDate) } } diff --git a/app/src/main/java/ani/dantotsu/profile/ActivityActivity.kt b/app/src/main/java/ani/dantotsu/profile/ActivityActivity.kt index 30b2f685..47d2ad67 100644 --- a/app/src/main/java/ani/dantotsu/profile/ActivityActivity.kt +++ b/app/src/main/java/ani/dantotsu/profile/ActivityActivity.kt @@ -1,48 +1,29 @@ package ani.dantotsu.profile +import android.annotation.SuppressLint import android.os.Bundle import android.view.ViewGroup -import android.view.Window -import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.ContextCompat import androidx.core.view.updateLayoutParams -import ani.dantotsu.R -import ani.dantotsu.databinding.ActivityActivityBinding +import ani.dantotsu.databinding.ActivityFollowBinding import ani.dantotsu.initActivity -import ani.dantotsu.settings.saving.PrefManager -import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.statusBarHeight import ani.dantotsu.themes.ThemeManager - class ActivityActivity : AppCompatActivity() { - private lateinit var binding: ActivityActivityBinding + private lateinit var binding: ActivityFollowBinding + @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { - val immersiveMode = PrefManager.getVal(PrefName.ImmersiveMode) - if (immersiveMode) { - requestWindowFeature(Window.FEATURE_NO_TITLE) - } super.onCreate(savedInstanceState) ThemeManager(this).applyTheme() initActivity(this) - binding = ActivityActivityBinding.inflate(layoutInflater) - if (!immersiveMode) { - this.window.statusBarColor = - ContextCompat.getColor(this, R.color.nav_bg_inv) - binding.root.fitsSystemWindows = true - - } else { - binding.root.fitsSystemWindows = false - window.setFlags( - WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN - ) - binding.listTitle.updateLayoutParams { - topMargin = statusBarHeight - } - } + binding = ActivityFollowBinding.inflate(layoutInflater) setContentView(binding.root) + + binding.listTitle.text = "Activity" + binding.listToolbar.updateLayoutParams { topMargin = statusBarHeight } + binding.followerGrid.visibility = ViewGroup.GONE + binding.followerList.visibility = ViewGroup.GONE } } \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt b/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt index 0c528118..9cb1b612 100644 --- a/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt +++ b/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt @@ -2,23 +2,17 @@ package ani.dantotsu.profile import android.content.Intent import android.os.Bundle -import android.view.ViewGroup import android.view.ViewGroup.MarginLayoutParams -import android.view.Window -import android.view.WindowManager import android.widget.ImageButton import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.ContextCompat import androidx.core.view.updateLayoutParams import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager -import ani.dantotsu.R import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.api.User import ani.dantotsu.databinding.ActivityFollowBinding import ani.dantotsu.initActivity -import ani.dantotsu.navBarHeight import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.statusBarHeight @@ -36,31 +30,11 @@ class FollowActivity : AppCompatActivity(){ private lateinit var selected: ImageButton override fun onCreate(savedInstanceState: Bundle?) { - val immersiveMode = PrefManager.getVal(PrefName.ImmersiveMode) - if (immersiveMode) { - requestWindowFeature(Window.FEATURE_NO_TITLE) - } super.onCreate(savedInstanceState) ThemeManager(this).applyTheme() initActivity(this) binding = ActivityFollowBinding.inflate(layoutInflater) - - if (!immersiveMode) { - this.window.statusBarColor = - ContextCompat.getColor(this, R.color.nav_bg_inv) - binding.root.fitsSystemWindows = true - - } else { - binding.root.fitsSystemWindows = false - window.setFlags( - WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN - ) - binding.listTitle.updateLayoutParams { - topMargin = statusBarHeight - } - } - + binding.listToolbar.updateLayoutParams { topMargin = statusBarHeight } setContentView(binding.root) val layoutType = PrefManager.getVal(PrefName.FollowerLayout) selected = getSelected(layoutType) diff --git a/app/src/main/java/ani/dantotsu/profile/FollowerItem.kt b/app/src/main/java/ani/dantotsu/profile/FollowerItem.kt index 518e6164..378a1b82 100644 --- a/app/src/main/java/ani/dantotsu/profile/FollowerItem.kt +++ b/app/src/main/java/ani/dantotsu/profile/FollowerItem.kt @@ -1,10 +1,17 @@ package ani.dantotsu.profile +import android.app.Activity +import android.content.Context import android.view.View import ani.dantotsu.R import ani.dantotsu.databinding.ItemFollowerBinding import ani.dantotsu.loadImage +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.model.GlideUrl +import com.bumptech.glide.request.RequestOptions import com.xwray.groupie.viewbinding.BindableItem +import jp.wasabeef.glide.transformations.BlurTransformation class FollowerItem( private val id: Int, @@ -18,9 +25,16 @@ class FollowerItem( override fun bind(viewBinding: ItemFollowerBinding, position: Int) { binding = viewBinding binding.profileUserName.text = name + val context = binding.profileBannerImage.context avatar?.let { binding.profileUserAvatar.loadImage(it) } if (banner != null) { binding.profileBannerImage.loadImage(banner) + if (!(context as Activity).isDestroyed) + Glide.with(context as Context) + .load(GlideUrl(banner)) + .diskCacheStrategy(DiskCacheStrategy.ALL).override(400) + .apply(RequestOptions.bitmapTransform(BlurTransformation(2, 6))) + .into(binding.profileBannerImage) } else { binding.profileBannerImage.setImageResource(R.drawable.linear_gradient_bg) } diff --git a/app/src/main/java/ani/dantotsu/notifications/NotificationActivity.kt b/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt similarity index 64% rename from app/src/main/java/ani/dantotsu/notifications/NotificationActivity.kt rename to app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt index 2c4f5e60..a7ff26dc 100644 --- a/app/src/main/java/ani/dantotsu/notifications/NotificationActivity.kt +++ b/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt @@ -1,64 +1,43 @@ -package ani.dantotsu.notifications +package ani.dantotsu.profile.activity +import android.annotation.SuppressLint import android.content.Intent import android.os.Bundle import android.view.ViewGroup -import android.view.Window -import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.core.view.updateLayoutParams import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager -import ani.dantotsu.R import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.api.Notification -import ani.dantotsu.databinding.ActivityNotificationBinding +import ani.dantotsu.databinding.ActivityFollowBinding import ani.dantotsu.initActivity import ani.dantotsu.media.MediaDetailsActivity import ani.dantotsu.profile.ProfileActivity -import ani.dantotsu.profile.activity.NotificationItem -import ani.dantotsu.settings.saving.PrefManager -import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.statusBarHeight import ani.dantotsu.themes.ThemeManager import com.xwray.groupie.GroupieAdapter import kotlinx.coroutines.launch class NotificationActivity : AppCompatActivity() { - private lateinit var binding: ActivityNotificationBinding + private lateinit var binding: ActivityFollowBinding private var adapter: GroupieAdapter = GroupieAdapter() private var notificationList: List = emptyList() + @SuppressLint("SetTextI18n") override fun onCreate(savedInstanceState: Bundle?) { - val immersiveMode = PrefManager.getVal(PrefName.ImmersiveMode) - if (immersiveMode) { - requestWindowFeature(Window.FEATURE_NO_TITLE) - } super.onCreate(savedInstanceState) ThemeManager(this).applyTheme() initActivity(this) - binding = ActivityNotificationBinding.inflate(layoutInflater) - if (!immersiveMode) { - this.window.statusBarColor = - ContextCompat.getColor(this, R.color.nav_bg_inv) - binding.root.fitsSystemWindows = true - - } else { - binding.root.fitsSystemWindows = false - window.setFlags( - WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN - ) - binding.listTitle.updateLayoutParams { - topMargin = statusBarHeight - } - } + binding = ActivityFollowBinding.inflate(layoutInflater) setContentView(binding.root) - - binding.notificationList.adapter = adapter - binding.notificationList.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) - + binding.listTitle.text = "Notifications" + binding.listToolbar.updateLayoutParams { topMargin = statusBarHeight } + binding.listRecyclerView.adapter = adapter + binding.listRecyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) + binding.followerGrid.visibility = ViewGroup.GONE + binding.followerList.visibility = ViewGroup.GONE binding.listBack.setOnClickListener { onBackPressed() } diff --git a/app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt b/app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt index 1559be45..31290be3 100644 --- a/app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt +++ b/app/src/main/java/ani/dantotsu/profile/activity/NotificationItem.kt @@ -1,13 +1,27 @@ package ani.dantotsu.profile.activity +import android.app.Activity +import android.content.Context +import android.content.res.Resources +import android.util.TypedValue import android.view.View +import android.view.ViewGroup +import androidx.core.view.updateLayoutParams import ani.dantotsu.R import ani.dantotsu.connections.anilist.api.Notification import ani.dantotsu.connections.anilist.api.NotificationType import ani.dantotsu.databinding.ItemNotificationBinding import ani.dantotsu.loadImage -import ani.dantotsu.notifications.NotificationActivity +import ani.dantotsu.navBarHeight +import ani.dantotsu.settings.saving.PrefManager +import ani.dantotsu.settings.saving.PrefName +import ani.dantotsu.statusBarHeight +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.model.GlideUrl +import com.bumptech.glide.request.RequestOptions import com.xwray.groupie.viewbinding.BindableItem +import jp.wasabeef.glide.transformations.BlurTransformation class NotificationItem( private val notification: Notification, @@ -29,107 +43,133 @@ class NotificationItem( return ItemNotificationBinding.bind(view) } + private fun image(user: Boolean = false) { + val context = binding.notificationBannerImage.context + val cover = if (user) notification.user?.bannerImage else notification.media?.bannerImage + if (cover != null) { + if (!(context as Activity).isDestroyed) + Glide.with(context as Context) + .load(GlideUrl(cover)) + .diskCacheStrategy(DiskCacheStrategy.ALL).override(400) + .apply(RequestOptions.bitmapTransform(BlurTransformation(2, 6))) + .into(binding.notificationBannerImage) + } else { + binding.notificationBannerImage.setImageResource(R.drawable.linear_gradient_bg) + } + if (user) { + binding.notificationCover.visibility = View.GONE + binding.notificationCoverUserContainer.visibility = View.VISIBLE + binding.notificationCoverUser.loadImage(notification.user?.avatar?.large) + val height = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80f, context.resources.displayMetrics).toInt() + binding.notificationBannerImage.layoutParams.height = height + binding.notificationBannerGradient.layoutParams.height = height + } else{ + binding.notificationCoverUser.visibility = View.VISIBLE + binding.notificationCoverUserContainer.visibility = View.GONE + binding.notificationCover.loadImage(notification.media?.coverImage?.large) + } + } + private fun setBinding() { val notificationType: NotificationType = NotificationType.valueOf(notification.notificationType) binding.notificationText.text = NotificationItemBuilder.getContent(notification) binding.notificationDate.text = NotificationItemBuilder.getDateTime(notification.createdAt) binding.root.setOnClickListener { clickCallback(id, clickType) } - + when (notificationType) { NotificationType.ACTIVITY_MESSAGE -> { binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.ACTIVITY_REPLY -> { binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.FOLLOWING -> { binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.ACTIVITY_MENTION -> { binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.THREAD_COMMENT_MENTION -> { binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.THREAD_SUBSCRIBED -> { binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.THREAD_COMMENT_REPLY -> { binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.AIRING -> { binding.notificationCover.loadImage(notification.media?.coverImage?.large) - binding.notificationBannerImage.loadImage(notification.media?.bannerImage) + image() clickType = NotificationActivity.Companion.NotificationClickType.MEDIA id = notification.media?.id ?: 0 } NotificationType.ACTIVITY_LIKE -> { - binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.ACTIVITY_REPLY_LIKE -> { binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.THREAD_LIKE -> { binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.THREAD_COMMENT_LIKE -> { binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.ACTIVITY_REPLY_SUBSCRIBED -> { binding.notificationCover.loadImage(notification.user?.avatar?.large) - binding.notificationBannerImage.loadImage(notification.user?.bannerImage) + image(true) clickType = NotificationActivity.Companion.NotificationClickType.USER id = notification.user?.id ?: 0 } NotificationType.RELATED_MEDIA_ADDITION -> { binding.notificationCover.loadImage(notification.media?.coverImage?.large) - binding.notificationBannerImage.loadImage(notification.media?.bannerImage) + image() clickType = NotificationActivity.Companion.NotificationClickType.MEDIA id = notification.media?.id ?: 0 } NotificationType.MEDIA_DATA_CHANGE -> { binding.notificationCover.loadImage(notification.media?.coverImage?.large) - binding.notificationBannerImage.loadImage(notification.media?.bannerImage) + image() clickType = NotificationActivity.Companion.NotificationClickType.MEDIA id = notification.media?.id ?: 0 } NotificationType.MEDIA_MERGE -> { binding.notificationCover.loadImage(notification.media?.coverImage?.large) - binding.notificationBannerImage.loadImage(notification.media?.bannerImage) + image() clickType = NotificationActivity.Companion.NotificationClickType.MEDIA id = notification.media?.id ?: 0 } diff --git a/app/src/main/java/ani/dantotsu/profile/activity/NotificationItemBuilder.kt b/app/src/main/java/ani/dantotsu/profile/activity/NotificationItemBuilder.kt index 84911091..c894f65a 100644 --- a/app/src/main/java/ani/dantotsu/profile/activity/NotificationItemBuilder.kt +++ b/app/src/main/java/ani/dantotsu/profile/activity/NotificationItemBuilder.kt @@ -138,11 +138,33 @@ interface NotificationItemBuilder { } } - fun getDateTime(time: Int): String { - val date = Date(time * 1000L) - val sdf = SimpleDateFormat("dd/MM/yyyy hh:mm a", Locale.getDefault()) - return sdf.format(date) - } + fun getDateTime(timestamp: Int): String { + + val targetDate = Date(timestamp * 1000L) + + if (targetDate < Date(946684800000L)) { // January 1, 2000 (who want dates before that?) + return "" + } + + val currentDate = Date() + val difference = currentDate.time - targetDate.time + + return when (val daysDifference = difference / (1000 * 60 * 60 * 24)) { + 0L -> { + val hoursDifference = difference / (1000 * 60 * 60) + val minutesDifference = (difference / (1000 * 60)) % 60 + + when { + hoursDifference > 0 -> "$hoursDifference hour${if (hoursDifference > 1) "s" else ""} ago" + minutesDifference > 0 -> "$minutesDifference minute${if (minutesDifference > 1) "s" else ""} ago" + else -> "Just now" + } + } + 1L -> "1 day ago" + in 2..6 -> "$daysDifference days ago" + else -> SimpleDateFormat("dd MMM yyyy", Locale.getDefault()).format(targetDate) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt b/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt index 5692e047..8a1c9be4 100644 --- a/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt +++ b/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt @@ -23,10 +23,8 @@ import ani.dantotsu.home.MangaFragment import ani.dantotsu.home.NoInternet import ani.dantotsu.incognitoNotification import ani.dantotsu.loadImage -import ani.dantotsu.notifications.NotificationActivity +import ani.dantotsu.profile.activity.NotificationActivity import ani.dantotsu.offline.OfflineFragment -import ani.dantotsu.openLinkInBrowser -import ani.dantotsu.others.imagesearch.ImageSearchActivity import ani.dantotsu.setSafeOnClickListener import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName @@ -79,31 +77,31 @@ class SettingsDialogFragment : BottomSheetDialogFragment() { Anilist.loginIntent(requireActivity()) } } + binding.settingsNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE + binding.settingsNotificationCount.text = Anilist.unreadNotificationCount.toString() binding.settingsUserAvatar.setOnClickListener{ ContextCompat.startActivity( requireContext(), Intent(requireContext(), ProfileActivity::class.java) .putExtra("userId", Anilist.userid), null ) } - binding.settingsIncognito.isChecked = - PrefManager.getVal(PrefName.Incognito) + binding.settingsIncognito.isChecked = PrefManager.getVal(PrefName.Incognito) binding.settingsIncognito.setOnCheckedChangeListener { _, isChecked -> PrefManager.setVal(PrefName.Incognito, isChecked) incognitoNotification(requireContext()) } + binding.settingsExtensionSettings.setSafeOnClickListener { startActivity(Intent(activity, ExtensionsActivity::class.java)) dismiss() } + binding.settingsSettings.setSafeOnClickListener { startActivity(Intent(activity, SettingsActivity::class.java)) dismiss() } - binding.settingsAnilistSettings.setOnClickListener { - openLinkInBrowser("https://anilist.co/settings/lists") - dismiss() - } + binding.settingsNotification.setOnClickListener { startActivity(Intent(activity, NotificationActivity::class.java)) dismiss() diff --git a/app/src/main/res/drawable/notification_circle.xml b/app/src/main/res/drawable/notification_circle.xml index fe33dad2..d864d738 100644 --- a/app/src/main/res/drawable/notification_circle.xml +++ b/app/src/main/res/drawable/notification_circle.xml @@ -1,7 +1,7 @@ - + diff --git a/app/src/main/res/layout/activity_follow.xml b/app/src/main/res/layout/activity_follow.xml index 60df0bc2..ce25a262 100644 --- a/app/src/main/res/layout/activity_follow.xml +++ b/app/src/main/res/layout/activity_follow.xml @@ -15,6 +15,7 @@ android:visibility="gone" /> diff --git a/app/src/main/res/layout/activity_notification.xml b/app/src/main/res/layout/activity_notification.xml deleted file mode 100644 index 047efd00..00000000 --- a/app/src/main/res/layout/activity_notification.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml index 56aa08e2..8c077fe8 100644 --- a/app/src/main/res/layout/activity_profile.xml +++ b/app/src/main/res/layout/activity_profile.xml @@ -67,6 +67,7 @@ android:layout_height="82dp" android:layout_gravity="center" android:backgroundTint="@color/transparent" + app:strokeColor="@color/transparent" app:cardCornerRadius="64dp"> - + android:layout_height="match_parent" + android:background="@drawable/bottom_sheet_background"> + android:layout_height="match_parent" + android:orientation="vertical"> + android:layout_gravity="bottom" + android:orientation="horizontal" + android:padding="16dp"> - + + + + + + + android:layout_marginStart="16dp" + android:layout_weight="1" + android:gravity="center_vertical" + android:minHeight="64dp" + android:orientation="vertical"> - + + + + + + + + android:layout_height="wrap_content"> + + + + + + + + - - - - - - - - - - + + - + android:layout_height="match_parent" + android:layout_marginEnd="58dp" + android:orientation="vertical"> - - +