From 3af7926d20c6340d31a16bcbb4b35b0e433becd2 Mon Sep 17 00:00:00 2001
From: rebelonion <87634197+rebelonion@users.noreply.github.com>
Date: Fri, 8 Mar 2024 22:04:25 -0600
Subject: [PATCH 1/6] feat: text activity
---
.../dantotsu/profile/activity/ActivityItem.kt | 33 ++++++++----
app/src/main/res/layout/item_activity.xml | 50 +++++++++++++++++--
app/src/main/res/values/strings.xml | 10 +++-
3 files changed, 80 insertions(+), 13 deletions(-)
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
index 7860d93e..ee7481c6 100644
--- a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
+++ b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
@@ -4,6 +4,7 @@ import android.content.Context
import android.view.View
import androidx.core.content.ContextCompat
import ani.dantotsu.R
+import ani.dantotsu.buildMarkwon
import ani.dantotsu.connections.anilist.api.Activity
import ani.dantotsu.databinding.ItemActivityBinding
import ani.dantotsu.loadImage
@@ -21,21 +22,27 @@ class ActivityItem(
private lateinit var binding: ItemActivityBinding
override fun bind(viewBinding: ItemActivityBinding, position: Int) {
binding = viewBinding
+
+ binding.activityUserName.text = activity.user?.name
+ binding.activityUserAvatar.loadImage(activity.user?.avatar?.medium)
+ binding.activityTime.text = ActivityItemBuilder.getDateTime(activity.createdAt)
+ val color = if (activity.isLiked == true)
+ ContextCompat.getColor(binding.root.context, R.color.yt_red)
+ else
+ ContextCompat.getColor(binding.root.context, R.color.bg_opp)
+ binding.activityFavorite.setColorFilter(color)
+ binding.commentRepliesContainer.visibility = if (activity.replyCount > 0) View.VISIBLE else View.GONE
+
+ val context = binding.root.context
+
when (activity.typename) {
"ListActivity" ->{
- binding.activityUserName.text = activity.user?.name
- binding.activityUserAvatar.loadImage(activity.user?.avatar?.medium)
- binding.activityTime.text = ActivityItemBuilder.getDateTime(activity.createdAt)
- val color = if (activity.isLiked == true)
- ContextCompat.getColor(binding.root.context, R.color.yt_red)
- else
- ContextCompat.getColor(binding.root.context, R.color.bg_opp)
- binding.activityFavorite.setColorFilter(color)
+ binding.activityContent.visibility = View.GONE
+ binding.activityBannerContainer.visibility = View.VISIBLE
binding.activityMediaName.text = activity.media?.title?.userPreferred
binding.activityText.text = "${activity.user!!.name} ${activity.status} ${activity.media!!.title!!.userPreferred}"
binding.activityCover.loadImage(activity.media.coverImage?.medium)
- val context = binding.root.context
val banner = activity.media.bannerImage
if (banner != null) {
if (!(context as android.app.Activity).isDestroyed)
@@ -48,6 +55,14 @@ class ActivityItem(
binding.activityBannerImage.setImageResource(R.drawable.linear_gradient_bg)
}
}
+ "TextActivity" -> {
+ binding.activityBannerContainer.visibility = View.GONE
+ binding.activityContent.visibility = View.VISIBLE
+ if (!(context as android.app.Activity).isDestroyed) {
+ val markwon = buildMarkwon(context, false)
+ markwon.setMarkdown(binding.activityContent, activity.text ?: "")
+ }
+ }
}
}
diff --git a/app/src/main/res/layout/item_activity.xml b/app/src/main/res/layout/item_activity.xml
index eb63b17a..2220d60e 100644
--- a/app/src/main/res/layout/item_activity.xml
+++ b/app/src/main/res/layout/item_activity.xml
@@ -5,6 +5,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
+ android:background="?attr/colorSurface"
android:orientation="vertical">
+
+
+ tools:ignore="ContentDescription"
+ tools:srcCompat="@tools:sample/backgrounds/scenic" />
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 89cc8d51..5a16848f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -684,5 +684,13 @@
Manga Mean Score
About me
Follow
-
+
+
+Lorem ipsum dolor sit amet. Est consectetur sint qui internos optio nam Quis excepturi qui voluptatem animi. Qui labore quasi vel suscipit deleniti et doloremque omnis in velit suscipit et quasi eaque. Et doloribus recusandae id laudantium Quis qui natus velit in voluptatem voluptatem!
+
+Et magni quasi vel nemo omnis et voluptate quisquam vel corporis fuga ut consequatur voluptas At quis veniam. At assumenda illum id minus veritatis id consequatur ipsum est quod corrupti quo adipisci sint. Quo explicabo doloribus et excepturi internos est reiciendis laboriosam ut explicabo veniam ut culpa mollitia in ducimus sint aut autem voluptatem! In consectetur laudantium non omnis saepe nam sint fuga.
+
+Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exercitationem adipisci quo nemo aliquam ea numquam beatae. Eum Quis dolore aut quia accusantium sed vero autem vel quaerat eaque et beatae dicta non delectus galisum non ullam nulla.
+
+
From 98f4d4f30b71c043c232464decdfd2dbfff96fb0 Mon Sep 17 00:00:00 2001
From: rebelonion <87634197+rebelonion@users.noreply.github.com>
Date: Sat, 9 Mar 2024 04:33:06 -0600
Subject: [PATCH 2/6] feat: global/personal feed | like posts | pagination
---
app/src/main/AndroidManifest.xml | 2 +-
app/src/main/java/ani/dantotsu/Functions.kt | 4 +-
.../connections/anilist/AnilistQueries.kt | 21 +++-
.../dantotsu/connections/anilist/api/Feed.kt | 32 +++--
.../ani/dantotsu/profile/FollowActivity.kt | 2 +
.../ani/dantotsu/profile/ProfileActivity.kt | 26 ++--
.../ani/dantotsu/profile/ProfileFragment.kt | 2 +-
.../profile/activity/ActivityActivity.kt | 60 ----------
.../dantotsu/profile/activity/ActivityItem.kt | 57 +++++++--
.../dantotsu/profile/activity/FeedActivity.kt | 81 +++++++++++++
.../dantotsu/profile/activity/FeedFragment.kt | 111 ++++++++++++++++++
.../profile/activity/NotificationActivity.kt | 33 +++++-
.../settings/SettingsDialogFragment.kt | 6 +
app/src/main/res/drawable/ic_globe_24.xml | 10 ++
...ctivity_activity.xml => activity_feed.xml} | 50 +++++---
app/src/main/res/layout/activity_follow.xml | 27 ++++-
app/src/main/res/layout/activity_profile.xml | 10 +-
app/src/main/res/layout/fragment_feed.xml | 44 ++++++-
app/src/main/res/layout/item_activity.xml | 4 +-
19 files changed, 438 insertions(+), 144 deletions(-)
delete mode 100644 app/src/main/java/ani/dantotsu/profile/activity/ActivityActivity.kt
create mode 100644 app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt
create mode 100644 app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt
create mode 100644 app/src/main/res/drawable/ic_globe_24.xml
rename app/src/main/res/layout/{activity_activity.xml => activity_feed.xml} (50%)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8590ff4d..12e7eccc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -115,7 +115,7 @@
android:windowSoftInputMode="adjustResize|stateHidden"
android:parentActivityName=".MainActivity" />
diff --git a/app/src/main/java/ani/dantotsu/Functions.kt b/app/src/main/java/ani/dantotsu/Functions.kt
index 683263a7..67af749c 100644
--- a/app/src/main/java/ani/dantotsu/Functions.kt
+++ b/app/src/main/java/ani/dantotsu/Functions.kt
@@ -28,6 +28,7 @@ import android.telephony.TelephonyManager
import android.text.InputFilter
import android.text.Spanned
import android.util.AttributeSet
+import android.util.Log
import android.util.TypedValue
import android.view.*
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
@@ -129,7 +130,8 @@ var loadIsMAL = false
fun logger(e: Any?, print: Boolean = true) {
if (print)
- println(e)
+ //println(e)
+ Log.d("Logger", e.toString())
}
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 91244488..e1b52dba 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
@@ -8,10 +8,10 @@ import ani.dantotsu.connections.anilist.Anilist.authorRoles
import ani.dantotsu.connections.anilist.Anilist.executeQuery
import ani.dantotsu.connections.anilist.api.FeedResponse
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.connections.anilist.api.ToggleLike
import ani.dantotsu.currContext
import ani.dantotsu.isOnline
import ani.dantotsu.logError
@@ -1265,10 +1265,15 @@ Page(page:$page,perPage:50) {
}
suspend fun toggleFollow(id: Int): Query.ToggleFollow? {
- val response = executeQuery(
+ return executeQuery(
"""mutation{ToggleFollow(userId:$id){id, isFollowing, isFollower}}"""
)
- return response
+ }
+
+ suspend fun toggleLike(id: Int, type: String): ToggleLike? {
+ return executeQuery(
+ """mutation Like{ToggleLikeV2(id:$id,type:$type){__typename}}"""
+ )
}
suspend fun getUserProfile(id: Int): Query.UserProfileResponse? {
@@ -1342,8 +1347,8 @@ Page(page:$page,perPage:50) {
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)
+ suspend fun getNotifications(id: Int, page: Int = 1): NotificationResponse? {
+ val res = executeQuery("""{User(id:$id){unreadNotificationCount}Page(page:$page,perPage:$ITEMS_PER_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
}
@@ -1354,7 +1359,11 @@ Page(page:$page,perPage:50) {
val filter = if (userId != null) "userId:$userId,"
else if (global) "isFollowing:false,"
else "isFollowing:true,"
- val res = executeQuery("""{Page(page:$page,perPage:25){activities(${filter}sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id title{english romaji native userPreferred}bannerImage coverImage{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id recipientId messengerId type replyCount message(asHtml:true)isLocked isSubscribed isLiked isPrivate siteUrl createdAt recipient{id name bannerImage avatar{medium large}}messenger{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}}}}""")
+ val res = executeQuery("""{Page(page:$page,perPage:$ITEMS_PER_PAGE){activities(${filter}sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id title{english romaji native userPreferred}bannerImage coverImage{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id recipientId messengerId type replyCount message(asHtml:true)isLocked isSubscribed isLiked isPrivate siteUrl createdAt recipient{id name bannerImage avatar{medium large}}messenger{id name bannerImage avatar{medium large}}replies{id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}likes{id name bannerImage avatar{medium large}}}}}}""")
return res
}
+
+ companion object {
+ const val ITEMS_PER_PAGE = 25
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt b/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt
index ca31d6f9..b8cc5cc9 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt
@@ -7,19 +7,19 @@ import kotlinx.serialization.Serializable
data class FeedResponse(
@SerialName("data")
val data: Data
-) {
+) : java.io.Serializable {
@Serializable
data class Data(
@SerialName("Page")
val page: ActivityPage
- )
+ ) : java.io.Serializable
}
@Serializable
data class ActivityPage(
@SerialName("activities")
val activities: List
-)
+) : java.io.Serializable
@Serializable
data class Activity(
@@ -52,9 +52,9 @@ data class Activity(
@SerialName("isSubscribed")
val isSubscribed: Boolean,
@SerialName("likeCount")
- val likeCount: Int?,
+ var likeCount: Int?,
@SerialName("isLiked")
- val isLiked: Boolean?,
+ var isLiked: Boolean?,
@SerialName("isPinned")
val isPinned: Boolean?,
@SerialName("isPrivate")
@@ -69,7 +69,7 @@ data class Activity(
val replies: List?,
@SerialName("likes")
val likes: List?,
-)
+) : java.io.Serializable
@Serializable
data class Reply(
@@ -89,4 +89,22 @@ data class Reply(
val user: User,
@SerialName("likes")
val likes: List?,
-)
\ No newline at end of file
+) : java.io.Serializable
+
+@Serializable
+data class ToggleLike(
+ @SerialName("data")
+ val data: Data
+) : java.io.Serializable {
+ @Serializable
+ data class Data(
+ @SerialName("ToggleLikeV2")
+ val toggleLike: LikeData
+ ) : java.io.Serializable
+}
+
+@Serializable
+data class LikeData(
+ @SerialName("__typename")
+ val typename: String
+) : java.io.Serializable
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt b/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt
index fa30f6a3..daa984bc 100644
--- a/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt
+++ b/app/src/main/java/ani/dantotsu/profile/FollowActivity.kt
@@ -14,6 +14,7 @@ import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.api.User
import ani.dantotsu.databinding.ActivityFollowBinding
import ani.dantotsu.initActivity
+import ani.dantotsu.navBarHeight
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.statusBarHeight
@@ -36,6 +37,7 @@ class FollowActivity : AppCompatActivity(){
initActivity(this)
binding = ActivityFollowBinding.inflate(layoutInflater)
binding.listToolbar.updateLayoutParams { topMargin = statusBarHeight }
+ binding.listFrameLayout.updateLayoutParams { bottomMargin = navBarHeight }
setContentView(binding.root)
val layoutType = PrefManager.getVal(PrefName.FollowerLayout)
selected = getSelected(layoutType)
diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt
index b180a833..a7f8216d 100644
--- a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt
+++ b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt
@@ -22,7 +22,7 @@ import ani.dantotsu.initActivity
import ani.dantotsu.loadImage
import ani.dantotsu.navBarHeight
import ani.dantotsu.others.ImageViewDialog
-import ani.dantotsu.profile.activity.ActivityActivity
+import ani.dantotsu.profile.activity.FeedFragment
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
@@ -36,8 +36,8 @@ import nl.joery.animatedbottombar.AnimatedBottomBar
class ProfileActivity : AppCompatActivity() {
- private lateinit var binding: ActivityProfileBinding
- private var selected: Int = 0
+ lateinit var binding: ActivityProfileBinding
+ private var selected: Int = 1
private lateinit var navBar: AnimatedBottomBar
@SuppressLint("SetTextI18n")
@@ -49,8 +49,10 @@ class ProfileActivity : AppCompatActivity() {
setContentView(binding.root)
navBar = binding.profileNavBar
navBar.updateLayoutParams { bottomMargin = navBarHeight }
+ val feedTab = navBar.createTab(R.drawable.ic_round_filter_24, "Feed")
val profileTab = navBar.createTab(R.drawable.ic_round_person_24, "Profile")
val statsTab = navBar.createTab(R.drawable.ic_stats_24, "Stats")
+ navBar.addTab(feedTab)
navBar.addTab(profileTab)
navBar.addTab(statsTab)
navBar.visibility = View.GONE
@@ -70,6 +72,7 @@ class ProfileActivity : AppCompatActivity() {
}
binding.profileViewPager.adapter =
ViewPagerAdapter(supportFragmentManager, lifecycle, user)
+ binding.profileViewPager.setCurrentItem(selected, false)
navBar.visibility = View.VISIBLE
navBar.selectTabAt(selected)
navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
@@ -106,15 +109,6 @@ 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)
@@ -161,7 +155,6 @@ class ProfileActivity : AppCompatActivity() {
binding.profileBannerImage.updateLayoutParams { height += statusBarHeight }
binding.profileBannerGradient.updateLayoutParams { height += statusBarHeight }
binding.profileMenuButton.updateLayoutParams { topMargin += statusBarHeight }
- binding.profileActivityButton.updateLayoutParams { topMargin += statusBarHeight }
binding.profileBannerImage.setOnLongClickListener {
ImageViewDialog.newInstance(
this@ProfileActivity,
@@ -188,10 +181,11 @@ class ProfileActivity : AppCompatActivity() {
) :
FragmentStateAdapter(fragmentManager, lifecycle) {
- override fun getItemCount(): Int = 2
+ override fun getItemCount(): Int = 3
override fun createFragment(position: Int): Fragment = when (position) {
- 0 -> ProfileFragment.newInstance(user)
- 1 -> StatsFragment.newInstance(user)
+ 0 -> FeedFragment.newInstance(user.id, false)
+ 1 -> ProfileFragment.newInstance(user)
+ 2 -> StatsFragment.newInstance(user)
else -> ProfileFragment.newInstance(user)
}
}
diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt
index afb62d82..340c415f 100644
--- a/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt
+++ b/app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt
@@ -32,7 +32,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-class ProfileFragment() : Fragment() {
+class ProfileFragment : Fragment() {
lateinit var binding: FragmentProfileBinding
private lateinit var activity: ProfileActivity
private lateinit var user: Query.UserProfile
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/ActivityActivity.kt b/app/src/main/java/ani/dantotsu/profile/activity/ActivityActivity.kt
deleted file mode 100644
index a9482820..00000000
--- a/app/src/main/java/ani/dantotsu/profile/activity/ActivityActivity.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-package ani.dantotsu.profile.activity
-
-import android.annotation.SuppressLint
-import android.os.Bundle
-import android.view.ViewGroup
-import androidx.appcompat.app.AppCompatActivity
-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.Activity
-import ani.dantotsu.databinding.ActivityFollowBinding
-import ani.dantotsu.initActivity
-import ani.dantotsu.statusBarHeight
-import ani.dantotsu.themes.ThemeManager
-import com.xwray.groupie.GroupieAdapter
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-
-class ActivityActivity : AppCompatActivity() {
- private lateinit var binding: ActivityFollowBinding
- private var adapter: GroupieAdapter = GroupieAdapter()
- private var activityList: List = 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 = "Activity"
- binding.listToolbar.updateLayoutParams { topMargin = statusBarHeight }
- binding.listRecyclerView.adapter = adapter
- binding.listRecyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
- binding.followerGrid.visibility = ViewGroup.GONE
- binding.followerList.visibility = ViewGroup.GONE
- binding.listBack.setOnClickListener {
- onBackPressed()
- }
- binding.listProgressBar.visibility = ViewGroup.VISIBLE
- var userId: Int? = intent.getIntExtra("userId", -1)
- if (userId == -1) userId = null
- val global = intent.getBooleanExtra("global", false)
-
- lifecycleScope.launch(Dispatchers.IO) {
- val res = Anilist.query.getFeed(userId, global)
-
- withContext(Dispatchers.Main){
- res?.data?.page?.activities?.let { activities ->
- activityList = activities
- adapter.update(activityList.map { ActivityItem(it){} })
- }
- binding.listProgressBar.visibility = ViewGroup.GONE
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
index 5744c6c6..c69d5950 100644
--- a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
+++ b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt
@@ -6,21 +6,29 @@ import android.view.View
import androidx.core.content.ContextCompat
import ani.dantotsu.R
import ani.dantotsu.buildMarkwon
+import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.api.Activity
import ani.dantotsu.databinding.ItemActivityBinding
import ani.dantotsu.loadImage
+import ani.dantotsu.snackString
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
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
class ActivityItem(
private val activity: Activity,
- val clickCallback: (Int) -> Unit
-): BindableItem() {
+ val clickCallback: (Int, type: String) -> Unit
+) : BindableItem() {
private lateinit var binding: ItemActivityBinding
+
@SuppressLint("SetTextI18n")
override fun bind(viewBinding: ItemActivityBinding, position: Int) {
binding = viewBinding
@@ -28,24 +36,48 @@ class ActivityItem(
binding.activityUserName.text = activity.user?.name
binding.activityUserAvatar.loadImage(activity.user?.avatar?.medium)
binding.activityTime.text = ActivityItemBuilder.getDateTime(activity.createdAt)
- val color = if (activity.isLiked == true)
- ContextCompat.getColor(binding.root.context, R.color.yt_red)
- else
- ContextCompat.getColor(binding.root.context, R.color.bg_opp)
- binding.activityFavorite.setColorFilter(color)
- binding.commentRepliesContainer.visibility = if (activity.replyCount > 0) View.VISIBLE else View.GONE
+ val likeColor = ContextCompat.getColor(binding.root.context, R.color.yt_red)
+ val notLikeColor = ContextCompat.getColor(binding.root.context, R.color.bg_opp)
+ binding.activityLike.setColorFilter(if (activity.isLiked == true) likeColor else notLikeColor)
+ binding.commentRepliesContainer.visibility =
+ if (activity.replyCount > 0) View.VISIBLE else View.GONE
+ binding.activityLikeCount.text = activity.likeCount.toString()
+
+ binding.activityLike.setOnClickListener {
+ val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
+ scope.launch {
+ val res = Anilist.query.toggleLike(activity.id, "ACTIVITY")
+ withContext(Dispatchers.Main) {
+ if (res != null) {
+
+ if (activity.isLiked == true) {
+ activity.likeCount = activity.likeCount?.minus(1)
+ } else {
+ activity.likeCount = activity.likeCount?.plus(1)
+ }
+ binding.activityLikeCount.text = activity.likeCount.toString()
+ activity.isLiked = !activity.isLiked!!
+ binding.activityLike.setColorFilter(if (activity.isLiked == true) likeColor else notLikeColor)
+
+ } else {
+ snackString("Failed to like activity")
+ }
+ }
+ }
+ }
val context = binding.root.context
when (activity.typename) {
- "ListActivity" ->{
+ "ListActivity" -> {
binding.activityContent.visibility = View.GONE
binding.activityBannerContainer.visibility = View.VISIBLE
binding.activityMediaName.text = activity.media?.title?.userPreferred
- binding.activityText.text = "${activity.user!!.name} ${activity.status} ${activity.media!!.title!!.userPreferred}"
- binding.activityCover.loadImage(activity.media.coverImage?.medium)
- val banner = activity.media.bannerImage
+ binding.activityText.text =
+ """${activity.user!!.name} ${activity.status} ${activity.progress ?: ""}"""
+ binding.activityCover.loadImage(activity.media?.coverImage?.medium)
+ val banner = activity.media?.bannerImage
if (banner != null) {
if (!(context as android.app.Activity).isDestroyed) {
Glide.with(context as Context)
@@ -58,6 +90,7 @@ class ActivityItem(
binding.activityBannerImage.setImageResource(R.drawable.linear_gradient_bg)
}
}
+
"TextActivity" -> {
binding.activityBannerContainer.visibility = View.GONE
binding.activityContent.visibility = View.VISIBLE
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt b/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt
new file mode 100644
index 00000000..8513ceb2
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt
@@ -0,0 +1,81 @@
+package ani.dantotsu.profile.activity
+
+import android.os.Bundle
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.view.updateLayoutParams
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import androidx.lifecycle.Lifecycle
+import androidx.viewpager2.adapter.FragmentStateAdapter
+import ani.dantotsu.R
+import ani.dantotsu.databinding.ActivityFeedBinding
+import ani.dantotsu.initActivity
+import ani.dantotsu.navBarHeight
+import ani.dantotsu.statusBarHeight
+import ani.dantotsu.themes.ThemeManager
+import nl.joery.animatedbottombar.AnimatedBottomBar
+
+class FeedActivity: AppCompatActivity() {
+ private lateinit var binding: ActivityFeedBinding
+ private var selected: Int = 0
+ private lateinit var navBar: AnimatedBottomBar
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ ThemeManager(this).applyTheme()
+ initActivity(this)
+ binding = ActivityFeedBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+ navBar = binding.feedNavBar
+ navBar.updateLayoutParams { bottomMargin += navBarHeight }
+ val personalTab = navBar.createTab(R.drawable.ic_round_person_24, "Personal")
+ val globalTab = navBar.createTab(R.drawable.ic_globe_24, "Global")
+ navBar.addTab(personalTab)
+ navBar.addTab(globalTab)
+ binding.listTitle.text = "Activities"
+ binding.feedViewPager.updateLayoutParams {
+ bottomMargin += navBarHeight
+ topMargin += statusBarHeight
+ }
+ binding.listToolbar.updateLayoutParams { topMargin += statusBarHeight }
+ binding.feedViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle)
+ binding.feedViewPager.setCurrentItem(selected, false)
+ binding.feedViewPager.isUserInputEnabled = false
+ navBar.selectTabAt(selected)
+ navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
+ override fun onTabSelected(
+ lastIndex: Int,
+ lastTab: AnimatedBottomBar.Tab?,
+ newIndex: Int,
+ newTab: AnimatedBottomBar.Tab
+ ) {
+ selected = newIndex
+ binding.feedViewPager.setCurrentItem(selected, true)
+ }
+ })
+ binding.listBack.setOnClickListener {
+ onBackPressed()
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ navBar.selectTabAt(selected)
+ }
+
+
+ private class ViewPagerAdapter(
+ fragmentManager: FragmentManager,
+ lifecycle: Lifecycle
+ ) : FragmentStateAdapter(fragmentManager, lifecycle) {
+ override fun getItemCount(): Int = 2
+
+ override fun createFragment(position: Int): Fragment {
+ return when (position) {
+ 0 -> FeedFragment.newInstance(null, false)
+ else -> FeedFragment.newInstance(null, true)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt b/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt
new file mode 100644
index 00000000..f6751d53
--- /dev/null
+++ b/app/src/main/java/ani/dantotsu/profile/activity/FeedFragment.kt
@@ -0,0 +1,111 @@
+package ani.dantotsu.profile.activity
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.LinearLayoutManager
+import ani.dantotsu.connections.anilist.Anilist
+import ani.dantotsu.connections.anilist.AnilistQueries
+import ani.dantotsu.connections.anilist.api.Activity
+import ani.dantotsu.databinding.FragmentFeedBinding
+import ani.dantotsu.logger
+import ani.dantotsu.profile.ProfileActivity
+import ani.dantotsu.snackString
+import com.xwray.groupie.GroupieAdapter
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+class FeedFragment : Fragment() {
+ private lateinit var binding: FragmentFeedBinding
+ private var adapter: GroupieAdapter = GroupieAdapter()
+ private var activityList: List = emptyList()
+ private lateinit var activity: androidx.activity.ComponentActivity
+ private var page: Int = 1
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ binding = FragmentFeedBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ activity = requireActivity()
+ binding.listRecyclerView.adapter = adapter
+ binding.listRecyclerView.layoutManager =
+ LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
+ binding.listProgressBar.visibility = ViewGroup.VISIBLE
+ var userId: Int? = arguments?.getInt("userId", -1)
+ if (userId == -1) userId = null
+ val global = arguments?.getBoolean("global", false) ?: false
+
+ activity.lifecycleScope.launch(Dispatchers.IO) {
+ val res = Anilist.query.getFeed(userId, global)
+ withContext(Dispatchers.Main) {
+ res?.data?.page?.activities?.let { activities ->
+ activityList = activities
+ adapter.update(activityList.map { ActivityItem(it) { _, _ -> } })
+ }
+ binding.listProgressBar.visibility = ViewGroup.GONE
+ val scrollView = if (activity is ProfileActivity) {
+ (activity as ProfileActivity).binding.profileScrollView
+ } else {
+ binding.listRecyclerView
+ }
+ binding.listRecyclerView.setOnTouchListener { _, event ->
+ if (event?.action == MotionEvent.ACTION_UP) {
+ if (adapter.itemCount % AnilistQueries.ITEMS_PER_PAGE != 0) {
+ snackString("No more activities")
+ } else if (!scrollView.canScrollVertically(1) && !binding.feedRefresh.isVisible
+ && binding.listRecyclerView.adapter!!.itemCount != 0 &&
+ (binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.listRecyclerView.adapter!!.itemCount - 1)
+ ) {
+ page++
+ binding.feedRefresh.visibility = ViewGroup.VISIBLE
+ activity.lifecycleScope.launch(Dispatchers.IO) {
+ val res = Anilist.query.getFeed(userId, global, page)
+ withContext(Dispatchers.Main) {
+ res?.data?.page?.activities?.let { activities ->
+ activityList += activities
+ adapter.addAll(activities.map { ActivityItem(it) { _, _ -> } })
+ }
+ binding.feedRefresh.visibility = ViewGroup.GONE
+ }
+ }
+ }
+ }
+ false
+ }
+ }
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ if (this::binding.isInitialized) {
+ binding.root.requestLayout()
+ }
+ }
+
+ companion object {
+ fun newInstance(userId: Int?, global: Boolean): FeedFragment {
+ val fragment = FeedFragment()
+ val args = Bundle()
+ args.putInt("userId", userId ?: -1)
+ args.putBoolean("global", global)
+ fragment.arguments = args
+ return fragment
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt b/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt
index f699b274..881c9975 100644
--- a/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt
+++ b/app/src/main/java/ani/dantotsu/profile/activity/NotificationActivity.kt
@@ -3,18 +3,23 @@ package ani.dantotsu.profile.activity
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
+import android.view.MotionEvent
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
+import androidx.core.view.isVisible
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.AnilistQueries
import ani.dantotsu.connections.anilist.api.Notification
import ani.dantotsu.databinding.ActivityFollowBinding
import ani.dantotsu.initActivity
import ani.dantotsu.media.MediaDetailsActivity
+import ani.dantotsu.navBarHeight
import ani.dantotsu.profile.ProfileActivity
+import ani.dantotsu.snackString
import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager
import com.xwray.groupie.GroupieAdapter
@@ -26,8 +31,9 @@ class NotificationActivity : AppCompatActivity() {
private lateinit var binding: ActivityFollowBinding
private var adapter: GroupieAdapter = GroupieAdapter()
private var notificationList: List = emptyList()
+ private var page: Int = 1
- @SuppressLint("SetTextI18n")
+ @SuppressLint("SetTextI18n", "ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
ThemeManager(this).applyTheme()
@@ -36,6 +42,7 @@ class NotificationActivity : AppCompatActivity() {
setContentView(binding.root)
binding.listTitle.text = "Notifications"
binding.listToolbar.updateLayoutParams { topMargin = statusBarHeight }
+ binding.listFrameLayout.updateLayoutParams { bottomMargin = navBarHeight }
binding.listRecyclerView.adapter = adapter
binding.listRecyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
binding.followerGrid.visibility = ViewGroup.GONE
@@ -52,6 +59,30 @@ class NotificationActivity : AppCompatActivity() {
}
withContext(Dispatchers.Main){
binding.listProgressBar.visibility = ViewGroup.GONE
+ binding.listRecyclerView.setOnTouchListener { _, event ->
+ if (event?.action == MotionEvent.ACTION_UP) {
+ if (adapter.itemCount % AnilistQueries.ITEMS_PER_PAGE != 0) {
+ snackString("No more notifications")
+ } else if (!binding.listRecyclerView.canScrollVertically(1) && !binding.followRefresh.isVisible
+ && binding.listRecyclerView.adapter!!.itemCount != 0 &&
+ (binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.listRecyclerView.adapter!!.itemCount - 1)
+ ) {
+ page++
+ binding.followRefresh.visibility = ViewGroup.VISIBLE
+ lifecycleScope.launch(Dispatchers.IO) {
+ val res = Anilist.query.getNotifications(Anilist.userid?:0, page)
+ withContext(Dispatchers.Main) {
+ res?.data?.page?.notifications?.let { notifications ->
+ notificationList += notifications
+ adapter.addAll(notifications.map { NotificationItem(it, ::onNotificationClick) })
+ }
+ binding.followRefresh.visibility = ViewGroup.GONE
+ }
+ }
+ }
+ }
+ false
+ }
}
}
}
diff --git a/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt b/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt
index 6638b151..b2aa43e6 100644
--- a/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt
+++ b/app/src/main/java/ani/dantotsu/settings/SettingsDialogFragment.kt
@@ -25,6 +25,7 @@ import ani.dantotsu.incognitoNotification
import ani.dantotsu.loadImage
import ani.dantotsu.profile.activity.NotificationActivity
import ani.dantotsu.offline.OfflineFragment
+import ani.dantotsu.profile.activity.FeedActivity
import ani.dantotsu.setSafeOnClickListener
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
@@ -108,6 +109,11 @@ class SettingsDialogFragment : BottomSheetDialogFragment() {
dismiss()
}
+ binding.settingsActivity.setSafeOnClickListener {
+ startActivity(Intent(activity, FeedActivity::class.java))
+ dismiss()
+ }
+
binding.settingsNotification.setOnClickListener {
startActivity(Intent(activity, NotificationActivity::class.java))
dismiss()
diff --git a/app/src/main/res/drawable/ic_globe_24.xml b/app/src/main/res/drawable/ic_globe_24.xml
new file mode 100644
index 00000000..ff6e71b0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_globe_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_activity.xml b/app/src/main/res/layout/activity_feed.xml
similarity index 50%
rename from app/src/main/res/layout/activity_activity.xml
rename to app/src/main/res/layout/activity_feed.xml
index 584c5588..295a8a10 100644
--- a/app/src/main/res/layout/activity_activity.xml
+++ b/app/src/main/res/layout/activity_feed.xml
@@ -1,19 +1,13 @@
-
+
-
-
@@ -38,18 +32,38 @@
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" />
+ tools:text="Activities" />
+
-
-
\ No newline at end of file
+ android:layout_height="match_parent"
+ android:layout_marginBottom="72dp"
+ android:layout_marginTop="48dp"
+ tools:ignore="SpeakableTextPresentCheck" />
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_follow.xml b/app/src/main/res/layout/activity_follow.xml
index 59358670..9dfe9846 100644
--- a/app/src/main/res/layout/activity_follow.xml
+++ b/app/src/main/res/layout/activity_follow.xml
@@ -93,11 +93,26 @@
-
+ android:layout_height="wrap_content">
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml
index 1583039d..409e6860 100644
--- a/app/src/main/res/layout/activity_profile.xml
+++ b/app/src/main/res/layout/activity_profile.xml
@@ -20,6 +20,7 @@
-
-
-
+ android:layout_height="match_parent"
+ android:orientation="vertical">
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_activity.xml b/app/src/main/res/layout/item_activity.xml
index 361df9d2..a21d7e05 100644
--- a/app/src/main/res/layout/item_activity.xml
+++ b/app/src/main/res/layout/item_activity.xml
@@ -70,14 +70,14 @@
android:orientation="vertical">
Date: Sat, 9 Mar 2024 15:58:15 -0500
Subject: [PATCH 3/6] fix: swap chapter names and nav on RTL (#230)
* fix: swap chapter names and nav on RTL
* fix: swipe RTL no longer needs invert
---
.../manga/mangareader/MangaReaderActivity.kt | 59 ++++++++++++-------
1 file changed, 39 insertions(+), 20 deletions(-)
diff --git a/app/src/main/java/ani/dantotsu/media/manga/mangareader/MangaReaderActivity.kt b/app/src/main/java/ani/dantotsu/media/manga/mangareader/MangaReaderActivity.kt
index ef8725e1..a6ce9bd3 100644
--- a/app/src/main/java/ani/dantotsu/media/manga/mangareader/MangaReaderActivity.kt
+++ b/app/src/main/java/ani/dantotsu/media/manga/mangareader/MangaReaderActivity.kt
@@ -285,16 +285,26 @@ class MangaReaderActivity : AppCompatActivity() {
binding.mangaReaderNextChapter.performClick()
}
binding.mangaReaderNextChapter.setOnClickListener {
- if (chaptersArr.size > currentChapterIndex + 1) progress { change(currentChapterIndex + 1) }
- else snackString(getString(R.string.next_chapter_not_found))
+ if (defaultSettings.direction == RIGHT_TO_LEFT) {
+ if (currentChapterIndex > 0) change(currentChapterIndex - 1)
+ else snackString(getString(R.string.first_chapter))
+ } else {
+ if (chaptersArr.size > currentChapterIndex + 1) progress { change(currentChapterIndex + 1) }
+ else snackString(getString(R.string.next_chapter_not_found))
+ }
}
//Prev Chapter
binding.mangaReaderPrevChap.setOnClickListener {
binding.mangaReaderPreviousChapter.performClick()
}
binding.mangaReaderPreviousChapter.setOnClickListener {
- if (currentChapterIndex > 0) change(currentChapterIndex - 1)
- else snackString(getString(R.string.first_chapter))
+ if (defaultSettings.direction == RIGHT_TO_LEFT) {
+ if (chaptersArr.size > currentChapterIndex + 1) progress { change(currentChapterIndex + 1) }
+ else snackString(getString(R.string.next_chapter_not_found))
+ } else {
+ if (currentChapterIndex > 0) change(currentChapterIndex - 1)
+ else snackString(getString(R.string.first_chapter))
+ }
}
model.getMangaChapter().observe(this) { chap ->
@@ -305,10 +315,17 @@ class MangaReaderActivity : AppCompatActivity() {
PrefManager.setCustomVal("${media.id}_current_chp", chap.number)
currentChapterIndex = chaptersArr.indexOf(chap.number)
binding.mangaReaderChapterSelect.setSelection(currentChapterIndex)
- binding.mangaReaderNextChap.text =
- chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
- binding.mangaReaderPrevChap.text =
- chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
+ if (defaultSettings.direction == RIGHT_TO_LEFT) {
+ binding.mangaReaderNextChap.text =
+ chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
+ binding.mangaReaderPrevChap.text =
+ chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
+ } else {
+ binding.mangaReaderNextChap.text =
+ chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
+ binding.mangaReaderPrevChap.text =
+ chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
+ }
applySettings()
val context = this
val offline: Boolean = PrefManager.getVal(PrefName.OfflineMode)
@@ -459,27 +476,26 @@ class MangaReaderActivity : AppCompatActivity() {
} else {
binding.mangaReaderSwipy.vertical = false
if (defaultSettings.direction == RIGHT_TO_LEFT) {
+ binding.mangaReaderNextChap.text =
+ chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
+ binding.mangaReaderPrevChap.text =
+ chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
binding.LeftSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1)
?: getString(R.string.no_chapter)
binding.RightSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1)
?: getString(R.string.no_chapter)
- binding.mangaReaderSwipy.onLeftSwiped = {
- binding.mangaReaderNextChapter.performClick()
- }
- binding.mangaReaderSwipy.onRightSwiped = {
- binding.mangaReaderPreviousChapter.performClick()
- }
} else {
+ binding.mangaReaderNextChap.text =
+ chaptersTitleArr.getOrNull(currentChapterIndex + 1) ?: ""
+ binding.mangaReaderPrevChap.text =
+ chaptersTitleArr.getOrNull(currentChapterIndex - 1) ?: ""
binding.LeftSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex - 1)
?: getString(R.string.no_chapter)
binding.RightSwipeText.text = chaptersTitleArr.getOrNull(currentChapterIndex + 1)
?: getString(R.string.no_chapter)
- binding.mangaReaderSwipy.onLeftSwiped = {
- binding.mangaReaderPreviousChapter.performClick()
- }
- binding.mangaReaderSwipy.onRightSwiped = {
- binding.mangaReaderNextChapter.performClick()
- }
+ }
+ binding.mangaReaderSwipy.onLeftSwiped = {
+ binding.mangaReaderPreviousChapter.performClick()
}
binding.mangaReaderSwipy.leftBeingSwiped = { value ->
binding.LeftSwipeContainer.apply {
@@ -487,6 +503,9 @@ class MangaReaderActivity : AppCompatActivity() {
translationX = -width.dp * (1 - min(value, 1f))
}
}
+ binding.mangaReaderSwipy.onRightSwiped = {
+ binding.mangaReaderNextChapter.performClick()
+ }
binding.mangaReaderSwipy.rightBeingSwiped = { value ->
binding.RightSwipeContainer.apply {
alpha = value
From 7504bb9081356e75d18cab064d510dded33bbce5 Mon Sep 17 00:00:00 2001
From: TwistedUmbrellaX <1173913+AbandonedCart@users.noreply.github.com>
Date: Sat, 9 Mar 2024 16:00:00 -0500
Subject: [PATCH 4/6] fix: optimize querying download uri (#232)
---
.../java/ani/dantotsu/others/AppUpdater.kt | 24 +++----------------
1 file changed, 3 insertions(+), 21 deletions(-)
diff --git a/app/src/google/java/ani/dantotsu/others/AppUpdater.kt b/app/src/google/java/ani/dantotsu/others/AppUpdater.kt
index 153cf970..595aaab4 100644
--- a/app/src/google/java/ani/dantotsu/others/AppUpdater.kt
+++ b/app/src/google/java/ani/dantotsu/others/AppUpdater.kt
@@ -161,21 +161,8 @@ object AppUpdater {
DownloadManager.EXTRA_DOWNLOAD_ID, id
) ?: id
- val query = DownloadManager.Query()
- query.setFilterById(downloadId)
- val c = downloadManager.query(query)
-
- if (c.moveToFirst()) {
- val columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS)
- if (DownloadManager.STATUS_SUCCESSFUL == c
- .getInt(columnIndex)
- ) {
- c.getColumnIndex(DownloadManager.COLUMN_MEDIAPROVIDER_URI)
- val uri = Uri.parse(
- c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI))
- )
- openApk(this@downloadUpdate, uri)
- }
+ downloadManager.getUriForDownloadedFile(downloadId)?.let {
+ openApk(this@downloadUpdate, it)
}
} catch (e: Exception) {
logError(e)
@@ -190,16 +177,11 @@ object AppUpdater {
private fun openApk(context: Context, uri: Uri) {
try {
uri.path?.let {
- val contentUri = FileProvider.getUriForFile(
- context,
- BuildConfig.APPLICATION_ID + ".provider",
- File(it)
- )
val installIntent = Intent(Intent.ACTION_VIEW).apply {
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
- data = contentUri
+ data = uri
}
context.startActivity(installIntent)
}
From 7f36eba7093fe67f2b13779943fd8d6d84568ca7 Mon Sep 17 00:00:00 2001
From: ibo <41344259+sneazy-ibo@users.noreply.github.com>
Date: Sat, 9 Mar 2024 22:02:23 +0100
Subject: [PATCH 5/6] feat: longclicklistener for AL profile now accessible
everywhere (#228)
* feat: added longclicklistener for AL profile in AnimePageAdapter and MangaPageAdapter
* feat: add delete to smaller media bottom sheet
---
.../ani/dantotsu/home/AnimePageAdapter.kt | 10 ++++
.../java/ani/dantotsu/home/HomeFragment.kt | 2 +-
.../ani/dantotsu/home/MangaPageAdapter.kt | 9 ++++
.../media/MediaListDialogSmallFragment.kt | 26 ++++++++++
.../layout/bottom_sheet_media_list_small.xml | 47 ++++++++++++++-----
5 files changed, 80 insertions(+), 14 deletions(-)
diff --git a/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt b/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt
index fc480ae3..7665ace2 100644
--- a/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt
@@ -26,6 +26,7 @@ import ani.dantotsu.media.CalendarActivity
import ani.dantotsu.media.GenreActivity
import ani.dantotsu.media.MediaAdaptor
import ani.dantotsu.media.SearchActivity
+import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.px
import ani.dantotsu.setSafeOnClickListener
import ani.dantotsu.setSlideIn
@@ -94,6 +95,15 @@ class AnimePageAdapter : RecyclerView.Adapter
+ ContextCompat.startActivity(
+ view.context,
+ Intent(view.context, ProfileActivity::class.java)
+ .putExtra("userId", Anilist.userid),null
+ )
+ false
+ }
+
binding.animeNotificationCount.visibility = if (Anilist.unreadNotificationCount > 0) View.VISIBLE else View.GONE
binding.animeNotificationCount.text = Anilist.unreadNotificationCount.toString()
diff --git a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
index 9652c43b..e0839e90 100644
--- a/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
+++ b/app/src/main/java/ani/dantotsu/home/HomeFragment.kt
@@ -124,7 +124,7 @@ class HomeFragment : Fragment() {
binding.homeUserAvatarContainer.setOnLongClickListener {
ContextCompat.startActivity(
requireContext(), Intent(requireContext(), ProfileActivity::class.java)
- .putExtra("userId", Anilist.userid), null
+ .putExtra("userId", Anilist.userid),null
)
false
}
diff --git a/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt b/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt
index 1f714260..ca0a6e59 100644
--- a/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt
+++ b/app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt
@@ -25,6 +25,7 @@ import ani.dantotsu.loadImage
import ani.dantotsu.media.GenreActivity
import ani.dantotsu.media.MediaAdaptor
import ani.dantotsu.media.SearchActivity
+import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.px
import ani.dantotsu.setSafeOnClickListener
import ani.dantotsu.setSlideIn
@@ -90,6 +91,14 @@ class MangaPageAdapter : RecyclerView.Adapter
+ ContextCompat.startActivity(
+ view.context,
+ Intent(view.context, ProfileActivity::class.java)
+ .putExtra("userId", Anilist.userid),null
+ )
+ false
+ }
binding.mangaSearchBar.setEndIconOnClickListener {
binding.mangaSearchBarText.performClick()
diff --git a/app/src/main/java/ani/dantotsu/media/MediaListDialogSmallFragment.kt b/app/src/main/java/ani/dantotsu/media/MediaListDialogSmallFragment.kt
index cb7390ce..185e4916 100644
--- a/app/src/main/java/ani/dantotsu/media/MediaListDialogSmallFragment.kt
+++ b/app/src/main/java/ani/dantotsu/media/MediaListDialogSmallFragment.kt
@@ -58,6 +58,32 @@ class MediaListDialogSmallFragment : BottomSheetDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.mediaListContainer.updateLayoutParams { bottomMargin += navBarHeight }
val scope = viewLifecycleOwner.lifecycleScope
+ binding.mediaListDelete.setOnClickListener {
+ val id = media.userListId
+ if (id != null) {
+ viewLifecycleOwner.lifecycleScope.launch {
+ withContext(Dispatchers.IO) {
+ try {
+ Anilist.mutation.deleteList(id)
+ MAL.query.deleteList(media.anime != null, media.idMAL)
+ } catch (e: Exception) {
+ withContext(Dispatchers.Main) {
+ snackString("Failed to delete because of... ${e.message}")
+ }
+ return@withContext
+ }
+ }
+ withContext(Dispatchers.Main) {
+ Refresh.all()
+ snackString(getString(R.string.deleted_from_list))
+ dismissAllowingStateLoss()
+ }
+ }
+ } else {
+ snackString(getString(R.string.no_list_id))
+ Refresh.all()
+ }
+ }
binding.mediaListProgressBar.visibility = View.GONE
binding.mediaListLayout.visibility = View.VISIBLE
diff --git a/app/src/main/res/layout/bottom_sheet_media_list_small.xml b/app/src/main/res/layout/bottom_sheet_media_list_small.xml
index ecab76ba..1cb457c2 100644
--- a/app/src/main/res/layout/bottom_sheet_media_list_small.xml
+++ b/app/src/main/res/layout/bottom_sheet_media_list_small.xml
@@ -178,22 +178,43 @@
android:fontFamily="@font/poppins_bold"
android:text="@string/list_private" />
-
+ android:layout_height="match_parent"
+ android:layout_marginTop="16dp"
+ android:orientation="horizontal">
+
+
+
Date: Sat, 9 Mar 2024 16:06:48 -0500
Subject: [PATCH 6/6] A few build and navigation bar improvements (#231)
* fix: match project root to repo name
* feat: hide navigation bar until swiped
* fix: limit announcements to official
* feat: keep navigation visible for back
* fix: remove a duplicate permission
---
.github/workflows/beta.yml | 1 +
app/src/main/AndroidManifest.xml | 1 -
app/src/main/java/ani/dantotsu/Functions.kt | 14 +++++----
.../main/java/ani/dantotsu/MainActivity.kt | 30 ++++++++++++++++++-
.../connections/anilist/AnilistQueries.kt | 2 +-
settings.gradle.kts | 2 +-
6 files changed, 40 insertions(+), 10 deletions(-)
diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml
index cd4c449f..a1277018 100644
--- a/.github/workflows/beta.yml
+++ b/.github/workflows/beta.yml
@@ -89,6 +89,7 @@ jobs:
path: "app/build/outputs/apk/google/alpha/app-google-alpha.apk"
- name: Upload APK to Discord and Telegram
+ if: ${{ github.repository == 'rebelonion/Dantotsu' }}
shell: bash
run: |
#Discord
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 12e7eccc..5883981b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -16,7 +16,6 @@
-
diff --git a/app/src/main/java/ani/dantotsu/Functions.kt b/app/src/main/java/ani/dantotsu/Functions.kt
index 67af749c..cdc8ffdd 100644
--- a/app/src/main/java/ani/dantotsu/Functions.kt
+++ b/app/src/main/java/ani/dantotsu/Functions.kt
@@ -904,16 +904,16 @@ fun toast(string: String?) {
}
}
-fun snackString(s: String?, activity: Activity? = null, clipboard: String? = null) {
+fun snackString(s: String?, activity: Activity? = null, clipboard: String? = null) : Snackbar? {
try { //I have no idea why this sometimes crashes for some people...
if (s != null) {
(activity ?: currActivity())?.apply {
+ val snackBar = Snackbar.make(
+ window.decorView.findViewById(android.R.id.content),
+ s,
+ Snackbar.LENGTH_SHORT
+ )
runOnUiThread {
- val snackBar = Snackbar.make(
- window.decorView.findViewById(android.R.id.content),
- s,
- Snackbar.LENGTH_SHORT
- )
snackBar.view.apply {
updateLayoutParams {
gravity = (Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM)
@@ -933,6 +933,7 @@ fun snackString(s: String?, activity: Activity? = null, clipboard: String? = nul
}
snackBar.show()
}
+ return snackBar
}
logger(s)
}
@@ -940,6 +941,7 @@ fun snackString(s: String?, activity: Activity? = null, clipboard: String? = nul
logger(e.stackTraceToString())
Injekt.get().logException(e)
}
+ return null
}
open class NoPaddingArrayAdapter(context: Context, layoutId: Int, items: List) :
diff --git a/app/src/main/java/ani/dantotsu/MainActivity.kt b/app/src/main/java/ani/dantotsu/MainActivity.kt
index a2bb5f31..ba47d2fb 100644
--- a/app/src/main/java/ani/dantotsu/MainActivity.kt
+++ b/app/src/main/java/ani/dantotsu/MainActivity.kt
@@ -22,6 +22,9 @@ import androidx.annotation.OptIn
import androidx.appcompat.app.AppCompatActivity
import androidx.core.animation.doOnEnd
import androidx.core.content.ContextCompat
+import androidx.core.view.WindowCompat
+import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.doOnAttach
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
@@ -49,6 +52,8 @@ import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.settings.saving.SharedPreferenceBooleanLiveData
import ani.dantotsu.subcriptions.Subscription.Companion.startSubscription
import ani.dantotsu.themes.ThemeManager
+import com.google.android.material.snackbar.BaseTransientBottomBar
+import com.google.android.material.snackbar.Snackbar
import eu.kanade.domain.source.service.SourcePreferences
import io.noties.markwon.Markwon
import io.noties.markwon.SoftBreakAddsNewLinePlugin
@@ -141,7 +146,20 @@ class MainActivity : AppCompatActivity() {
finish()
}
doubleBackToExitPressedOnce = true
- snackString(this@MainActivity.getString(R.string.back_to_exit))
+ WindowInsetsControllerCompat(window, window.decorView)
+ .show(WindowInsetsCompat.Type.navigationBars())
+ snackString(this@MainActivity.getString(R.string.back_to_exit)).apply {
+ this?.addCallback(object : BaseTransientBottomBar.BaseCallback() {
+ override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
+ super.onDismissed(transientBottomBar, event)
+ WindowInsetsControllerCompat(window, window.decorView).let { controller ->
+ controller.systemBarsBehavior =
+ WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+ controller.hide(WindowInsetsCompat.Type.navigationBars())
+ }
+ }
+ })
+ }
Handler(Looper.getMainLooper()).postDelayed(
{ doubleBackToExitPressedOnce = false },
2000
@@ -349,6 +367,16 @@ class MainActivity : AppCompatActivity() {
}
}
+ override fun onResume() {
+ super.onResume()
+
+ WindowCompat.setDecorFitsSystemWindows(window, false)
+
+ WindowInsetsControllerCompat(window, window.decorView).let { controller ->
+ controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+ controller.hide(WindowInsetsCompat.Type.navigationBars())
+ }
+ }
//ViewPager
private class ViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
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 e1b52dba..bbc2bb07 100644
--- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
+++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt
@@ -281,7 +281,7 @@ class AnilistQueries {
} else {
if (currContext()?.let { isOnline(it) } == true) {
snackString(currContext()?.getString(R.string.error_getting_data))
- }
+ } else { }
}
}
val mal = async {
diff --git a/settings.gradle.kts b/settings.gradle.kts
index f4dce558..8174ef2b 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -5,5 +5,5 @@ dependencyResolutionManagement {
maven("https://jitpack.io")
}
}
-rootProject.name = "dantotsu"
+rootProject.name = "Dantotsu"
include(":app")