syncthing.android.ui.sessionsettings.EditFolderPresenter.java Source code

Java tutorial

Introduction

Here is the source code for syncthing.android.ui.sessionsettings.EditFolderPresenter.java

Source

/*
 * Copyright (c) 2015 OpenSilk Productions LLC
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package syncthing.android.ui.sessionsettings;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.databinding.Bindable;
import android.databinding.BindingAdapter;
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.app.AlertDialog;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.Filter;
import android.widget.LinearLayout;

import com.jakewharton.rxbinding.widget.RxCompoundButton;

import org.apache.commons.lang3.StringUtils;
import org.opensilk.common.core.dagger2.ScreenScope;
import org.opensilk.common.ui.mortar.ActionBarConfig;
import org.opensilk.common.ui.mortar.ActionBarMenuConfig;
import org.opensilk.common.ui.mortar.ActivityResultsController;
import org.opensilk.common.ui.mortar.ActivityResultsListener;
import org.opensilk.common.ui.mortar.DialogPresenter;
import org.opensilk.common.ui.mortar.ToolbarOwner;
import org.opensilk.common.ui.mortarfragment.FragmentManagerOwner;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.inject.Inject;

import mortar.MortarScope;
import rx.Subscription;
import rx.functions.Action1;
import syncthing.android.R;
import syncthing.android.service.SyncthingUtils;
import syncthing.android.ui.ManageActivity;
import syncthing.android.ui.common.ActivityRequestCodes;
import syncthing.android.ui.folderpicker.FolderPickerFragment;
import syncthing.api.SessionManager;
import syncthing.api.model.DeviceConfig;
import syncthing.api.model.FolderConfig;
import syncthing.api.model.FolderDeviceConfig;
import syncthing.api.model.FolderType;
import syncthing.api.model.PullOrder;
import syncthing.api.model.SystemInfo;
import syncthing.api.model.Version;
import syncthing.api.model.VersioningExternal;
import syncthing.api.model.VersioningNone;
import syncthing.api.model.VersioningSimple;
import syncthing.api.model.VersioningStaggered;
import syncthing.api.model.VersioningTrashCan;
import syncthing.api.model.VersioningType;
import timber.log.Timber;

import static syncthing.android.ui.sessionsettings.EditPresenterConfig.INVALID_ID;

/**
 * Created by drew on 3/16/15.
 */
@ScreenScope
public class EditFolderPresenter extends EditPresenter<CoordinatorLayout>
        implements ActivityResultsListener, android.databinding.DataBindingComponent {

    final FragmentManagerOwner fm;

    FolderConfig origFolder;
    VersioningTrashCan.Params trashCanParams = new VersioningTrashCan.Params();
    VersioningSimple.Params simpleParams = new VersioningSimple.Params();
    VersioningStaggered.Params staggeredParams = new VersioningStaggered.Params();
    VersioningExternal.Params externalParams = new VersioningExternal.Params();
    boolean newShare;
    TreeMap<String, Boolean> sharedDevices;

    Subscription deleteSubscription;

    String errorFolderId;
    String errorFolderPath;
    String errorRescanInterval;
    String errorTrashCanParamCleanoutDays;
    String errorSimpleParamKeep;
    String errorStaggeredParamMaxAge;
    String errorExternalParamCmd;

    @Inject
    public EditFolderPresenter(SessionManager manager, DialogPresenter dialogPresenter,
            ActivityResultsController activityResultContoller, ToolbarOwner toolbarOwner,
            EditPresenterConfig config, FragmentManagerOwner fm) {
        super(manager, dialogPresenter, activityResultContoller, toolbarOwner, config);
        this.fm = fm;
    }

    @Override
    protected void onEnterScope(MortarScope scope) {
        super.onEnterScope(scope);
        activityResultsController.register(scope, this);
    }

    @Override
    protected void onExitScope() {
        super.onExitScope();
        unsubscribe(deleteSubscription);
    }

    @Override
    @SuppressWarnings("unchecked")
    protected void onLoad(Bundle savedInstanceState) {
        super.onLoad(savedInstanceState);
        if (!wasPreviouslyLoaded && savedInstanceState != null) {
            origFolder = (FolderConfig) savedInstanceState.getSerializable("folder");
            newShare = savedInstanceState.getBoolean("newShare");
            sharedDevices = (TreeMap<String, Boolean>) savedInstanceState.getSerializable("sharedDevices");
            initParams(origFolder);
        } else if (!wasPreviouslyLoaded) {
            if (isAdd) {
                origFolder = FolderConfig.withDefaults();
                if (!INVALID_ID.equals(folderId)) {
                    origFolder.id = folderId;
                    newShare = true;
                }
                SystemInfo sys = controller.getSystemInfo();
                if (sys != null) {
                    origFolder.path = sys.tilde;
                }
                Version ver = controller.getVersion();
                if (ver != null && StringUtils.equals(ver.os, "android")) {
                    //set ignore perms on android by default
                    origFolder.ignorePerms = true;
                }
            } else {
                FolderConfig f = controller.getFolder(folderId);
                if (f != null) {
                    origFolder = f.clone();
                }
            }
            initParams(origFolder);
            sharedDevices = new TreeMap<>();
            List<DeviceConfig> devices = controller.getRemoteDevices();
            for (DeviceConfig d : devices) {
                sharedDevices.put(d.deviceID, false);
                if (origFolder != null && origFolder.devices != null) {
                    for (FolderDeviceConfig d2 : origFolder.devices) {
                        if (StringUtils.equals(d2.deviceID, d.deviceID)) {
                            sharedDevices.put(d.deviceID, true);
                            break;
                        }
                    }
                }
            }
            if (!INVALID_ID.equals(deviceId) && sharedDevices.containsKey(deviceId)) {
                sharedDevices.put(deviceId, true);
            }
        }
        wasPreviouslyLoaded = true;
        if (origFolder == null) {
            Timber.e("Folder was null! cannot continue.");
            dismissDialog();
        }
    }

    @Override
    protected void onSave(Bundle outState) {
        super.onSave(outState);
        outState.putSerializable("folder", origFolder);
        outState.putBoolean("newShare", newShare);
        outState.putSerializable("sharedDevices", sharedDevices);
    }

    @Override
    public ActionBarConfig getToolbarConfig() {
        if (isAdd) {
            return super.getToolbarConfig();
        }
        return super.getToolbarConfig().buildUpon().setMenuConfig(
                ActionBarMenuConfig.builder().withMenu(R.menu.folder_ignores).setActionHandler((context, id) -> {
                    switch (id) {
                    case R.id.edit_ignores:
                        openIgnoresEditor(context);
                        return true;
                    default:
                        return false;
                    }
                }).build()).build();
    }

    @Bindable
    public boolean isAdd() {
        return isAdd;
    }

    @Bindable
    public boolean isNewShare() {
        return newShare;
    }

    @Bindable
    public String getFolderID() {
        return origFolder.id;
    }

    public void setFolderID(CharSequence text) {
        if (!isAdd || newShare) {
            return;
        }
        if (validateFolderId(text)) {
            origFolder.id = text.toString();
        }
    }

    public final Action1<CharSequence> actionSetFolderID = new Action1<CharSequence>() {
        @Override
        public void call(CharSequence charSequence) {
            setFolderID(charSequence);
        }
    };

    @Bindable
    public String getFolderIDError() {
        return errorFolderId;
    }

    public void setFolderIDError(String text) {
        if (!StringUtils.equals(errorFolderId, text)) {
            errorFolderId = text;
            notifyChange(syncthing.android.BR.folderIDError);
        }
    }

    boolean validateFolderId(CharSequence text) {
        int e = 0;
        if (StringUtils.isEmpty(text.toString())) {
            e = R.string.the_folder_id_cannot_be_blank;
        } else if (!isFolderIdUnique(text.toString(), controller.getFolders())) {
            e = R.string.the_folder_id_must_be_unique;
        }
        if (hasView()) {
            setFolderIDError(e != 0 ? getView().getContext().getString(e) : null);
        }
        return e == 0;
    }

    static boolean isFolderIdUnique(CharSequence text, Collection<FolderConfig> folders) {
        for (FolderConfig f : folders)
            if (StringUtils.equals(f.id, text))
                return false;
        return true;
    }

    @Bindable
    public String getFolderPath() {
        return origFolder.path;
    }

    public void setFolderPath(CharSequence text) {
        if (validateFolderPath(text)) {
            origFolder.path = text.toString();
        }
    }

    public final Action1<CharSequence> actionSetFolderPath = new Action1<CharSequence>() {
        @Override
        public void call(CharSequence charSequence) {
            setFolderPath(charSequence);
        }
    };

    @Bindable
    public String getFolderPathError() {
        return errorFolderPath;
    }

    public void setFolderPathError(String text) {
        if (!StringUtils.equals(errorFolderPath, text)) {
            errorFolderPath = text;
            notifyChange(syncthing.android.BR.folderPathError);
        }
    }

    boolean validateFolderPath(CharSequence text) {
        boolean invalid = false;
        if (StringUtils.isEmpty(text)) {
            invalid = true;
        }
        if (hasView()) {
            setFolderPathError(
                    invalid ? getView().getContext().getString(R.string.the_folder_path_cannot_be_blank) : null);
        }
        return !invalid;
    }

    @Bindable
    public String getRescanInterval() {
        return String.valueOf(origFolder.rescanIntervalS);
    }

    public void setRescanInterval(CharSequence text) {
        if (validateRescanInterval(text)) {
            origFolder.rescanIntervalS = Integer.valueOf(text.toString());
        }
    }

    public final Action1<CharSequence> actionSetRescanInterval = new Action1<CharSequence>() {
        @Override
        public void call(CharSequence charSequence) {
            setRescanInterval(charSequence);
        }
    };

    @Bindable
    public String getRescanIntervalError() {
        return errorRescanInterval;
    }

    public void setRescanIntervalError(String text) {
        if (!StringUtils.equals(errorRescanInterval, text)) {
            errorRescanInterval = text;
            notifyChange(syncthing.android.BR.rescanIntervalError);
        }
    }

    boolean validateRescanInterval(CharSequence text) {
        boolean invalid = false;
        //input disallows negative numbers and non numerals;
        if (StringUtils.isEmpty(text)) {
            invalid = true;
        }
        if (hasView()) {
            setRescanIntervalError(invalid ? getView().getContext()
                    .getString(R.string.the_rescan_interval_must_be_a_nonnegative_number_of_seconds) : null);
        }
        return !invalid;
    }

    @Bindable
    public boolean getReadOnly() {
        return origFolder.type == FolderType.READONLY;
    }

    public void setFolderType(FolderType type) {
        origFolder.type = type;
    }

    public final Action1<Boolean> actionSetReadOnly = new Action1<Boolean>() {
        @Override
        public void call(Boolean isReadOnly) {
            if (isReadOnly) {
                setFolderType(FolderType.READONLY);
            } else {
                setFolderType(FolderType.READWRITE);
            }
        }
    };

    @Bindable
    public boolean isIgnorePerms() {
        return origFolder.ignorePerms;
    }

    public void setIgnorePerms(boolean ignorePerms) {
        origFolder.ignorePerms = ignorePerms;
    }

    public final Action1<Boolean> actionSetIgnorePerms = new Action1<Boolean>() {
        @Override
        public void call(Boolean aBoolean) {
            setIgnorePerms(aBoolean);
        }
    };

    @Bindable
    public PullOrder getPullOrder() {
        return origFolder.order;
    }

    public void setPullOrder(PullOrder order) {
        origFolder.order = order;
    }

    public final Action1<Integer> actionOnPullOrderChanged = new Action1<Integer>() {
        @Override
        public void call(Integer checkedId) {
            switch (checkedId) {
            case R.id.radio_pullorder_alphabetic:
                setPullOrder(PullOrder.ALPHABETIC);
                break;
            case R.id.radio_pullorder_smallestfirst:
                setPullOrder(PullOrder.SMALLESTFIRST);
                break;
            case R.id.radio_pullorder_largestfirst:
                setPullOrder(PullOrder.LARGESTFIRST);
                break;
            case R.id.radio_pullorder_oldestfirst:
                setPullOrder(PullOrder.OLDESTFIRST);
                break;
            case R.id.radio_pullorder_newestfirst:
                setPullOrder(PullOrder.NEWESTFIRST);
                break;
            case R.id.radio_pullorder_random:
                setPullOrder(PullOrder.RANDOM);
                break;
            }
        }
    };

    @Bindable
    public VersioningType getVersioningType() {
        return origFolder.versioning.type;
    }

    public void setVersioningType(VersioningType type) {
        switch (type) {
        case TRASHCAN:
            origFolder.versioning = new VersioningTrashCan(type, trashCanParams);
            break;
        case SIMPLE:
            origFolder.versioning = new VersioningSimple(type, simpleParams);
            break;
        case STAGGERED:
            origFolder.versioning = new VersioningStaggered(type, staggeredParams);
            break;
        case EXTERNAL:
            origFolder.versioning = new VersioningExternal(type, externalParams);
            break;
        case NONE:
            origFolder.versioning = new VersioningNone(type);
            break;
        }
        notifyChange(syncthing.android.BR.versioningType);
    }

    public final Action1<Integer> actionOnVersioningChanged = new Action1<Integer>() {
        @Override
        public void call(Integer checkedId) {
            switch (checkedId) {
            case R.id.radio_trashcan_versioning:
                setVersioningType(VersioningType.TRASHCAN);
                break;
            case R.id.radio_simple_versioning:
                setVersioningType(VersioningType.SIMPLE);
                break;
            case R.id.radio_staggered_versioning:
                setVersioningType(VersioningType.STAGGERED);
                break;
            case R.id.radio_external_versioning:
                setVersioningType(VersioningType.EXTERNAL);
                break;
            case R.id.radio_no_versioning:
                setVersioningType(VersioningType.NONE);
                break;
            }
        }
    };

    private void initParams(FolderConfig f) {
        if (f == null || f.versioning == null)
            return;
        switch (origFolder.versioning.type) {
        case TRASHCAN:
            trashCanParams = (VersioningTrashCan.Params) origFolder.versioning.params;
            break;
        case SIMPLE:
            simpleParams = (VersioningSimple.Params) origFolder.versioning.params;
            break;
        case STAGGERED:
            staggeredParams = (VersioningStaggered.Params) origFolder.versioning.params;
            break;
        case EXTERNAL:
            externalParams = (VersioningExternal.Params) origFolder.versioning.params;
            break;
        }
    }

    @Bindable
    public VersioningTrashCan.Params getTrashCanParams() {
        return trashCanParams;
    }

    public void setTrashCanParamCleanDays(CharSequence text) {
        if (validateTrashCanVersioningCleanoutDays(text)) {
            trashCanParams.cleanoutDays = text.toString();
        }
    }

    public final Action1<CharSequence> actionSetTrashCanParamCleanoutDays = new Action1<CharSequence>() {
        @Override
        public void call(CharSequence charSequence) {
            setTrashCanParamCleanDays(charSequence);
        }
    };

    @Bindable
    public String getTrashCanParamCleanoutDaysError() {
        return errorTrashCanParamCleanoutDays;
    }

    public void setTrashCanParamCleanoutDaysError(String text) {
        if (!StringUtils.equals(errorTrashCanParamCleanoutDays, text)) {
            errorTrashCanParamCleanoutDays = text;
            notifyChange(syncthing.android.BR.trashCanParamCleanoutDaysError);
        }
    }

    boolean validateTrashCanVersioningCleanoutDays(CharSequence text) {
        boolean invalid = false;
        //input disallows negative numbers and non numerals;
        if (StringUtils.isEmpty(text)) {
            invalid = true;
        }
        if (hasView()) {
            setTrashCanParamCleanoutDaysError(invalid ? getView().getContext()
                    .getString(R.string.the_number_of_days_must_be_a_number_and_cannot_be_blank) : null);
        }
        return !invalid;
    }

    @Bindable
    public VersioningSimple.Params getSimpleParams() {
        return simpleParams;
    }

    public void setSimpleParamKeep(CharSequence text) {
        if (validateSimpleVersioningKeep(text)) {
            simpleParams.keep = text.toString();
        }
    }

    public final Action1<CharSequence> actionSetSimpleParamKeep = new Action1<CharSequence>() {
        @Override
        public void call(CharSequence charSequence) {
            setSimpleParamKeep(charSequence);
        }
    };

    @Bindable
    public String getSimpleParamKeepError() {
        return errorSimpleParamKeep;
    }

    public void setSimpleParamKeepError(String text) {
        if (!StringUtils.equals(errorSimpleParamKeep, text)) {
            errorSimpleParamKeep = text;
            notifyChange(syncthing.android.BR.simpleParamKeepError);
        }
    }

    boolean validateSimpleVersioningKeep(CharSequence text) {
        int e = 0;
        //input disallows negative numbers and non numerals;
        if (StringUtils.isEmpty(text)) {
            e = R.string.the_number_of_versions_must_be_a_number_and_cannot_be_blank;
        } else if (Integer.parseInt(text.toString()) == 0) {
            e = R.string.you_must_keep_at_least_one_version;
        }
        if (hasView()) {
            setSimpleParamKeepError(e != 0 ? getView().getContext().getString(e) : null);
        }
        return e == 0;
    }

    @Bindable
    public VersioningStaggered.Params getStaggeredParams() {
        return staggeredParams;
    }

    @Bindable
    public String getStaggeredParamMaxAge() {
        return SyncthingUtils.secondsToDays(staggeredParams.maxAge);
    }

    public void setStaggeredParamMaxAge(CharSequence text) {
        if (validateStaggeredMaxAge(text)) {
            staggeredParams.maxAge = SyncthingUtils.daysToSeconds(text.toString());
        }
    }

    public final Action1<CharSequence> actionSetStaggeredParamMaxAge = new Action1<CharSequence>() {
        @Override
        public void call(CharSequence charSequence) {
            setStaggeredParamMaxAge(charSequence);
        }
    };

    @Bindable
    public String getStaggeredParamMaxAgeError() {
        return errorStaggeredParamMaxAge;
    }

    public void setStaggeredParamMaxAgeError(String text) {
        if (!StringUtils.equals(errorStaggeredParamMaxAge, text)) {
            errorStaggeredParamMaxAge = text;
            notifyChange(syncthing.android.BR.staggeredParamMaxAgeError);
        }
    }

    boolean validateStaggeredMaxAge(CharSequence text) {
        boolean invalid = false;
        //input disallows negative numbers and non numerals;
        if (StringUtils.isEmpty(text)) {
            invalid = true;
        }
        if (hasView()) {
            setStaggeredParamMaxAgeError(invalid ? getView().getContext()
                    .getString(R.string.the_maximum_age_must_be_a_number_and_cannot_be_blank) : null);
        }
        return !invalid;
    }

    public void setStaggeredParamPath(CharSequence text) {
        staggeredParams.versionPath = StringUtils.isEmpty(text) ? "" : text.toString();
    }

    public final Action1<CharSequence> actionSetStaggeredParamPath = new Action1<CharSequence>() {
        @Override
        public void call(CharSequence charSequence) {
            setStaggeredParamPath(charSequence);
        }
    };

    @Bindable
    public VersioningExternal.Params getExternalParams() {
        return externalParams;
    }

    public void setExternalParamCmd(CharSequence text) {
        if (validateExternalVersioningCmd(text)) {
            externalParams.command = text.toString();
        }
    }

    public final Action1<CharSequence> actionSetExternalParamCmd = new Action1<CharSequence>() {
        @Override
        public void call(CharSequence charSequence) {
            setExternalParamCmd(charSequence);
        }
    };

    @Bindable
    public String getExternalParamCmdError() {
        return errorExternalParamCmd;
    }

    public void setExternalParamCmdError(String text) {
        if (!StringUtils.equals(errorExternalParamCmd, text)) {
            errorExternalParamCmd = text;
            notifyChange(syncthing.android.BR.externalParamCmdError);
        }
    }

    boolean validateExternalVersioningCmd(CharSequence text) {
        boolean invalid = false;
        if (StringUtils.isEmpty(text)) {
            invalid = true;
        }
        if (hasView()) {
            setExternalParamCmdError(
                    invalid ? getView().getContext().getString(R.string.the_path_cannot_be_blank) : null);
        }
        return !invalid;
    }

    public void setDeviceShared(String id, boolean shared) {
        sharedDevices.put(id, shared);
    }

    @BindingAdapter("addShareDevices")
    public static void addShareDevices(LinearLayout shareDevicesContainer, EditFolderPresenter presenter) {
        if (presenter == null)
            return;
        shareDevicesContainer.removeAllViews();
        for (Map.Entry<String, Boolean> e : presenter.sharedDevices.entrySet()) {
            final String id = e.getKey();
            CheckBox checkBox = new CheckBox(shareDevicesContainer.getContext());
            DeviceConfig device = presenter.controller.getDevice(id);
            if (device == null) {
                device = new DeviceConfig();
                device.deviceID = id;
            }
            checkBox.setText(SyncthingUtils.getDisplayName(device));
            checkBox.setChecked(e.getValue());
            shareDevicesContainer.addView(checkBox);
            presenter.bindingSubscriptions().add(RxCompoundButton.checkedChanges(checkBox).subscribe(b -> {
                presenter.setDeviceShared(id, b);
            }));
        }
    }

    public void saveFolder(View btn) {
        boolean invalid = false;
        invalid |= errorFolderId != null;
        invalid |= errorFolderPath != null;
        invalid |= errorRescanInterval != null;
        switch (getVersioningType()) {
        case TRASHCAN:
            invalid |= errorTrashCanParamCleanoutDays != null;
            break;
        case STAGGERED:
            invalid |= errorStaggeredParamMaxAge != null;
            break;
        case SIMPLE:
            invalid |= errorSimpleParamKeep != null;
            break;
        case EXTERNAL:
            invalid |= errorExternalParamCmd != null;
            break;
        }
        if (invalid) {
            dialogPresenter.showDialog(context -> new AlertDialog.Builder(context).setTitle(R.string.input_error)
                    .setMessage(R.string.input_error_message).setPositiveButton(android.R.string.cancel, null)
                    .setNegativeButton(R.string.save, (d, w) -> {
                        saveFolder();
                    }).create());
        } else {
            saveFolder();
        }
    }

    private void saveFolder() {
        List<FolderDeviceConfig> devices = new ArrayList<>();
        for (Map.Entry<String, Boolean> e : sharedDevices.entrySet()) {
            if (e.getValue()) {
                devices.add(new FolderDeviceConfig(e.getKey()));
            }
        }
        origFolder.devices = devices;
        unsubscribe(saveSubscription);
        onSaveStart();
        saveSubscription = controller.editFolder(origFolder, this::onSavefailed, this::onSaveSuccessfull);
    }

    public void deleteFolder(View btn) {
        unsubscribe(deleteSubscription);
        onSaveStart();
        deleteSubscription = controller.deleteFolder(origFolder, this::onSavefailed, this::onSaveSuccessfull);
    }

    public void openIgnoresEditor(Context context) {
        EditIgnoresFragment f = EditIgnoresFragment.ni(context, credentials, folderId);
        fm.replaceMainContent(f, true);
    }

    public void openFolderPicker(View btn) {
        String path = getFolderPath();
        if (StringUtils.endsWith(path, "/")) {
            path = path.substring(0, path.length() - 1);
        } else if (path.lastIndexOf("/") > 0) {
            //we want the last directory they inputed not any partial name in there
            path = path.substring(0, path.lastIndexOf("/"));
        }
        Intent i = new Intent(btn.getContext(), ManageActivity.class)
                .putExtra(ManageActivity.EXTRA_FRAGMENT, FolderPickerFragment.NAME)
                .putExtra(ManageActivity.EXTRA_ARGS, FolderPickerFragment.makeArgs(credentials, path))
                .putExtra(ManageActivity.EXTRA_UP_IS_BACK, true);
        activityResultsController.startActivityForResult(i, ActivityRequestCodes.FOLDER_PICKER, null);
    }

    @Override
    public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == ActivityRequestCodes.FOLDER_PICKER) {
            if (resultCode == Activity.RESULT_OK) {
                String path = data.getStringExtra("path");
                if (path != null) {
                    setFolderPath(path);
                    notifyChange(syncthing.android.BR.folderPath);
                }
            }
            return true;
        } else {
            return false;
        }
    }

    static class DirectoryAutoCompleteAdapter extends ArrayAdapter<String> {
        final EditFolderPresenter presenter;

        DirectoryAutoCompleteAdapter(Context context, EditFolderPresenter presenter) {
            super(context, android.R.layout.simple_dropdown_item_1line);
            this.presenter = presenter;
            setNotifyOnChange(false);
        }

        @Override
        public Filter getFilter() {
            return new Filter() {
                @Override
                protected FilterResults performFiltering(CharSequence constraint) {
                    try {
                        List<String> results = presenter.controller
                                .getAutoCompleteDirectoryList(constraint.toString()).toBlocking().first();
                        FilterResults fr = new FilterResults();
                        fr.values = results;
                        fr.count = results.size();
                        return fr;
                    } catch (Exception e) { //cant remember what in throws
                        FilterResults fr = new FilterResults();
                        fr.values = new ArrayList<String>();
                        fr.count = 0;
                        return fr;
                    }
                }

                @Override
                protected void publishResults(CharSequence constraint, FilterResults results) {
                    if (results.count == 0) {
                        clear();
                        notifyDataSetInvalidated();
                    } else {
                        clear();
                        addAll((List<String>) results.values);
                        notifyDataSetChanged();
                    }
                }
            };
        }
    }

}