Merge branch 'dev' into string

This commit is contained in:
rebel onion
2024-03-07 17:35:58 -06:00
committed by GitHub
47 changed files with 1575 additions and 402 deletions

View File

@@ -114,6 +114,16 @@
android:name=".profile.FollowActivity"
android:windowSoftInputMode="adjustResize|stateHidden"
android:parentActivityName=".MainActivity" />
<activity
android:name=".profile.ActivityActivity"
android:label="Inbox Activity"
android:parentActivityName=".MainActivity" >
</activity>
<activity
android:name=".profile.activity.NotificationActivity"
android:label="Inbox Activity"
android:parentActivityName=".MainActivity" >
</activity>
<activity
android:name=".others.imagesearch.ImageSearchActivity"
android:parentActivityName=".MainActivity" />
@@ -221,6 +231,7 @@
<data android:host="discord.dantotsu.com" />
</intent-filter>
</activity>
<activity
android:name=".connections.anilist.UrlMedia"
android:configChanges="orientation|screenSize|layoutDirection"

View File

@@ -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<String>? = null
var tags: Map<Boolean, List<String>>? = null

View File

@@ -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
}
@@ -65,7 +68,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.Media>(query, force = true, show = true)
@@ -136,6 +139,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 +238,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 +260,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"
)
}
}
@@ -1310,4 +1340,12 @@ Page(page:$page,perPage:50) {
default[1] = userBannerImage("MANGA",id)
return default
}
suspend fun getNotifications(id: Int): NotificationResponse? {
val res = executeQuery<NotificationResponse>("""{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
}
}

View File

@@ -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<Notification>,
) : 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<String>?,
@SerialName("context")
val context: String?,
@SerialName("reason")
val reason: String?,
@SerialName("deletedMediaTitle")
val deletedMediaTitle: String?,
@SerialName("deletedMediaTitles")
val deletedMediaTitles: List<String>?,
@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

View File

@@ -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?,

View File

@@ -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?,

View File

@@ -283,7 +283,6 @@ class AnimeFragment : Fragment() {
binding.root.requestApplyInsets()
binding.root.requestLayout()
}
super.onResume()
}
}

View File

@@ -94,6 +94,8 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
SettingsDialogFragment.newInstance(SettingsDialogFragment.Companion.PageType.ANIME)
dialogFragment.show((it.context as AppCompatActivity).supportFragmentManager, "dialog")
}
binding.animeNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
binding.animeNotificationCount.text = Anilist.unreadNotificationCount.toString()
listOf(
binding.animePreviousSeason,

View File

@@ -79,6 +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.homeNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
binding.homeNotificationCount.text = Anilist.unreadNotificationCount.toString()
binding.homeAnimeList.setOnClickListener {
ContextCompat.startActivity(
@@ -305,6 +307,7 @@ class HomeFragment : Fragment() {
}
}
val array = arrayOf(
"AnimeContinue",
"AnimeFav",
@@ -357,9 +360,12 @@ class HomeFragment : Fragment() {
}
}
}
override fun onResume() {
if (!model.loaded) Refresh.activity[1]!!.postValue(true)
if (_binding != null) {
binding.homeNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
binding.homeNotificationCount.text = Anilist.unreadNotificationCount.toString()
}
super.onResume()
}
}

View File

@@ -74,7 +74,8 @@ class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHold
}
updateAvatar()
binding.mangaNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
binding.mangaNotificationCount.text = Anilist.unreadNotificationCount.toString()
binding.mangaSearchBar.hint = "MANGA"
binding.mangaSearchBarText.setOnClickListener {
ContextCompat.startActivity(

View File

@@ -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<String, ArrayList<Media>>? = null
) : Serializable

View File

@@ -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<Author>
) : RecyclerView.Adapter<AuthorAdapter.AuthorViewHolder>() {
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()
)
}
}
}
}

View File

@@ -58,6 +58,7 @@ data class Media(
var endDate: FuzzyDate? = null,
var characters: ArrayList<Character>? = null,
var staff: ArrayList<Author>? = null,
var prequel: Media? = null,
var sequel: Media? = null,
var relations: ArrayList<Media>? = null,

View File

@@ -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<RecyclerView.ViewHolder>() {
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
}
}

View File

@@ -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),

View File

@@ -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()
}

View File

@@ -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)
}
}

View File

@@ -0,0 +1,29 @@
package ani.dantotsu.profile
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.updateLayoutParams
import ani.dantotsu.databinding.ActivityFollowBinding
import ani.dantotsu.initActivity
import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager
class ActivityActivity : AppCompatActivity() {
private lateinit var binding: ActivityFollowBinding
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeManager(this).applyTheme()
initActivity(this)
binding = ActivityFollowBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.listTitle.text = "Activity"
binding.listToolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin = statusBarHeight }
binding.followerGrid.visibility = ViewGroup.GONE
binding.followerList.visibility = ViewGroup.GONE
}
}

View File

@@ -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
@@ -40,24 +34,8 @@ class FollowActivity : AppCompatActivity(){
ThemeManager(this).applyTheme()
initActivity(this)
binding = ActivityFollowBinding.inflate(layoutInflater)
binding.listToolbar.updateLayoutParams<MarginLayoutParams> { topMargin = statusBarHeight }
setContentView(binding.root)
if (!PrefManager.getVal<Boolean>(PrefName.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
)
binding.listTitle.updateLayoutParams<MarginLayoutParams> {
topMargin = statusBarHeight
}
}
val layoutType = PrefManager.getVal<Int>(PrefName.FollowerLayout)
selected = getSelected(layoutType)
binding.followerGrid.alpha = 0.33f

View File

@@ -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,8 +25,19 @@ 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) }
banner?.let { binding.profileBannerImage.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)
}
binding.root.setOnClickListener { clickCallback(id) }
}

View File

@@ -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<ViewGroup.MarginLayoutParams> {
topMargin += statusBarHeight
}
binding.profileMenuButton.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
binding.profileActivityButton.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
binding.profileBannerImage.setOnLongClickListener {
ImageViewDialog.newInstance(
this@ProfileActivity,

View File

@@ -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
@@ -68,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
@@ -118,7 +121,6 @@ class ProfileFragment() : Fragment() {
binding.profileFavAnimeContainer,
binding.profileFavAnimeRecyclerView,
binding.profileFavAnimeProgressBar,
binding.profileFavAnimeEmpty,
binding.profileFavAnime
)
@@ -127,7 +129,6 @@ class ProfileFragment() : Fragment() {
binding.profileFavMangaContainer,
binding.profileFavMangaRecyclerView,
binding.profileFavMangaProgressBar,
binding.profileFavMangaEmpty,
binding.profileFavManga
)
@@ -145,14 +146,14 @@ class ProfileFragment() : Fragment() {
false
)
val favStaff = arrayListOf<Character>()
val favStaff = arrayListOf<Author>()
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,
@@ -184,21 +185,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,
@@ -209,7 +207,7 @@ class ProfileFragment() : Fragment() {
LayoutAnimationController(setSlideIn(), 0.25f)
} else {
empty.visibility = View.VISIBLE
container.visibility = View.GONE
}
title.visibility = View.VISIBLE
title.startAnimation(setSlideUp())
@@ -218,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("&nbsp;", " ")
.replace("&amp;", "&")
.replace("&lt;", "<")
.replace("&gt;", ">")
.replace("&quot;", "\"")
.replace("&apos;", "'")
.replace("<pre>", "")
.replace("`", "")
.replace("~", "")
val step2 = step1.replace("(?s)___(.*?)___".toRegex(), "<br><em><strong>$1</strong></em><br>")
val step3 = step2.replace("(?s)__(.*?)__".toRegex(), "<br><strong>$1</strong><br>")
return """
<html>
<head>
@@ -236,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()};
}
@@ -243,7 +260,7 @@ class ProfileFragment() : Fragment() {
</style>
</head>
<body>
$html
$step3
</body>
""".trimIndent()

View File

@@ -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<ItemNotificationBinding>() {
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)
}
}

View File

@@ -0,0 +1,79 @@
package ani.dantotsu.profile.activity
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.view.ViewGroup
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.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.api.Notification
import ani.dantotsu.databinding.ActivityFollowBinding
import ani.dantotsu.initActivity
import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.profile.ProfileActivity
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: ActivityFollowBinding
private var adapter: GroupieAdapter = GroupieAdapter()
private var notificationList: List<Notification> = emptyList()
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeManager(this).applyTheme()
initActivity(this)
binding = ActivityFollowBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.listTitle.text = "Notifications"
binding.listToolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> { 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()
}
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
}
}
}

View File

@@ -0,0 +1,184 @@
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.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,
val clickCallback: (Int, NotificationActivity.Companion.NotificationClickType) -> Unit
): BindableItem<ItemNotificationBinding>() {
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 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)
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.ACTIVITY_REPLY -> {
binding.notificationCover.loadImage(notification.user?.avatar?.large)
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.FOLLOWING -> {
binding.notificationCover.loadImage(notification.user?.avatar?.large)
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.ACTIVITY_MENTION -> {
binding.notificationCover.loadImage(notification.user?.avatar?.large)
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.THREAD_COMMENT_MENTION -> {
binding.notificationCover.loadImage(notification.user?.avatar?.large)
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.THREAD_SUBSCRIBED -> {
binding.notificationCover.loadImage(notification.user?.avatar?.large)
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.THREAD_COMMENT_REPLY -> {
binding.notificationCover.loadImage(notification.user?.avatar?.large)
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.AIRING -> {
binding.notificationCover.loadImage(notification.media?.coverImage?.large)
image()
clickType = NotificationActivity.Companion.NotificationClickType.MEDIA
id = notification.media?.id ?: 0
}
NotificationType.ACTIVITY_LIKE -> {
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.ACTIVITY_REPLY_LIKE -> {
binding.notificationCover.loadImage(notification.user?.avatar?.large)
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.THREAD_LIKE -> {
binding.notificationCover.loadImage(notification.user?.avatar?.large)
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.THREAD_COMMENT_LIKE -> {
binding.notificationCover.loadImage(notification.user?.avatar?.large)
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.ACTIVITY_REPLY_SUBSCRIBED -> {
binding.notificationCover.loadImage(notification.user?.avatar?.large)
image(true)
clickType = NotificationActivity.Companion.NotificationClickType.USER
id = notification.user?.id ?: 0
}
NotificationType.RELATED_MEDIA_ADDITION -> {
binding.notificationCover.loadImage(notification.media?.coverImage?.large)
image()
clickType = NotificationActivity.Companion.NotificationClickType.MEDIA
id = notification.media?.id ?: 0
}
NotificationType.MEDIA_DATA_CHANGE -> {
binding.notificationCover.loadImage(notification.media?.coverImage?.large)
image()
clickType = NotificationActivity.Companion.NotificationClickType.MEDIA
id = notification.media?.id ?: 0
}
NotificationType.MEDIA_MERGE -> {
binding.notificationCover.loadImage(notification.media?.coverImage?.large)
image()
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
}
}
}
}

View File

@@ -0,0 +1,170 @@
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(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)
}
}
}
}

View File

@@ -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,9 +23,8 @@ import ani.dantotsu.home.MangaFragment
import ani.dantotsu.home.NoInternet
import ani.dantotsu.incognitoNotification
import ani.dantotsu.loadImage
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,32 +77,35 @@ 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(
currContext()!!, Intent(currContext()!!, ProfileActivity::class.java)
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")
binding.settingsNotification.setOnClickListener {
startActivity(Intent(activity, NotificationActivity::class.java))
dismiss()
}
binding.settingsDownloads.isChecked = PrefManager.getVal(PrefName.OfflineMode)
binding.settingsDownloads.setOnCheckedChangeListener { _, isChecked ->
Timer().schedule(300) {

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M19,3L4.99,3c-1.11,0 -1.98,0.89 -1.98,2L3,19c0,1.1 0.88,2 1.99,2L19,21c1.1,0 2,-0.9 2,-2L21,5c0,-1.11 -0.9,-2 -2,-2zM19,15h-4c0,1.66 -1.35,3 -3,3s-3,-1.34 -3,-3L4.99,15L4.99,5L19,5v10z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M19,3L4.99,3c-1.11,0 -1.98,0.9 -1.98,2L3,19c0,1.1 0.88,2 1.99,2L19,21c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,15h-4c0,1.66 -1.35,3 -3,3s-3,-1.34 -3,-3L4.99,15L4.99,5L19,5v10zM16,10h-2L14,7h-4v3L8,10l4,4 4,-4z"/>
</vector>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#C6140A"/>
<size
android:width="100dp"
android:height="100dp"/>
</shape>

View File

@@ -0,0 +1,55 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ProgressBar
android:id="@+id/listProgressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/listBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="12dp"
android:src="@drawable/ic_round_arrow_back_ios_new_24"
app:tint="?attr/colorOnBackground"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/listTitle"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="44dp"
android:ellipsize="end"
android:fontFamily="@font/poppins_bold"
android:gravity="center|start"
android:singleLine="true"
android:text="Activity"
android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"
android:textColor="?attr/colorOnBackground"
android:textSize="18sp"
tools:ignore="HardcodedText" />
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
tools:listitem="@layout/item_activity" />
</LinearLayout>

View File

@@ -15,6 +15,7 @@
android:visibility="gone" />
<FrameLayout
android:id="@+id/listToolbar"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal">
@@ -33,11 +34,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 +88,11 @@
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
tools:listitem="@layout/item_follower" />
</LinearLayout>

View File

@@ -58,8 +58,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:orientation="vertical"
tools:visibility="visible">
android:layout_marginBottom="8dp"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:id="@+id/profileUserAvatarContainer"
@@ -67,6 +67,7 @@
android:layout_height="82dp"
android:layout_gravity="center"
android:backgroundTint="@color/transparent"
app:strokeColor="@color/transparent"
app:cardCornerRadius="64dp">
<com.google.android.material.imageview.ShapeableImageView
@@ -97,28 +98,43 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:backgroundTint="?attr/colorPrimaryContainer"
android:backgroundTint="?attr/colorSecondaryContainer"
android:enabled="true"
android:fontFamily="@font/poppins_bold"
android:text="@string/follow"
android:textColor="@color/bg_opp"
android:textSize="14sp"
app:cornerRadius="8dp"
app:strokeColor="?attr/colorPrimaryContainer"
tools:ignore="SpeakableTextPresentCheck" />
app:strokeColor="?attr/colorSecondaryContainer"
tools:ignore="HardcodedText,SpeakableTextPresentCheck" />
</LinearLayout>
<ImageView
android:id="@+id/profileMenuButton"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="20dp"
android:layout_marginEnd="16dp"
android:contentDescription="@string/menu"
android:src="@drawable/ic_round_dots_vertical_24" />
android:orientation="horizontal">
<ImageView
android:id="@+id/profileActivityButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="8dp"
android:contentDescription="@string/menu"
android:src="@drawable/inbox_empty"
app:tint="@color/bg_opp" />
<ImageView
android:id="@+id/profileMenuButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:contentDescription="@string/menu"
android:src="@drawable/ic_round_dots_vertical_24"
app:tint="@color/bg_opp" />
</LinearLayout>
</FrameLayout>
<androidx.viewpager2.widget.ViewPager2

View File

@@ -2,13 +2,9 @@
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:background="@drawable/bottom_sheet_background"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
android:layout_height="match_parent"
android:background="@drawable/bottom_sheet_background">
<LinearLayout
android:layout_width="match_parent"
@@ -17,178 +13,218 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:orientation="horizontal"
android:padding="16dp">
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:minHeight="64dp"
android:orientation="vertical">
android:layout_gravity="bottom"
android:orientation="horizontal"
android:padding="16dp">
<TextView
android:id="@+id/settingsUsername"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="-4dp"
android:fontFamily="@font/poppins_bold"
android:gravity="center"
android:text="@string/username"
android:textSize="16sp" />
<TextView
android:id="@+id/settingsLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="-16dp"
android:layout_marginTop="-16dp"
android:layout_marginBottom="-16dp"
android:fontFamily="@font/poppins_bold"
android:padding="16dp"
android:text="@string/logout"
android:textColor="?attr/colorSecondary"
android:textSize="14sp" />
</LinearLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/homeUserAvatarContainer"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_marginTop="4dp"
android:backgroundTint="@color/nav_bg_inv"
app:cardCornerRadius="26dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/settingsUserAvatar"
<com.google.android.material.card.MaterialCardView
android:id="@+id/homeUserAvatarContainer"
android:layout_width="52dp"
android:layout_height="52dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_round_person_24"
tools:ignore="ContentDescription,ImageContrastCheck" />
android:layout_marginTop="4dp"
android:backgroundTint="@color/nav_bg_inv"
app:cardCornerRadius="26dp">
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/settingsUserAvatar"
android:layout_width="52dp"
android:layout_height="52dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_round_person_24"
tools:ignore="ContentDescription,ImageContrastCheck" />
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:minHeight="64dp"
android:orientation="vertical">
<TextView
android:id="@+id/settingsUsername"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="-4dp"
android:fontFamily="@font/poppins_bold"
android:gravity="center"
android:text="@string/username"
android:textSize="16sp" />
<TextView
android:id="@+id/settingsLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="-16dp"
android:layout_marginTop="-16dp"
android:layout_marginBottom="-16dp"
android:fontFamily="@font/poppins_bold"
android:padding="16dp"
android:text="@string/logout"
android:textColor="?attr/colorSecondary"
android:textSize="14sp" />
</LinearLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.google.android.material.card.MaterialCardView
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="16dp"
android:backgroundTint="@color/nav_bg_inv"
app:cardCornerRadius="26dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/settingsNotification"
android:layout_width="52dp"
android:layout_height="52dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_round_notifications_active_24"
app:tint="@color/bg_opp"
tools:ignore="ContentDescription,ImageContrastCheck" />
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/settingsNotificationCount"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_gravity="end|bottom"
android:background="@drawable/notification_circle"
android:fontFamily="@font/poppins_semi_bold"
android:gravity="center"
android:textColor="#F3F3F3"
android:textSize="12sp"
android:visibility="gone"
tools:ignore="SmallSp"
tools:text="1"
tools:visibility="visible" />
</FrameLayout>
</LinearLayout>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/settingsIncognito"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:checked="false"
android:drawableStart="@drawable/ic_incognito_24"
android:drawablePadding="16dp"
android:elegantTextHeight="true"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="@string/incognito_mode"
android:textAlignment="viewStart"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:drawableTint="?attr/colorPrimary"
app:showText="false"
app:thumbTint="@color/button_switch_track" />
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/settingsDownloads"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:checked="false"
android:drawableStart="@drawable/ic_download_24"
android:drawablePadding="16dp"
android:elegantTextHeight="true"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="@string/offline_mode"
android:textAlignment="viewStart"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:drawableTint="?attr/colorPrimary"
app:showText="false"
app:thumbTint="@color/button_switch_track" />
</LinearLayout>
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/settingsIncognito"
style="@style/Widget.Material3.Button.TextButton"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="64dp"
android:checked="false"
android:drawableStart="@drawable/ic_incognito_24"
android:drawablePadding="16dp"
android:elegantTextHeight="true"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="@string/incognito_mode"
android:textAlignment="viewStart"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:drawableTint="?attr/colorPrimary"
app:showText="false"
app:thumbTint="@color/button_switch_track" />
android:layout_height="match_parent"
android:layout_marginEnd="58dp"
android:orientation="vertical">
<com.google.android.material.materialswitch.MaterialSwitch
android:id="@+id/settingsDownloads"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:checked="false"
android:drawableStart="@drawable/ic_download_24"
android:drawablePadding="16dp"
android:elegantTextHeight="true"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="@string/offline_mode"
android:textAlignment="viewStart"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:drawableTint="?attr/colorPrimary"
app:showText="false"
app:thumbTint="@color/button_switch_track" />
</LinearLayout>
<Button
android:id="@+id/settingsActivity"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="Activity"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/inbox_empty"
app:iconPadding="16dp"
app:iconSize="24dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="58dp"
android:orientation="vertical">
<Button
android:id="@+id/settingsExtensionSettings"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="@string/extension_settings"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/ic_extension"
app:iconPadding="16dp"
app:iconSize="24dp" />
<Button
android:id="@+id/settingsAnilistSettings"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="@string/anilist_settings"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/ic_anilist"
app:iconPadding="16dp"
app:iconSize="24dp" />
<Button
android:id="@+id/settingsExtensionSettings"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="@string/extension_settings"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/ic_extension"
app:iconPadding="16dp"
app:iconSize="24dp" />
<Button
android:id="@+id/settingsSettings"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginBottom="16dp"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="@string/settings"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/ic_round_settings_24"
app:iconPadding="16dp"
app:iconSize="24dp" />
</LinearLayout>
<Button
android:id="@+id/settingsSettings"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="match_parent"
android:layout_height="64dp"
android:layout_marginBottom="16dp"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="@string/settings"
android:textAlignment="viewStart"
android:textAllCaps="false"
android:textColor="?attr/colorOnBackground"
app:cornerRadius="0dp"
app:icon="@drawable/ic_round_settings_24"
app:iconPadding="16dp"
app:iconSize="24dp" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -135,23 +135,43 @@
</FrameLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/homeUserAvatarContainer"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_marginTop="4dp"
android:backgroundTint="@color/nav_bg_inv"
app:cardCornerRadius="26dp">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/homeUserAvatar"
<com.google.android.material.card.MaterialCardView
android:id="@+id/homeUserAvatarContainer"
android:layout_width="52dp"
android:layout_height="52dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_round_settings_24"
tools:ignore="ContentDescription,ImageContrastCheck" />
android:layout_marginTop="4dp"
android:backgroundTint="@color/nav_bg_inv"
app:cardCornerRadius="26dp">
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/homeUserAvatar"
android:layout_width="52dp"
android:layout_height="52dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_round_settings_24"
tools:ignore="ContentDescription,ImageContrastCheck" />
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/homeNotificationCount"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_gravity="end|bottom"
android:background="@drawable/notification_circle"
android:fontFamily="@font/poppins_semi_bold"
android:gravity="center"
android:textColor="#F3F3F3"
android:textSize="12sp"
android:visibility="gone"
tools:ignore="SmallSp"
tools:text="1"
tools:visibility="visible" />
</FrameLayout>
</LinearLayout>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -143,10 +143,11 @@
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:padding="8dp"
android:fontFamily="@font/poppins_bold"
android:text="@string/stats"
android:textSize="18sp"/>
android:padding="8dp"
android:textSize="18sp"
tools:ignore="HardcodedText" />
<TableLayout
android:layout_width="match_parent"
@@ -332,8 +333,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">
<TextView
android:id="@+id/profileUserBioTitle"
@@ -342,21 +343,22 @@
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:padding="8dp"
android:fontFamily="@font/poppins_bold"
android:text="@string/about_me"
android:padding="8dp"
android:text="Bio"
android:textSize="18sp"/>
<WebView
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" />
</LinearLayout>
@@ -365,8 +367,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
android:visibility="gone">
<TextView
@@ -381,36 +382,7 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="250dp">
<LinearLayout
android:id="@+id/profileFavAnimeEmpty"
android:layout_width="match_parent"
android:layout_height="250dp"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="match_parent"
android:layout_height="32dp"
android:src="@drawable/ic_round_heart_broken_24"
app:tint="?attr/colorPrimary"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.58"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="@string/no_fav_anime"
android:textAlignment="center"
tools:ignore="TextContrastCheck" />
</LinearLayout>
android:layout_height="wrap_content">
<ProgressBar
android:id="@+id/profileFavAnimeProgressBar"
@@ -442,7 +414,6 @@
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="@+id/profileFavManga"
android:layout_width="wrap_content"
@@ -455,36 +426,7 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="250dp">
<LinearLayout
android:id="@+id/profileFavMangaEmpty"
android:layout_width="match_parent"
android:layout_height="250dp"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="match_parent"
android:layout_height="32dp"
android:src="@drawable/ic_round_heart_broken_24"
app:tint="?attr/colorPrimary"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.58"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="@string/no_fav_manga"
android:textAlignment="center"
tools:ignore="TextContrastCheck" />
</LinearLayout>
android:layout_height="wrap_content">
<ProgressBar
android:id="@+id/profileFavMangaProgressBar"
@@ -508,21 +450,23 @@
tools:orientation="horizontal" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/profileFavCharactersContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:padding="8dp"
android:fontFamily="@font/poppins_bold"
android:text="@string/fav_character"
android:padding="8dp"
android:textSize="18sp" />
<ani.dantotsu.FadingEdgeRecyclerView
@@ -546,15 +490,16 @@
android:layout_height="wrap_content"
android:orientation="vertical"
tools:visibility="gone">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="32dp"
android:padding="8dp"
android:fontFamily="@font/poppins_bold"
android:text="@string/fav_staff"
android:padding="8dp"
android:textSize="18sp" />
<ani.dantotsu.FadingEdgeRecyclerView

View File

@@ -0,0 +1,156 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.card.MaterialCardView
android:id="@+id/activityAvatarContainer"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="16dp"
android:backgroundTint="@color/bg_white"
app:cardCornerRadius="64dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/activityUserAvatar"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:ignore="ContentDescription,ImageContrastCheck"
tools:tint="@color/transparent" />
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/activityUserName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="Username"
android:textSize="15sp"
tools:ignore="HardcodedText,RtlSymmetry" />
<TextView
android:id="@+id/activityTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold"
android:text="Wed,06 March 2024, 7:00PM"
android:textSize="14sp"
tools:ignore="HardcodedText" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center"
android:layout_marginEnd="16dp"
android:src="@drawable/ic_round_favorite_24"
tools:ignore="ContentDescription" />
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_marginTop="8dp">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:backgroundTint="@color/bg_white"
app:cardCornerRadius="24dp">
<ImageView
android:id="@+id/activityBannerImage"
android:layout_width="match_parent"
android:layout_height="153dp"
android:scaleType="centerCrop"
tools:srcCompat="@tools:sample/backgrounds/scenic"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="153dp"
app:srcCompat="@drawable/linear_gradient_nav"
tools:ignore="ContentDescription" />
<com.google.android.material.card.MaterialCardView
android:id="@+id/activityCoverContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="16dp"
android:backgroundTint="@color/bg_white"
app:cardCornerRadius="16dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/activityCover"
android:layout_width="102dp"
android:layout_height="154dp"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:ignore="ContentDescription,ImageContrastCheck"
tools:tint="@color/transparent" />
</com.google.android.material.card.MaterialCardView>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="128dp"
android:layout_marginEnd="8dp"
android:orientation="vertical">
<TextView
android:id="@+id/activityMediaName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:fontFamily="@font/poppins_semi_bold"
android:maxLines="2"
android:text="@string/anime"
android:textColor="@color/bg_white"
android:textSize="14sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/activityText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/slogan"
android:textColor="@color/bg_white"
android:textSize="14sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</FrameLayout>
</LinearLayout>

View File

@@ -59,26 +59,43 @@
tools:ignore="LabelFor,TextContrastCheck" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/animeUserAvatarContainer"
android:layout_width="52dp"
android:layout_height="match_parent"
android:layout_marginTop="4dp"
app:cardBackgroundColor="?attr/colorPrimaryContainer"
app:cardCornerRadius="26dp"
app:strokeColor="@color/text_input_layout_stroke_color">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/animeUserAvatar"
<com.google.android.material.card.MaterialCardView
android:id="@+id/animeUserAvatarContainer"
android:layout_width="52dp"
android:layout_height="52dp"
android:scaleType="center"
android:tint="@color/bg_opp"
app:srcCompat="@drawable/ic_round_settings_24"
tools:ignore="ContentDescription,ImageContrastCheck" />
android:layout_marginTop="4dp"
android:backgroundTint="@color/nav_bg_inv"
app:cardCornerRadius="26dp">
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/animeUserAvatar"
android:layout_width="52dp"
android:layout_height="52dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_round_settings_24"
tools:ignore="ContentDescription,ImageContrastCheck" />
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/animeNotificationCount"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_gravity="end|bottom"
android:background="@drawable/notification_circle"
android:fontFamily="@font/poppins_semi_bold"
android:gravity="center"
android:textColor="#F3F3F3"
android:textSize="12sp"
android:visibility="gone"
tools:ignore="SmallSp"
tools:text="1"
tools:visibility="visible" />
</FrameLayout>
</LinearLayout>
<ProgressBar

View File

@@ -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" />
</LinearLayout>

View File

@@ -1,49 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="120dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="horizontal">
<com.google.android.material.card.MaterialCardView
android:id="@+id/profile"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="80dp"
android:layout_gravity="start|center_vertical"
android:backgroundTint="@color/bg_white"
app:cardCornerRadius="32dp">
app:cardCornerRadius="24dp">
<ImageView
android:id="@+id/profileBannerImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/linear_gradient_bg"
tools:srcCompat="@tools:sample/backgrounds/scenic"
tools:ignore="ContentDescription" />
<View
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg_black_50"
app:srcCompat="@drawable/linear_gradient_nav"
tools:ignore="ContentDescription" />
<com.google.android.material.card.MaterialCardView
android:id="@+id/profileUserAvatarContainer"
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="16dp"
android:backgroundTint="@color/bg_white"
android:backgroundTint="@color/transparent"
app:strokeColor="@color/transparent"
app:cardCornerRadius="64dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profileUserAvatar"
android:layout_width="82dp"
android:layout_height="82dp"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:tint="@color/transparent"
tools:ignore="ContentDescription,ImageContrastCheck" />
tools:ignore="ContentDescription,ImageContrastCheck"
tools:tint="@color/transparent" />
</com.google.android.material.card.MaterialCardView>

View File

@@ -61,25 +61,43 @@
tools:ignore="LabelFor,TextContrastCheck" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.card.MaterialCardView
android:id="@+id/mangaUserAvatarContainer"
android:layout_width="52dp"
android:layout_height="match_parent"
android:layout_marginTop="4dp"
app:cardBackgroundColor="?attr/colorPrimaryContainer"
app:cardCornerRadius="26dp"
app:strokeColor="@color/text_input_layout_stroke_color">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/mangaUserAvatar"
<com.google.android.material.card.MaterialCardView
android:id="@+id/mangaUserAvatarContainer"
android:layout_width="52dp"
android:layout_height="52dp"
android:scaleType="center"
android:tint="@color/bg_opp"
app:srcCompat="@drawable/ic_round_settings_24"
tools:ignore="ContentDescription,ImageContrastCheck" />
android:layout_marginTop="4dp"
android:backgroundTint="@color/nav_bg_inv"
app:cardCornerRadius="26dp">
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/mangaUserAvatar"
android:layout_width="52dp"
android:layout_height="52dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_round_settings_24"
tools:ignore="ContentDescription,ImageContrastCheck" />
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/mangaNotificationCount"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_gravity="end|bottom"
android:background="@drawable/notification_circle"
android:fontFamily="@font/poppins_semi_bold"
android:gravity="center"
android:textColor="#F3F3F3"
android:textSize="12sp"
android:visibility="gone"
tools:ignore="SmallSp"
tools:text="1"
tools:visibility="visible" />
</FrameLayout>
</LinearLayout>

View File

@@ -94,9 +94,11 @@
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginBottom="4dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
@@ -113,7 +115,7 @@
android:layout_height="wrap_content"
android:alpha="0.58"
android:ellipsize="end"
android:maxLines="1"
android:maxLines="2"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:singleLine="true"
@@ -123,7 +125,7 @@
android:textStyle="italic"
android:transitionName="mediaTitle"
tools:ignore="TextContrastCheck"
tools:text="Relation " />
tools:text="Relation" />
</LinearLayout>
@@ -149,6 +151,7 @@
tools:text="@string/get_recommendations" />
<LinearLayout
android:id="@+id/itemCompactProgressContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">

View File

@@ -9,7 +9,6 @@
app:cardBackgroundColor="@color/nav_bg"
app:cardCornerRadius="28dp">
<ImageView
android:id="@+id/itemCompactBanner"
android:layout_width="match_parent"

View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/notificationContainer"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:orientation="horizontal">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
app:cardBackgroundColor="@color/nav_bg"
app:cardCornerRadius="24dp">
<ImageView
android:id="@+id/notificationBannerImage"
android:layout_width="match_parent"
android:layout_height="170dp"
android:scaleType="centerCrop"
tools:srcCompat="@tools:sample/backgrounds/scenic"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/notificationBannerGradient"
android:layout_width="match_parent"
android:layout_height="170dp"
app:srcCompat="@drawable/linear_gradient_nav"
tools:ignore="ContentDescription" />
<com.google.android.material.card.MaterialCardView
android:id="@+id/notificationCoverContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="16dp"
android:backgroundTint="@color/transparent"
app:strokeColor="@color/transparent"
app:cardCornerRadius="16dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/notificationCover"
android:layout_width="96dp"
android:layout_height="144dp"
android:layout_gravity="center"
android:scaleType="centerCrop"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:ignore="ContentDescription,ImageContrastCheck"
tools:tint="@color/transparent" />
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/notificationCoverUserContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="23dp"
android:backgroundTint="@color/transparent"
app:strokeColor="@color/transparent"
app:cardCornerRadius="64dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/notificationCoverUser"
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_gravity="center"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:ignore="ContentDescription,ImageContrastCheck"
tools:tint="@color/transparent" />
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/notificationText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="end|center"
android:layout_marginStart="128dp"
android:padding="8dp"
android:ellipsize="end"
android:fontFamily="@font/poppins_semi_bold"
android:maxLines="2"
android:textSize="14dp"
android:transitionName="mediaTitle"
tools:ignore="SpUsage"
tools:text="@string/slogan" />
<TextView
android:id="@+id/notificationDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_marginTop="2dp"
android:layout_marginEnd="12dp"
android:fontFamily="@font/poppins_semi_bold"
android:text="Wed,06 March 2024, 7:00PM"
android:textSize="10sp"
tools:ignore="HardcodedText" />
</com.google.android.material.card.MaterialCardView>
</FrameLayout>

View File

@@ -123,6 +123,7 @@
<string name="description">Synopsis</string>
<string name="characters">Characters</string>
<string name="relations">Relations</string>
<string name="staff">Staff</string>
<string name="roles">Roles</string>
<string name="details">Details</string>