/* * Copyright (c) 2016 Zhang Hai <Dreaming.in.Code.ZH@Gmail.com> * All Rights Reserved. */ package me.zhanghai.android.douya.navigation.ui; import android.accounts.Account; import android.accounts.OnAccountsUpdateListener; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.NavigationView; import android.support.v4.app.Fragment; import android.support.v4.util.ArrayMap; import android.support.v4.widget.DrawerLayout; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import com.android.volley.VolleyError; import butterknife.BindView; import butterknife.ButterKnife; import me.zhanghai.android.douya.R; import me.zhanghai.android.douya.account.content.AccountUserResource; import me.zhanghai.android.douya.account.util.AccountUtils; import me.zhanghai.android.douya.link.NotImplementedManager; import me.zhanghai.android.douya.network.api.info.apiv2.SimpleUser; import me.zhanghai.android.douya.network.api.info.apiv2.User; import me.zhanghai.android.douya.profile.ui.ProfileActivity; import me.zhanghai.android.douya.settings.ui.SettingsActivity; import me.zhanghai.android.douya.util.ViewUtils; public class NavigationFragment extends Fragment implements OnAccountsUpdateListener, AccountUserResource.Listener, NavigationHeaderLayout.Adapter, NavigationHeaderLayout.Listener, NavigationAccountListLayout.Adapter, NavigationAccountListLayout.Listener, ConfirmRemoveCurrentAccountDialogFragment.Listener { private static final String KEY_PREFIX = NavigationFragment.class.getName() + '.'; private static final String KEY_SHOWING_ACCOUNT_LIST = KEY_PREFIX + "showing_account_list"; private static final String KEY_NEED_RELOAD_FOR_ACTIVE_ACCOUNT_CHANGE = KEY_PREFIX + "need_reload_for_active_account_change"; @BindView(R.id.navigation) NavigationView mNavigationView; private NavigationHeaderLayout mHeaderLayout; private ArrayMap<Account, AccountUserResource> mUserResourceMap; private NavigationViewAdapter mNavigationViewAdapter; private boolean mHasPendingAccountListChange; private boolean mNeedReloadForActiveAccountChange; private boolean mWillReloadForActiveAccountChange; public static NavigationFragment newInstance() { //noinspection deprecation return new NavigationFragment(); } /** * @deprecated Use {@link #newInstance()} instead. */ public NavigationFragment() {} @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.navigation_fragment, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ButterKnife.bind(this, view); mHeaderLayout = (NavigationHeaderLayout) mNavigationView.getHeaderView(0); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mUserResourceMap = new ArrayMap<>(); for (Account account : AccountUtils.getAccounts()) { mUserResourceMap.put(account, AccountUserResource.attachTo(account, this, account.name, -1)); } AccountUtils.addOnAccountListUpdatedListener(this); mHeaderLayout.setAdapter(this); mHeaderLayout.setListener(this); mHeaderLayout.bind(); mNavigationView.setNavigationItemSelectedListener( new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem menuItem) { switch (menuItem.getItemId()) { case R.id.navigation_home: // TODO break; case R.id.navigation_settings: openSettings(); break; default: // TODO NotImplementedManager.showNotYetImplementedToast(getActivity()); } // TODO if (menuItem.getGroupId() == R.id.navigation_group_primary) { menuItem.setChecked(true); } getDrawer().closeDrawer(getView()); return true; } }); // FIXME: Check remembered checked position. mNavigationView.getMenu().getItem(0).setChecked(true); mNavigationViewAdapter = NavigationViewAdapter.override(mNavigationView, this, this); if (savedInstanceState != null) { mHeaderLayout.setShowingAccountList(savedInstanceState.getBoolean( KEY_SHOWING_ACCOUNT_LIST)); if (savedInstanceState.getBoolean(KEY_NEED_RELOAD_FOR_ACTIVE_ACCOUNT_CHANGE)) { reloadForActiveAccountChange(); } } } @Override public void onResume() { super.onResume(); if (mHasPendingAccountListChange) { mHasPendingAccountListChange = false; onAccountListChanged(); } } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); // NavigationHeaderLayout resides inside a RecyclerView which cannot save its own instance // state. outState.putBoolean(KEY_SHOWING_ACCOUNT_LIST, mHeaderLayout.isShowingAccountList()); outState.putBoolean(KEY_NEED_RELOAD_FOR_ACTIVE_ACCOUNT_CHANGE, mNeedReloadForActiveAccountChange); } @Override public void onDestroy() { super.onDestroy(); AccountUtils.removeOnAccountListUpdatedListener(this); for (AccountUserResource userResource : mUserResourceMap.values()) { userResource.detach(); } } @Override public void onAccountsUpdated(Account[] accounts) { // In case the only account is removed. if (AccountUtils.getActiveAccount() == null) { AccountUtils.ensureActiveAccountAvailability(getActivity()); return; } if (isResumed()) { onAccountListChanged(); } else { mHasPendingAccountListChange = true; } } private void onAccountListChanged() { ArrayMap<Account, AccountUserResource> oldUserResourceMap = mUserResourceMap; mUserResourceMap = new ArrayMap<>(); for (Account account : AccountUtils.getAccounts()) { mUserResourceMap.put(account, AccountUserResource.attachTo(account, this, account.name, -1)); oldUserResourceMap.remove(account); } for (AccountUserResource userResource : oldUserResourceMap.values()) { userResource.detach(); } mHeaderLayout.onAccountListChanged(); mNavigationViewAdapter.onAccountListChanged(); } @Override public void onLoadUserStarted(int requestCode) {} @Override public void onLoadUserFinished(int requestCode) {} @Override public void onLoadUserError(int requestCode, VolleyError error) {} @Override public void onUserChanged(int requestCode, User newUser) { mHeaderLayout.bind(); mNavigationViewAdapter.onUserChanged(); } @Override public void onUserWriteStarted(int requestCode) {} @Override public void onUserWriteFinished(int requestCode) {} @Override public SimpleUser getPartialUser(Account account) { return mUserResourceMap.get(account).getPartialUser(); } @Override public User getUser(Account account) { return mUserResourceMap.get(account).get(); } @Override public void openProfile(Account account) { AccountUserResource userResource = mUserResourceMap.get(account); Intent intent; if (userResource.has()) { // User info contains information such as isFollowed, which is affected by active user. intent = ProfileActivity.makeIntent((SimpleUser) userResource.get(), getActivity()); } else { // If we don't have user info, then user must also be partial. In this case we // can only pass user id or uid. intent = ProfileActivity.makeIntent(userResource.getUserIdOrUid(), getActivity()); } startActivity(intent); } @Override public void showAccountList(boolean show) { mNavigationViewAdapter.showAccountList(show); } @Override public void onAccountTransitionStart() { mNeedReloadForActiveAccountChange = true; } @Override public void onAccountTransitionEnd() { reloadForActiveAccountChange(); } private void reloadForActiveAccountChange() { if (getNavigationHost() == null) { return; } DrawerLayout drawerLayout = getDrawer(); View drawerView = getView(); boolean drawerVisible = drawerLayout.isDrawerVisible(drawerView); if (!mWillReloadForActiveAccountChange) { mWillReloadForActiveAccountChange = true; Runnable reloadRunnable = new Runnable() { @Override public void run() { if (getNavigationHost() != null) { getNavigationHost().reloadForActiveAccountChange(); mWillReloadForActiveAccountChange = false; mNeedReloadForActiveAccountChange = false; } } }; if (drawerVisible) { ViewUtils.postOnDrawerClosed(drawerLayout, reloadRunnable); } else { reloadRunnable.run(); } } if (drawerVisible) { drawerLayout.closeDrawer(drawerView); } } @Override public void switchToAccount(Account account) { mHeaderLayout.switchToAccountWithTransitionIfNotRunning(account); } @Override public void onRemoveCurrentAccount() { ConfirmRemoveCurrentAccountDialogFragment.show(this); } @Override public void removeCurrentAccount() { mHeaderLayout.setShowingAccountList(false); Account oldActiveAccount = AccountUtils.getActiveAccount(); AccountUtils.setActiveAccount(AccountUtils.getRecentOneAccount()); AccountUtils.removeAccount(oldActiveAccount); // Calls onAccountsUpdated() later. } private void openSettings() { startActivity(SettingsActivity.makeIntent(getActivity())); } private DrawerLayout getDrawer() { return getNavigationHost().getDrawer(); } private Host getNavigationHost() { return (Host) getActivity(); } public interface Host { DrawerLayout getDrawer(); void reloadForActiveAccountChange(); } }