Browse Source

re-implement viewing highlights

renovate/org.jetbrains.kotlinx-kotlinx-coroutines-test-1.x
Austin Huang 3 years ago
parent
commit
379468d577
No known key found for this signature in database GPG Key ID: 84C23AA04587A91F
  1. 119
      app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.kt
  2. 2
      app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.kt
  3. 19
      app/src/main/java/awais/instagrabber/viewmodels/HighlightsViewModel.java
  4. 15
      app/src/main/java/awais/instagrabber/viewmodels/ProfileFragmentViewModel.kt

119
app/src/main/java/awais/instagrabber/fragments/StoryViewerFragment.kt

@ -18,7 +18,9 @@ import androidx.appcompat.widget.PopupMenu
import androidx.core.view.GestureDetectorCompat import androidx.core.view.GestureDetectorCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.navigation.NavController import androidx.navigation.NavController
@ -29,6 +31,7 @@ import awais.instagrabber.R
import awais.instagrabber.adapters.StoriesAdapter import awais.instagrabber.adapters.StoriesAdapter
import awais.instagrabber.customviews.helpers.SwipeGestureListener import awais.instagrabber.customviews.helpers.SwipeGestureListener
import awais.instagrabber.databinding.FragmentStoryViewerBinding import awais.instagrabber.databinding.FragmentStoryViewerBinding
import awais.instagrabber.fragments.main.ProfileFragment
import awais.instagrabber.fragments.settings.PreferenceKeys import awais.instagrabber.fragments.settings.PreferenceKeys
import awais.instagrabber.interfaces.SwipeEvent import awais.instagrabber.interfaces.SwipeEvent
import awais.instagrabber.models.Resource import awais.instagrabber.models.Resource
@ -38,14 +41,13 @@ import awais.instagrabber.models.enums.StoryPaginationType
import awais.instagrabber.repositories.requests.StoryViewerOptions import awais.instagrabber.repositories.requests.StoryViewerOptions
import awais.instagrabber.repositories.responses.directmessages.RankedRecipient import awais.instagrabber.repositories.responses.directmessages.RankedRecipient
import awais.instagrabber.repositories.responses.stories.* import awais.instagrabber.repositories.responses.stories.*
import awais.instagrabber.utils.*
import awais.instagrabber.utils.Constants
import awais.instagrabber.utils.DownloadUtils.download import awais.instagrabber.utils.DownloadUtils.download
import awais.instagrabber.utils.TextUtils.epochSecondToString import awais.instagrabber.utils.TextUtils.epochSecondToString
import awais.instagrabber.utils.ResponseBodyUtils
import awais.instagrabber.utils.Utils
import awais.instagrabber.utils.extensions.TAG import awais.instagrabber.utils.extensions.TAG
import awais.instagrabber.viewmodels.ArchivesViewModel
import awais.instagrabber.viewmodels.FeedStoriesViewModel
import awais.instagrabber.viewmodels.HighlightsViewModel
import awais.instagrabber.viewmodels.StoryFragmentViewModel
import awais.instagrabber.viewmodels.*
import awais.instagrabber.webservices.MediaRepository import awais.instagrabber.webservices.MediaRepository
import awais.instagrabber.webservices.StoriesRepository import awais.instagrabber.webservices.StoriesRepository
import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.drawee.backends.pipeline.Fresco
@ -68,10 +70,8 @@ import java.util.*
class StoryViewerFragment : Fragment() { class StoryViewerFragment : Fragment() {
private val TAG = "StoryViewerFragment" private val TAG = "StoryViewerFragment"
private val cookie = Utils.settingsHelper.getString(Constants.COOKIE)
private var root: View? = null private var root: View? = null
private var currentStoryUsername: String? = null private var currentStoryUsername: String? = null
private var highlightTitle: String? = null
private var storiesAdapter: StoriesAdapter? = null private var storiesAdapter: StoriesAdapter? = null
private var swipeEvent: SwipeEvent? = null private var swipeEvent: SwipeEvent? = null
private var gestureDetector: GestureDetectorCompat? = null private var gestureDetector: GestureDetectorCompat? = null
@ -84,10 +84,7 @@ class StoryViewerFragment : Fragment() {
private var actionBarTitle: String? = null private var actionBarTitle: String? = null
private var actionBarSubtitle: String? = null private var actionBarSubtitle: String? = null
private var fetching = false
private val sticking = false
private var shouldRefresh = true private var shouldRefresh = true
private var dmVisible = false
private var currentFeedStoryIndex = 0 private var currentFeedStoryIndex = 0
private var sliderValue = 0.0 private var sliderValue = 0.0
private var options: StoryViewerOptions? = null private var options: StoryViewerOptions? = null
@ -95,6 +92,7 @@ class StoryViewerFragment : Fragment() {
private var backStackSavedStateResultLiveData: MutableLiveData<Any?>? = null private var backStackSavedStateResultLiveData: MutableLiveData<Any?>? = null
private lateinit var fragmentActivity: AppCompatActivity private lateinit var fragmentActivity: AppCompatActivity
private lateinit var storiesViewModel: StoryFragmentViewModel private lateinit var storiesViewModel: StoryFragmentViewModel
private lateinit var appStateViewModel: AppStateViewModel
private lateinit var binding: FragmentStoryViewerBinding private lateinit var binding: FragmentStoryViewerBinding
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@ -123,6 +121,7 @@ class StoryViewerFragment : Fragment() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
fragmentActivity = requireActivity() as AppCompatActivity fragmentActivity = requireActivity() as AppCompatActivity
storiesViewModel = ViewModelProvider(this).get(StoryFragmentViewModel::class.java) storiesViewModel = ViewModelProvider(this).get(StoryFragmentViewModel::class.java)
appStateViewModel = ViewModelProvider(fragmentActivity).get(AppStateViewModel::class.java)
setHasOptionsMenu(true) setHasOptionsMenu(true)
} }
@ -152,12 +151,7 @@ class StoryViewerFragment : Fragment() {
menuProfile!!.isVisible = profileVisible menuProfile!!.isVisible = profileVisible
} }
override fun onPrepareOptionsMenu(menu: Menu) {
// hide menu items from activity
}
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
val context = context ?: return false
val itemId = item.itemId val itemId = item.itemId
if (itemId == R.id.action_profile) { if (itemId == R.id.action_profile) {
val username = storiesViewModel.getCurrentStory().value?.user?.username val username = storiesViewModel.getCurrentStory().value?.user?.username
@ -205,18 +199,18 @@ class StoryViewerFragment : Fragment() {
val type = options!!.type val type = options!!.type
if (currentFeedStoryIndex >= 0) { if (currentFeedStoryIndex >= 0) {
listViewModel = when (type) { listViewModel = when (type) {
StoryViewerOptions.Type.HIGHLIGHT -> ViewModelProvider(fragmentActivity).get(
HighlightsViewModel::class.java
)
StoryViewerOptions.Type.STORY_ARCHIVE -> ViewModelProvider(fragmentActivity).get(
ArchivesViewModel::class.java
)
StoryViewerOptions.Type.FEED_STORY_POSITION -> ViewModelProvider(fragmentActivity).get(
FeedStoriesViewModel::class.java
)
else -> ViewModelProvider(fragmentActivity).get(
FeedStoriesViewModel::class.java
)
StoryViewerOptions.Type.HIGHLIGHT -> {
val pArgs = Bundle()
pArgs.putString("username", options!!.name)
ViewModelProvider(
this, ProfileFragmentViewModelFactory(null, null, this, pArgs)
).get(ProfileFragmentViewModel::class.java)
}
StoryViewerOptions.Type.STORY_ARCHIVE ->
ViewModelProvider(fragmentActivity).get(ArchivesViewModel::class.java)
StoryViewerOptions.Type.FEED_STORY_POSITION ->
ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel::class.java)
else -> ViewModelProvider(fragmentActivity).get(FeedStoriesViewModel::class.java)
} }
} }
setupButtons() setupButtons()
@ -228,7 +222,7 @@ class StoryViewerFragment : Fragment() {
val context = context ?: return val context = context ?: return
binding.storiesList.layoutManager = binding.storiesList.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
storiesAdapter = StoriesAdapter { model: StoryMedia?, position: Int ->
storiesAdapter = StoriesAdapter { _, position ->
storiesViewModel.setMedia(position) storiesViewModel.setMedia(position)
} }
binding.storiesList.adapter = storiesAdapter binding.storiesList.adapter = storiesAdapter
@ -240,15 +234,13 @@ class StoryViewerFragment : Fragment() {
storyMedias.set(0, newItem) storyMedias.set(0, newItem)
storiesAdapter!!.submitList(storyMedias) storiesAdapter!!.submitList(storyMedias)
storiesViewModel.setMedia(0) storiesViewModel.setMedia(0)
binding.listToggle.setEnabled(true)
binding.storiesList.setVisibility(
if (Utils.settingsHelper.getBoolean(PreferenceKeys.PREF_STORY_SHOW_LIST)) View.VISIBLE
binding.listToggle.isEnabled = true
binding.storiesList.visibility = if (Utils.settingsHelper.getBoolean(PreferenceKeys.PREF_STORY_SHOW_LIST)) View.VISIBLE
else View.GONE else View.GONE
)
} }
else { else {
binding.listToggle.setEnabled(false)
binding.storiesList.setVisibility(View.GONE)
binding.listToggle.isEnabled = false
binding.storiesList.visibility = View.GONE
} }
}) })
storiesViewModel.getDate().observe(fragmentActivity, { storiesViewModel.getDate().observe(fragmentActivity, {
@ -266,8 +258,6 @@ class StoryViewerFragment : Fragment() {
storiesViewModel.getOptions().observe(fragmentActivity, { storiesViewModel.getOptions().observe(fragmentActivity, {
binding.stickers.isEnabled = it.first.size > 0 binding.stickers.isEnabled = it.first.size > 0
}) })
resetView()
} }
private fun setupButtons() { private fun setupButtons() {
@ -278,36 +268,38 @@ class StoryViewerFragment : Fragment() {
binding.btnReply.setOnClickListener({ _ -> createReplyDialog(null) }) binding.btnReply.setOnClickListener({ _ -> createReplyDialog(null) })
binding.stickers.setOnClickListener({ _ -> showStickerMenu() }) binding.stickers.setOnClickListener({ _ -> showStickerMenu() })
binding.listToggle.setOnClickListener({ _ -> binding.listToggle.setOnClickListener({ _ ->
binding.storiesList.setVisibility(
if (binding.storiesList.visibility == View.GONE) View.VISIBLE
binding.storiesList.visibility = if (binding.storiesList.visibility == View.GONE) View.VISIBLE
else View.GONE else View.GONE
)
}) })
} }
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
private fun setupListeners() { private fun setupListeners() {
val hasFeedStories: Boolean
var models: List<Story>? = null
var liveModels: LiveData<List<Story>?>? = null
if (currentFeedStoryIndex >= 0) { if (currentFeedStoryIndex >= 0) {
val type = options!!.type val type = options!!.type
when (type) { when (type) {
StoryViewerOptions.Type.HIGHLIGHT -> { StoryViewerOptions.Type.HIGHLIGHT -> {
val highlightsViewModel = listViewModel as HighlightsViewModel?
models = highlightsViewModel!!.list.value
val profileFragmentViewModel = listViewModel as ProfileFragmentViewModel?
appStateViewModel.currentUserLiveData.observe(
viewLifecycleOwner, profileFragmentViewModel!!::setCurrentUser
)
profileFragmentViewModel.currentUserProfileActionLiveData.observe(viewLifecycleOwner) {}
profileFragmentViewModel.userHighlights.observe(viewLifecycleOwner) {}
liveModels = profileFragmentViewModel.highlights
} }
StoryViewerOptions.Type.FEED_STORY_POSITION -> { StoryViewerOptions.Type.FEED_STORY_POSITION -> {
val feedStoriesViewModel = listViewModel as FeedStoriesViewModel? val feedStoriesViewModel = listViewModel as FeedStoriesViewModel?
models = feedStoriesViewModel!!.list.value
liveModels = feedStoriesViewModel!!.list
} }
StoryViewerOptions.Type.STORY_ARCHIVE -> { StoryViewerOptions.Type.STORY_ARCHIVE -> {
val archivesViewModel = listViewModel as ArchivesViewModel? val archivesViewModel = listViewModel as ArchivesViewModel?
models = archivesViewModel!!.list.value
liveModels = archivesViewModel!!.list
} }
} }
} }
hasFeedStories = models != null && !models.isEmpty()
if (liveModels != null) liveModels.observe(viewLifecycleOwner, { models ->
Log.d("austin_debug", "models (observer): " + models)
storiesViewModel.getPagination().observe(fragmentActivity, { storiesViewModel.getPagination().observe(fragmentActivity, {
if (models != null) { if (models != null) {
when (it) { when (it) {
@ -336,14 +328,18 @@ class StoryViewerFragment : Fragment() {
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }
StoryPaginationType.DO_NOTHING -> {
} // do nothing
} }
} }
}) })
if (models != null && !models.isEmpty()) {
binding.btnBackward.isEnabled = currentFeedStoryIndex != 0
binding.btnForward.isEnabled = currentFeedStoryIndex != models.size - 1
resetView()
}
})
val context = context ?: return val context = context ?: return
swipeEvent = label@ SwipeEvent { isRightSwipe: Boolean ->
swipeEvent = SwipeEvent { isRightSwipe: Boolean ->
storiesViewModel.paginate(isRightSwipe) storiesViewModel.paginate(isRightSwipe)
} }
gestureDetector = GestureDetectorCompat(context, SwipeGestureListener(swipeEvent)) gestureDetector = GestureDetectorCompat(context, SwipeGestureListener(swipeEvent))
@ -370,13 +366,7 @@ class StoryViewerFragment : Fragment() {
return false return false
} }
} }
if (hasFeedStories) {
binding.btnBackward.isEnabled = currentFeedStoryIndex != 0
binding.btnForward.isEnabled = currentFeedStoryIndex != models!!.size - 1
}
binding.imageViewer.setTapListener(simpleOnGestureListener) binding.imageViewer.setTapListener(simpleOnGestureListener)
// process stickers
} }
private fun resetView() { private fun resetView() {
@ -389,15 +379,14 @@ class StoryViewerFragment : Fragment() {
var fetchOptions: StoryViewerOptions? = null var fetchOptions: StoryViewerOptions? = null
when (type) { when (type) {
StoryViewerOptions.Type.HIGHLIGHT -> { StoryViewerOptions.Type.HIGHLIGHT -> {
val highlightsViewModel = listViewModel as HighlightsViewModel?
val models = highlightsViewModel!!.list.value
val profileFragmentViewModel = listViewModel as ProfileFragmentViewModel?
val models = profileFragmentViewModel!!.highlights.value
Log.d("austin_debug", "models (resetView): " + models)
if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size || currentFeedStoryIndex < 0) { if (models == null || models.isEmpty() || currentFeedStoryIndex >= models.size || currentFeedStoryIndex < 0) {
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT)
.show()
Toast.makeText(context, R.string.downloader_unknown_error, Toast.LENGTH_SHORT).show()
return return
} }
val (id, _, _, _, _, _, _, _, _, title) = models[currentFeedStoryIndex]
fetchOptions = StoryViewerOptions.forHighlight(id)
fetchOptions = StoryViewerOptions.forHighlight(models[currentFeedStoryIndex].id)
} }
StoryViewerOptions.Type.FEED_STORY_POSITION -> { StoryViewerOptions.Type.FEED_STORY_POSITION -> {
val feedStoriesViewModel = listViewModel as FeedStoriesViewModel? val feedStoriesViewModel = listViewModel as FeedStoriesViewModel?
@ -434,7 +423,9 @@ class StoryViewerFragment : Fragment() {
return return
} }
storiesViewModel.fetchStory(fetchOptions).observe(fragmentActivity, { storiesViewModel.fetchStory(fetchOptions).observe(fragmentActivity, {
// toast error if necessary?
if (it.status == Resource.Status.ERROR) {
Toast.makeText(context, "Error: " + it.message, Toast.LENGTH_SHORT).show()
}
}) })
} }
@ -578,7 +569,7 @@ class StoryViewerFragment : Fragment() {
}) })
player!!.setMediaSource(mediaSource) player!!.setMediaSource(mediaSource)
player!!.prepare() player!!.prepare()
binding.playerView.setOnClickListener { v: View? ->
binding.playerView.setOnClickListener { _ ->
if (player != null) { if (player != null) {
if (player!!.playbackState == Player.STATE_ENDED) player!!.seekTo(0) if (player!!.playbackState == Player.STATE_ENDED) player!!.seekTo(0)
player!!.playWhenReady = player!!.playWhenReady =

2
app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.kt

@ -843,7 +843,7 @@ class ProfileFragment : Fragment(), OnRefreshListener, ConfirmDialogFragmentCall
private fun setupHighlights() { private fun setupHighlights() {
val context = context ?: return val context = context ?: return
highlightsAdapter = HighlightsAdapter { model, position -> highlightsAdapter = HighlightsAdapter { model, position ->
val options = StoryViewerOptions.forHighlight(model.title)
val options = StoryViewerOptions.forHighlight(model.user?.username)
options.currentFeedStoryIndex = position options.currentFeedStoryIndex = position
val action = ProfileFragmentDirections.actionProfileFragmentToStoryViewerFragment(options) val action = ProfileFragmentDirections.actionProfileFragmentToStoryViewerFragment(options)
NavHostFragment.findNavController(this).navigate(action) NavHostFragment.findNavController(this).navigate(action)

19
app/src/main/java/awais/instagrabber/viewmodels/HighlightsViewModel.java

@ -1,19 +0,0 @@
package awais.instagrabber.viewmodels;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import java.util.List;
import awais.instagrabber.repositories.responses.stories.Story;
public class HighlightsViewModel extends ViewModel {
private MutableLiveData<List<Story>> list;
public MutableLiveData<List<Story>> getList() {
if (list == null) {
list = new MutableLiveData<>();
}
return list;
}
}

15
app/src/main/java/awais/instagrabber/viewmodels/ProfileFragmentViewModel.kt

@ -218,6 +218,7 @@ class ProfileFragmentViewModel(
} }
} }
} }
val highlights: LiveData<List<Story>?> = userHighlights.map { it.data }
private suspend fun fetchUser( private suspend fun fetchUser(
currentUser: User?, currentUser: User?,
@ -326,7 +327,7 @@ class ProfileFragmentViewModel(
val currentUserId = currentUser.value?.data?.pk ?: return@afterPrevious val currentUserId = currentUser.value?.data?.pk ?: return@afterPrevious
val targetUserId = profile.value?.data?.pk ?: return@afterPrevious val targetUserId = profile.value?.data?.pk ?: return@afterPrevious
val csrfToken = csrfToken ?: return@afterPrevious val csrfToken = csrfToken ?: return@afterPrevious
val deviceUuid = deviceUuid ?: return@afterPrevious
val deviceUuid = deviceUuid
if (following) { if (following) {
if (!confirmed) { if (!confirmed) {
_eventLiveData.postValue(Event(ShowConfirmUnfollowDialog)) _eventLiveData.postValue(Event(ShowConfirmUnfollowDialog))
@ -365,7 +366,7 @@ class ProfileFragmentViewModel(
val currentUserId = currentUser.value?.data?.pk ?: return@afterPrevious val currentUserId = currentUser.value?.data?.pk ?: return@afterPrevious
val targetUserId = profile.value?.data?.pk ?: return@afterPrevious val targetUserId = profile.value?.data?.pk ?: return@afterPrevious
val csrfToken = csrfToken ?: return@afterPrevious val csrfToken = csrfToken ?: return@afterPrevious
val deviceUuid = deviceUuid ?: return@afterPrevious
val deviceUuid = deviceUuid
val username = profile.value?.data?.username ?: return@afterPrevious val username = profile.value?.data?.username ?: return@afterPrevious
val thread = directMessagesRepository.createThread( val thread = directMessagesRepository.createThread(
csrfToken, csrfToken,
@ -399,7 +400,7 @@ class ProfileFragmentViewModel(
val profile = profile.value?.data ?: return@afterPrevious val profile = profile.value?.data ?: return@afterPrevious
friendshipRepository.toggleRestrict( friendshipRepository.toggleRestrict(
csrfToken ?: return@afterPrevious, csrfToken ?: return@afterPrevious,
deviceUuid ?: return@afterPrevious,
deviceUuid,
profile.pk, profile.pk,
!(profile.friendshipStatus?.isRestricted ?: false), !(profile.friendshipStatus?.isRestricted ?: false),
) )
@ -421,7 +422,7 @@ class ProfileFragmentViewModel(
friendshipRepository.changeBlock( friendshipRepository.changeBlock(
csrfToken ?: return@afterPrevious, csrfToken ?: return@afterPrevious,
currentUser.value?.data?.pk ?: return@afterPrevious, currentUser.value?.data?.pk ?: return@afterPrevious,
deviceUuid ?: return@afterPrevious,
deviceUuid,
profile.friendshipStatus?.blocking ?: return@afterPrevious, profile.friendshipStatus?.blocking ?: return@afterPrevious,
profile.pk profile.pk
) )
@ -443,7 +444,7 @@ class ProfileFragmentViewModel(
friendshipRepository.changeMute( friendshipRepository.changeMute(
csrfToken ?: return@afterPrevious, csrfToken ?: return@afterPrevious,
currentUser.value?.data?.pk ?: return@afterPrevious, currentUser.value?.data?.pk ?: return@afterPrevious,
deviceUuid ?: return@afterPrevious,
deviceUuid,
profile.friendshipStatus?.isMutingReel ?: return@afterPrevious, profile.friendshipStatus?.isMutingReel ?: return@afterPrevious,
profile.pk, profile.pk,
true true
@ -466,7 +467,7 @@ class ProfileFragmentViewModel(
friendshipRepository.changeMute( friendshipRepository.changeMute(
csrfToken ?: return@afterPrevious, csrfToken ?: return@afterPrevious,
currentUser.value?.data?.pk ?: return@afterPrevious, currentUser.value?.data?.pk ?: return@afterPrevious,
deviceUuid ?: return@afterPrevious,
deviceUuid,
profile.friendshipStatus?.muting ?: return@afterPrevious, profile.friendshipStatus?.muting ?: return@afterPrevious,
profile.pk, profile.pk,
false false
@ -488,7 +489,7 @@ class ProfileFragmentViewModel(
friendshipRepository.removeFollower( friendshipRepository.removeFollower(
csrfToken ?: return@afterPrevious, csrfToken ?: return@afterPrevious,
currentUser.value?.data?.pk ?: return@afterPrevious, currentUser.value?.data?.pk ?: return@afterPrevious,
deviceUuid ?: return@afterPrevious,
deviceUuid,
profile.value?.data?.pk ?: return@afterPrevious profile.value?.data?.pk ?: return@afterPrevious
) )
profileAction.postValue(REFRESH_FRIENDSHIP) profileAction.postValue(REFRESH_FRIENDSHIP)

Loading…
Cancel
Save