/*
* Copyright (c) 2015 Ha Duy Trung
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.hidroh.materialistic;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import javax.inject.Inject;
import javax.inject.Named;
import io.github.hidroh.materialistic.annotation.Synthetic;
import io.github.hidroh.materialistic.data.Item;
import io.github.hidroh.materialistic.data.ItemManager;
import io.github.hidroh.materialistic.data.ResponseListener;
import io.github.hidroh.materialistic.data.WebItem;
import io.github.hidroh.materialistic.widget.CommentItemDecoration;
import io.github.hidroh.materialistic.widget.ItemRecyclerViewAdapter;
import io.github.hidroh.materialistic.widget.MultiPageItemRecyclerViewAdapter;
import io.github.hidroh.materialistic.widget.SinglePageItemRecyclerViewAdapter;
import io.github.hidroh.materialistic.widget.SnappyLinearLayoutManager;
public class ItemFragment extends LazyLoadFragment implements Scrollable, Navigable {
public static final String EXTRA_ITEM = ItemFragment.class.getName() + ".EXTRA_ITEM";
public static final String EXTRA_CACHE_MODE = ItemFragment.class.getName() + ".EXTRA_CACHE_MODE";
private static final String STATE_ITEM = "state:item";
private static final String STATE_ITEM_ID = "state:itemId";
private static final String STATE_ADAPTER_ITEMS = "state:adapterItems";
private static final String STATE_CACHE_MODE = "state:cacheMode";
private RecyclerView mRecyclerView;
private View mEmptyView;
private Item mItem;
private String mItemId;
@Inject @Named(ActivityModule.HN) ItemManager mItemManager;
private SwipeRefreshLayout mSwipeRefreshLayout;
private SinglePageItemRecyclerViewAdapter.SavedState mAdapterItems;
private ItemRecyclerViewAdapter mAdapter;
private KeyDelegate.RecyclerViewHelper mScrollableHelper;
private @ItemManager.CacheMode int mCacheMode = ItemManager.MODE_DEFAULT;
private final Preferences.Observable mPreferenceObservable = new Preferences.Observable();
private CommentItemDecoration mItemDecoration;
private View mFragmentView;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mPreferenceObservable.subscribe(context, this::onPreferenceChanged,
R.string.pref_comment_display,
R.string.pref_max_lines,
R.string.pref_username,
R.string.pref_line_height,
R.string.pref_color_code,
R.string.pref_thread_indicator,
R.string.pref_font,
R.string.pref_text_size,
R.string.pref_smooth_scroll);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
if (savedInstanceState != null) {
mCacheMode = savedInstanceState.getInt(STATE_CACHE_MODE, ItemManager.MODE_DEFAULT);
mItem = savedInstanceState.getParcelable(STATE_ITEM);
mItemId = savedInstanceState.getString(STATE_ITEM_ID);
mAdapterItems = savedInstanceState.getParcelable(STATE_ADAPTER_ITEMS);
} else {
mCacheMode = getArguments().getInt(EXTRA_CACHE_MODE, ItemManager.MODE_DEFAULT);
WebItem item = getArguments().getParcelable(EXTRA_ITEM);
if (item instanceof Item) {
mItem = (Item) item;
}
mItemId = item != null ? item.getId() : null;
}
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable final Bundle savedInstanceState) {
if (isNewInstance()) {
mFragmentView = getLayoutInflater(savedInstanceState).inflate(R.layout.fragment_item, container, false);
mEmptyView = mFragmentView.findViewById(R.id.empty);
mRecyclerView = (RecyclerView) mFragmentView.findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new SnappyLinearLayoutManager(getActivity(), true));
mItemDecoration = new CommentItemDecoration(getActivity());
mRecyclerView.addItemDecoration(mItemDecoration);
mSwipeRefreshLayout = (SwipeRefreshLayout) mFragmentView.findViewById(R.id.swipe_layout);
mSwipeRefreshLayout.setColorSchemeResources(R.color.white);
mSwipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.redA200);
mSwipeRefreshLayout.setOnRefreshListener(() -> {
if (TextUtils.isEmpty(mItemId)) {
return;
}
mCacheMode = ItemManager.MODE_NETWORK;
if (mAdapter != null) {
mAdapter.setCacheMode(mCacheMode);
}
loadKidData();
});
}
return mFragmentView;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (isNewInstance()) {
mScrollableHelper = new KeyDelegate.RecyclerViewHelper(mRecyclerView,
KeyDelegate.RecyclerViewHelper.SCROLL_ITEM);
mScrollableHelper.smoothScrollEnabled(Preferences.smoothScrollEnabled(getActivity()));
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_comments) {
showPreferences();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(STATE_ITEM, mItem);
outState.putString(STATE_ITEM_ID, mItemId);
outState.putParcelable(STATE_ADAPTER_ITEMS, mAdapterItems);
outState.putInt(STATE_CACHE_MODE, mCacheMode);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mAdapter != null) {
mAdapter.detach(getActivity(), mRecyclerView);
}
}
@Override
public void onDetach() {
super.onDetach();
mPreferenceObservable.unsubscribe(getActivity());
}
@Override
public void scrollToTop() {
mScrollableHelper.scrollToTop();
}
@Override
public boolean scrollToNext() {
return mScrollableHelper.scrollToNext();
}
@Override
public boolean scrollToPrevious() {
return mScrollableHelper.scrollToPrevious();
}
@Override
public void onNavigate(int direction) {
if (mAdapter == null) { // no kids
return;
}
mAdapter.getNextPosition(mScrollableHelper.getCurrentPosition(),
direction,
position -> mAdapter.lockBinding(mScrollableHelper.scrollToPosition(position)));
}
@Override
protected void load() {
if (mItem != null) {
bindKidData();
} else if (!TextUtils.isEmpty(mItemId)) {
loadKidData();
}
}
@Override
protected void createOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_item_view, menu);
}
private void loadKidData() {
mItemManager.getItem(mItemId, mCacheMode, new ItemResponseListener(this));
}
void onItemLoaded(@Nullable Item item) {
mSwipeRefreshLayout.setRefreshing(false);
if (item != null) {
mAdapterItems = null;
mItem = item;
notifyItemLoaded(item);
bindKidData();
}
}
private void bindKidData() {
if (mItem == null || mItem.getKidCount() == 0) {
mEmptyView.setVisibility(View.VISIBLE);
return;
}
mEmptyView.setVisibility(View.GONE);
String displayOption = Preferences.getCommentDisplayOption(getActivity());
if (Preferences.isSinglePage(getActivity(), displayOption)) {
boolean autoExpand = Preferences.isAutoExpand(getActivity(), displayOption);
// if collapsed or no saved state then start a fresh (adapter items all collapsed)
if (!autoExpand || mAdapterItems == null) {
mAdapterItems = new SinglePageItemRecyclerViewAdapter.SavedState(
new ArrayList<>(Arrays.asList(mItem.getKidItems())));
}
mAdapter = new SinglePageItemRecyclerViewAdapter(mItemManager, mAdapterItems, autoExpand);
} else {
mAdapter = new MultiPageItemRecyclerViewAdapter(mItemManager, mItem.getKidItems());
}
mAdapter.setCacheMode(mCacheMode);
mAdapter.initDisplayOptions(getActivity());
mAdapter.attach(getActivity(), mRecyclerView);
mRecyclerView.setAdapter(mAdapter);
}
private void onPreferenceChanged(int key, boolean contextChanged) {
if (contextChanged || key == R.string.pref_comment_display) {
load();
} else if (mAdapter != null) {
mScrollableHelper.smoothScrollEnabled(Preferences.smoothScrollEnabled(getActivity()));
mItemDecoration.setColorCodeEnabled(Preferences.colorCodeEnabled(getActivity()));
mItemDecoration.setThreadIndicatorEnabled(Preferences.threadIndicatorEnabled(getActivity()));
mAdapter.initDisplayOptions(getActivity());
mAdapter.notifyDataSetChanged();
}
}
private void showPreferences() {
Bundle args = new Bundle();
args.putInt(PopupSettingsFragment.EXTRA_TITLE, R.string.font_options);
args.putInt(PopupSettingsFragment.EXTRA_SUMMARY, R.string.pull_up_hint);
args.putIntArray(PopupSettingsFragment.EXTRA_XML_PREFERENCES, new int[]{
R.xml.preferences_font,
R.xml.preferences_comments});
((DialogFragment) Fragment.instantiate(getActivity(),
PopupSettingsFragment.class.getName(), args))
.show(getFragmentManager(), PopupSettingsFragment.class.getName());
}
private void notifyItemLoaded(@NonNull Item item) {
if (getActivity() instanceof ItemChangedListener) {
((ItemChangedListener) getActivity()).onItemChanged(item);
}
}
static class ItemResponseListener implements ResponseListener<Item> {
private WeakReference<ItemFragment> mItemFragment;
@Synthetic
ItemResponseListener(ItemFragment itemFragment) {
mItemFragment = new WeakReference<>(itemFragment);
}
@Override
public void onResponse(@Nullable Item response) {
if (mItemFragment.get() != null && mItemFragment.get().isAttached()) {
mItemFragment.get().onItemLoaded(response);
}
}
@Override
public void onError(String errorMessage) {
if (mItemFragment.get() != null && mItemFragment.get().isAttached()) {
mItemFragment.get().onItemLoaded(null);
}
}
}
interface ItemChangedListener {
void onItemChanged(@NonNull Item item);
}
}