am c890a4e4
: Display dialog if unsaved settings would be lost
* commit 'c890a4e4a2cbb489aea4847cf25368a723586530': Display dialog if unsaved settings would be lost
This commit is contained in:
commit
5134b1ee80
@ -31,6 +31,9 @@ import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
/**
|
||||
* Common base class for server settings fragments, so they can be more easily manipulated by
|
||||
* AccountSettingsXL. Provides the following common functionality:
|
||||
@ -42,18 +45,22 @@ import android.widget.Button;
|
||||
public abstract class AccountServerBaseFragment extends Fragment
|
||||
implements AccountCheckSettingsFragment.Callbacks, OnClickListener {
|
||||
|
||||
public static Bundle sSetupModeArgs = null;
|
||||
protected static URI sDefaultUri;
|
||||
|
||||
private final static String BUNDLE_KEY_SETTINGS = "AccountServerBaseFragment.settings";
|
||||
|
||||
protected Context mContext;
|
||||
protected Callback mCallback = EmptyCallback.INSTANCE;
|
||||
protected boolean mSettingsMode;
|
||||
// The URI that represents this account's currently saved settings
|
||||
protected URI mLoadedUri;
|
||||
|
||||
// This is null in the setup wizard screens, and non-null in AccountSettings mode
|
||||
public Button mProceedButton;
|
||||
// This is used to debounce multiple clicks on the proceed button (which does async work)
|
||||
public boolean mProceedButtonPressed;
|
||||
|
||||
public static Bundle sSetupModeArgs = null;
|
||||
|
||||
/**
|
||||
* Callback interface that owning activities must provide
|
||||
*/
|
||||
@ -99,6 +106,16 @@ public abstract class AccountServerBaseFragment extends Fragment
|
||||
return sSetupModeArgs;
|
||||
}
|
||||
|
||||
public AccountServerBaseFragment() {
|
||||
if (sDefaultUri == null) {
|
||||
try {
|
||||
sDefaultUri = new URI("");
|
||||
} catch (URISyntaxException ignore) {
|
||||
// ignore; will never happen
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* At onCreate time, read the fragment arguments
|
||||
*/
|
||||
@ -272,6 +289,21 @@ public abstract class AccountServerBaseFragment extends Fragment
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not any settings have changed.
|
||||
*/
|
||||
public boolean haveSettingsChanged() {
|
||||
URI newUri = null;
|
||||
|
||||
try {
|
||||
newUri = getUri();
|
||||
} catch (URISyntaxException ignore) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return (mLoadedUri == null) || !mLoadedUri.equals(newUri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save settings after "OK" result from checker. Concrete classes must implement.
|
||||
* This is called from a worker thread and is allowed to perform DB operations.
|
||||
@ -288,4 +320,7 @@ public abstract class AccountServerBaseFragment extends Fragment
|
||||
* Respond to a click of the "Next" button. Concrete classes must implement.
|
||||
*/
|
||||
public abstract void onNext();
|
||||
|
||||
protected abstract URI getUri() throws URISyntaxException;
|
||||
|
||||
}
|
||||
|
@ -66,7 +66,6 @@ import java.util.List;
|
||||
* dealing with accounts being added/deleted and triggering the header reload.
|
||||
*/
|
||||
public class AccountSettingsXL extends PreferenceActivity {
|
||||
|
||||
// Intent extras for our internal activity launch
|
||||
/* package */ static final String EXTRA_ACCOUNT_ID = "AccountSettingsXL.account_id";
|
||||
private static final String EXTRA_ENABLE_DEBUG = "AccountSettingsXL.enable_debug";
|
||||
@ -243,8 +242,8 @@ public class AccountSettingsXL extends PreferenceActivity {
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Any time we exit via this pathway, and we are showing a server settings fragment,
|
||||
* we should put up the exit-save-changes dialog. This will work for the following cases:
|
||||
* Any time we exit via this pathway, and we are showing a server settings fragment,
|
||||
* we put up the exit-save-changes dialog. This will work for the following cases:
|
||||
* Cancel button
|
||||
* Back button
|
||||
* Up arrow in application icon
|
||||
@ -254,6 +253,15 @@ public class AccountSettingsXL extends PreferenceActivity {
|
||||
*/
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (mCurrentFragment instanceof AccountServerBaseFragment) {
|
||||
boolean changed = ((AccountServerBaseFragment)mCurrentFragment).haveSettingsChanged();
|
||||
if (changed) {
|
||||
UnsavedChangesDialogFragment dialogFragment =
|
||||
UnsavedChangesDialogFragment.newInstanceForBack();
|
||||
dialogFragment.show(getFragmentManager(), UnsavedChangesDialogFragment.TAG);
|
||||
return; // Prevent "back" from being handled
|
||||
}
|
||||
}
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
@ -444,12 +452,13 @@ public class AccountSettingsXL extends PreferenceActivity {
|
||||
public void onHeaderClick(Header header, int position) {
|
||||
// special case when exiting the server settings fragments
|
||||
if (mCurrentFragment instanceof AccountServerBaseFragment) {
|
||||
if (position != mCurrentHeaderPosition) {
|
||||
boolean changed = ((AccountServerBaseFragment)mCurrentFragment).haveSettingsChanged();
|
||||
if (changed) {
|
||||
UnsavedChangesDialogFragment dialogFragment =
|
||||
UnsavedChangesDialogFragment.newInstance(position);
|
||||
UnsavedChangesDialogFragment.newInstanceForHeader(position);
|
||||
dialogFragment.show(getFragmentManager(), UnsavedChangesDialogFragment.TAG);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Secret keys: Click 10x to enable debug settings
|
||||
@ -472,10 +481,23 @@ public class AccountSettingsXL extends PreferenceActivity {
|
||||
* in {@link #onHeaderClick(Header, int)}. Called after we interrupted a header switch
|
||||
* with a dialog, and the user OK'd it.
|
||||
*/
|
||||
private void forceSwitchHeader(int newPosition) {
|
||||
mCurrentHeaderPosition = newPosition;
|
||||
Header header = mGeneratedHeaders.get(newPosition);
|
||||
switchToHeader(header.fragment, header.fragmentArguments);
|
||||
private void forceSwitchHeader(int position) {
|
||||
mCurrentHeaderPosition = position;
|
||||
// Clear the current fragment; we're navigating away
|
||||
mCurrentFragment = null;
|
||||
// Ensure the UI visually shows the correct header selected
|
||||
setSelection(position);
|
||||
Header header = mGeneratedHeaders.get(position);
|
||||
switchToHeader(header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forcefully go backward in the stack. This may potentially discard unsaved settings.
|
||||
*/
|
||||
private void forceBack() {
|
||||
// Clear the current fragment; we're navigating away
|
||||
mCurrentFragment = null;
|
||||
onBackPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -539,6 +561,8 @@ public class AccountSettingsXL extends PreferenceActivity {
|
||||
*/
|
||||
public void onCheckSettingsComplete(int result, int setupMode) {
|
||||
if (result == AccountCheckSettingsFragment.CHECK_SETTINGS_OK) {
|
||||
// Settings checked & saved; clear current fragment
|
||||
mCurrentFragment = null;
|
||||
onBackPressed();
|
||||
}
|
||||
}
|
||||
@ -653,27 +677,47 @@ public class AccountSettingsXL extends PreferenceActivity {
|
||||
/**
|
||||
* Dialog fragment to show "exit with unsaved changes?" dialog
|
||||
*/
|
||||
public static class UnsavedChangesDialogFragment extends DialogFragment {
|
||||
/* package */ static class UnsavedChangesDialogFragment extends DialogFragment {
|
||||
private final static String TAG = "UnsavedChangesDialogFragment";
|
||||
|
||||
// Argument bundle keys
|
||||
private final static String BUNDLE_KEY_NEW_HEADER = "UnsavedChangesDialogFragment.Header";
|
||||
private final static String BUNDLE_KEY_HEADER = "UnsavedChangesDialogFragment.Header";
|
||||
private final static String BUNDLE_KEY_BACK = "UnsavedChangesDialogFragment.Back";
|
||||
|
||||
/**
|
||||
* Create the dialog with parameters
|
||||
* Creates a save changes dialog when the user selects a new header
|
||||
* @param position The new header index to make active if the user accepts the dialog. This
|
||||
* must be a valid header index although there is no error checking.
|
||||
*/
|
||||
public static UnsavedChangesDialogFragment newInstance(int newPosition) {
|
||||
public static UnsavedChangesDialogFragment newInstanceForHeader(int position) {
|
||||
UnsavedChangesDialogFragment f = new UnsavedChangesDialogFragment();
|
||||
Bundle b = new Bundle();
|
||||
b.putInt(BUNDLE_KEY_NEW_HEADER, newPosition);
|
||||
b.putInt(BUNDLE_KEY_HEADER, position);
|
||||
f.setArguments(b);
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a save changes dialog when the user navigates "back".
|
||||
* {@link AccountSettingsXL#onBackPressed()} defines in which case this may be triggered.
|
||||
*/
|
||||
public static UnsavedChangesDialogFragment newInstanceForBack() {
|
||||
UnsavedChangesDialogFragment f = new UnsavedChangesDialogFragment();
|
||||
Bundle b = new Bundle();
|
||||
b.putBoolean(BUNDLE_KEY_BACK, true);
|
||||
f.setArguments(b);
|
||||
return f;
|
||||
}
|
||||
|
||||
// Force usage of newInstance()
|
||||
private UnsavedChangesDialogFragment() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final AccountSettingsXL activity = (AccountSettingsXL) getActivity();
|
||||
final int newPosition = getArguments().getInt(BUNDLE_KEY_NEW_HEADER);
|
||||
final int position = getArguments().getInt(BUNDLE_KEY_HEADER);
|
||||
final boolean isBack = getArguments().getBoolean(BUNDLE_KEY_BACK);
|
||||
|
||||
return new AlertDialog.Builder(activity)
|
||||
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||
@ -683,13 +727,16 @@ public class AccountSettingsXL extends PreferenceActivity {
|
||||
R.string.okay_action,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
activity.forceSwitchHeader(newPosition);
|
||||
if (isBack) {
|
||||
activity.forceBack();
|
||||
} else {
|
||||
activity.forceSwitchHeader(position);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(
|
||||
activity.getString(R.string.cancel_action),
|
||||
null)
|
||||
activity.getString(R.string.cancel_action), null)
|
||||
.create();
|
||||
}
|
||||
}
|
||||
|
@ -262,6 +262,12 @@ public class AccountSetupExchangeFragment extends AccountServerBaseFragment
|
||||
mTrustCertificatesView.setChecked(trustCertificates);
|
||||
showTrustCertificates(ssl);
|
||||
|
||||
try {
|
||||
mLoadedUri = getUri();
|
||||
} catch (URISyntaxException ignore) {
|
||||
// ignore; should not happen
|
||||
}
|
||||
|
||||
mLoaded = true;
|
||||
return validateFields();
|
||||
}
|
||||
@ -347,7 +353,8 @@ public class AccountSetupExchangeFragment extends AccountServerBaseFragment
|
||||
* a problem with the user input.
|
||||
* @return a URI built from the account setup fields
|
||||
*/
|
||||
/* package */ URI getUri() throws URISyntaxException {
|
||||
@Override
|
||||
protected URI getUri() throws URISyntaxException {
|
||||
boolean sslRequired = mSslSecurityView.isChecked();
|
||||
boolean trustCertificates = mTrustCertificatesView.isChecked();
|
||||
String scheme = (sslRequired)
|
||||
|
@ -78,6 +78,8 @@ public class AccountSetupIncomingFragment extends AccountServerBaseFragment {
|
||||
private Spinner mDeletePolicyView;
|
||||
private View mImapPathPrefixSectionView;
|
||||
private EditText mImapPathPrefixView;
|
||||
// Delete policy as loaded from the device
|
||||
private int mLoadedDeletePolicy;
|
||||
|
||||
// Support for lifecycle
|
||||
private boolean mStarted;
|
||||
@ -333,7 +335,8 @@ public class AccountSetupIncomingFragment extends AccountServerBaseFragment {
|
||||
}
|
||||
|
||||
if (uri.getScheme().startsWith("pop3")) {
|
||||
SpinnerOption.setSpinnerOptionValue(mDeletePolicyView, account.getDeletePolicy());
|
||||
mLoadedDeletePolicy = account.getDeletePolicy();
|
||||
SpinnerOption.setSpinnerOptionValue(mDeletePolicyView, mLoadedDeletePolicy);
|
||||
} else if (uri.getScheme().startsWith("imap")) {
|
||||
if (uri.getPath() != null && uri.getPath().length() > 0) {
|
||||
mImapPathPrefixView.setText(uri.getPath().substring(1));
|
||||
@ -363,6 +366,13 @@ public class AccountSetupIncomingFragment extends AccountServerBaseFragment {
|
||||
*/
|
||||
throw new Error(use);
|
||||
}
|
||||
|
||||
try {
|
||||
mLoadedUri = getUri();
|
||||
} catch (URISyntaxException ignore) {
|
||||
// ignore; should not happen
|
||||
}
|
||||
|
||||
mLoaded = true;
|
||||
validateFields();
|
||||
}
|
||||
@ -440,7 +450,8 @@ public class AccountSetupIncomingFragment extends AccountServerBaseFragment {
|
||||
* a problem with the user input.
|
||||
* @return a URI built from the account setup fields
|
||||
*/
|
||||
/* package */ URI getUri() throws URISyntaxException {
|
||||
@Override
|
||||
protected URI getUri() throws URISyntaxException {
|
||||
int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value;
|
||||
String path = null;
|
||||
if (mAccountSchemes[securityType].startsWith("imap")) {
|
||||
@ -485,4 +496,18 @@ public class AccountSetupIncomingFragment extends AccountServerBaseFragment {
|
||||
throw new Error(use);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean haveSettingsChanged() {
|
||||
boolean deletePolicyChanged = false;
|
||||
|
||||
// Only verify the delete policy if the control is visible (i.e. is a pop3 account)
|
||||
if (mDeletePolicyView.getVisibility() == View.VISIBLE) {
|
||||
int newDeletePolicy =
|
||||
(Integer)((SpinnerOption)mDeletePolicyView.getSelectedItem()).value;
|
||||
deletePolicyChanged = mLoadedDeletePolicy != newDeletePolicy;
|
||||
}
|
||||
|
||||
return deletePolicyChanged || super.haveSettingsChanged();
|
||||
}
|
||||
}
|
||||
|
@ -300,6 +300,13 @@ public class AccountSetupOutgoingFragment extends AccountServerBaseFragment
|
||||
*/
|
||||
throw new Error(use);
|
||||
}
|
||||
|
||||
try {
|
||||
mLoadedUri = getUri();
|
||||
} catch (URISyntaxException ignore) {
|
||||
// ignore; should not happen
|
||||
}
|
||||
|
||||
mLoaded = true;
|
||||
validateFields();
|
||||
}
|
||||
@ -368,7 +375,8 @@ public class AccountSetupOutgoingFragment extends AccountServerBaseFragment
|
||||
* a problem with the user input.
|
||||
* @return a URI built from the account setup fields
|
||||
*/
|
||||
/* package */ URI getUri() throws URISyntaxException {
|
||||
@Override
|
||||
protected URI getUri() throws URISyntaxException {
|
||||
int securityType = (Integer)((SpinnerOption)mSecurityTypeView.getSelectedItem()).value;
|
||||
String userInfo = null;
|
||||
if (mRequireLoginView.isChecked()) {
|
||||
|
Loading…
Reference in New Issue
Block a user