Merge branch 'dev' of https://github.com/rebelonion/Dantotsu into dev
This commit is contained in:
commit
0b32636c1b
25 changed files with 852 additions and 679 deletions
2
.github/workflows/beta.yml
vendored
2
.github/workflows/beta.yml
vendored
|
@ -108,7 +108,7 @@ jobs:
|
||||||
|
|
||||||
#Telegram
|
#Telegram
|
||||||
curl -F "chat_id=${{ secrets.TELEGRAM_CHANNEL_ID }}" \
|
curl -F "chat_id=${{ secrets.TELEGRAM_CHANNEL_ID }}" \
|
||||||
-F "document=@app/build/outputs/apk/google/alpha/app-google-universal-alpha.apk" \
|
-F "document=@app/build/outputs/apk/google/alpha/app-google-alpha.apk" \
|
||||||
-F "caption=Alpha-Build: ${VERSION}: ${commit_messages}" \
|
-F "caption=Alpha-Build: ${VERSION}: ${commit_messages}" \
|
||||||
https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendDocument
|
https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendDocument
|
||||||
|
|
||||||
|
|
|
@ -194,7 +194,7 @@
|
||||||
android:label="Inbox Activity"
|
android:label="Inbox Activity"
|
||||||
android:parentActivityName=".MainActivity" />
|
android:parentActivityName=".MainActivity" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".profile.activity.NotificationActivity"
|
android:name=".profile.notification.NotificationActivity"
|
||||||
android:label="Inbox Activity"
|
android:label="Inbox Activity"
|
||||||
android:parentActivityName=".MainActivity" />
|
android:parentActivityName=".MainActivity" />
|
||||||
<activity
|
<activity
|
||||||
|
|
|
@ -51,7 +51,7 @@ import ani.dantotsu.others.CustomBottomDialog
|
||||||
import ani.dantotsu.others.calc.CalcActivity
|
import ani.dantotsu.others.calc.CalcActivity
|
||||||
import ani.dantotsu.profile.ProfileActivity
|
import ani.dantotsu.profile.ProfileActivity
|
||||||
import ani.dantotsu.profile.activity.FeedActivity
|
import ani.dantotsu.profile.activity.FeedActivity
|
||||||
import ani.dantotsu.profile.activity.NotificationActivity
|
import ani.dantotsu.profile.notification.NotificationActivity
|
||||||
import ani.dantotsu.settings.ExtensionsActivity
|
import ani.dantotsu.settings.ExtensionsActivity
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefManager.asLiveBool
|
import ani.dantotsu.settings.saving.PrefManager.asLiveBool
|
||||||
|
@ -365,7 +365,6 @@ class MainActivity : AppCompatActivity() {
|
||||||
} else if (fragmentToLoad == "NOTIFICATIONS" && activityId != -1) {
|
} else if (fragmentToLoad == "NOTIFICATIONS" && activityId != -1) {
|
||||||
Logger.log("MainActivity, onCreate: $activityId")
|
Logger.log("MainActivity, onCreate: $activityId")
|
||||||
val notificationIntent = Intent(this, NotificationActivity::class.java).apply {
|
val notificationIntent = Intent(this, NotificationActivity::class.java).apply {
|
||||||
putExtra("FRAGMENT_TO_LOAD", "NOTIFICATIONS")
|
|
||||||
putExtra("activityId", activityId)
|
putExtra("activityId", activityId)
|
||||||
}
|
}
|
||||||
launched = true
|
launched = true
|
||||||
|
|
|
@ -435,7 +435,7 @@ class AnilistQueries {
|
||||||
response.data.page2.activities
|
response.data.page2.activities
|
||||||
).asSequence().flatten()
|
).asSequence().flatten()
|
||||||
.filter { it.typename != "MessageActivity" }
|
.filter { it.typename != "MessageActivity" }
|
||||||
.filter { if (Anilist.adult) true else it.media?.isAdult == false }
|
.filter { if (Anilist.adult) true else it.media?.isAdult != true }
|
||||||
.filter { it.createdAt * 1000L > threeDaysAgo }.toList()
|
.filter { it.createdAt * 1000L > threeDaysAgo }.toList()
|
||||||
.sortedByDescending { it.createdAt }
|
.sortedByDescending { it.createdAt }
|
||||||
val anilistActivities = mutableListOf<User>()
|
val anilistActivities = mutableListOf<User>()
|
||||||
|
|
|
@ -268,8 +268,9 @@ class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHold
|
||||||
LinearLayoutManager.HORIZONTAL,
|
LinearLayoutManager.HORIZONTAL,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
MediaListViewActivity.passedMedia = media.toCollection(ArrayList())
|
|
||||||
more.setOnClickListener {
|
more.setOnClickListener {
|
||||||
|
MediaListViewActivity.passedMedia = media.toCollection(ArrayList())
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
it.context, Intent(it.context, MediaListViewActivity::class.java)
|
it.context, Intent(it.context, MediaListViewActivity::class.java)
|
||||||
.putExtra("title", string),
|
.putExtra("title", string),
|
||||||
|
|
|
@ -19,6 +19,7 @@ import ani.dantotsu.snackString
|
||||||
import ani.dantotsu.util.MarkdownCreatorActivity
|
import ani.dantotsu.util.MarkdownCreatorActivity
|
||||||
import com.xwray.groupie.GroupieAdapter
|
import com.xwray.groupie.GroupieAdapter
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
@ -58,6 +59,11 @@ class RepliesBottomDialog : BottomSheetDialogFragment() {
|
||||||
activityId = requireArguments().getInt("activityId")
|
activityId = requireArguments().getInt("activityId")
|
||||||
loading(true)
|
loading(true)
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun loadData() {
|
||||||
val response = Anilist.query.getReplies(activityId)
|
val response = Anilist.query.getReplies(activityId)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
loading(false)
|
loading(false)
|
||||||
|
@ -81,8 +87,6 @@ class RepliesBottomDialog : BottomSheetDialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onClick(int: Int) {
|
private fun onClick(int: Int) {
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
|
@ -101,6 +105,15 @@ class RepliesBottomDialog : BottomSheetDialogFragment() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
loading(true)
|
||||||
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
delay(2000)
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance(activityId: Int): RepliesBottomDialog {
|
fun newInstance(activityId: Int): RepliesBottomDialog {
|
||||||
return RepliesBottomDialog().apply {
|
return RepliesBottomDialog().apply {
|
||||||
|
|
|
@ -74,8 +74,7 @@ class Stories @JvmOverloads constructor(
|
||||||
|
|
||||||
if (context is StoriesCallback) storiesListener = context as StoriesCallback
|
if (context is StoriesCallback) storiesListener = context as StoriesCallback
|
||||||
|
|
||||||
binding.leftTouchPanel.setOnTouchListener(this)
|
binding.touchPanel.setOnTouchListener(this)
|
||||||
binding.rightTouchPanel.setOnTouchListener(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -264,49 +263,7 @@ class Stories @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private var startClickTime = 0L
|
|
||||||
private var startX = 0f
|
|
||||||
private var startY = 0f
|
|
||||||
private var isLongPress = false
|
|
||||||
private val swipeThreshold = 100
|
|
||||||
override fun onTouch(view: View?, event: MotionEvent?): Boolean {
|
|
||||||
val maxClickDuration = 200
|
|
||||||
when (event?.action) {
|
|
||||||
MotionEvent.ACTION_DOWN -> {
|
|
||||||
startX = event.x
|
|
||||||
startY = event.y
|
|
||||||
startClickTime = Calendar.getInstance().timeInMillis
|
|
||||||
pause()
|
|
||||||
isLongPress = false
|
|
||||||
}
|
|
||||||
|
|
||||||
MotionEvent.ACTION_MOVE -> {
|
|
||||||
val deltaX = event.x - startX
|
|
||||||
val deltaY = event.y - startY
|
|
||||||
if (!isLongPress && (abs(deltaX) > swipeThreshold || abs(deltaY) > swipeThreshold)) {
|
|
||||||
isLongPress = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MotionEvent.ACTION_UP -> {
|
|
||||||
val clickDuration = Calendar.getInstance().timeInMillis - startClickTime
|
|
||||||
if (clickDuration < maxClickDuration && !isLongPress) {
|
|
||||||
when (view?.id) {
|
|
||||||
R.id.leftTouchPanel -> leftPanelTouch()
|
|
||||||
R.id.rightTouchPanel -> rightPanelTouch()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
resume()
|
|
||||||
}
|
|
||||||
val deltaX = event.x - startX
|
|
||||||
if (abs(deltaX) > swipeThreshold) {
|
|
||||||
if (deltaX > 0) onStoriesPrevious()
|
|
||||||
else onStoriesCompleted()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun rightPanelTouch() {
|
private fun rightPanelTouch() {
|
||||||
Logger.log("rightPanelTouch: $storyIndex")
|
Logger.log("rightPanelTouch: $storyIndex")
|
||||||
|
@ -359,6 +316,7 @@ class Stories @JvmOverloads constructor(
|
||||||
timer.resume()
|
timer.resume()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
private fun loadStory(story: Activity) {
|
private fun loadStory(story: Activity) {
|
||||||
val key = "activities"
|
val key = "activities"
|
||||||
val set = PrefManager.getCustomVal<Set<Int>>(key, setOf()).plus((story.id))
|
val set = PrefManager.getCustomVal<Set<Int>>(key, setOf()).plus((story.id))
|
||||||
|
@ -374,6 +332,15 @@ class Stories @JvmOverloads constructor(
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.textActivity.setOnTouchListener { v, event ->
|
||||||
|
onTouchView(v, event, true)
|
||||||
|
v.onTouchEvent(event)
|
||||||
|
}
|
||||||
|
binding.textActivityContainer.setOnTouchListener { v, event ->
|
||||||
|
onTouchView(v, event, true)
|
||||||
|
v.onTouchEvent(event)
|
||||||
|
}
|
||||||
fun visible(isList: Boolean) {
|
fun visible(isList: Boolean) {
|
||||||
binding.textActivity.isVisible = !isList
|
binding.textActivity.isVisible = !isList
|
||||||
binding.textActivityContainer.isVisible = !isList
|
binding.textActivityContainer.isVisible = !isList
|
||||||
|
@ -502,4 +469,66 @@ class Stories @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private var startClickTime = 0L
|
||||||
|
private var startX = 0f
|
||||||
|
private var startY = 0f
|
||||||
|
private var isLongPress = false
|
||||||
|
private val swipeThreshold = 100
|
||||||
|
override fun onTouch(view: View, event: MotionEvent): Boolean {
|
||||||
|
onTouchView(view, event)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
private fun onTouchView(view: View, event: MotionEvent, isText: Boolean = false){
|
||||||
|
val maxClickDuration = 200
|
||||||
|
val screenWidth = view.width
|
||||||
|
val leftHalf = screenWidth / 2
|
||||||
|
val leftQuarter = screenWidth * 0.15
|
||||||
|
val rightQuarter = screenWidth * 0.85
|
||||||
|
when (event.action) {
|
||||||
|
MotionEvent.ACTION_DOWN -> {
|
||||||
|
startX = event.x
|
||||||
|
startY = event.y
|
||||||
|
startClickTime = Calendar.getInstance().timeInMillis
|
||||||
|
pause()
|
||||||
|
isLongPress = false
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_MOVE -> {
|
||||||
|
val deltaX = event.x - startX
|
||||||
|
val deltaY = event.y - startY
|
||||||
|
if (!isLongPress && (abs(deltaX) > swipeThreshold || abs(deltaY) > swipeThreshold)) {
|
||||||
|
isLongPress = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_UP -> {
|
||||||
|
val clickDuration = Calendar.getInstance().timeInMillis - startClickTime
|
||||||
|
if (isText) {
|
||||||
|
if (clickDuration < maxClickDuration && !isLongPress) {
|
||||||
|
if (event.x < leftQuarter) {
|
||||||
|
leftPanelTouch()
|
||||||
|
} else if (event.x > rightQuarter) {
|
||||||
|
rightPanelTouch()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resume()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (clickDuration < maxClickDuration && !isLongPress) {
|
||||||
|
if (event.x < leftHalf) {
|
||||||
|
leftPanelTouch()
|
||||||
|
} else {
|
||||||
|
rightPanelTouch()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val deltaX = event.x - startX
|
||||||
|
if (abs(deltaX) > swipeThreshold) {
|
||||||
|
if (deltaX > 0) onStoriesPrevious()
|
||||||
|
else onStoriesCompleted()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -30,8 +30,8 @@ import ani.dantotsu.media.user.ListActivity
|
||||||
import ani.dantotsu.navBarHeight
|
import ani.dantotsu.navBarHeight
|
||||||
import ani.dantotsu.openImage
|
import ani.dantotsu.openImage
|
||||||
import ani.dantotsu.openLinkInBrowser
|
import ani.dantotsu.openLinkInBrowser
|
||||||
import ani.dantotsu.others.ImageViewDialog
|
import ani.dantotsu.profile.activity.ActivityFragment
|
||||||
import ani.dantotsu.profile.activity.FeedFragment
|
import ani.dantotsu.profile.activity.ActivityFragment.Companion.ActivityType
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
|
@ -156,6 +156,7 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
|
||||||
openLinkInBrowser("https://anilist.co/user/${user.name}")
|
openLinkInBrowser("https://anilist.co/user/${user.name}")
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_create_new_activity -> {
|
R.id.action_create_new_activity -> {
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
context,
|
context,
|
||||||
|
@ -165,6 +166,7 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
|
||||||
)
|
)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,7 +179,8 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
|
||||||
user.avatar?.medium ?: ""
|
user.avatar?.medium ?: ""
|
||||||
)
|
)
|
||||||
profileUserName.text = user.name
|
profileUserName.text = user.name
|
||||||
val bannerAnimations: ImageView= if (PrefManager.getVal(PrefName.BannerAnimations)) profileBannerImage else profileBannerImageNoKen
|
val bannerAnimations: ImageView =
|
||||||
|
if (PrefManager.getVal(PrefName.BannerAnimations)) profileBannerImage else profileBannerImageNoKen
|
||||||
|
|
||||||
blurImage(
|
blurImage(
|
||||||
bannerAnimations,
|
bannerAnimations,
|
||||||
|
@ -199,7 +202,8 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
|
||||||
profileAppBar.addOnOffsetChangedListener(context)
|
profileAppBar.addOnOffsetChangedListener(context)
|
||||||
|
|
||||||
|
|
||||||
profileFollowerCount.text = (respond.data.followerPage?.pageInfo?.total ?: 0).toString()
|
profileFollowerCount.text =
|
||||||
|
(respond.data.followerPage?.pageInfo?.total ?: 0).toString()
|
||||||
profileFollowerCountContainer.setOnClickListener {
|
profileFollowerCountContainer.setOnClickListener {
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
context,
|
context,
|
||||||
|
@ -209,7 +213,8 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
profileFollowingCount.text = (respond.data.followingPage?.pageInfo?.total ?: 0).toString()
|
profileFollowingCount.text =
|
||||||
|
(respond.data.followingPage?.pageInfo?.total ?: 0).toString()
|
||||||
profileFollowingCountContainer.setOnClickListener {
|
profileFollowingCountContainer.setOnClickListener {
|
||||||
ContextCompat.startActivity(
|
ContextCompat.startActivity(
|
||||||
context,
|
context,
|
||||||
|
@ -320,7 +325,7 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene
|
||||||
override fun getItemCount(): Int = 3
|
override fun getItemCount(): Int = 3
|
||||||
override fun createFragment(position: Int): Fragment = when (position) {
|
override fun createFragment(position: Int): Fragment = when (position) {
|
||||||
0 -> ProfileFragment.newInstance(user)
|
0 -> ProfileFragment.newInstance(user)
|
||||||
1 -> FeedFragment.newInstance(user.id, false, -1)
|
1 -> ActivityFragment(ActivityType.OTHER_USER, user.id)
|
||||||
2 -> StatsFragment.newInstance(user)
|
2 -> StatsFragment.newInstance(user)
|
||||||
else -> ProfileFragment.newInstance(user)
|
else -> ProfileFragment.newInstance(user)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
package ani.dantotsu.profile.activity
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.view.updateLayoutParams
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import ani.dantotsu.R
|
||||||
|
import ani.dantotsu.connections.anilist.Anilist
|
||||||
|
import ani.dantotsu.connections.anilist.api.Activity
|
||||||
|
import ani.dantotsu.databinding.FragmentFeedBinding
|
||||||
|
import ani.dantotsu.media.MediaDetailsActivity
|
||||||
|
import ani.dantotsu.navBarHeight
|
||||||
|
import ani.dantotsu.profile.ProfileActivity
|
||||||
|
import ani.dantotsu.setBaseline
|
||||||
|
import com.xwray.groupie.GroupieAdapter
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class ActivityFragment(
|
||||||
|
var type: ActivityType,
|
||||||
|
val userId: Int? = null,
|
||||||
|
var activityId: Int? = null,
|
||||||
|
) : Fragment() {
|
||||||
|
private lateinit var binding: FragmentFeedBinding
|
||||||
|
private var adapter: GroupieAdapter = GroupieAdapter()
|
||||||
|
private var page: Int = 1
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
binding = FragmentFeedBinding.inflate(inflater, container, false)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val navBar = if (userId != null) {
|
||||||
|
(activity as ProfileActivity).navBar
|
||||||
|
} else {
|
||||||
|
(activity as FeedActivity).navBar
|
||||||
|
}
|
||||||
|
binding.listRecyclerView.setBaseline(navBar)
|
||||||
|
binding.listRecyclerView.adapter = adapter
|
||||||
|
binding.listRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||||
|
binding.listProgressBar.isVisible = true
|
||||||
|
binding.feedRefresh.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
bottomMargin = navBarHeight
|
||||||
|
}
|
||||||
|
binding.emptyTextView.text = getString(R.string.no_notifications)
|
||||||
|
lifecycleScope.launch {
|
||||||
|
getList()
|
||||||
|
if (adapter.itemCount == 0) {
|
||||||
|
binding.emptyTextView.isVisible = true
|
||||||
|
}
|
||||||
|
binding.listProgressBar.isVisible = false
|
||||||
|
}
|
||||||
|
binding.feedSwipeRefresh.setOnRefreshListener {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
adapter.clear()
|
||||||
|
page = 1
|
||||||
|
getList()
|
||||||
|
binding.feedSwipeRefresh.isRefreshing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.listRecyclerView.addOnScrollListener(object :
|
||||||
|
RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
|
if (shouldLoadMore()) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
binding.feedRefresh.isVisible = true
|
||||||
|
getList()
|
||||||
|
binding.feedRefresh.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private suspend fun getList() {
|
||||||
|
val list = when (type) {
|
||||||
|
ActivityType.GLOBAL -> getActivities(true)
|
||||||
|
ActivityType.USER -> getActivities()
|
||||||
|
ActivityType.OTHER_USER -> getActivities(userId = userId)
|
||||||
|
ActivityType.ONE -> getActivities(activityId = activityId)
|
||||||
|
}
|
||||||
|
adapter.addAll(list.map { ActivityItem(it, ::onActivityClick, requireActivity()) })
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getActivities(
|
||||||
|
global: Boolean = false,
|
||||||
|
userId: Int? = null,
|
||||||
|
activityId: Int? = null,
|
||||||
|
): List<Activity> {
|
||||||
|
val res = Anilist.query.getFeed(userId, global, page, activityId)?.data?.page?.activities
|
||||||
|
page += 1
|
||||||
|
return res
|
||||||
|
?.filter { if (Anilist.adult) true else it.media?.isAdult != true }
|
||||||
|
?.filterNot { it.recipient?.id != null && it.recipient.id != Anilist.userid }
|
||||||
|
?: emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldLoadMore(): Boolean {
|
||||||
|
val layoutManager =
|
||||||
|
(binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition()
|
||||||
|
val adapter = binding.listRecyclerView.adapter
|
||||||
|
return !binding.listRecyclerView.canScrollVertically(1) &&
|
||||||
|
!binding.feedRefresh.isVisible && adapter?.itemCount != 0 &&
|
||||||
|
layoutManager == (adapter!!.itemCount - 1)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onActivityClick(id: Int, type: String) {
|
||||||
|
when (type) {
|
||||||
|
"USER" -> {
|
||||||
|
ContextCompat.startActivity(
|
||||||
|
requireContext(), Intent(requireContext(), ProfileActivity::class.java)
|
||||||
|
.putExtra("userId", id), null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
"MEDIA" -> {
|
||||||
|
ContextCompat.startActivity(
|
||||||
|
requireContext(), Intent(requireContext(), MediaDetailsActivity::class.java)
|
||||||
|
.putExtra("mediaId", id), null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
if (this::binding.isInitialized) {
|
||||||
|
binding.root.requestLayout()
|
||||||
|
val navBar = if (userId != null) {
|
||||||
|
(activity as ProfileActivity).navBar
|
||||||
|
} else {
|
||||||
|
(activity as FeedActivity).navBar
|
||||||
|
}
|
||||||
|
binding.listRecyclerView.setBaseline(navBar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
enum class ActivityType {
|
||||||
|
GLOBAL, USER, OTHER_USER, ONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package ani.dantotsu.profile.activity
|
||||||
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
|
@ -10,16 +11,20 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.databinding.ActivityFeedBinding
|
import ani.dantotsu.databinding.ActivityFeedBinding
|
||||||
|
import ani.dantotsu.databinding.ActivityNotificationBinding
|
||||||
import ani.dantotsu.initActivity
|
import ani.dantotsu.initActivity
|
||||||
import ani.dantotsu.navBarHeight
|
import ani.dantotsu.navBarHeight
|
||||||
import ani.dantotsu.statusBarHeight
|
import ani.dantotsu.statusBarHeight
|
||||||
import ani.dantotsu.themes.ThemeManager
|
import ani.dantotsu.themes.ThemeManager
|
||||||
|
import ani.dantotsu.profile.activity.ActivityFragment.Companion.ActivityType
|
||||||
|
import ani.dantotsu.profile.notification.NotificationActivity
|
||||||
import nl.joery.animatedbottombar.AnimatedBottomBar
|
import nl.joery.animatedbottombar.AnimatedBottomBar
|
||||||
|
|
||||||
class FeedActivity : AppCompatActivity() {
|
class FeedActivity : AppCompatActivity() {
|
||||||
private lateinit var binding: ActivityFeedBinding
|
private lateinit var binding: ActivityNotificationBinding
|
||||||
private var selected: Int = 0
|
private var selected: Int = 0
|
||||||
lateinit var navBar: AnimatedBottomBar
|
lateinit var navBar: AnimatedBottomBar
|
||||||
|
|
||||||
|
@ -27,28 +32,27 @@ class FeedActivity : AppCompatActivity() {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
ThemeManager(this).applyTheme()
|
ThemeManager(this).applyTheme()
|
||||||
initActivity(this)
|
initActivity(this)
|
||||||
binding = ActivityFeedBinding.inflate(layoutInflater)
|
binding = ActivityNotificationBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
navBar = binding.feedNavBar
|
binding.notificationTitle.text = getString(R.string.activities)
|
||||||
val navBarMargin = if (resources.configuration.orientation ==
|
binding.notificationToolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
Configuration.ORIENTATION_LANDSCAPE
|
topMargin = statusBarHeight
|
||||||
) 0 else navBarHeight
|
|
||||||
navBar.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin = navBarMargin }
|
|
||||||
val personalTab = navBar.createTab(R.drawable.ic_round_person_24, "Following")
|
|
||||||
val globalTab = navBar.createTab(R.drawable.ic_globe_24, "Global")
|
|
||||||
navBar.addTab(personalTab)
|
|
||||||
navBar.addTab(globalTab)
|
|
||||||
binding.listTitle.text = getString(R.string.activities)
|
|
||||||
binding.feedViewPager.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
|
||||||
bottomMargin = navBarMargin
|
|
||||||
topMargin += statusBarHeight
|
|
||||||
}
|
}
|
||||||
binding.listToolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> { topMargin += statusBarHeight }
|
navBar = binding.notificationNavBar
|
||||||
val activityId = intent.getIntExtra("activityId", -1)
|
binding.root.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
binding.feedViewPager.adapter =
|
bottomMargin = navBarHeight
|
||||||
ViewPagerAdapter(supportFragmentManager, lifecycle, activityId)
|
}
|
||||||
binding.feedViewPager.setCurrentItem(selected, false)
|
val tabs = listOf(
|
||||||
binding.feedViewPager.isUserInputEnabled = false
|
Pair(R.drawable.ic_round_person_24, "Following"),
|
||||||
|
Pair(R.drawable.ic_globe_24, "Global"),
|
||||||
|
)
|
||||||
|
tabs.forEach { (icon, title) -> navBar.addTab(navBar.createTab(icon, title)) }
|
||||||
|
binding.notificationBack.setOnClickListener { onBackPressedDispatcher.onBackPressed() }
|
||||||
|
val getOne = intent.getIntExtra("activityId", -1)
|
||||||
|
if (getOne != -1) { navBar.visibility = View.GONE }
|
||||||
|
binding.notificationViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle, getOne)
|
||||||
|
binding.notificationViewPager.setOffscreenPageLimit(4)
|
||||||
|
binding.notificationViewPager.setCurrentItem(selected, false)
|
||||||
navBar.selectTabAt(selected)
|
navBar.selectTabAt(selected)
|
||||||
navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
|
navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
|
||||||
override fun onTabSelected(
|
override fun onTabSelected(
|
||||||
|
@ -58,24 +62,15 @@ class FeedActivity : AppCompatActivity() {
|
||||||
newTab: AnimatedBottomBar.Tab
|
newTab: AnimatedBottomBar.Tab
|
||||||
) {
|
) {
|
||||||
selected = newIndex
|
selected = newIndex
|
||||||
binding.feedViewPager.setCurrentItem(selected, true)
|
binding.notificationViewPager.setCurrentItem(selected, true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
binding.listBack.setOnClickListener {
|
binding.notificationViewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||||
onBackPressedDispatcher.onBackPressed()
|
override fun onPageSelected(position: Int) {
|
||||||
|
super.onPageSelected(position)
|
||||||
|
navBar.selectTabAt(position)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
|
||||||
super.onConfigurationChanged(newConfig)
|
|
||||||
val margin =
|
|
||||||
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) 0 else navBarHeight
|
|
||||||
val params: ViewGroup.MarginLayoutParams =
|
|
||||||
binding.feedViewPager.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
val paramsNav: ViewGroup.MarginLayoutParams =
|
|
||||||
navBar.layoutParams as ViewGroup.MarginLayoutParams
|
|
||||||
params.updateMargins(bottom = margin)
|
|
||||||
paramsNav.updateMargins(bottom = margin)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
@ -88,12 +83,12 @@ class FeedActivity : AppCompatActivity() {
|
||||||
lifecycle: Lifecycle,
|
lifecycle: Lifecycle,
|
||||||
private val activityId: Int
|
private val activityId: Int
|
||||||
) : FragmentStateAdapter(fragmentManager, lifecycle) {
|
) : FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||||
override fun getItemCount(): Int = 2
|
override fun getItemCount(): Int = if (activityId != -1) 1 else 2
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment {
|
override fun createFragment(position: Int): Fragment {
|
||||||
return when (position) {
|
return when (position) {
|
||||||
0 -> FeedFragment.newInstance(null, false, activityId)
|
0 -> ActivityFragment(if (activityId != -1) ActivityType.ONE else ActivityType.USER, activityId = activityId)
|
||||||
else -> FeedFragment.newInstance(null, true, -1)
|
else -> ActivityFragment(ActivityType.GLOBAL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,188 +0,0 @@
|
||||||
package ani.dantotsu.profile.activity
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
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.media.MediaDetailsActivity
|
|
||||||
import ani.dantotsu.profile.ProfileActivity
|
|
||||||
import ani.dantotsu.setBaseline
|
|
||||||
import ani.dantotsu.util.Logger
|
|
||||||
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
|
|
||||||
private var loadedFirstTime = false
|
|
||||||
private var userId: Int? = null
|
|
||||||
private var global: Boolean = false
|
|
||||||
private var activityId: Int = -1
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View {
|
|
||||||
binding = FragmentFeedBinding.inflate(inflater, container, false)
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
activity = requireActivity()
|
|
||||||
|
|
||||||
userId = arguments?.getInt("userId", -1)
|
|
||||||
activityId = arguments?.getInt("activityId", -1) ?: -1
|
|
||||||
if (userId == -1) userId = null
|
|
||||||
global = arguments?.getBoolean("global", false) ?: false
|
|
||||||
|
|
||||||
val navBar = if (userId != null) {
|
|
||||||
(activity as ProfileActivity).navBar
|
|
||||||
} else {
|
|
||||||
(activity as FeedActivity).navBar
|
|
||||||
}
|
|
||||||
binding.listRecyclerView.setBaseline(navBar)
|
|
||||||
binding.listRecyclerView.adapter = adapter
|
|
||||||
binding.listRecyclerView.layoutManager =
|
|
||||||
LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
|
|
||||||
binding.listProgressBar.visibility = ViewGroup.VISIBLE
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
if (this::binding.isInitialized) {
|
|
||||||
binding.root.requestLayout()
|
|
||||||
val navBar = if (userId != null) {
|
|
||||||
(activity as ProfileActivity).navBar
|
|
||||||
} else {
|
|
||||||
(activity as FeedActivity).navBar
|
|
||||||
}
|
|
||||||
binding.listRecyclerView.setBaseline(navBar)
|
|
||||||
if (!loadedFirstTime) {
|
|
||||||
activity.lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
val nulledId = if (activityId == -1) null else activityId
|
|
||||||
val res = Anilist.query.getFeed(userId, global, activityId = nulledId)
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
res?.data?.page?.activities?.let { activities ->
|
|
||||||
activityList = activities
|
|
||||||
val filtered =
|
|
||||||
activityList
|
|
||||||
.filter { if (Anilist.adult) true else it.media?.isAdult == false }
|
|
||||||
.filterNot { //filter out messages that are not directed to the user
|
|
||||||
it.recipient?.id != null && it.recipient.id != Anilist.userid
|
|
||||||
}
|
|
||||||
adapter.update(filtered.map {
|
|
||||||
ActivityItem(
|
|
||||||
it,
|
|
||||||
::onActivityClick,
|
|
||||||
requireActivity()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
binding.listProgressBar.visibility = ViewGroup.GONE
|
|
||||||
val scrollView = binding.listRecyclerView
|
|
||||||
|
|
||||||
binding.listRecyclerView.setOnTouchListener { _, event ->
|
|
||||||
if (event?.action == MotionEvent.ACTION_UP) {
|
|
||||||
if (activityList.size % AnilistQueries.ITEMS_PER_PAGE != 0 && !global) {
|
|
||||||
//snackString("No more activities") fix spam?
|
|
||||||
Logger.log("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
|
|
||||||
loadPage {
|
|
||||||
binding.feedRefresh.visibility = ViewGroup.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.feedSwipeRefresh.setOnRefreshListener {
|
|
||||||
page = 1
|
|
||||||
adapter.clear()
|
|
||||||
activityList = emptyList()
|
|
||||||
loadPage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loadedFirstTime = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadPage(onFinish: () -> Unit = {}) {
|
|
||||||
activity.lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
val newRes = Anilist.query.getFeed(userId, global, page)
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
newRes?.data?.page?.activities?.let { activities ->
|
|
||||||
activityList += activities
|
|
||||||
val filtered = activities.filterNot {
|
|
||||||
it.recipient?.id != null && it.recipient.id != Anilist.userid
|
|
||||||
}
|
|
||||||
adapter.addAll(filtered.map {
|
|
||||||
ActivityItem(
|
|
||||||
it,
|
|
||||||
::onActivityClick,
|
|
||||||
requireActivity()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
binding.feedSwipeRefresh.isRefreshing = false
|
|
||||||
onFinish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onActivityClick(id: Int, type: String) {
|
|
||||||
when (type) {
|
|
||||||
"USER" -> {
|
|
||||||
ContextCompat.startActivity(
|
|
||||||
activity, Intent(activity, ProfileActivity::class.java)
|
|
||||||
.putExtra("userId", id), null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
"MEDIA" -> {
|
|
||||||
ContextCompat.startActivity(
|
|
||||||
activity, Intent(activity, MediaDetailsActivity::class.java)
|
|
||||||
.putExtra("mediaId", id), null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance(userId: Int?, global: Boolean, activityId: Int): FeedFragment {
|
|
||||||
val fragment = FeedFragment()
|
|
||||||
val args = Bundle()
|
|
||||||
args.putInt("userId", userId ?: -1)
|
|
||||||
args.putBoolean("global", global)
|
|
||||||
args.putInt("activityId", activityId)
|
|
||||||
fragment.arguments = args
|
|
||||||
return fragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,309 +0,0 @@
|
||||||
package ani.dantotsu.profile.activity
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.CheckBox
|
|
||||||
import android.widget.ImageButton
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
|
||||||
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.R
|
|
||||||
import ani.dantotsu.connections.anilist.Anilist
|
|
||||||
import ani.dantotsu.connections.anilist.api.Notification
|
|
||||||
import ani.dantotsu.connections.anilist.api.NotificationType
|
|
||||||
import ani.dantotsu.connections.anilist.api.NotificationType.Companion.fromFormattedString
|
|
||||||
import ani.dantotsu.currContext
|
|
||||||
import ani.dantotsu.databinding.ActivityFollowBinding
|
|
||||||
import ani.dantotsu.initActivity
|
|
||||||
import ani.dantotsu.media.MediaDetailsActivity
|
|
||||||
import ani.dantotsu.navBarHeight
|
|
||||||
import ani.dantotsu.notifications.comment.CommentStore
|
|
||||||
import ani.dantotsu.notifications.subscription.SubscriptionStore
|
|
||||||
import ani.dantotsu.profile.ProfileActivity
|
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
|
||||||
import ani.dantotsu.statusBarHeight
|
|
||||||
import ani.dantotsu.themes.ThemeManager
|
|
||||||
import ani.dantotsu.util.Logger
|
|
||||||
import com.xwray.groupie.GroupieAdapter
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
class NotificationActivity : AppCompatActivity() {
|
|
||||||
private lateinit var binding: ActivityFollowBinding
|
|
||||||
private lateinit var commentStore: List<CommentStore>
|
|
||||||
private lateinit var subscriptionStore: List<SubscriptionStore>
|
|
||||||
private var adapter: GroupieAdapter = GroupieAdapter()
|
|
||||||
private var notificationList: List<Notification> = emptyList()
|
|
||||||
val filters = ArrayList<String>()
|
|
||||||
private var currentPage: Int = 1
|
|
||||||
private var hasNextPage: Boolean = true
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
ThemeManager(this).applyTheme()
|
|
||||||
initActivity(this)
|
|
||||||
binding = ActivityFollowBinding.inflate(layoutInflater)
|
|
||||||
setContentView(binding.root)
|
|
||||||
binding.listTitle.text = getString(R.string.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
|
|
||||||
binding.followerList.visibility = ViewGroup.GONE
|
|
||||||
binding.listBack.setOnClickListener {
|
|
||||||
onBackPressedDispatcher.onBackPressed()
|
|
||||||
}
|
|
||||||
binding.listProgressBar.visibility = ViewGroup.VISIBLE
|
|
||||||
commentStore = PrefManager.getNullableVal<List<CommentStore>>(
|
|
||||||
PrefName.CommentNotificationStore,
|
|
||||||
null
|
|
||||||
) ?: listOf()
|
|
||||||
subscriptionStore = PrefManager.getNullableVal<List<SubscriptionStore>>(
|
|
||||||
PrefName.SubscriptionNotificationStore,
|
|
||||||
null
|
|
||||||
) ?: listOf()
|
|
||||||
|
|
||||||
binding.followFilterButton.setOnClickListener {
|
|
||||||
val dialogView = LayoutInflater.from(currContext()).inflate(R.layout.custom_dialog_layout, null)
|
|
||||||
val checkboxContainer = dialogView.findViewById<LinearLayout>(R.id.checkboxContainer)
|
|
||||||
val tickAllButton = dialogView.findViewById<ImageButton>(R.id.toggleButton)
|
|
||||||
val title = dialogView.findViewById<TextView>(R.id.scantitle)
|
|
||||||
title.visibility = ViewGroup.GONE
|
|
||||||
fun getToggleImageResource(container: ViewGroup): Int {
|
|
||||||
var allChecked = true
|
|
||||||
var allUnchecked = true
|
|
||||||
|
|
||||||
for (i in 0 until container.childCount) {
|
|
||||||
val checkBox = container.getChildAt(i) as CheckBox
|
|
||||||
if (!checkBox.isChecked) {
|
|
||||||
allChecked = false
|
|
||||||
} else {
|
|
||||||
allUnchecked = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return when {
|
|
||||||
allChecked -> R.drawable.untick_all_boxes
|
|
||||||
allUnchecked -> R.drawable.tick_all_boxes
|
|
||||||
else -> R.drawable.invert_all_boxes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NotificationType.entries.forEach { notificationType ->
|
|
||||||
val checkBox = CheckBox(currContext())
|
|
||||||
checkBox.text = notificationType.toFormattedString()
|
|
||||||
checkBox.isChecked = !filters.contains(notificationType.value.fromFormattedString())
|
|
||||||
checkBox.setOnCheckedChangeListener { _, isChecked ->
|
|
||||||
if (isChecked) {
|
|
||||||
filters.remove(notificationType.value.fromFormattedString())
|
|
||||||
} else {
|
|
||||||
filters.add(notificationType.value.fromFormattedString())
|
|
||||||
}
|
|
||||||
tickAllButton.setImageResource(getToggleImageResource(checkboxContainer))
|
|
||||||
}
|
|
||||||
checkboxContainer.addView(checkBox)
|
|
||||||
}
|
|
||||||
tickAllButton.setImageResource(getToggleImageResource(checkboxContainer))
|
|
||||||
tickAllButton.setOnClickListener {
|
|
||||||
for (i in 0 until checkboxContainer.childCount) {
|
|
||||||
val checkBox = checkboxContainer.getChildAt(i) as CheckBox
|
|
||||||
checkBox.isChecked = !checkBox.isChecked
|
|
||||||
}
|
|
||||||
|
|
||||||
tickAllButton.setImageResource(getToggleImageResource(checkboxContainer))
|
|
||||||
}
|
|
||||||
val alertD = AlertDialog.Builder(this, R.style.MyPopup)
|
|
||||||
alertD.setTitle("Filter")
|
|
||||||
alertD.setView(dialogView)
|
|
||||||
alertD.setPositiveButton("OK") { _, _ ->
|
|
||||||
currentPage = 1
|
|
||||||
hasNextPage = true
|
|
||||||
adapter.clear()
|
|
||||||
adapter.addAll(notificationList.filter { notification ->
|
|
||||||
!filters.contains(notification.notificationType)
|
|
||||||
}.map {
|
|
||||||
NotificationItem(
|
|
||||||
it,
|
|
||||||
::onNotificationClick
|
|
||||||
)
|
|
||||||
})
|
|
||||||
loadPage(-1) {
|
|
||||||
binding.followRefresh.visibility = ViewGroup.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
alertD.setNegativeButton("Cancel") { _, _ -> }
|
|
||||||
val dialog = alertD.show()
|
|
||||||
dialog.window?.setDimAmount(0.8f)
|
|
||||||
}
|
|
||||||
|
|
||||||
val activityId = intent.getIntExtra("activityId", -1)
|
|
||||||
lifecycleScope.launch {
|
|
||||||
loadPage(activityId) {
|
|
||||||
binding.listProgressBar.visibility = ViewGroup.GONE
|
|
||||||
}
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
binding.listProgressBar.visibility = ViewGroup.GONE
|
|
||||||
binding.listRecyclerView.setOnTouchListener { _, event ->
|
|
||||||
if (event?.action == MotionEvent.ACTION_UP) {
|
|
||||||
if (hasNextPage && !binding.listRecyclerView.canScrollVertically(1) && !binding.followRefresh.isVisible
|
|
||||||
&& binding.listRecyclerView.adapter!!.itemCount != 0 &&
|
|
||||||
(binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.listRecyclerView.adapter!!.itemCount - 1)
|
|
||||||
) {
|
|
||||||
binding.followRefresh.visibility = ViewGroup.VISIBLE
|
|
||||||
loadPage(-1) {
|
|
||||||
binding.followRefresh.visibility = ViewGroup.GONE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.followSwipeRefresh.setOnRefreshListener {
|
|
||||||
currentPage = 1
|
|
||||||
hasNextPage = true
|
|
||||||
adapter.clear()
|
|
||||||
notificationList = emptyList()
|
|
||||||
loadPage(-1) {
|
|
||||||
binding.followSwipeRefresh.isRefreshing = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadPage(activityId: Int, onFinish: () -> Unit = {}) {
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
|
||||||
val resetNotification = activityId == -1
|
|
||||||
val res = Anilist.query.getNotifications(
|
|
||||||
Anilist.userid ?: PrefManager.getVal<String>(PrefName.AnilistUserId).toIntOrNull()
|
|
||||||
?: 0, currentPage, resetNotification = resetNotification
|
|
||||||
)
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
val newNotifications: MutableList<Notification> = mutableListOf()
|
|
||||||
res?.data?.page?.notifications?.let { notifications ->
|
|
||||||
Logger.log("Notifications: $notifications")
|
|
||||||
newNotifications += if (activityId != -1) {
|
|
||||||
notifications.filter { it.id == activityId }
|
|
||||||
} else {
|
|
||||||
notifications
|
|
||||||
}.toMutableList()
|
|
||||||
}
|
|
||||||
if (activityId == -1) {
|
|
||||||
val furthestTime = newNotifications.minOfOrNull { it.createdAt } ?: 0
|
|
||||||
commentStore.forEach {
|
|
||||||
if ((it.time > furthestTime * 1000L || !hasNextPage) && notificationList.none { notification ->
|
|
||||||
notification.commentId == it.commentId && notification.createdAt == (it.time / 1000L).toInt()
|
|
||||||
}) {
|
|
||||||
val notification = Notification(
|
|
||||||
it.type.toString(),
|
|
||||||
System.currentTimeMillis().toInt(),
|
|
||||||
commentId = it.commentId,
|
|
||||||
notificationType = it.type.toString(),
|
|
||||||
mediaId = it.mediaId,
|
|
||||||
context = it.title + "\n" + it.content,
|
|
||||||
createdAt = (it.time / 1000L).toInt(),
|
|
||||||
)
|
|
||||||
newNotifications += notification
|
|
||||||
}
|
|
||||||
}
|
|
||||||
subscriptionStore.forEach {
|
|
||||||
if ((it.time > furthestTime * 1000L || !hasNextPage) && notificationList.none { notification ->
|
|
||||||
notification.mediaId == it.mediaId && notification.createdAt == (it.time / 1000L).toInt()
|
|
||||||
}) {
|
|
||||||
val notification = Notification(
|
|
||||||
it.type,
|
|
||||||
System.currentTimeMillis().toInt(),
|
|
||||||
commentId = it.mediaId,
|
|
||||||
mediaId = it.mediaId,
|
|
||||||
notificationType = it.type,
|
|
||||||
context = it.title + ": " + it.content,
|
|
||||||
createdAt = (it.time / 1000L).toInt(),
|
|
||||||
image = it.image,
|
|
||||||
banner = it.banner ?: it.image
|
|
||||||
)
|
|
||||||
newNotifications += notification
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newNotifications.sortByDescending { it.createdAt }
|
|
||||||
}
|
|
||||||
|
|
||||||
notificationList += newNotifications
|
|
||||||
adapter.addAll(newNotifications.filter { notification ->
|
|
||||||
!filters.contains(notification.notificationType)
|
|
||||||
}.map {
|
|
||||||
NotificationItem(
|
|
||||||
it,
|
|
||||||
::onNotificationClick
|
|
||||||
)
|
|
||||||
})
|
|
||||||
currentPage = res?.data?.page?.pageInfo?.currentPage?.plus(1) ?: 1
|
|
||||||
hasNextPage = res?.data?.page?.pageInfo?.hasNextPage ?: false
|
|
||||||
binding.followSwipeRefresh.isRefreshing = false
|
|
||||||
onFinish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onNotificationClick(id: Int, optional: Int?, type: NotificationClickType) {
|
|
||||||
when (type) {
|
|
||||||
NotificationClickType.USER -> {
|
|
||||||
ContextCompat.startActivity(
|
|
||||||
this, Intent(this, ProfileActivity::class.java)
|
|
||||||
.putExtra("userId", id), null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationClickType.MEDIA -> {
|
|
||||||
ContextCompat.startActivity(
|
|
||||||
this, Intent(this, MediaDetailsActivity::class.java)
|
|
||||||
.putExtra("mediaId", id), null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationClickType.ACTIVITY -> {
|
|
||||||
ContextCompat.startActivity(
|
|
||||||
this, Intent(this, FeedActivity::class.java)
|
|
||||||
.putExtra("activityId", id), null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationClickType.COMMENT -> {
|
|
||||||
ContextCompat.startActivity(
|
|
||||||
this, Intent(this, MediaDetailsActivity::class.java)
|
|
||||||
.putExtra("FRAGMENT_TO_LOAD", "COMMENTS")
|
|
||||||
.putExtra("mediaId", id)
|
|
||||||
.putExtra("commentId", optional ?: -1),
|
|
||||||
null
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationClickType.UNDEFINED -> {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
enum class NotificationClickType {
|
|
||||||
USER, MEDIA, ACTIVITY, COMMENT, UNDEFINED
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
package ani.dantotsu.profile.notification
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
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 androidx.viewpager2.widget.ViewPager2
|
||||||
|
import ani.dantotsu.R
|
||||||
|
import ani.dantotsu.databinding.ActivityNotificationBinding
|
||||||
|
import ani.dantotsu.initActivity
|
||||||
|
import ani.dantotsu.navBarHeight
|
||||||
|
import ani.dantotsu.statusBarHeight
|
||||||
|
import ani.dantotsu.themes.ThemeManager
|
||||||
|
import ani.dantotsu.profile.notification.NotificationFragment.Companion.NotificationType
|
||||||
|
import nl.joery.animatedbottombar.AnimatedBottomBar
|
||||||
|
|
||||||
|
class NotificationActivity : AppCompatActivity() {
|
||||||
|
private lateinit var binding: ActivityNotificationBinding
|
||||||
|
private var selected: Int = 0
|
||||||
|
lateinit var navBar: AnimatedBottomBar
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
ThemeManager(this).applyTheme()
|
||||||
|
initActivity(this)
|
||||||
|
binding = ActivityNotificationBinding.inflate(layoutInflater)
|
||||||
|
setContentView(binding.root)
|
||||||
|
binding.notificationTitle.text = getString(R.string.notifications)
|
||||||
|
binding.notificationToolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
topMargin = statusBarHeight
|
||||||
|
}
|
||||||
|
navBar = binding.notificationNavBar
|
||||||
|
binding.root.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
bottomMargin = navBarHeight
|
||||||
|
}
|
||||||
|
val tabs = listOf(
|
||||||
|
Pair(R.drawable.ic_round_movie_filter_24, "Media"),
|
||||||
|
Pair(R.drawable.ic_round_person_24, "User"),
|
||||||
|
Pair(R.drawable.ic_round_notifications_active_24, "Subs"),
|
||||||
|
Pair(R.drawable.ic_round_comment_24, "Comments")
|
||||||
|
)
|
||||||
|
tabs.forEach { (icon, title) -> navBar.addTab(navBar.createTab(icon, title)) }
|
||||||
|
|
||||||
|
binding.notificationBack.setOnClickListener { onBackPressedDispatcher.onBackPressed() }
|
||||||
|
val getOne = intent.getIntExtra("activityId", -1)
|
||||||
|
if (getOne != -1) navBar.isVisible = false
|
||||||
|
binding.notificationViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle, getOne)
|
||||||
|
binding.notificationViewPager.setOffscreenPageLimit(4)
|
||||||
|
binding.notificationViewPager.setCurrentItem(selected, 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.notificationViewPager.setCurrentItem(selected, true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
binding.notificationViewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
|
||||||
|
override fun onPageSelected(position: Int) {
|
||||||
|
super.onPageSelected(position)
|
||||||
|
navBar.selectTabAt(position)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
if (this::navBar.isInitialized) {
|
||||||
|
navBar.selectTabAt(selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private class ViewPagerAdapter(
|
||||||
|
fragmentManager: FragmentManager,
|
||||||
|
lifecycle: Lifecycle,
|
||||||
|
val id: Int = -1
|
||||||
|
) : FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||||
|
override fun getItemCount(): Int = if (id != -1) 1 else 4
|
||||||
|
|
||||||
|
override fun createFragment(position: Int): Fragment = when (position) {
|
||||||
|
0 -> NotificationFragment(if (id != -1) NotificationType.ONE else NotificationType.MEDIA, id)
|
||||||
|
1 -> NotificationFragment(NotificationType.USER)
|
||||||
|
2 -> NotificationFragment(NotificationType.SUBSCRIPTION)
|
||||||
|
3 -> NotificationFragment(NotificationType.COMMENT)
|
||||||
|
else -> NotificationFragment(NotificationType.MEDIA)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,228 @@
|
||||||
|
package ani.dantotsu.profile.notification
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.view.updateLayoutParams
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.webkit.internal.ApiFeature.N
|
||||||
|
import ani.dantotsu.R
|
||||||
|
import ani.dantotsu.connections.anilist.Anilist
|
||||||
|
import ani.dantotsu.connections.anilist.api.Notification
|
||||||
|
import ani.dantotsu.databinding.FragmentNotificationsBinding
|
||||||
|
import ani.dantotsu.media.MediaDetailsActivity
|
||||||
|
import ani.dantotsu.navBarHeight
|
||||||
|
import ani.dantotsu.notifications.comment.CommentStore
|
||||||
|
import ani.dantotsu.notifications.subscription.SubscriptionStore
|
||||||
|
import ani.dantotsu.profile.ProfileActivity
|
||||||
|
import ani.dantotsu.profile.activity.FeedActivity
|
||||||
|
import ani.dantotsu.setBaseline
|
||||||
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
|
import com.xwray.groupie.GroupieAdapter
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationFragment(
|
||||||
|
val type: NotificationType,
|
||||||
|
val getID: Int = -1
|
||||||
|
) : Fragment() {
|
||||||
|
private lateinit var binding: FragmentNotificationsBinding
|
||||||
|
private var adapter: GroupieAdapter = GroupieAdapter()
|
||||||
|
private var currentPage = 1
|
||||||
|
private var hasNextPage = false
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
binding = FragmentNotificationsBinding.inflate(inflater, container, false)
|
||||||
|
return binding.root
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val navbar = (activity as NotificationActivity).navBar
|
||||||
|
binding.notificationRecyclerView.setBaseline(navbar)
|
||||||
|
binding.notificationRecyclerView.adapter = adapter
|
||||||
|
binding.notificationRecyclerView.layoutManager = LinearLayoutManager(context)
|
||||||
|
binding.notificationProgressBar.isVisible = true
|
||||||
|
binding.notificationRefresh.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
|
bottomMargin = navBarHeight
|
||||||
|
}
|
||||||
|
binding.emptyTextView.text = getString(R.string.no_notifications)
|
||||||
|
lifecycleScope.launch {
|
||||||
|
getList()
|
||||||
|
if (adapter.itemCount == 0) {
|
||||||
|
binding.emptyTextView.isVisible = true
|
||||||
|
}
|
||||||
|
binding.notificationProgressBar.isVisible = false
|
||||||
|
}
|
||||||
|
binding.notificationSwipeRefresh.setOnRefreshListener {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
adapter.clear()
|
||||||
|
currentPage = 1
|
||||||
|
getList()
|
||||||
|
binding.notificationSwipeRefresh.isRefreshing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding.notificationRecyclerView.addOnScrollListener(object :
|
||||||
|
RecyclerView.OnScrollListener() {
|
||||||
|
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||||
|
super.onScrolled(recyclerView, dx, dy)
|
||||||
|
if (shouldLoadMore()) {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
binding.notificationRefresh.isVisible = true
|
||||||
|
getList()
|
||||||
|
binding.notificationRefresh.isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getList() {
|
||||||
|
val list = when (type) {
|
||||||
|
NotificationType.ONE -> getNotificationsFiltered(false) { it.id == getID }
|
||||||
|
NotificationType.MEDIA -> getNotificationsFiltered { it.media != null }
|
||||||
|
NotificationType.USER -> getNotificationsFiltered { it.media == null }
|
||||||
|
NotificationType.SUBSCRIPTION -> getSubscriptions()
|
||||||
|
NotificationType.COMMENT -> getComments()
|
||||||
|
}
|
||||||
|
adapter.addAll(list.map { NotificationItem(it, ::onClick) })
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getNotificationsFiltered(
|
||||||
|
reset: Boolean = true,
|
||||||
|
filter: (Notification) -> Boolean
|
||||||
|
): List<Notification> {
|
||||||
|
val userId =
|
||||||
|
Anilist.userid ?: PrefManager.getVal<String>(PrefName.AnilistUserId).toIntOrNull() ?: 0
|
||||||
|
val res = Anilist.query.getNotifications(userId, currentPage, reset)?.data?.page
|
||||||
|
currentPage = res?.pageInfo?.currentPage?.plus(1) ?: 1
|
||||||
|
hasNextPage = res?.pageInfo?.hasNextPage ?: false
|
||||||
|
return res?.notifications?.filter(filter) ?: listOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSubscriptions(): List<Notification> {
|
||||||
|
val list = PrefManager.getNullableVal<List<SubscriptionStore>>(
|
||||||
|
PrefName.SubscriptionNotificationStore,
|
||||||
|
null
|
||||||
|
) ?: listOf()
|
||||||
|
return list.sortedByDescending { (it.time / 1000L).toInt() }
|
||||||
|
.filter { it.image != null }.map {
|
||||||
|
Notification(
|
||||||
|
it.type,
|
||||||
|
System.currentTimeMillis().toInt(),
|
||||||
|
commentId = it.mediaId,
|
||||||
|
mediaId = it.mediaId,
|
||||||
|
notificationType = it.type,
|
||||||
|
context = it.title + ": " + it.content,
|
||||||
|
createdAt = (it.time / 1000L).toInt(),
|
||||||
|
image = it.image,
|
||||||
|
banner = it.banner ?: it.image
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getComments(): List<Notification> {
|
||||||
|
val list = PrefManager.getNullableVal<List<CommentStore>>(
|
||||||
|
PrefName.CommentNotificationStore,
|
||||||
|
null
|
||||||
|
) ?: listOf()
|
||||||
|
return list
|
||||||
|
.sortedByDescending { (it.time / 1000L).toInt() }
|
||||||
|
.map {
|
||||||
|
Notification(
|
||||||
|
it.type.toString(),
|
||||||
|
System.currentTimeMillis().toInt(),
|
||||||
|
commentId = it.commentId,
|
||||||
|
notificationType = it.type.toString(),
|
||||||
|
mediaId = it.mediaId,
|
||||||
|
context = it.title + "\n" + it.content,
|
||||||
|
createdAt = (it.time / 1000L).toInt(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldLoadMore(): Boolean {
|
||||||
|
val layoutManager =
|
||||||
|
(binding.notificationRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition()
|
||||||
|
val adapter = binding.notificationRecyclerView.adapter
|
||||||
|
|
||||||
|
return hasNextPage && !binding.notificationRefresh.isVisible && adapter?.itemCount != 0 &&
|
||||||
|
layoutManager == (adapter!!.itemCount - 1) &&
|
||||||
|
!binding.notificationRecyclerView.canScrollVertically(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onClick(
|
||||||
|
id: Int,
|
||||||
|
optional: Int?,
|
||||||
|
type: NotificationClickType
|
||||||
|
) {
|
||||||
|
when (type) {
|
||||||
|
NotificationClickType.USER -> {
|
||||||
|
ContextCompat.startActivity(
|
||||||
|
requireContext(), Intent(requireContext(), ProfileActivity::class.java)
|
||||||
|
.putExtra("userId", id), null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationClickType.MEDIA -> {
|
||||||
|
ContextCompat.startActivity(
|
||||||
|
requireContext(), Intent(requireContext(), MediaDetailsActivity::class.java)
|
||||||
|
.putExtra("mediaId", id), null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationClickType.ACTIVITY -> {
|
||||||
|
ContextCompat.startActivity(
|
||||||
|
requireContext(), Intent(requireContext(), FeedActivity::class.java)
|
||||||
|
.putExtra("activityId", id), null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationClickType.COMMENT -> {
|
||||||
|
ContextCompat.startActivity(
|
||||||
|
requireContext(), Intent(requireContext(), MediaDetailsActivity::class.java)
|
||||||
|
.putExtra("FRAGMENT_TO_LOAD", "COMMENTS")
|
||||||
|
.putExtra("mediaId", id)
|
||||||
|
.putExtra("commentId", optional ?: -1),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationClickType.UNDEFINED -> {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
if (this::binding.isInitialized) {
|
||||||
|
binding.root.requestLayout()
|
||||||
|
binding.root.setBaseline((activity as NotificationActivity).navBar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
enum class NotificationClickType {
|
||||||
|
USER, MEDIA, ACTIVITY, COMMENT, UNDEFINED
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class NotificationType {
|
||||||
|
MEDIA, USER, SUBSCRIPTION, COMMENT, ONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package ani.dantotsu.profile.activity
|
package ani.dantotsu.profile.notification
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -8,7 +8,8 @@ import ani.dantotsu.connections.anilist.api.Notification
|
||||||
import ani.dantotsu.connections.anilist.api.NotificationType
|
import ani.dantotsu.connections.anilist.api.NotificationType
|
||||||
import ani.dantotsu.databinding.ItemNotificationBinding
|
import ani.dantotsu.databinding.ItemNotificationBinding
|
||||||
import ani.dantotsu.loadImage
|
import ani.dantotsu.loadImage
|
||||||
import ani.dantotsu.profile.activity.NotificationActivity.Companion.NotificationClickType
|
import ani.dantotsu.profile.notification.NotificationFragment.Companion.NotificationClickType
|
||||||
|
import ani.dantotsu.profile.activity.ActivityItemBuilder
|
||||||
import ani.dantotsu.setAnimation
|
import ani.dantotsu.setAnimation
|
||||||
import ani.dantotsu.toPx
|
import ani.dantotsu.toPx
|
||||||
import com.xwray.groupie.viewbinding.BindableItem
|
import com.xwray.groupie.viewbinding.BindableItem
|
|
@ -1,6 +1,5 @@
|
||||||
package ani.dantotsu.settings
|
package ani.dantotsu.settings
|
||||||
|
|
||||||
import android.app.AlertDialog
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -16,7 +15,6 @@ import ani.dantotsu.connections.anilist.Anilist
|
||||||
import ani.dantotsu.databinding.BottomSheetSettingsBinding
|
import ani.dantotsu.databinding.BottomSheetSettingsBinding
|
||||||
import ani.dantotsu.download.anime.OfflineAnimeFragment
|
import ani.dantotsu.download.anime.OfflineAnimeFragment
|
||||||
import ani.dantotsu.download.manga.OfflineMangaFragment
|
import ani.dantotsu.download.manga.OfflineMangaFragment
|
||||||
import ani.dantotsu.getAppString
|
|
||||||
import ani.dantotsu.getThemeColor
|
import ani.dantotsu.getThemeColor
|
||||||
import ani.dantotsu.home.AnimeFragment
|
import ani.dantotsu.home.AnimeFragment
|
||||||
import ani.dantotsu.home.HomeFragment
|
import ani.dantotsu.home.HomeFragment
|
||||||
|
@ -28,7 +26,7 @@ import ani.dantotsu.loadImage
|
||||||
import ani.dantotsu.offline.OfflineFragment
|
import ani.dantotsu.offline.OfflineFragment
|
||||||
import ani.dantotsu.profile.ProfileActivity
|
import ani.dantotsu.profile.ProfileActivity
|
||||||
import ani.dantotsu.profile.activity.FeedActivity
|
import ani.dantotsu.profile.activity.FeedActivity
|
||||||
import ani.dantotsu.profile.activity.NotificationActivity
|
import ani.dantotsu.profile.notification.NotificationActivity
|
||||||
import ani.dantotsu.setSafeOnClickListener
|
import ani.dantotsu.setSafeOnClickListener
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
|
|
|
@ -135,6 +135,7 @@ class AlertDialogBuilder(private val context: Context) {
|
||||||
} else if (checkedItems != null && onItemsSelected != null) {
|
} else if (checkedItems != null && onItemsSelected != null) {
|
||||||
builder.setMultiChoiceItems(items, checkedItems) { _, which, isChecked ->
|
builder.setMultiChoiceItems(items, checkedItems) { _, which, isChecked ->
|
||||||
checkedItems?.set(which, isChecked)
|
checkedItems?.set(which, isChecked)
|
||||||
|
onItemsSelected?.invoke(checkedItems!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
app:abb_animationInterpolator="@anim/over_shoot"
|
app:abb_animationInterpolator="@anim/over_shoot"
|
||||||
app:abb_indicatorAppearance="round"
|
app:abb_indicatorAppearance="round"
|
||||||
app:abb_indicatorLocation="top"
|
app:abb_indicatorLocation="top"
|
||||||
|
app:abb_indicatorMargin="28dp"
|
||||||
app:abb_selectedTabType="text"
|
app:abb_selectedTabType="text"
|
||||||
app:abb_textAppearance="@style/NavBarText"
|
app:abb_textAppearance="@style/NavBarText"
|
||||||
app:itemActiveIndicatorStyle="@style/BottomNavBar"
|
app:itemActiveIndicatorStyle="@style/BottomNavBar"
|
||||||
|
|
|
@ -103,15 +103,18 @@
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<LinearLayout
|
||||||
android:id="@+id/listFrameLayout"
|
android:id="@+id/listFrameLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center_horizontal">
|
||||||
|
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/followSwipeRefresh"
|
android:id="@+id/followSwipeRefresh"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
android:layout_marginEnd="12dp"
|
android:layout_marginEnd="12dp"
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
|
@ -120,7 +123,7 @@
|
||||||
<ani.dantotsu.FadingEdgeRecyclerView
|
<ani.dantotsu.FadingEdgeRecyclerView
|
||||||
android:id="@+id/listRecyclerView"
|
android:id="@+id/listRecyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:nestedScrollingEnabled="true"
|
android:nestedScrollingEnabled="true"
|
||||||
android:requiresFadingEdge="vertical"
|
android:requiresFadingEdge="vertical"
|
||||||
tools:listitem="@layout/item_follower" />
|
tools:listitem="@layout/item_follower" />
|
||||||
|
@ -132,8 +135,8 @@
|
||||||
style="?android:attr/progressBarStyle"
|
style="?android:attr/progressBarStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom|center_horizontal"
|
|
||||||
android:layout_marginBottom="32dp"
|
android:layout_marginBottom="32dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone"
|
||||||
</FrameLayout>
|
android:layout_gravity="center_horizontal" />
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
76
app/src/main/res/layout/activity_notification.xml
Normal file
76
app/src/main/res/layout/activity_notification.xml
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/notificationToolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/notificationBack"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="start|center_vertical"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:src="@drawable/ic_round_arrow_back_ios_new_24"
|
||||||
|
app:tint="?attr/colorOnBackground"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/notificationTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="44dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:gravity="center|start"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="@style/TextAppearance.Widget.AppCompat.Toolbar.Title"
|
||||||
|
android:textColor="?attr/colorOnBackground"
|
||||||
|
android:textSize="18sp"
|
||||||
|
tools:text="Notifications" />
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
|
android:id="@+id/notificationViewPager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:nestedScrollingEnabled="true"
|
||||||
|
tools:ignore="SpeakableTextPresentCheck" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<nl.joery.animatedbottombar.AnimatedBottomBar
|
||||||
|
android:id="@+id/notificationNavBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal|bottom"
|
||||||
|
android:layout_marginTop="-64dp"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
|
android:padding="0dp"
|
||||||
|
app:abb_animationInterpolator="@anim/over_shoot"
|
||||||
|
app:abb_indicatorAppearance="round"
|
||||||
|
app:abb_indicatorLocation="top"
|
||||||
|
app:abb_indicatorMargin="28dp"
|
||||||
|
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" />
|
||||||
|
</LinearLayout>
|
|
@ -85,7 +85,7 @@
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:layout_width="52dp"
|
android:layout_width="52dp"
|
||||||
android:layout_height="52dp"
|
android:layout_height="52dp"
|
||||||
|
app:strokeColor="@color/transparent"
|
||||||
android:backgroundTint="@color/nav_bg_inv"
|
android:backgroundTint="@color/nav_bg_inv"
|
||||||
app:cardCornerRadius="26dp">
|
app:cardCornerRadius="26dp">
|
||||||
|
|
||||||
|
|
|
@ -4,50 +4,62 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<ProgressBar
|
<LinearLayout
|
||||||
android:id="@+id/listProgressBar"
|
android:id="@+id/listProgressBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
tools:visibility="gone">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
style="?android:attr/progressBarStyle"
|
style="?android:attr/progressBarStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content" />
|
||||||
android:layout_gravity="center"
|
</LinearLayout>
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<FrameLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/emptyTextView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/feedSwipeRefresh"
|
android:id="@+id/feedSwipeRefresh"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="0dp"
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
android:layout_marginEnd="12dp"
|
android:layout_marginEnd="12dp"
|
||||||
|
android:layout_weight="1"
|
||||||
android:clipChildren="false"
|
android:clipChildren="false"
|
||||||
android:clipToPadding="false">
|
android:clipToPadding="false">
|
||||||
|
|
||||||
<ani.dantotsu.FadingEdgeRecyclerView
|
<ani.dantotsu.FadingEdgeRecyclerView
|
||||||
android:id="@+id/listRecyclerView"
|
android:id="@+id/listRecyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:nestedScrollingEnabled="true"
|
android:nestedScrollingEnabled="true"
|
||||||
android:requiresFadingEdge="vertical"
|
android:requiresFadingEdge="vertical"
|
||||||
android:visibility="visible"
|
|
||||||
tools:listitem="@layout/item_activity" />
|
tools:listitem="@layout/item_activity" />
|
||||||
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/feedRefresh"
|
android:id="@+id/feedRefresh"
|
||||||
style="?android:attr/progressBarStyle"
|
style="?android:attr/progressBarStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom|center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:layout_marginBottom="32dp"
|
android:layout_marginBottom="32dp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
</FrameLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
64
app/src/main/res/layout/fragment_notifications.xml
Normal file
64
app/src/main/res/layout/fragment_notifications.xml
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<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:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/notificationProgressBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
tools:visibility="gone">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/emptyTextView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
|
android:gravity="center"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
|
android:id="@+id/notificationSwipeRefresh"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginStart="12dp"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false">
|
||||||
|
|
||||||
|
<ani.dantotsu.FadingEdgeRecyclerView
|
||||||
|
android:id="@+id/notificationRecyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:nestedScrollingEnabled="true"
|
||||||
|
android:requiresFadingEdge="vertical"
|
||||||
|
tools:listitem="@layout/item_follower" />
|
||||||
|
|
||||||
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/notificationRefresh"
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginBottom="32dp"
|
||||||
|
android:visibility="gone" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
|
@ -28,45 +28,36 @@
|
||||||
android:src="@drawable/linear_gradient_bg"
|
android:src="@drawable/linear_gradient_bg"
|
||||||
tools:ignore="ContentDescription" />
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/touchPanel"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true" />
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
android:id="@+id/textActivityContainer"
|
android:id="@+id/textActivityContainer"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:orientation="horizontal">
|
android:layout_marginVertical="94dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:scrollbars="none">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/textActivity"
|
android:id="@+id/textActivity"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
android:fontFamily="@font/poppins_semi_bold"
|
android:fontFamily="@font/poppins_semi_bold"
|
||||||
android:gravity="center"
|
|
||||||
android:paddingHorizontal="12dp"
|
android:paddingHorizontal="12dp"
|
||||||
android:text="Play"
|
android:text="test"
|
||||||
|
android:textAlignment="center"
|
||||||
android:textColor="@color/bg_white"
|
android:textColor="@color/bg_white"
|
||||||
android:textSize="18sp"
|
android:textSize="18sp"
|
||||||
android:visibility="gone"
|
|
||||||
tools:ignore="HardcodedText" />
|
tools:ignore="HardcodedText" />
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/leftTouchPanel"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintWidth_percent="0.5" />
|
|
||||||
|
|
||||||
|
|
||||||
<FrameLayout
|
|
||||||
android:id="@+id/rightTouchPanel"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintWidth_percent="0.5" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -90,14 +90,14 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:backgroundTint="?attr/colorSecondaryContainer"
|
android:backgroundTint="?attr/colorOnPrimary"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:fontFamily="@font/poppins_bold"
|
android:fontFamily="@font/poppins_bold"
|
||||||
android:text="@string/follow"
|
android:text="@string/follow"
|
||||||
android:textColor="@color/bg_opp"
|
android:textColor="@color/bg_opp"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
app:cornerRadius="8dp"
|
app:cornerRadius="8dp"
|
||||||
app:strokeColor="?attr/colorSecondaryContainer"
|
app:strokeColor="?attr/colorOnPrimary"
|
||||||
tools:ignore="SpeakableTextPresentCheck" />
|
tools:ignore="SpeakableTextPresentCheck" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue