123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- /**
- * Nextcloud Android client application
- *
- * @author Andy Scherzinger
- * Copyright (C) 2016 Andy Scherzinger
- * Copyright (C) 2016 Nextcloud
- * <p>
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or any later version.
- * <p>
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
- * <p>
- * You should have received a copy of the GNU Affero General Public
- * License along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- package com.owncloud.android.ui.activity;
- import android.accounts.Account;
- import android.content.Intent;
- import android.os.Bundle;
- import android.os.Handler;
- import android.support.annotation.NonNull;
- import android.support.design.widget.BottomNavigationView;
- import android.support.v4.app.FragmentManager;
- import android.support.v4.app.FragmentTransaction;
- import android.support.v4.widget.DrawerLayout;
- import android.support.v7.widget.GridLayoutManager;
- import android.support.v7.widget.RecyclerView;
- import android.view.MenuItem;
- import android.view.View;
- import android.widget.LinearLayout;
- import android.widget.TextView;
- import com.owncloud.android.MainApp;
- import com.owncloud.android.R;
- import com.owncloud.android.authentication.AccountUtils;
- import com.owncloud.android.datamodel.MediaFolder;
- import com.owncloud.android.datamodel.MediaProvider;
- import com.owncloud.android.datamodel.OCFile;
- import com.owncloud.android.datamodel.SyncedFolder;
- import com.owncloud.android.datamodel.SyncedFolderDisplayItem;
- import com.owncloud.android.datamodel.SyncedFolderProvider;
- import com.owncloud.android.files.services.FileUploader;
- import com.owncloud.android.ui.adapter.FolderSyncAdapter;
- import com.owncloud.android.ui.decoration.MediaGridItemDecoration;
- import com.owncloud.android.ui.dialog.SyncedFolderPreferencesDialogFragment;
- import com.owncloud.android.ui.dialog.parcel.SyncedFolderParcelable;
- import com.owncloud.android.utils.AnalyticsUtils;
- import com.owncloud.android.utils.DisplayUtils;
- import java.io.File;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Comparator;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.TimerTask;
- import static com.owncloud.android.datamodel.SyncedFolderDisplayItem.UNPERSISTED_ID;
- /**
- * Activity displaying all auto-synced folders and/or instant upload media folders.
- */
- public class FolderSyncActivity extends FileActivity implements FolderSyncAdapter.ClickListener,
- SyncedFolderPreferencesDialogFragment.OnSyncedFolderPreferenceListener {
- private static final String SYNCED_FOLDER_PREFERENCES_DIALOG_TAG = "SYNCED_FOLDER_PREFERENCES_DIALOG";
- public static final String PRIORITIZED_FOLDER = "Camera";
- public static final String EXTRA_SHOW_SIDEBAR = "SHOW_SIDEBAR";
- private static final String SCREEN_NAME = "Auto upload";
- private static final String TAG = FolderSyncActivity.class.getSimpleName();
- private RecyclerView mRecyclerView;
- private FolderSyncAdapter mAdapter;
- private LinearLayout mProgress;
- private TextView mEmpty;
- private SyncedFolderProvider mSyncedFolderProvider;
- private List<SyncedFolderDisplayItem> syncFolderItems;
- private SyncedFolderPreferencesDialogFragment mSyncedFolderPreferencesDialogFragment;
- private boolean showSidebar = true;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (getIntent().getExtras() != null) {
- showSidebar = getIntent().getExtras().getBoolean(EXTRA_SHOW_SIDEBAR);
- }
- setContentView(R.layout.folder_sync_layout);
- // setup toolbar
- setupToolbar();
- // setup drawer
- setupDrawer(R.id.nav_folder_sync);
- if (!showSidebar) {
- setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- mDrawerToggle.setDrawerIndicatorEnabled(false);
- }
- setupContent();
- getSupportActionBar().setTitle(getString(R.string.drawer_folder_sync));
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- }
- @Override
- protected void onResume() {
- super.onResume();
- AnalyticsUtils.setCurrentScreenName(this, SCREEN_NAME, TAG);
- }
- /**
- * sets up the UI elements and loads all media/synced folders.
- */
- private void setupContent() {
- mRecyclerView = (RecyclerView) findViewById(android.R.id.list);
- mProgress = (LinearLayout) findViewById(android.R.id.progress);
- mEmpty = (TextView) findViewById(android.R.id.empty);
- final int gridWidth = getResources().getInteger(R.integer.media_grid_width);
- boolean lightVersion = getResources().getBoolean(R.bool.syncedFolder_light);
- mAdapter = new FolderSyncAdapter(this, gridWidth, this, lightVersion);
- mSyncedFolderProvider = new SyncedFolderProvider(getContentResolver());
- final GridLayoutManager lm = new GridLayoutManager(this, gridWidth);
- mAdapter.setLayoutManager(lm);
- int spacing = getResources().getDimensionPixelSize(R.dimen.media_grid_spacing);
- mRecyclerView.addItemDecoration(new MediaGridItemDecoration(spacing));
- mRecyclerView.setLayoutManager(lm);
- mRecyclerView.setAdapter(mAdapter);
- BottomNavigationView bottomNavigationView = (BottomNavigationView) findViewById(R.id.bottom_navigation_view);
- if (getResources().getBoolean(R.bool.bottom_toolbar_enabled)) {
- bottomNavigationView.setVisibility(View.VISIBLE);
- DisplayUtils.setupBottomBar(bottomNavigationView, getResources(), this, -1);
- }
- load(gridWidth * 2);
- }
- /**
- * loads all media/synced folders, adds them to the recycler view adapter and shows the list.
- *
- * @param perFolderMediaItemLimit the amount of media items to be loaded/shown per media folder
- */
- private void load(final int perFolderMediaItemLimit) {
- if (mAdapter.getItemCount() > 0) {
- return;
- }
- setListShown(false);
- final Handler mHandler = new Handler();
- new Thread(new Runnable() {
- @Override
- public void run() {
- final List<MediaFolder> mediaFolders = MediaProvider.getMediaFolders(getContentResolver(),
- perFolderMediaItemLimit);
- List<SyncedFolder> syncedFolderArrayList = mSyncedFolderProvider.getSyncedFolders();
- List<SyncedFolder> currentAccountSyncedFoldersList = new ArrayList<SyncedFolder>();
- Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(FolderSyncActivity.this);
- for (SyncedFolder syncedFolder : syncedFolderArrayList) {
- if (syncedFolder.getAccount().equals(currentAccount.name)) {
- currentAccountSyncedFoldersList.add(syncedFolder);
- }
- }
- syncFolderItems = sortSyncedFolderItems(mergeFolderData(currentAccountSyncedFoldersList,
- mediaFolders));
- mHandler.post(new TimerTask() {
- @Override
- public void run() {
- mAdapter.setSyncFolderItems(syncFolderItems);
- setListShown(true);
- }
- });
- }
- }).start();
- }
- /**
- * merges two lists of {@link SyncedFolder} and {@link MediaFolder} items into one of SyncedFolderItems.
- *
- * @param syncedFolders the synced folders
- * @param mediaFolders the media folders
- * @return the merged list of SyncedFolderItems
- */
- @NonNull
- private List<SyncedFolderDisplayItem> mergeFolderData(List<SyncedFolder> syncedFolders,
- @NonNull List<MediaFolder> mediaFolders) {
- Map<String, SyncedFolder> syncedFoldersMap = createSyncedFoldersMap(syncedFolders);
- List<SyncedFolderDisplayItem> result = new ArrayList<>();
- for (MediaFolder mediaFolder : mediaFolders) {
- if (syncedFoldersMap.containsKey(mediaFolder.absolutePath)) {
- SyncedFolder syncedFolder = syncedFoldersMap.get(mediaFolder.absolutePath);
- syncedFoldersMap.remove(mediaFolder.absolutePath);
- result.add(createSyncedFolder(syncedFolder, mediaFolder));
- } else {
- result.add(createSyncedFolderFromMediaFolder(mediaFolder));
- }
- }
- for (SyncedFolder syncedFolder : syncedFoldersMap.values()) {
- SyncedFolderDisplayItem syncedFolderDisplayItem = createSyncedFolderWithoutMediaFolder(syncedFolder);
- result.add(syncedFolderDisplayItem);
- }
- return result;
- }
- /**
- * Sorts list of {@link SyncedFolderDisplayItem}s.
- *
- * @param syncFolderItemList list of items to be sorted
- * @return sorted list of items
- */
- public static List<SyncedFolderDisplayItem> sortSyncedFolderItems(List<SyncedFolderDisplayItem>
- syncFolderItemList) {
- Collections.sort(syncFolderItemList, new Comparator<SyncedFolderDisplayItem>() {
- public int compare(SyncedFolderDisplayItem f1, SyncedFolderDisplayItem f2) {
- if (f1 == null && f2 == null) {
- return 0;
- } else if (f1 == null) {
- return -1;
- } else if (f2 == null) {
- return 1;
- } else if (f1.isEnabled() && f2.isEnabled()) {
- return f1.getFolderName().toLowerCase().compareTo(f2.getFolderName().toLowerCase());
- } else if (f1.isEnabled()) {
- return -1;
- } else if (f2.isEnabled()) {
- return 1;
- } else if (f1.getFolderName() == null && f2.getFolderName() == null) {
- return 0;
- } else if (f1.getFolderName() == null) {
- return -1;
- } else if (f2.getFolderName() == null) {
- return 1;
- } else if (PRIORITIZED_FOLDER.equals(f1.getFolderName())) {
- return -1;
- } else if (PRIORITIZED_FOLDER.equals(f2.getFolderName())) {
- return 1;
- } else {
- return f1.getFolderName().toLowerCase().compareTo(f2.getFolderName().toLowerCase());
- }
- }
- });
- return syncFolderItemList;
- }
- @NonNull
- private SyncedFolderDisplayItem createSyncedFolderWithoutMediaFolder(@NonNull SyncedFolder syncedFolder) {
- return new SyncedFolderDisplayItem(
- syncedFolder.getId(),
- syncedFolder.getLocalPath(),
- syncedFolder.getRemotePath(),
- syncedFolder.getWifiOnly(),
- syncedFolder.getChargingOnly(),
- syncedFolder.getSubfolderByDate(),
- syncedFolder.getAccount(),
- syncedFolder.getUploadAction(),
- syncedFolder.isEnabled(),
- new File(syncedFolder.getLocalPath()).getName());
- }
- /**
- * creates a SyncedFolderDisplayItem merging a {@link SyncedFolder} and a {@link MediaFolder} object instance.
- *
- * @param syncedFolder the synced folder object
- * @param mediaFolder the media folder object
- * @return the created SyncedFolderDisplayItem
- */
- @NonNull
- private SyncedFolderDisplayItem createSyncedFolder(@NonNull SyncedFolder syncedFolder, @NonNull MediaFolder mediaFolder) {
- return new SyncedFolderDisplayItem(
- syncedFolder.getId(),
- syncedFolder.getLocalPath(),
- syncedFolder.getRemotePath(),
- syncedFolder.getWifiOnly(),
- syncedFolder.getChargingOnly(),
- syncedFolder.getSubfolderByDate(),
- syncedFolder.getAccount(),
- syncedFolder.getUploadAction(),
- syncedFolder.isEnabled(),
- mediaFolder.filePaths,
- mediaFolder.folderName,
- mediaFolder.numberOfFiles);
- }
- /**
- * creates a {@link SyncedFolderDisplayItem} based on a {@link MediaFolder} object instance.
- *
- * @param mediaFolder the media folder object
- * @return the created SyncedFolderDisplayItem
- */
- @NonNull
- private SyncedFolderDisplayItem createSyncedFolderFromMediaFolder(@NonNull MediaFolder mediaFolder) {
- return new SyncedFolderDisplayItem(
- UNPERSISTED_ID,
- mediaFolder.absolutePath,
- getString(R.string.instant_upload_path) + "/" + mediaFolder.folderName,
- true,
- false,
- false,
- AccountUtils.getCurrentOwnCloudAccount(this).name,
- FileUploader.LOCAL_BEHAVIOUR_FORGET,
- false,
- mediaFolder.filePaths,
- mediaFolder.folderName,
- mediaFolder.numberOfFiles);
- }
- /**
- * creates a lookup map for a list of given {@link SyncedFolder}s with their local path as the key.
- *
- * @param syncFolders list of {@link SyncedFolder}s
- * @return the lookup map for {@link SyncedFolder}s
- */
- @NonNull
- private Map<String, SyncedFolder> createSyncedFoldersMap(List<SyncedFolder> syncFolders) {
- Map<String, SyncedFolder> result = new HashMap<>();
- if (syncFolders != null) {
- for (SyncedFolder syncFolder : syncFolders) {
- result.put(syncFolder.getLocalPath(), syncFolder);
- }
- }
- return result;
- }
- /**
- * show/hide recycler view list or the empty message / progress info.
- *
- * @param shown flag if list should be shown
- */
- private void setListShown(boolean shown) {
- if (mRecyclerView != null) {
- mRecyclerView.setVisibility(shown ? View.VISIBLE : View.GONE);
- mProgress.setVisibility(shown ? View.GONE : View.VISIBLE);
- mEmpty.setVisibility(shown && mAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
- }
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- boolean result = true;
- switch (item.getItemId()) {
- case android.R.id.home: {
- if (showSidebar) {
- if (isDrawerOpen()) {
- closeDrawer();
- } else {
- openDrawer();
- }
- } else {
- Intent settingsIntent = new Intent(getApplicationContext(), Preferences.class);
- startActivity(settingsIntent);
- }
- break;
- }
- default:
- result = super.onOptionsItemSelected(item);
- }
- return result;
- }
- @Override
- public void restart() {
- Intent i = new Intent(this, FileDisplayActivity.class);
- i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(i);
- }
- @Override
- public void showFiles(boolean onDeviceOnly) {
- MainApp.showOnlyFilesOnDevice(onDeviceOnly);
- Intent fileDisplayActivity = new Intent(getApplicationContext(), FileDisplayActivity.class);
- fileDisplayActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(fileDisplayActivity);
- }
- @Override
- public void onSyncStatusToggleClick(int section, SyncedFolderDisplayItem syncedFolderDisplayItem) {
- if (syncedFolderDisplayItem.getId() > UNPERSISTED_ID) {
- mSyncedFolderProvider.updateFolderSyncEnabled(syncedFolderDisplayItem.getId(),
- syncedFolderDisplayItem.isEnabled());
- } else {
- long storedId = mSyncedFolderProvider.storeFolderSync(syncedFolderDisplayItem);
- if (storedId != -1) {
- syncedFolderDisplayItem.setId(storedId);
- }
- }
- }
- @Override
- public void onSyncFolderSettingsClick(int section, SyncedFolderDisplayItem syncedFolderDisplayItem) {
- FragmentManager fm = getSupportFragmentManager();
- FragmentTransaction ft = fm.beginTransaction();
- ft.addToBackStack(null);
- mSyncedFolderPreferencesDialogFragment = SyncedFolderPreferencesDialogFragment.newInstance(
- syncedFolderDisplayItem, section);
- mSyncedFolderPreferencesDialogFragment.show(ft, SYNCED_FOLDER_PREFERENCES_DIALOG_TAG);
- }
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == SyncedFolderPreferencesDialogFragment.REQUEST_CODE__SELECT_REMOTE_FOLDER
- && resultCode == RESULT_OK && mSyncedFolderPreferencesDialogFragment != null) {
- OCFile chosenFolder = data.getParcelableExtra(FolderPickerActivity.EXTRA_FOLDER);
- mSyncedFolderPreferencesDialogFragment.setRemoteFolderSummary(chosenFolder.getRemotePath());
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- }
- }
- @Override
- public void onSaveSyncedFolderPreference(SyncedFolderParcelable syncedFolder) {
- SyncedFolderDisplayItem item = syncFolderItems.get(syncedFolder.getSection());
- boolean dirty = item.isEnabled() != syncedFolder.getEnabled();
- item = updateSyncedFolderItem(item, syncedFolder.getLocalPath(), syncedFolder.getRemotePath(), syncedFolder
- .getWifiOnly(), syncedFolder.getChargingOnly(), syncedFolder.getSubfolderByDate(), syncedFolder
- .getUploadAction(), syncedFolder.getEnabled());
- if (syncedFolder.getId() == UNPERSISTED_ID) {
- // newly set up folder sync config
- long storedId = mSyncedFolderProvider.storeFolderSync(item);
- if (storedId != -1) {
- item.setId(storedId);
- }
- } else {
- // existing synced folder setup to be updated
- mSyncedFolderProvider.updateSyncFolder(item);
- }
- mSyncedFolderPreferencesDialogFragment = null;
- if (dirty) {
- mAdapter.setSyncFolderItem(syncedFolder.getSection(), item);
- }
- }
- @Override
- public void onCancelSyncedFolderPreference() {
- mSyncedFolderPreferencesDialogFragment = null;
- }
- /**
- * update given synced folder with the given values.
- *
- * @param item the synced folder to be updated
- * @param localPath the local path
- * @param remotePath the remote path
- * @param wifiOnly upload on wifi only
- * @param chargingOnly upload on charging only
- * @param subfolderByDate created sub folders
- * @param uploadAction upload action
- * @param enabled is sync enabled
- * @return the updated item
- */
- private SyncedFolderDisplayItem updateSyncedFolderItem(SyncedFolderDisplayItem item,
- String localPath,
- String remotePath,
- Boolean wifiOnly,
- Boolean chargingOnly,
- Boolean subfolderByDate,
- Integer uploadAction,
- Boolean enabled) {
- item.setLocalPath(localPath);
- item.setRemotePath(remotePath);
- item.setWifiOnly(wifiOnly);
- item.setChargingOnly(chargingOnly);
- item.setSubfolderByDate(subfolderByDate);
- item.setUploadAction(uploadAction);
- item.setEnabled(enabled);
- return item;
- }
- }
|