diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java b/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java index 502b9ff82201..af1028068541 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java +++ b/AnkiDroid/src/main/java/com/ichi2/anki/DeckPicker.java @@ -439,8 +439,8 @@ public void onClick(View v) { onSdCardNotMounted(); } else if (!CollectionHelper.isCurrentAnkiDroidDirAccessible(this)) { // AnkiDroid directory inaccessible - Intent prefIntent = CompatHelper.getCompat().getAdvancedPreferencesIntent(this); - startActivityForResultWithoutAnimation(prefIntent, REQUEST_PATH_UPDATE); + Intent i = CompatHelper.getCompat().getPreferenceSubscreenIntent(this, "com.ichi2.anki.prefs.advanced"); + startActivityForResultWithoutAnimation(i, REQUEST_PATH_UPDATE); Toast.makeText(this, R.string.directory_inaccessible, Toast.LENGTH_LONG).show(); } else { showDatabaseErrorDialog(DatabaseErrorDialog.DIALOG_LOAD_FAILED); diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/Preferences.java b/AnkiDroid/src/main/java/com/ichi2/anki/Preferences.java index b3b44e48a0fd..a1cfc6cd60d4 100644 --- a/AnkiDroid/src/main/java/com/ichi2/anki/Preferences.java +++ b/AnkiDroid/src/main/java/com/ichi2/anki/Preferences.java @@ -181,6 +181,7 @@ protected void onResume() { // syncAccount's summary can change while preferences are still open (user logs // in from preferences screen), so we need to update it here. updatePreference(prefs, "syncAccount", this); + updatePreference(prefs, "custom_sync_server_link", this); } } @@ -282,6 +283,16 @@ public boolean onPreferenceChange(Preference preference, final Object newValue) } } }); + // Custom sync server option + Preference customSyncServerPreference = screen.findPreference("custom_sync_server_link"); + customSyncServerPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + Intent i = CompatHelper.getCompat().getPreferenceSubscreenIntent(Preferences.this, + "com.ichi2.anki.prefs.custom_sync_server"); + startActivity(i); + return true; + } + }); // Force full sync option Preference fullSyncPreference = screen.findPreference("force_full_sync"); fullSyncPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { @@ -296,6 +307,10 @@ public boolean onPreferenceClick(Preference preference) { // Workaround preferences removeUnnecessaryAdvancedPrefs(screen); break; + case "com.ichi2.anki.prefs.custom_sync_server": + getSupportActionBar().setTitle(R.string.custom_sync_server_title); + listener.addPreferencesFromResource(R.xml.preferences_custom_sync_server); + break; } } @@ -374,7 +389,6 @@ private void initPreference(Preference pref) { CharSequence s = pref.getSummary(); mOriginalSumarries.put(pref.getKey(), (s != null) ? s.toString() : ""); // Update summary - updateSummary(pref); } @@ -515,8 +529,15 @@ private void updateSummary(Preference pref) { if (pref == null || pref.getKey() == null) { return; } + // Handle special cases if (pref.getKey().equals("about_dialog_preference")) { pref.setSummary(getResources().getString(R.string.about_version) + " " + VersionUtils.getPkgVersionName()); + } else if (pref.getKey().equals("custom_sync_server_link")) { + if (!AnkiDroidApp.getSharedPrefs(this).getBoolean("useCustomSyncServer", false)) { + pref.setSummary(R.string.disabled); + } else { + pref.setSummary(AnkiDroidApp.getSharedPrefs(this).getString("syncBaseUrl", "")); + } } // Get value text String value; @@ -709,6 +730,7 @@ public void onResume() { // syncAccount's summary can change while preferences are still open (user logs // in from preferences screen), so we need to update it here. ((Preferences) getActivity()).updatePreference(prefs, "syncAccount", this); + ((Preferences) getActivity()).updatePreference(prefs, "custom_sync_server_link", this); } @Override diff --git a/AnkiDroid/src/main/java/com/ichi2/compat/Compat.java b/AnkiDroid/src/main/java/com/ichi2/compat/Compat.java index d41bfebd0123..df5833efad23 100644 --- a/AnkiDroid/src/main/java/com/ichi2/compat/Compat.java +++ b/AnkiDroid/src/main/java/com/ichi2/compat/Compat.java @@ -59,6 +59,6 @@ public interface Compat { void setSelectableBackground(View view); void openUrl(AnkiActivity activity, Uri uri); void supportAddContentMenu(final DeckPicker a); - Intent getAdvancedPreferencesIntent(Context context); + Intent getPreferenceSubscreenIntent(Context context, String subscreen); } diff --git a/AnkiDroid/src/main/java/com/ichi2/compat/CompatV10.java b/AnkiDroid/src/main/java/com/ichi2/compat/CompatV10.java index 3d3b93aab9ea..ea93b1f91833 100644 --- a/AnkiDroid/src/main/java/com/ichi2/compat/CompatV10.java +++ b/AnkiDroid/src/main/java/com/ichi2/compat/CompatV10.java @@ -161,10 +161,10 @@ public void onClick(@NonNull MaterialDialog d, @NonNull DialogAction w) { } @Override - public Intent getAdvancedPreferencesIntent(Context context) { + public Intent getPreferenceSubscreenIntent(Context context, String subscreen) { // We're using "legacy preference headers" below API 11 Intent i = new Intent(context, Preferences.class); - i.setAction("com.ichi2.anki.prefs.advanced"); + i.setAction(subscreen); return i; } } \ No newline at end of file diff --git a/AnkiDroid/src/main/java/com/ichi2/compat/CompatV11.java b/AnkiDroid/src/main/java/com/ichi2/compat/CompatV11.java index 53e3079f308b..4f7fcfcfaea5 100644 --- a/AnkiDroid/src/main/java/com/ichi2/compat/CompatV11.java +++ b/AnkiDroid/src/main/java/com/ichi2/compat/CompatV11.java @@ -38,12 +38,13 @@ public void disableDatabaseWriteAheadLogging(SQLiteDatabase db) { } @Override - public Intent getAdvancedPreferencesIntent(Context context) { + public Intent getPreferenceSubscreenIntent(Context context, String subscreen) { Intent i = new Intent(context, Preferences.class); i.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, "com.ichi2.anki.Preferences$SettingsFragment"); Bundle extras = new Bundle(); - extras.putString("subscreen", "com.ichi2.anki.prefs.advanced"); + extras.putString("subscreen", subscreen); i.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, extras); + i.putExtra(PreferenceActivity.EXTRA_NO_HEADERS, true); return i; } } diff --git a/AnkiDroid/src/main/java/com/ichi2/libanki/sync/FullSyncer.java b/AnkiDroid/src/main/java/com/ichi2/libanki/sync/FullSyncer.java index 6e4733c0e13e..8f0b914dca78 100644 --- a/AnkiDroid/src/main/java/com/ichi2/libanki/sync/FullSyncer.java +++ b/AnkiDroid/src/main/java/com/ichi2/libanki/sync/FullSyncer.java @@ -16,11 +16,13 @@ package com.ichi2.libanki.sync; +import android.content.SharedPreferences; import android.database.sqlite.SQLiteDatabaseCorruptException; import com.ichi2.anki.AnkiDatabaseManager; import com.ichi2.anki.AnkiDb; +import com.ichi2.anki.AnkiDroidApp; import com.ichi2.anki.R; import com.ichi2.anki.exception.UnknownHttpResponseException; import com.ichi2.async.Connection; @@ -60,6 +62,13 @@ public FullSyncer(Collection col, String hkey, Connection con) { @Override public String syncURL() { + // Allow user to specify custom sync server + SharedPreferences userPreferences = AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance()); + if (userPreferences!= null && userPreferences.getBoolean("useCustomSyncServer", false)) { + File syncBase = new File(userPreferences.getString("syncBaseUrl", Consts.SYNC_BASE)); + return new File(syncBase, "/sync").toString() + "/"; + } + // Usual case return Consts.SYNC_BASE + "sync/"; } diff --git a/AnkiDroid/src/main/java/com/ichi2/libanki/sync/HttpSyncer.java b/AnkiDroid/src/main/java/com/ichi2/libanki/sync/HttpSyncer.java index cfa39d8067a5..3ed608d7caac 100644 --- a/AnkiDroid/src/main/java/com/ichi2/libanki/sync/HttpSyncer.java +++ b/AnkiDroid/src/main/java/com/ichi2/libanki/sync/HttpSyncer.java @@ -20,6 +20,8 @@ +import android.content.SharedPreferences; + import com.ichi2.anki.AnkiDroidApp; import com.ichi2.anki.exception.UnknownHttpResponseException; import com.ichi2.async.Connection; @@ -448,6 +450,13 @@ public HttpResponse register(String user, String pw) throws UnknownHttpResponseE public String syncURL() { + // Allow user to specify custom sync server + SharedPreferences userPreferences = AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance()); + if (userPreferences!= null && userPreferences.getBoolean("useCustomSyncServer", false)) { + File syncBase = new File(userPreferences.getString("syncBaseUrl", Consts.SYNC_BASE)); + return new File(syncBase, "/sync").toString() + "/"; + } + // Usual case return Consts.SYNC_BASE + "sync/"; } } diff --git a/AnkiDroid/src/main/java/com/ichi2/libanki/sync/RemoteMediaServer.java b/AnkiDroid/src/main/java/com/ichi2/libanki/sync/RemoteMediaServer.java index 8a27e17bf36b..9b5b768c4cde 100644 --- a/AnkiDroid/src/main/java/com/ichi2/libanki/sync/RemoteMediaServer.java +++ b/AnkiDroid/src/main/java/com/ichi2/libanki/sync/RemoteMediaServer.java @@ -17,8 +17,10 @@ package com.ichi2.libanki.sync; +import android.content.SharedPreferences; import android.text.TextUtils; +import com.ichi2.anki.AnkiDroidApp; import com.ichi2.anki.exception.MediaSyncException; import com.ichi2.anki.exception.UnknownHttpResponseException; import com.ichi2.async.Connection; @@ -55,6 +57,13 @@ public RemoteMediaServer(Collection col, String hkey, Connection con) { @Override public String syncURL() { + // Allow user to specify custom sync server + SharedPreferences userPreferences = AnkiDroidApp.getSharedPrefs(AnkiDroidApp.getInstance()); + if (userPreferences!= null && userPreferences.getBoolean("useCustomSyncServer", false)) { + File mediaSyncBase = new File(userPreferences.getString("syncMediaUrl", Consts.SYNC_MEDIA_BASE)); + return mediaSyncBase.toString() + "/"; + } + // Usual case return Consts.SYNC_MEDIA_BASE; } diff --git a/AnkiDroid/src/main/res/layout/my_account.xml b/AnkiDroid/src/main/res/layout/my_account.xml index 835ef05346fc..e6d0605b63c5 100644 --- a/AnkiDroid/src/main/res/layout/my_account.xml +++ b/AnkiDroid/src/main/res/layout/my_account.xml @@ -108,8 +108,15 @@ android:text="@string/sign_up_description" android:layout_gravity="center" android:textSize="@dimen/abc_text_size_button_material" - android:textStyle="bold" - /> + android:textStyle="bold"/> +