Convert DirectMessageInboxFragment to kotlin

This commit is contained in:
Ammar Githam 2021-06-01 20:03:00 +09:00
parent 652c57aa24
commit fd3b1a8d18
2 changed files with 192 additions and 237 deletions

View File

@ -753,10 +753,9 @@ class MainActivity : BaseLanguageActivity(), FragmentManager.OnBackStackChangedL
EmojiCompat.init(config) EmojiCompat.init(config)
} }
var toolbar: Toolbar? var toolbar: Toolbar
get() = binding.toolbar get() = binding.toolbar
set(toolbar) { set(toolbar) {
toolbar ?: return
binding.appBarLayout.visibility = View.GONE binding.appBarLayout.visibility = View.GONE
removeScrollingBehaviour() removeScrollingBehaviour()
setSupportActionBar(toolbar) setSupportActionBar(toolbar)

View File

@ -1,282 +1,238 @@
package awais.instagrabber.fragments.directmessages; package awais.instagrabber.fragments.directmessages
import android.annotation.SuppressLint; import android.annotation.SuppressLint
import android.content.Context; import android.content.res.Configuration
import android.content.IntentFilter; import android.os.Bundle
import android.content.res.Configuration; import android.os.Handler
import android.os.Bundle; import android.os.Looper
import android.os.Handler; import android.util.Log
import android.util.Log; import android.view.*
import android.view.LayoutInflater; import androidx.coordinatorlayout.widget.CoordinatorLayout
import android.view.Menu; import androidx.fragment.app.Fragment
import android.view.MenuInflater; import androidx.lifecycle.Observer
import android.view.MenuItem; import androidx.lifecycle.ViewModelProvider
import android.view.View; import androidx.navigation.fragment.NavHostFragment
import android.view.ViewGroup; import androidx.recyclerview.widget.LinearLayoutManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
import awais.instagrabber.R
import awais.instagrabber.activities.MainActivity
import awais.instagrabber.adapters.DirectMessageInboxAdapter
import awais.instagrabber.customviews.helpers.RecyclerLazyLoaderAtEdge
import awais.instagrabber.databinding.FragmentDirectMessagesInboxBinding
import awais.instagrabber.models.Resource
import awais.instagrabber.repositories.responses.directmessages.DirectInbox
import awais.instagrabber.repositories.responses.directmessages.DirectThread
import awais.instagrabber.utils.extensions.TAG
import awais.instagrabber.viewmodels.DirectInboxViewModel
import com.google.android.material.badge.BadgeDrawable
import com.google.android.material.badge.BadgeUtils
import com.google.android.material.internal.ToolbarUtils
import com.google.android.material.snackbar.Snackbar
import androidx.annotation.NonNull; class DirectMessageInboxFragment : Fragment(), OnRefreshListener {
import androidx.annotation.Nullable; private lateinit var fragmentActivity: MainActivity
import androidx.appcompat.view.menu.ActionMenuItemView; private lateinit var viewModel: DirectInboxViewModel
import androidx.coordinatorlayout.widget.CoordinatorLayout; private lateinit var root: CoordinatorLayout
import androidx.fragment.app.Fragment; private lateinit var binding: FragmentDirectMessagesInboxBinding
import androidx.lifecycle.Observer; private lateinit var inboxAdapter: DirectMessageInboxAdapter
import androidx.lifecycle.ViewModelProvider; private lateinit var lazyLoader: RecyclerLazyLoaderAtEdge
import androidx.navigation.NavDirections;
import androidx.navigation.fragment.NavHostFragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.badge.BadgeDrawable; private var shouldRefresh = true
import com.google.android.material.badge.BadgeUtils; // private var receiver: DMRefreshBroadcastReceiver? = null
import com.google.android.material.internal.ToolbarUtils; private var scrollToTop = false
import com.google.android.material.snackbar.Snackbar; private var navigating = false
private var threadsObserver: Observer<List<DirectThread?>>? = null
private var pendingRequestsMenuItem: MenuItem? = null
private var pendingRequestTotalBadgeDrawable: BadgeDrawable? = null
private var isPendingRequestTotalBadgeAttached = false
import java.util.List; override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
fragmentActivity = requireActivity() as MainActivity
viewModel = ViewModelProvider(fragmentActivity).get(DirectInboxViewModel::class.java)
setHasOptionsMenu(true)
}
import awais.instagrabber.R; override fun onCreateView(
import awais.instagrabber.activities.MainActivity; inflater: LayoutInflater,
import awais.instagrabber.adapters.DirectMessageInboxAdapter; container: ViewGroup?,
import awais.instagrabber.broadcasts.DMRefreshBroadcastReceiver; savedInstanceState: Bundle?,
import awais.instagrabber.customviews.helpers.RecyclerLazyLoaderAtEdge; ): View {
import awais.instagrabber.databinding.FragmentDirectMessagesInboxBinding; if (this::root.isInitialized) {
import awais.instagrabber.repositories.responses.directmessages.DirectThread; shouldRefresh = false
import awais.instagrabber.viewmodels.DirectInboxViewModel; return root
public class DirectMessageInboxFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = "DirectMessagesInboxFrag";
private CoordinatorLayout root;
private RecyclerLazyLoaderAtEdge lazyLoader;
private DirectInboxViewModel viewModel;
private boolean shouldRefresh = true;
private FragmentDirectMessagesInboxBinding binding;
private DMRefreshBroadcastReceiver receiver;
private DirectMessageInboxAdapter inboxAdapter;
private MainActivity fragmentActivity;
private boolean scrollToTop = false;
private boolean navigating;
private Observer<List<DirectThread>> threadsObserver;
private MenuItem pendingRequestsMenuItem;
private BadgeDrawable pendingRequestTotalBadgeDrawable;
private boolean isPendingRequestTotalBadgeAttached;
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragmentActivity = (MainActivity) getActivity();
if (fragmentActivity != null) {
viewModel = new ViewModelProvider(fragmentActivity).get(DirectInboxViewModel.class);
} }
setHasOptionsMenu(true); binding = FragmentDirectMessagesInboxBinding.inflate(inflater, container, false)
root = binding.root
return root
} }
@Override override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
public View onCreateView(@NonNull final LayoutInflater inflater, if (!shouldRefresh) return
final ViewGroup container, init()
final Bundle savedInstanceState) {
if (root != null) {
shouldRefresh = false;
return root;
}
binding = FragmentDirectMessagesInboxBinding.inflate(inflater, container, false);
root = binding.getRoot();
return root;
} }
@Override override fun onRefresh() {
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { lazyLoader.resetState()
if (!shouldRefresh) return; scrollToTop = true
init(); viewModel.refresh()
} }
@Override @SuppressLint("UnsafeExperimentalUsageError", "UnsafeOptInUsageError")
public void onRefresh() { override fun onPause() {
lazyLoader.resetState(); super.onPause()
scrollToTop = true; // unregisterReceiver()
if (viewModel != null) { isPendingRequestTotalBadgeAttached = false
viewModel.refresh(); pendingRequestsMenuItem?.let {
} @SuppressLint("RestrictedApi") val menuItemView = ToolbarUtils.getActionMenuItemView(fragmentActivity.toolbar, it.itemId)
} if (menuItemView != null) {
BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.toolbar, it.itemId)
@SuppressLint({"UnsafeExperimentalUsageError", "UnsafeOptInUsageError"}) pendingRequestTotalBadgeDrawable = null
@Override
public void onPause() {
super.onPause();
unregisterReceiver();
isPendingRequestTotalBadgeAttached = false;
@SuppressLint("RestrictedApi") final ActionMenuItemView menuItemView = ToolbarUtils
.getActionMenuItemView(fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId());
if (pendingRequestTotalBadgeDrawable != null && menuItemView != null) {
BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId());
pendingRequestTotalBadgeDrawable = null;
}
}
@Override
public void onResume() {
super.onResume();
setupObservers();
final Context context = getContext();
if (context == null) return;
receiver = new DMRefreshBroadcastReceiver(() -> {
Log.d(TAG, "onResume: broadcast received");
// refreshInbox = true;
});
context.registerReceiver(receiver, new IntentFilter(DMRefreshBroadcastReceiver.ACTION_REFRESH_DM));
}
@SuppressLint("UnsafeExperimentalUsageError")
@Override
public void onDestroyView() {
super.onDestroyView();
unregisterReceiver();
}
@Override
public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
inflater.inflate(R.menu.dm_inbox_menu, menu);
pendingRequestsMenuItem = menu.findItem(R.id.pending_requests);
pendingRequestsMenuItem.setVisible(isPendingRequestTotalBadgeAttached);
}
@Override
public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
if (item.getItemId() == R.id.pending_requests) {
final NavDirections directions = DirectMessageInboxFragmentDirections.actionInboxToPendingInbox();
try {
NavHostFragment.findNavController(this).navigate(directions);
} catch (Exception e) {
Log.e(TAG, "onOptionsItemSelected: ", e);
} }
return true;
} }
return super.onOptionsItemSelected(item);
} }
private void unregisterReceiver() { override fun onResume() {
if (receiver == null) return; super.onResume()
final Context context = getContext(); setupObservers()
if (context == null) return; // val context = context ?: return
context.unregisterReceiver(receiver); // receiver = DMRefreshBroadcastReceiver { Log.d(TAG, "onResume: broadcast received") }
receiver = null; // context.registerReceiver(receiver, IntentFilter(DMRefreshBroadcastReceiver.ACTION_REFRESH_DM))
} }
@Override override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
public void onConfigurationChanged(@NonNull final Configuration newConfig) { inflater.inflate(R.menu.dm_inbox_menu, menu)
super.onConfigurationChanged(newConfig); pendingRequestsMenuItem = menu.findItem(R.id.pending_requests)
init(); pendingRequestsMenuItem?.isVisible = isPendingRequestTotalBadgeAttached
} }
@Override override fun onOptionsItemSelected(item: MenuItem): Boolean {
public void onDestroy() { if (item.itemId == R.id.pending_requests) {
super.onDestroy(); val directions = DirectMessageInboxFragmentDirections.actionInboxToPendingInbox()
removeViewModelObservers(); try {
viewModel.onDestroy(); NavHostFragment.findNavController(this).navigate(directions)
} catch (e: Exception) {
Log.e(TAG, "onOptionsItemSelected: ", e)
}
return true
}
return super.onOptionsItemSelected(item)
} }
private void setupObservers() { // private fun unregisterReceiver() {
removeViewModelObservers(); // if (receiver == null) return
threadsObserver = list -> { // val context = context ?: return
if (inboxAdapter == null) return; // context.unregisterReceiver(receiver)
inboxAdapter.submitList(list, () -> { // receiver = null
if (!scrollToTop) return; // }
binding.inboxList.post(() -> binding.inboxList.smoothScrollToPosition(0));
scrollToTop = false; override fun onConfigurationChanged(newConfig: Configuration) {
}); super.onConfigurationChanged(newConfig)
}; init()
viewModel.getThreads().observe(fragmentActivity, threadsObserver); }
viewModel.getInbox().observe(getViewLifecycleOwner(), inboxResource -> {
if (inboxResource == null) return; override fun onDestroy() {
switch (inboxResource.status) { super.onDestroy()
case SUCCESS: removeViewModelObservers()
binding.swipeRefreshLayout.setRefreshing(false); viewModel.onDestroy()
break; }
case ERROR:
private fun setupObservers() {
removeViewModelObservers()
threadsObserver = Observer { list: List<DirectThread?> ->
inboxAdapter.submitList(list) {
if (!scrollToTop) return@submitList
binding.inboxList.post { binding.inboxList.smoothScrollToPosition(0) }
scrollToTop = false
}
}
threadsObserver?.let { viewModel.threads.observe(fragmentActivity, it) }
viewModel.inbox.observe(viewLifecycleOwner, { inboxResource: Resource<DirectInbox?>? ->
if (inboxResource == null) return@observe
when (inboxResource.status) {
Resource.Status.SUCCESS -> binding.swipeRefreshLayout.isRefreshing = false
Resource.Status.ERROR -> {
if (inboxResource.message != null) { if (inboxResource.message != null) {
Snackbar.make(binding.getRoot(), inboxResource.message, Snackbar.LENGTH_LONG).show(); Snackbar.make(binding.root, inboxResource.message, Snackbar.LENGTH_LONG).show()
} }
if (inboxResource.resId != 0) { if (inboxResource.resId != 0) {
Snackbar.make(binding.getRoot(), inboxResource.resId, Snackbar.LENGTH_LONG).show(); Snackbar.make(binding.root, inboxResource.resId, Snackbar.LENGTH_LONG).show()
} }
binding.swipeRefreshLayout.setRefreshing(false); binding.swipeRefreshLayout.isRefreshing = false
break; }
case LOADING: Resource.Status.LOADING -> binding.swipeRefreshLayout.isRefreshing = true
binding.swipeRefreshLayout.setRefreshing(true);
break;
} }
}); })
viewModel.getPendingRequestsTotal().observe(getViewLifecycleOwner(), this::attachPendingRequestsBadge); viewModel.pendingRequestsTotal.observe(viewLifecycleOwner, { count: Int? -> attachPendingRequestsBadge(count) })
} }
@SuppressLint({"UnsafeExperimentalUsageError", "UnsafeOptInUsageError"}) @SuppressLint("UnsafeExperimentalUsageError", "UnsafeOptInUsageError")
private void attachPendingRequestsBadge(@Nullable final Integer count) { private fun attachPendingRequestsBadge(count: Int?) {
if (pendingRequestsMenuItem == null) { val pendingRequestsMenuItem1 = pendingRequestsMenuItem
final Handler handler = new Handler(); if (pendingRequestsMenuItem1 == null) {
handler.postDelayed(() -> attachPendingRequestsBadge(count), 500); val handler = Handler(Looper.getMainLooper())
return; handler.postDelayed({ attachPendingRequestsBadge(count) }, 500)
return
} }
if (pendingRequestTotalBadgeDrawable == null) { if (pendingRequestTotalBadgeDrawable == null) {
final Context context = getContext(); val context = context ?: return
if (context == null) return; pendingRequestTotalBadgeDrawable = BadgeDrawable.create(context)
pendingRequestTotalBadgeDrawable = BadgeDrawable.create(context);
} }
if (count == null || count == 0) { if (count == null || count == 0) {
@SuppressLint("RestrictedApi") final ActionMenuItemView menuItemView = ToolbarUtils @SuppressLint("RestrictedApi") val menuItemView = ToolbarUtils.getActionMenuItemView(
.getActionMenuItemView(fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId()); fragmentActivity.toolbar,
pendingRequestsMenuItem1.itemId
)
if (menuItemView != null) { if (menuItemView != null) {
BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId()); BadgeUtils.detachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.toolbar, pendingRequestsMenuItem1.itemId)
} }
isPendingRequestTotalBadgeAttached = false; isPendingRequestTotalBadgeAttached = false
pendingRequestTotalBadgeDrawable.setNumber(0); pendingRequestTotalBadgeDrawable?.number = 0
pendingRequestsMenuItem.setVisible(false); pendingRequestsMenuItem1.isVisible = false
return; return
} }
pendingRequestsMenuItem.setVisible(true); pendingRequestsMenuItem1.isVisible = true
if (pendingRequestTotalBadgeDrawable.getNumber() == count) return; if (pendingRequestTotalBadgeDrawable?.number == count) return
pendingRequestTotalBadgeDrawable.setNumber(count); pendingRequestTotalBadgeDrawable?.number = count
if (!isPendingRequestTotalBadgeAttached) { if (!isPendingRequestTotalBadgeAttached) {
BadgeUtils.attachBadgeDrawable(pendingRequestTotalBadgeDrawable, fragmentActivity.getToolbar(), pendingRequestsMenuItem.getItemId()); pendingRequestTotalBadgeDrawable?.let {
isPendingRequestTotalBadgeAttached = true; BadgeUtils.attachBadgeDrawable(it, fragmentActivity.toolbar, pendingRequestsMenuItem1.itemId)
isPendingRequestTotalBadgeAttached = true
}
} }
} }
private void removeViewModelObservers() { private fun removeViewModelObservers() {
if (viewModel == null) return; threadsObserver?.let { viewModel.threads.removeObserver(it) }
if (threadsObserver != null) {
viewModel.getThreads().removeObserver(threadsObserver);
}
// no need to explicitly remove observers whose lifecycle owner is getViewLifecycleOwner // no need to explicitly remove observers whose lifecycle owner is getViewLifecycleOwner
} }
private void init() { private fun init() {
final Context context = getContext(); val context = context ?: return
if (context == null) return; setupObservers()
setupObservers(); binding.swipeRefreshLayout.setOnRefreshListener(this)
binding.swipeRefreshLayout.setOnRefreshListener(this); binding.inboxList.setHasFixedSize(true)
binding.inboxList.setHasFixedSize(true); binding.inboxList.setItemViewCacheSize(20)
binding.inboxList.setItemViewCacheSize(20); val layoutManager = LinearLayoutManager(context)
final LinearLayoutManager layoutManager = new LinearLayoutManager(context); binding.inboxList.layoutManager = layoutManager
binding.inboxList.setLayoutManager(layoutManager); inboxAdapter = DirectMessageInboxAdapter { thread ->
inboxAdapter = new DirectMessageInboxAdapter(thread -> { val threadId = thread.threadId
if (navigating) return; val threadTitle = thread.threadTitle
navigating = true; if (navigating || threadId.isNullOrBlank() || threadTitle.isNullOrBlank()) return@DirectMessageInboxAdapter
if (isAdded()) { navigating = true
final DirectMessageInboxFragmentDirections.ActionInboxToThread directions = DirectMessageInboxFragmentDirections if (isAdded) {
.actionInboxToThread(thread.getThreadId(), thread.getThreadTitle()); val directions = DirectMessageInboxFragmentDirections.actionInboxToThread(threadId, threadTitle)
try { try {
NavHostFragment.findNavController(this).navigate(directions); NavHostFragment.findNavController(this).navigate(directions)
} catch (Exception e) { } catch (e: Exception) {
Log.e(TAG, "init: ", e); Log.e(TAG, "init: ", e)
} }
} }
navigating = false; navigating = false
}); }
inboxAdapter.setHasStableIds(true); inboxAdapter.setHasStableIds(true)
binding.inboxList.setAdapter(inboxAdapter); binding.inboxList.adapter = inboxAdapter
lazyLoader = new RecyclerLazyLoaderAtEdge(layoutManager, page -> { lazyLoader = RecyclerLazyLoaderAtEdge(layoutManager) { viewModel.fetchInbox() }
if (viewModel == null) return; lazyLoader.let { binding.inboxList.addOnScrollListener(it) }
viewModel.fetchInbox();
});
binding.inboxList.addOnScrollListener(lazyLoader);
} }
} }