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] 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" />