/*
* Copyright 2014 Yaroslav Mytkalyk
* 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 com.docd.purefm.ui.activities;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import com.docd.purefm.Environment;
import com.docd.purefm.Extras;
import com.docd.purefm.PureFM;
import com.docd.purefm.R;
import com.docd.purefm.browser.Browser;
import com.docd.purefm.adapters.BookmarksAdapter;
import com.docd.purefm.adapters.BrowserTabsAdapter;
import com.docd.purefm.file.GenericFile;
import com.docd.purefm.operations.OperationsService;
import com.docd.purefm.ui.dialogs.MessageDialogBuilder;
import com.docd.purefm.ui.dialogs.ProgressAlertDialogBuilder;
import com.docd.purefm.ui.fragments.BrowserFragment;
import com.docd.purefm.utils.ClipBoard;
import com.docd.purefm.utils.PFMTextUtils;
import com.docd.purefm.utils.PreviewHolder;
import com.docd.purefm.ui.view.BreadCrumbTextView;
import com.docd.purefm.utils.ThemeUtils;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.widget.Toast;
import java.util.ArrayList;
/**
* Activity that holds ViewPager with BrowserFragments
* and manages ActionBar and Key events
*
* @author Doctoror
*/
public final class BrowserPagerActivity extends AbstractBrowserActivity
implements ServiceConnection, OperationsService.OperationListener {
/**
* Saved fragment state. This saving mechanism is used for restoring
* the state when Activity is recreated because of theme change
*/
private static final String EXTRA_SAVED_FRAGMENT_ADAPTER_STATE =
"BrowserPagerActivity.extras.SAVED_FRAGMENT_STATE";
private ActionBar mActionBar;
private BreadCrumbTextView mBreadCrumbView;
private boolean isDrawerOpened;
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private boolean mShowHomeAsUp;
private ListView mDrawerList;
private BookmarksAdapter mBookmarksAdapter;
private GenericFile currentPath;
private BrowserTabsAdapter mPagerAdapter;
private BrowserFragment mCurrentlyDisplayedFragment;
private Dialog mOperationProgressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
savedInstanceState = getIntent().getBundleExtra(EXTRA_SAVED_STATE);
}
this.setContentView(R.layout.activity_browser);
this.initActionBar();
this.initView();
this.restoreSavedState(savedInstanceState);
}
@Override
protected void onPause() {
super.onPause();
final FragmentManager fm = getFragmentManager();
final Fragment f = fm.findFragmentByTag(TAG_DIALOG);
if (f != null) {
fm.beginTransaction().remove(f).commit();
fm.executePendingTransactions();
}
}
@Override
protected void onResume() {
super.onResume();
this.invalidateOptionsMenu();
}
@Override
protected void setActionBarIcon(final Drawable icon) {
final ActionBar actionBar = getActionBar();
if (actionBar == null) {
throw new RuntimeException("Should have ActionBar");
}
actionBar.setIcon(icon);
}
@Override
protected void onSaveInstanceState(@NonNull final Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(EXTRA_SAVED_FRAGMENT_ADAPTER_STATE, mPagerAdapter.saveManualState());
}
private void restoreSavedState(final Bundle savedState) {
if (savedState != null) {
final Parcelable adapterState = savedState.getParcelable(EXTRA_SAVED_FRAGMENT_ADAPTER_STATE);
if (adapterState != null) {
if (mPagerAdapter != null) {
mPagerAdapter.restoreManualState(adapterState);
}
}
}
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
PreviewHolder.getInstance(this).recycle();
}
private void initActionBar() {
mActionBar = this.getActionBar();
if (mActionBar == null) {
throw new RuntimeException("BrowserPagerActivity should have an ActionBar");
}
mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME
| ActionBar.DISPLAY_SHOW_CUSTOM
| ActionBar.DISPLAY_USE_LOGO
| ActionBar.DISPLAY_HOME_AS_UP);
//noinspection InflateParams
final View custom = LayoutInflater.from(this).inflate(
R.layout.activity_browser_actionbar, null);
if (custom == null) {
throw new RuntimeException("Inflated View is null");
}
mActionBar.setCustomView(custom);
mBreadCrumbView = (BreadCrumbTextView) custom
.findViewById(R.id.bread_crumb_view);
}
private void initView() {
final ViewPager pager = (ViewPager) this.findViewById(R.id.pager);
mPagerAdapter = new BrowserTabsAdapter(getFragmentManager());
pager.setAdapter(mPagerAdapter);
mPagerAdapter.setViewPager(pager);
pager.setOffscreenPageLimit(2);
mDrawerLayout = (DrawerLayout) this.findViewById(R.id.drawer);
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
final int themeId = ThemeUtils.getInteger(getTheme(), R.attr.themeId, PureFM.THEME_ID_DARK);
mDrawerToggle = new BrowserActivityDrawerToggle(this, this.mDrawerLayout,
themeId == PureFM.THEME_ID_LIGHT ?
R.drawable.holo_light_ic_drawer :
R.drawable.holo_dark_ic_drawer,
R.string.menu_bookmarks, R.string.app_name);
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerList = (ListView) this.findViewById(R.id.drawerList);
mDrawerList.setAdapter(mBookmarksAdapter = new BookmarksAdapter(this));
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
@Override
protected void onStart() {
super.onStart();
bindService(new Intent(this, OperationsService.class), this,
BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
unbindService(this);
if (mBookmarksAdapter.isModified()) {
getSettings().setBookmarks(mBookmarksAdapter.getData());
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Pass the event to ActionBarDrawerToggle, if it returns
// true, then it has handled the app icon touch event
//noinspection SimplifiableIfStatement
if (mDrawerToggle.isDrawerIndicatorEnabled() &&
mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void invalidateList() {
mPagerAdapter.notifyDataSetChanged();
}
@Override
public boolean isHistoryEnabled() {
return true;
}
@Override
protected BrowserFragment getCurrentlyDisplayedFragment() {
return mCurrentlyDisplayedFragment;
}
@Override
public void setOnSequenceClickListener(BreadCrumbTextView.OnSequenceClickListener
sequenceListener) {
if (mBreadCrumbView != null) {
mBreadCrumbView.setOnSequenceClickListener(sequenceListener);
}
}
@Override
public boolean shouldShowBrowserFragmentMenu() {
return !isDrawerOpened;
}
@Override
public void setCurrentlyDisplayedFragment(final BrowserFragment fragment) {
mCurrentlyDisplayedFragment = fragment;
}
/**
* Toggles between using up button or navigation drawer icon by setting the DrawerListener
*/
void setDrawerIndicatorEnabled(final boolean showUpButton) {
mShowHomeAsUp = showUpButton;
mDrawerToggle.setDrawerIndicatorEnabled(!showUpButton);
}
@Override
public void onNavigate(GenericFile path) {
invalidateOptionsMenu();
}
@Override
public void onNavigationCompleted(GenericFile path) {
currentPath = path;
mBreadCrumbView.setFile(path.toFile());
setDrawerIndicatorEnabled(!path.toFile().equals(Environment.sRootDirectory));
invalidateOptionsMenu();
}
@Override
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_SEARCH) {
final Intent searchIntent = new Intent(this, SearchActivity.class);
searchIntent.putExtra(Extras.EXTRA_PATH, currentPath.getAbsolutePath());
startActivity(searchIntent);
return true;
}
return super.onKeyUp(keyCode, event);
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
if (this.isDrawerOpened) {
this.getMenuInflater().inflate(R.menu.activity_bookmarks, menu);
return true;
}
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onMenuItemSelected(final int featureId, @NonNull final MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_bookmarks_new:
if (currentPath != null) {
final String path = currentPath.getAbsolutePath();
this.mBookmarksAdapter.addItem(path);
}
return true;
default:
return super.onMenuItemSelected(featureId, item);
}
}
/**
* Should be called by BookmarksAdapter to set current path and close the Drawer
*/
public void setCurrentPath(GenericFile path) {
if (this.mDrawerLayout.isDrawerOpen(this.mDrawerList)) {
this.mDrawerLayout.closeDrawer(this.mDrawerList);
}
if (this.mCurrentlyDisplayedFragment != null) {
final Browser browser = this.mCurrentlyDisplayedFragment.getBrowser();
if (browser != null) {
browser.navigate(path, true);
}
}
}
@Override
public void onBackPressed() {
final boolean onFragmentBackPressed;
onFragmentBackPressed = this.mCurrentlyDisplayedFragment != null
&& this.mCurrentlyDisplayedFragment.onBackPressed();
if (!onFragmentBackPressed) {
final AlertDialog.Builder b = new AlertDialog.Builder(this);
b.setMessage(R.string.dialog_quit_message);
b.setCancelable(true);
b.setPositiveButton(R.string.yes,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
PreviewHolder.getInstance(BrowserPagerActivity.this).recycle();
finish();
}
});
b.setNegativeButton(R.string.no,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
final Dialog dialog = b.create();
if (!this.isFinishing()) {
dialog.show();
}
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
mBreadCrumbView.fullScrollRight();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_SETTINGS) {
if (resultCode == Activity.RESULT_OK) {
mPagerAdapter.notifyDataSetChanged();
}
}
}
// =================== SERVICE CONNECTION ==================
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
((OperationsService.LocalBinder) service).setOperationListener(this);
}
@Override
public void onServiceDisconnected(ComponentName name) {
if (mOperationProgressDialog != null) {
mOperationProgressDialog.dismiss();
mOperationProgressDialog = null;
}
}
// ================= OPERATION LISTENER ====================
@Override
public void onOperationStarted(@NonNull final String action,
@Nullable final CharSequence operationMessage,
@NonNull final Intent cancelIntent) {
if (mOperationProgressDialog == null || !mOperationProgressDialog.isShowing()) {
mOperationProgressDialog = ProgressAlertDialogBuilder.create(this,
operationMessage, new View.OnClickListener() {
@Override
public void onClick(final View view) {
startService(cancelIntent);
}
});
if (!isFinishing()) {
mOperationProgressDialog.show();
}
}
}
@Override
public void onOperationEnded(@Nullable final String operation,
@Nullable final Object result) {
if (mOperationProgressDialog != null) {
mOperationProgressDialog.dismiss();
mOperationProgressDialog = null;
}
if (operation != null) {
switch (operation) {
case OperationsService.ACTION_DELETE: {
@SuppressWarnings("unchecked")
final ArrayList<GenericFile> failed = (ArrayList<GenericFile>) result;
if (failed != null && !failed.isEmpty() && !isFinishing()) {
MessageDialogBuilder.create(this,
R.string.dialog_delete_failed, PFMTextUtils.fileListToDashList(
failed)
).show();
}
break;
}
case OperationsService.ACTION_PASTE: {
@SuppressWarnings("unchecked")
final ArrayList<GenericFile> failed = (ArrayList<GenericFile>) result;
if (failed != null && !failed.isEmpty() && !isFinishing()) {
MessageDialogBuilder.create(this, ClipBoard.isMove() ?
R.string.dialog_move_failed : R.string.dialog_copy_failed,
PFMTextUtils.fileListToDashList(failed)
).show();
}
invalidateOptionsMenu();
break;
}
case OperationsService.ACTION_RENAME:
case OperationsService.ACTION_CREATE_FILE:
case OperationsService.ACTION_CREATE_DIRECTORY:
if (result != null) {
Toast.makeText(this, (CharSequence) result, Toast.LENGTH_SHORT).show();
}
break;
}
}
}
/**
* ActionBarDrawerToggle that manages display options and title
*/
private final class BrowserActivityDrawerToggle extends ActionBarDrawerToggle {
private BrowserActivityDrawerToggle(Activity activity, DrawerLayout drawerLayout, int drawerImageRes, int openDrawerContentDescRes, int closeDrawerContentDescRes) {
super(activity, drawerLayout, drawerImageRes, openDrawerContentDescRes, closeDrawerContentDescRes);
}
@Override
public void onDrawerOpened(final View drawerView) {
super.onDrawerOpened(drawerView);
isDrawerOpened = true;
mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME
| ActionBar.DISPLAY_HOME_AS_UP
| ActionBar.DISPLAY_USE_LOGO
| ActionBar.DISPLAY_SHOW_TITLE);
mActionBar.setTitle(R.string.menu_bookmarks);
mDrawerToggle.setDrawerIndicatorEnabled(true);
invalidateOptionsMenu();
}
@Override
public void onDrawerClosed(final View drawerView) {
super.onDrawerClosed(drawerView);
isDrawerOpened = false;
mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_HOME
| ActionBar.DISPLAY_HOME_AS_UP
| ActionBar.DISPLAY_SHOW_CUSTOM
| ActionBar.DISPLAY_USE_LOGO);
mDrawerToggle.setDrawerIndicatorEnabled(!mShowHomeAsUp);
invalidateOptionsMenu();
}
}
}