Merge branch 'rebelonion:dev' into dev

This commit is contained in:
tutel
2024-03-09 23:13:20 +02:00
committed by GitHub
30 changed files with 674 additions and 215 deletions

View File

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

View File

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

View File

@@ -16,7 +16,6 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
@@ -115,7 +114,7 @@
android:windowSoftInputMode="adjustResize|stateHidden"
android:parentActivityName=".MainActivity" />
<activity
android:name=".profile.activity.ActivityActivity"
android:name=".profile.activity.FeedActivity"
android:label="Inbox Activity"
android:parentActivityName=".MainActivity" >
</activity>

View File

@@ -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())
}
@@ -902,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<FrameLayout.LayoutParams> {
gravity = (Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM)
@@ -931,6 +933,7 @@ fun snackString(s: String?, activity: Activity? = null, clipboard: String? = nul
}
snackBar.show()
}
return snackBar
}
logger(s)
}
@@ -938,6 +941,7 @@ fun snackString(s: String?, activity: Activity? = null, clipboard: String? = nul
logger(e.stackTraceToString())
Injekt.get<CrashlyticsInterface>().logException(e)
}
return null
}
open class NoPaddingArrayAdapter<T>(context: Context, layoutId: Int, items: List<T>) :

View File

@@ -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<Snackbar>() {
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) :

View File

@@ -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
@@ -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 {
@@ -1265,10 +1265,15 @@ Page(page:$page,perPage:50) {
}
suspend fun toggleFollow(id: Int): Query.ToggleFollow? {
val response = executeQuery<Query.ToggleFollow>(
return executeQuery<Query.ToggleFollow>(
"""mutation{ToggleFollow(userId:$id){id, isFollowing, isFollower}}"""
)
return response
}
suspend fun toggleLike(id: Int, type: String): ToggleLike? {
return executeQuery<ToggleLike>(
"""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<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)
suspend fun getNotifications(id: Int, page: Int = 1): NotificationResponse? {
val res = executeQuery<NotificationResponse>("""{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<FeedResponse>("""{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<FeedResponse>("""{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
}
}

View File

@@ -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<Activity>
)
) : 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<Reply>?,
@SerialName("likes")
val likes: List<User>?,
)
) : java.io.Serializable
@Serializable
data class Reply(
@@ -89,4 +89,22 @@ data class Reply(
val user: User,
@SerialName("likes")
val likes: List<User>?,
)
) : 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

View File

@@ -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<AnimePageAdapter.AnimePageViewHold
SettingsDialogFragment.newInstance(SettingsDialogFragment.Companion.PageType.ANIME)
dialogFragment.show((it.context as AppCompatActivity).supportFragmentManager, "dialog")
}
binding.animeUserAvatar.setOnLongClickListener { view ->
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()

View File

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

View File

@@ -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<MangaPageAdapter.MangaPageViewHold
SettingsDialogFragment.newInstance(SettingsDialogFragment.Companion.PageType.MANGA)
dialogFragment.show((it.context as AppCompatActivity).supportFragmentManager, "dialog")
}
binding.mangaUserAvatar.setOnLongClickListener { view ->
ContextCompat.startActivity(
view.context,
Intent(view.context, ProfileActivity::class.java)
.putExtra("userId", Anilist.userid),null
)
false
}
binding.mangaSearchBar.setEndIconOnClickListener {
binding.mangaSearchBarText.performClick()

View File

@@ -58,6 +58,32 @@ class MediaListDialogSmallFragment : BottomSheetDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.mediaListContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> { 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

View File

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

View File

@@ -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<MarginLayoutParams> { topMargin = statusBarHeight }
binding.listFrameLayout.updateLayoutParams<MarginLayoutParams> { bottomMargin = navBarHeight }
setContentView(binding.root)
val layoutType = PrefManager.getVal<Int>(PrefName.FollowerLayout)
selected = getSelected(layoutType)

View File

@@ -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<ViewGroup.MarginLayoutParams> { 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<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
binding.profileActivityButton.updateLayoutParams<ViewGroup.MarginLayoutParams> { 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)
}
}

View File

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

View File

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

View File

@@ -5,40 +5,79 @@ 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.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<ItemActivityBinding>() {
val clickCallback: (Int, type: String) -> Unit
) : BindableItem<ItemActivityBinding>() {
private lateinit var binding: ItemActivityBinding
@SuppressLint("SetTextI18n")
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 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" ->{
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.activityFavoriteCount.text = activity.likeCount.toString()
"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.progress ?: ""}"
binding.activityCover.loadImage(activity.media?.coverImage?.large)
val context = binding.root.context
val banner = activity.media?.bannerImage ?: activity.media?.coverImage?.large
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)
@@ -51,6 +90,15 @@ 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 ?: "")
}
}
}
}

View File

@@ -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<ViewGroup.MarginLayoutParams> { 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<ViewGroup.MarginLayoutParams> {
bottomMargin += navBarHeight
topMargin += statusBarHeight
}
binding.listToolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> { 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)
}
}
}
}

View File

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

View File

@@ -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<Notification> = 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<ViewGroup.MarginLayoutParams> { topMargin = statusBarHeight }
binding.listFrameLayout.updateLayoutParams<ViewGroup.MarginLayoutParams> { 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
}
}
}
}

View File

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

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480,880q-82,0 -155,-31.5t-127.5,-86Q143,708 111.5,635T80,480q0,-83 31.5,-155.5t86,-127Q252,143 325,111.5T480,80q83,0 155.5,31.5t127,86q54.5,54.5 86,127T880,480q0,82 -31.5,155t-86,127.5q-54.5,54.5 -127,86T480,880ZM480,798q26,-36 45,-75t31,-83L404,640q12,44 31,83t45,75ZM376,782q-18,-33 -31.5,-68.5T322,640L204,640q29,50 72.5,87t99.5,55ZM584,782q56,-18 99.5,-55t72.5,-87L638,640q-9,38 -22.5,73.5T584,782ZM170,560h136q-3,-20 -4.5,-39.5T300,480q0,-21 1.5,-40.5T306,400L170,400q-5,20 -7.5,39.5T160,480q0,21 2.5,40.5T170,560ZM386,560h188q3,-20 4.5,-39.5T580,480q0,-21 -1.5,-40.5T574,400L386,400q-3,20 -4.5,39.5T380,480q0,21 1.5,40.5T386,560ZM654,560h136q5,-20 7.5,-39.5T800,480q0,-21 -2.5,-40.5T790,400L654,400q3,20 4.5,39.5T660,480q0,21 -1.5,40.5T654,560ZM638,320h118q-29,-50 -72.5,-87T584,178q18,33 31.5,68.5T638,320ZM404,320h152q-12,-44 -31,-83t-45,-75q-26,36 -45,75t-31,83ZM204,320h118q9,-38 22.5,-73.5T376,178q-56,18 -99.5,55T204,320Z"/>
</vector>

View File

@@ -1,19 +1,13 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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:id="@+id/listToolbar"
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal">
@@ -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" />
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listRecyclerView"
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/feedViewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
tools:listitem="@layout/item_activity" />
</LinearLayout>
android:layout_height="match_parent"
android:layout_marginBottom="72dp"
android:layout_marginTop="48dp"
tools:ignore="SpeakableTextPresentCheck" />
<nl.joery.animatedbottombar.AnimatedBottomBar
android:id="@+id/feedNavBar"
android:layout_width="match_parent"
android:layout_height="72dp"
android:layout_gravity="center_horizontal|bottom"
android:background="?attr/colorSurface"
android:padding="0dp"
app:abb_animationInterpolator="@anim/over_shoot"
app:abb_indicatorAppearance="round"
app:abb_indicatorLocation="top"
app:abb_selectedTabType="text"
app:abb_textAppearance="@style/NavBarText"
app:itemActiveIndicatorStyle="@style/BottomNavBar"
app:itemIconTint="@color/tab_layout_icon"
app:itemRippleColor="#00000000"
app:itemTextAppearanceActive="@style/NavBarText"
app:itemTextAppearanceInactive="@style/NavBarText"
app:itemTextColor="@color/tab_layout_icon" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -93,11 +93,26 @@
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/listRecyclerView"
<FrameLayout
android:id="@+id/listFrameLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
tools:listitem="@layout/item_follower" />
android:layout_height="wrap_content">
<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"
android:nestedScrollingEnabled="true" />
<ProgressBar
android:id="@+id/followRefresh"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="32dp"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>

View File

@@ -20,6 +20,7 @@
</LinearLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/profileScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="72dp"
@@ -118,15 +119,6 @@
android:layout_marginEnd="16dp"
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"

View File

@@ -178,22 +178,43 @@
android:fontFamily="@font/poppins_bold"
android:text="@string/list_private" />
<Button
android:id="@+id/mediaListSave"
style="@style/Widget.Material3.Button.OutlinedButton"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginTop="24dp"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:padding="8dp"
android:text="@string/save"
android:textSize="16sp"
app:cornerRadius="16dp"
app:strokeColor="?attr/colorPrimaryContainer" />
android:layout_height="match_parent"
android:layout_marginTop="16dp"
android:orientation="horizontal">
<Button
android:id="@+id/mediaListDelete"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="128dp"
android:layout_height="56dp"
android:layout_gravity="center"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:padding="8dp"
android:text="@string/delete"
android:textSize="16sp"
app:cornerRadius="16dp"
app:strokeColor="?attr/colorPrimaryContainer" />
<Button
android:id="@+id/mediaListSave"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:fontFamily="@font/poppins_bold"
android:insetTop="0dp"
android:insetBottom="0dp"
android:padding="8dp"
android:text="@string/save"
android:textSize="16sp"
app:cornerRadius="16dp"
app:strokeColor="?attr/colorPrimaryContainer" />
</LinearLayout>
</LinearLayout>
<androidx.cardview.widget.CardView

View File

@@ -1,6 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:orientation="vertical">
</androidx.constraintlayout.widget.ConstraintLayout>
<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="wrap_content">
<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"
android:nestedScrollingEnabled="true"
android:visibility="visible"
tools:listitem="@layout/item_activity" />
<ProgressBar
android:id="@+id/feedRefresh"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="32dp"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>

View File

@@ -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">
<LinearLayout
@@ -69,14 +70,14 @@
android:orientation="vertical">
<ImageView
android:id="@+id/activityFavorite"
android:id="@+id/activityLike"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_round_favorite_24"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/activityFavoriteCount"
android:id="@+id/activityLikeCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
@@ -87,9 +88,23 @@
</LinearLayout>
<TextView
android:id="@+id/activityContent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:fontFamily="@font/poppins_semi_bold"
android:text="@string/lorem_ipsum"
android:textAlignment="center"
android:textSize="14sp" />
<FrameLayout
android:id="@+id/activityBannerContainer"
android:layout_width="match_parent"
android:layout_height="180dp">
android:layout_height="wrap_content"
android:layout_marginTop="8dp">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
@@ -170,4 +185,34 @@
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</FrameLayout>
<LinearLayout
android:id="@+id/commentRepliesContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|center_vertical"
android:layout_marginStart="16dp"
android:layout_marginTop="4dp"
android:orientation="horizontal">
<View
android:id="@+id/commentRepliesDivider"
android:layout_width="32dp"
android:layout_height="3dp"
android:layout_marginStart="4dp"
android:layout_marginTop="8dp"
android:background="@color/nav_tab" />
<TextView
android:id="@+id/commentTotalReplies"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:alpha="0.8"
android:fontFamily="@font/poppins_semi_bold"
android:text="View replies"
android:textSize="12sp"
tools:ignore="HardcodedText" />
</LinearLayout>
</LinearLayout>

View File

@@ -684,5 +684,13 @@
<string name="manga_mean_score">Manga Mean Score</string>
<string name="about_me">About me</string>
<string name="follow">Follow</string>
<string name="lorem_ipsum">
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.
</string>
</resources>

View File

@@ -5,5 +5,5 @@ dependencyResolutionManagement {
maven("https://jitpack.io")
}
}
rootProject.name = "dantotsu"
rootProject.name = "Dantotsu"
include(":app")