diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 090667d24..dfc7007f7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -570,6 +570,10 @@
android:name=".etesync.EteSyncCalendarSettingsActivity"
android:theme="@style/Tasks" />
+
+
> {
+public class AddEteSyncAccountViewModel extends CompletableViewModel> {
void addAccount(
PlayServices playServices,
Context context,
EteSyncClient client,
String url,
String username,
- String password,
- String encryptionPassword) {
+ String password) {
run(
() -> {
playServices.updateSecurityProvider(context);
- return client
- .setForeground()
- .forUrl(url, username, encryptionPassword, null)
- .getKeyAndToken(password);
+ return client.setForeground().forUrl(url, username, null, null).getInfoAndToken(password);
});
}
}
diff --git a/app/src/main/java/org/tasks/etesync/CreateUserInfoViewModel.java b/app/src/main/java/org/tasks/etesync/CreateUserInfoViewModel.java
new file mode 100644
index 000000000..ea9dd89b3
--- /dev/null
+++ b/app/src/main/java/org/tasks/etesync/CreateUserInfoViewModel.java
@@ -0,0 +1,14 @@
+package org.tasks.etesync;
+
+import org.tasks.data.CaldavAccount;
+import org.tasks.ui.CompletableViewModel;
+
+public class CreateUserInfoViewModel extends CompletableViewModel {
+
+ void createUserInfo(EteSyncClient client, CaldavAccount caldavAccount, String derivedKey) {
+ run(() -> {
+ client.forAccount(caldavAccount).createUserInfo(derivedKey);
+ return derivedKey;
+ });
+ }
+}
diff --git a/app/src/main/java/org/tasks/etesync/EncryptionSettingsActivity.java b/app/src/main/java/org/tasks/etesync/EncryptionSettingsActivity.java
new file mode 100644
index 000000000..620924ff2
--- /dev/null
+++ b/app/src/main/java/org/tasks/etesync/EncryptionSettingsActivity.java
@@ -0,0 +1,224 @@
+package org.tasks.etesync;
+
+import static android.text.TextUtils.isEmpty;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.MenuItem;
+import android.view.View;
+import androidx.appcompat.widget.Toolbar;
+import androidx.appcompat.widget.Toolbar.OnMenuItemClickListener;
+import androidx.core.content.ContextCompat;
+import androidx.lifecycle.ViewModelProviders;
+import at.bitfire.dav4jvm.exception.HttpException;
+import butterknife.ButterKnife;
+import butterknife.OnTextChanged;
+import com.etesync.journalmanager.Constants;
+import com.etesync.journalmanager.Crypto;
+import com.etesync.journalmanager.Crypto.CryptoManager;
+import com.etesync.journalmanager.Exceptions.IntegrityException;
+import com.etesync.journalmanager.Exceptions.VersionTooNewException;
+import com.etesync.journalmanager.GsonHelper;
+import com.etesync.journalmanager.UserInfoManager.UserInfo;
+import com.google.android.material.snackbar.Snackbar;
+import java.net.ConnectException;
+import javax.inject.Inject;
+import org.tasks.R;
+import org.tasks.data.CaldavAccount;
+import org.tasks.databinding.ActivityEtesyncEncryptionSettingsBinding;
+import org.tasks.injection.ActivityComponent;
+import org.tasks.injection.ThemedInjectingAppCompatActivity;
+import org.tasks.security.Encryption;
+import org.tasks.ui.DisplayableException;
+import org.tasks.ui.MenuColorizer;
+import timber.log.Timber;
+
+public class EncryptionSettingsActivity extends ThemedInjectingAppCompatActivity
+ implements OnMenuItemClickListener {
+
+ public static final String EXTRA_USER_INFO = "extra_user_info";
+ public static final String EXTRA_ACCOUNT = "extra_account";
+ public static final String EXTRA_DERIVED_KEY = "extra_derived_key";
+
+ @Inject EteSyncClient client;
+ @Inject Encryption encryption;
+
+ ActivityEtesyncEncryptionSettingsBinding binding;
+ private UserInfo userInfo;
+ private CaldavAccount caldavAccount;
+ CreateUserInfoViewModel createUserInfoViewModel;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ createUserInfoViewModel = ViewModelProviders.of(this).get(CreateUserInfoViewModel.class);
+
+ binding = ActivityEtesyncEncryptionSettingsBinding.inflate(getLayoutInflater());
+ setContentView(binding.getRoot());
+
+ ButterKnife.bind(this);
+
+ Intent intent = getIntent();
+ caldavAccount = intent.getParcelableExtra(EXTRA_ACCOUNT);
+ userInfo = GsonHelper.gson.fromJson(intent.getStringExtra(EXTRA_USER_INFO), UserInfo.class);
+
+ if (userInfo == null) {
+ binding.repeatEncryptionPasswordLayout.setVisibility(View.VISIBLE);
+ }
+
+ Toolbar toolbar = binding.toolbar.toolbar;
+ toolbar.setTitle(
+ caldavAccount == null ? getString(R.string.add_account) : caldavAccount.getName());
+ toolbar.setNavigationIcon(ContextCompat.getDrawable(this, R.drawable.ic_outline_save_24px));
+ toolbar.setNavigationOnClickListener(v -> save());
+ toolbar.inflateMenu(R.menu.menu_etesync_encryption_settings);
+ toolbar.setOnMenuItemClickListener(this);
+ MenuColorizer.colorToolbar(this, toolbar);
+
+ createUserInfoViewModel.observe(this, this::returnDerivedKey, this::requestFailed);
+
+ if (createUserInfoViewModel.inProgress()) {
+ showProgressIndicator();
+ }
+ }
+
+ private void showProgressIndicator() {
+ binding.progressBar.progressBar.setVisibility(View.VISIBLE);
+ }
+
+ private void hideProgressIndicator() {
+ binding.progressBar.progressBar.setVisibility(View.GONE);
+ }
+
+ private boolean requestInProgress() {
+ return binding.progressBar.progressBar.getVisibility() == View.VISIBLE;
+ }
+
+ private void returnDerivedKey(String derivedKey) {
+ hideProgressIndicator();
+
+ Intent result = new Intent();
+ result.putExtra(EXTRA_DERIVED_KEY, derivedKey);
+ setResult(RESULT_OK, result);
+ finish();
+ }
+
+ private void save() {
+ if (requestInProgress()) {
+ return;
+ }
+
+ String encryptionPassword = getNewEncryptionPassword();
+ String derivedKey = caldavAccount.getEncryptionPassword(encryption);
+
+ if (isEmpty(encryptionPassword) && isEmpty(derivedKey)) {
+ binding.encryptionPasswordLayout.setError(getString(R.string.encryption_password_required));
+ return;
+ }
+
+ if (userInfo == null) {
+ String repeatEncryptionPassword = binding.repeatEncryptionPassword.getText().toString().trim();
+ if (!encryptionPassword.equals(repeatEncryptionPassword)) {
+ binding.repeatEncryptionPasswordLayout.setError(getString(R.string.passwords_do_not_match));
+ return;
+ }
+ }
+
+ String key =
+ isEmpty(encryptionPassword)
+ ? derivedKey
+ : Crypto.deriveKey(caldavAccount.getUsername(), encryptionPassword);
+ CryptoManager cryptoManager;
+ try {
+ int version = userInfo == null ? Constants.CURRENT_VERSION : userInfo.getVersion();
+ cryptoManager = new CryptoManager(version, key, "userInfo");
+ } catch (VersionTooNewException | IntegrityException e) {
+ requestFailed(e);
+ return;
+ }
+
+ if (userInfo == null) {
+ showProgressIndicator();
+ createUserInfoViewModel.createUserInfo(client, caldavAccount, key);
+ } else {
+ try {
+ userInfo.verify(cryptoManager);
+ returnDerivedKey(key);
+ } catch (IntegrityException e) {
+ requestFailed(e);
+ }
+ }
+ }
+
+ protected void requestFailed(Throwable t) {
+ hideProgressIndicator();
+
+ if (t instanceof HttpException) {
+ showSnackbar(t.getMessage());
+ } else if (t instanceof DisplayableException) {
+ showSnackbar(((DisplayableException) t).getResId());
+ } else if (t instanceof ConnectException) {
+ showSnackbar(R.string.network_error);
+ } else {
+ Timber.e(t);
+ showSnackbar(R.string.error_adding_account, t.getMessage());
+ }
+ }
+
+ private void showSnackbar(int resId, Object... formatArgs) {
+ showSnackbar(getString(resId, formatArgs));
+ }
+
+ private void showSnackbar(String message) {
+ newSnackbar(message).show();
+ }
+
+ private Snackbar newSnackbar(String message) {
+ Snackbar snackbar =
+ Snackbar.make(binding.rootLayout, message, 8000)
+ .setTextColor(ContextCompat.getColor(this, R.color.snackbar_text_color))
+ .setActionTextColor(ContextCompat.getColor(this, R.color.snackbar_action_color));
+ snackbar
+ .getView()
+ .setBackgroundColor(ContextCompat.getColor(this, R.color.snackbar_background));
+ return snackbar;
+ }
+
+ @OnTextChanged(R.id.repeat_encryption_password)
+ void onRpeatEncryptionPasswordChanged() {
+ binding.repeatEncryptionPasswordLayout.setError(null);
+ }
+
+ @OnTextChanged(R.id.encryption_password)
+ void onEncryptionPasswordChanged() {
+ binding.encryptionPasswordLayout.setError(null);
+ }
+
+ private String getNewEncryptionPassword() {
+ return binding.encryptionPassword.getText().toString().trim();
+ }
+
+ @Override
+ public void finish() {
+ if (!requestInProgress()) {
+ super.finish();
+ }
+ }
+
+ @Override
+ public void inject(ActivityComponent component) {
+ component.inject(this);
+ }
+
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ if (item.getItemId() == R.id.help) {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://tasks.org/etesync")));
+ return true;
+ } else {
+ return onOptionsItemSelected(item);
+ }
+ }
+}
diff --git a/app/src/main/java/org/tasks/etesync/EteSyncAccountSettingsActivity.java b/app/src/main/java/org/tasks/etesync/EteSyncAccountSettingsActivity.java
index df1b03eeb..8fc444d75 100644
--- a/app/src/main/java/org/tasks/etesync/EteSyncAccountSettingsActivity.java
+++ b/app/src/main/java/org/tasks/etesync/EteSyncAccountSettingsActivity.java
@@ -1,29 +1,39 @@
package org.tasks.etesync;
+import static com.todoroo.astrid.data.Task.NO_ID;
+
import android.content.Context;
+import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.core.util.Pair;
import androidx.lifecycle.ViewModelProviders;
-import butterknife.OnFocusChange;
-import butterknife.OnTextChanged;
+import butterknife.OnCheckedChanged;
+import com.etesync.journalmanager.Crypto.CryptoManager;
+import com.etesync.journalmanager.Exceptions.IntegrityException;
+import com.etesync.journalmanager.Exceptions.VersionTooNewException;
+import com.etesync.journalmanager.GsonHelper;
+import com.etesync.journalmanager.UserInfoManager.UserInfo;
+import com.google.common.base.Strings;
import com.todoroo.astrid.helper.UUIDHelper;
import io.reactivex.Completable;
import io.reactivex.schedulers.Schedulers;
import javax.inject.Inject;
import org.tasks.R;
-import org.tasks.analytics.Tracking.Events;
import org.tasks.caldav.BaseCaldavAccountSettingsActivity;
import org.tasks.data.CaldavAccount;
import org.tasks.gtasks.PlayServices;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.ForApplication;
+import timber.log.Timber;
public class EteSyncAccountSettingsActivity extends BaseCaldavAccountSettingsActivity
implements Toolbar.OnMenuItemClickListener {
+ private static final int REQUEST_ENCRYPTION_PASSWORD = 10101;
+
@Inject @ForApplication Context context;
@Inject PlayServices playServices;
@Inject EteSyncClient eteSyncClient;
@@ -36,77 +46,113 @@ public class EteSyncAccountSettingsActivity extends BaseCaldavAccountSettingsAct
super.onCreate(savedInstanceState);
binding.repeat.setVisibility(View.GONE);
- binding.encryptionPasswordLayout.setVisibility(View.VISIBLE);
+ binding.showAdvanced.setVisibility(View.VISIBLE);
+ updateUrlVisibility();
addAccountViewModel = ViewModelProviders.of(this).get(AddEteSyncAccountViewModel.class);
updateAccountViewModel = ViewModelProviders.of(this).get(UpdateEteSyncAccountViewModel.class);
- if (savedInstanceState == null) {
- if (caldavAccount == null) {
- binding.url.setText(R.string.etesync_url);
- }
- }
-
addAccountViewModel.observe(this, this::addAccount, this::requestFailed);
updateAccountViewModel.observe(this, this::updateAccount, this::requestFailed);
}
- private void addAccount(Pair authentication) {
- CaldavAccount newAccount = new CaldavAccount();
- newAccount.setAccountType(CaldavAccount.TYPE_ETESYNC);
- newAccount.setUuid(UUIDHelper.newUUID());
- applyTo(newAccount, authentication);
- newAccount.setId(caldavDao.insert(newAccount));
-
- tracker.reportEvent(Events.CALDAV_ACCOUNT_ADDED);
-
- setResult(RESULT_OK);
- finish();
+ private void addAccount(Pair userInfoAndToken) {
+ caldavAccount = new CaldavAccount();
+ caldavAccount.setAccountType(CaldavAccount.TYPE_ETESYNC);
+ caldavAccount.setUuid(UUIDHelper.newUUID());
+ applyTo(caldavAccount, userInfoAndToken);
}
- private void updateAccount(Pair authentication) {
- applyTo(caldavAccount, authentication);
+ private void updateAccount(Pair userInfoAndToken) {
caldavAccount.setError("");
- caldavDao.update(caldavAccount);
- setResult(RESULT_OK);
- finish();
+ applyTo(caldavAccount, userInfoAndToken);
}
- private void applyTo(CaldavAccount account, @Nullable Pair authentication) {
+ private void applyTo(CaldavAccount account, Pair userInfoAndToken) {
+ hideProgressIndicator();
+
account.setName(getNewName());
account.setUrl(getNewURL());
account.setUsername(getNewUsername());
- if (authentication != null) {
- account.setPassword(encryption.encrypt(authentication.first));
- account.setEncryptionKey(encryption.encrypt(authentication.second));
+ String token = userInfoAndToken.second;
+ if (!token.equals(account.getPassword(encryption))) {
+ account.setPassword(encryption.encrypt(token));
+ }
+
+ UserInfo userInfo = userInfoAndToken.first;
+ if (testUserInfo(userInfo)) {
+ saveAccountAndFinish();
+ } else {
+ Intent intent = new Intent(this, EncryptionSettingsActivity.class);
+ intent.putExtra(EncryptionSettingsActivity.EXTRA_USER_INFO, toJson(userInfo));
+ intent.putExtra(EncryptionSettingsActivity.EXTRA_ACCOUNT, account);
+ startActivityForResult(intent, REQUEST_ENCRYPTION_PASSWORD);
}
}
- @Override
- protected boolean needsValidation() {
- return super.needsValidation() || encryptionPasswordChanged();
+ private boolean testUserInfo(UserInfo userInfo) {
+ String encryptionKey = caldavAccount.getEncryptionPassword(encryption);
+ if (userInfo != null && !Strings.isNullOrEmpty(encryptionKey)) {
+ try {
+ CryptoManager cryptoManager =
+ new CryptoManager(userInfo.getVersion(), encryptionKey, "userInfo");
+ userInfo.verify(cryptoManager);
+ return true;
+ } catch (IntegrityException | VersionTooNewException e) {
+ Timber.e(e);
+ }
+ }
+ return false;
+ }
+
+ private String toJson(UserInfo userInfo) {
+ return GsonHelper.gson.toJson(userInfo);
+ }
+
+ @OnCheckedChanged(R.id.show_advanced)
+ void toggleUrl() {
+ updateUrlVisibility();
+ }
+
+ private void updateUrlVisibility() {
+ binding.urlLayout.setVisibility(binding.showAdvanced.isChecked() ? View.VISIBLE : View.GONE);
}
- protected boolean encryptionPasswordChanged() {
- return caldavAccount == null
- || !PASSWORD_MASK.equals(binding.encryptionPassword.getText().toString().trim());
+ @Override
+ protected boolean needsValidation() {
+ return super.needsValidation() || Strings.isNullOrEmpty(caldavAccount.getEncryptionKey());
}
@Override
protected void addAccount(String url, String username, String password) {
- addAccountViewModel.addAccount(
- playServices, context, eteSyncClient, url, username, password, getNewEncryptionPassword());
+ addAccountViewModel.addAccount(playServices, context, eteSyncClient, url, username, password);
}
@Override
protected void updateAccount(String url, String username, String password) {
updateAccountViewModel.updateAccount(
- eteSyncClient, url, username, password, getNewEncryptionPassword());
+ eteSyncClient,
+ url,
+ username,
+ PASSWORD_MASK.equals(password) ? null : password,
+ caldavAccount.getPassword(encryption));
}
@Override
protected void updateAccount() {
- updateAccount(null);
+ caldavAccount.setName(getNewName());
+ saveAccountAndFinish();
+ }
+
+ @Override
+ protected String getNewURL() {
+ String url = super.getNewURL();
+ return Strings.isNullOrEmpty(url) ? getString(R.string.etesync_url) : url;
+ }
+
+ @Override
+ protected String getNewPassword() {
+ return binding.password.getText().toString().trim();
}
@Override
@@ -119,14 +165,27 @@ public class EteSyncAccountSettingsActivity extends BaseCaldavAccountSettingsAct
component.inject(this);
}
- @OnTextChanged(R.id.encryption_password)
- void onEncryptionPasswordChanged(CharSequence text) {
- binding.encryptionPasswordLayout.setError(null);
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+ if (requestCode == REQUEST_ENCRYPTION_PASSWORD) {
+ if (resultCode == RESULT_OK) {
+ String key = data.getStringExtra(EncryptionSettingsActivity.EXTRA_DERIVED_KEY);
+ caldavAccount.setEncryptionKey(encryption.encrypt(key));
+ saveAccountAndFinish();
+ }
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
}
- @OnFocusChange(R.id.encryption_password)
- void onEncryptionPasswordFocused(boolean hasFocus) {
- changePasswordFocus(binding.encryptionPassword, hasFocus);
+ private void saveAccountAndFinish() {
+ if (caldavAccount.getId() == NO_ID) {
+ caldavDao.insert(caldavAccount);
+ } else {
+ caldavDao.update(caldavAccount);
+ }
+ setResult(RESULT_OK);
+ finish();
}
@Override
diff --git a/app/src/main/java/org/tasks/etesync/EteSyncClient.java b/app/src/main/java/org/tasks/etesync/EteSyncClient.java
index 41731c513..ef6b20829 100644
--- a/app/src/main/java/org/tasks/etesync/EteSyncClient.java
+++ b/app/src/main/java/org/tasks/etesync/EteSyncClient.java
@@ -8,7 +8,7 @@ import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import at.bitfire.cert4android.CustomCertManager;
import at.bitfire.cert4android.CustomCertManager.CustomHostnameVerifier;
-import com.etesync.journalmanager.Crypto;
+import com.etesync.journalmanager.Constants;
import com.etesync.journalmanager.Crypto.CryptoManager;
import com.etesync.journalmanager.Exceptions;
import com.etesync.journalmanager.Exceptions.HttpException;
@@ -151,16 +151,15 @@ public class EteSyncClient {
foreground);
}
- Pair getKeyAndToken(String password)
- throws IOException, Exceptions.HttpException, VersionTooNewException, IntegrityException {
+ Pair getInfoAndToken(String password) throws IOException, HttpException {
JournalAuthenticator journalAuthenticator = new JournalAuthenticator(httpClient, httpUrl);
String token = journalAuthenticator.getAuthToken(username, password);
+ return Pair.create(getUserInfo(), token);
+ }
+
+ UserInfo getUserInfo() throws HttpException {
UserInfoManager userInfoManager = new UserInfoManager(httpClient, httpUrl);
- UserInfo userInfo = userInfoManager.fetch(username);
- String key = Crypto.deriveKey(username, encryptionPassword);
- CryptoManager cryptoManager = new CryptoManager(userInfo.getVersion(), key, "userInfo");
- userInfo.verify(cryptoManager);
- return Pair.create(token, key);
+ return userInfoManager.fetch(username);
}
CryptoManager getCrypto(Journal journal) throws VersionTooNewException, IntegrityException {
@@ -185,8 +184,13 @@ public class EteSyncClient {
Map result = new HashMap<>();
for (Journal journal : journalManager.list()) {
CollectionInfo collection = convertJournalToCollection(journal);
- if (collection != null && TYPE_TASKS.equals(collection.getType())) {
- result.put(journal, collection);
+ if (collection != null) {
+ if (TYPE_TASKS.equals(collection.getType())) {
+ Timber.v("Found %s", collection);
+ result.put(journal, collection);
+ } else {
+ Timber.v("Ignoring %s", collection);
+ }
}
}
return result;
@@ -222,7 +226,7 @@ public class EteSyncClient {
void invalidateToken() {
try {
- new JournalAuthenticator(httpClient, httpUrl).invalidateAuthToken(token);
+ new JournalAuthenticator(httpClient, httpUrl).invalidateAuthToken(token);
} catch (Exception e) {
Timber.e(e);
}
@@ -244,4 +248,12 @@ public class EteSyncClient {
void deleteCollection(CaldavCalendar calendar) throws HttpException {
journalManager.delete(Journal.fakeWithUid(calendar.getUrl()));
}
+
+ void createUserInfo(String derivedKey)
+ throws HttpException, VersionTooNewException, IntegrityException, IOException {
+ CryptoManager cryptoManager =
+ new CryptoManager(Constants.CURRENT_VERSION, derivedKey, "userInfo");
+ UserInfo userInfo = UserInfo.generate(cryptoManager, username);
+ new UserInfoManager(httpClient, httpUrl).create(userInfo);
+ }
}
diff --git a/app/src/main/java/org/tasks/etesync/UpdateEteSyncAccountViewModel.java b/app/src/main/java/org/tasks/etesync/UpdateEteSyncAccountViewModel.java
index e7a9dee8d..ef0fb6168 100644
--- a/app/src/main/java/org/tasks/etesync/UpdateEteSyncAccountViewModel.java
+++ b/app/src/main/java/org/tasks/etesync/UpdateEteSyncAccountViewModel.java
@@ -1,21 +1,25 @@
package org.tasks.etesync;
+import androidx.annotation.Nullable;
import androidx.core.util.Pair;
+import com.etesync.journalmanager.UserInfoManager.UserInfo;
+import com.google.common.base.Strings;
import org.tasks.ui.CompletableViewModel;
@SuppressWarnings("WeakerAccess")
-public class UpdateEteSyncAccountViewModel extends CompletableViewModel> {
+public class UpdateEteSyncAccountViewModel extends CompletableViewModel> {
void updateAccount(
EteSyncClient client,
String url,
String username,
- String password,
- String encryptionPassword) {
+ @Nullable String password,
+ @Nullable String token) {
run(
- () ->
- client
- .setForeground()
- .forUrl(url, username, encryptionPassword, null)
- .getKeyAndToken(password));
+ () -> {
+ EteSyncClient newClient = client.setForeground().forUrl(url, username, null, token);
+ return Strings.isNullOrEmpty(password)
+ ? Pair.create(newClient.getUserInfo(), token)
+ : newClient.getInfoAndToken(password);
+ });
}
}
diff --git a/app/src/main/java/org/tasks/injection/ActivityComponent.java b/app/src/main/java/org/tasks/injection/ActivityComponent.java
index e080218d3..2ac04ef84 100644
--- a/app/src/main/java/org/tasks/injection/ActivityComponent.java
+++ b/app/src/main/java/org/tasks/injection/ActivityComponent.java
@@ -19,6 +19,7 @@ import org.tasks.activities.DatePickerActivity;
import org.tasks.activities.FilterSelectionActivity;
import org.tasks.activities.FilterSettingsActivity;
import org.tasks.activities.GoogleTaskListSettingsActivity;
+import org.tasks.etesync.EncryptionSettingsActivity;
import org.tasks.etesync.EteSyncAccountSettingsActivity;
import org.tasks.etesync.EteSyncCalendarSettingsActivity;
import org.tasks.tags.TagPickerActivity;
@@ -152,4 +153,6 @@ public interface ActivityComponent {
void inject(TagPickerViewModel viewModel);
void inject(EteSyncCalendarSettingsActivity eteSyncCalendarSettingsActivity);
+
+ void inject(EncryptionSettingsActivity encryptionSettingsActivity);
}
diff --git a/app/src/main/res/layout/activity_caldav_account_settings.xml b/app/src/main/res/layout/activity_caldav_account_settings.xml
index d7687d823..d1ee7947f 100644
--- a/app/src/main/res/layout/activity_caldav_account_settings.xml
+++ b/app/src/main/res/layout/activity_caldav_account_settings.xml
@@ -29,6 +29,7 @@
@@ -47,19 +48,6 @@
-
-
-
-
-
-
@@ -76,7 +64,7 @@
+ app:endIconMode="password_toggle">
-
+ android:text="@string/show_advanced_settings"
+ android:visibility="gone" />
+
+
+ android:hint="@string/url"
+ android:imeOptions="flagNoExtractUi" />
diff --git a/app/src/main/res/layout/activity_etesync_encryption_settings.xml b/app/src/main/res/layout/activity_etesync_encryption_settings.xml
new file mode 100644
index 000000000..b11ce40c2
--- /dev/null
+++ b/app/src/main/res/layout/activity_etesync_encryption_settings.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_etesync_encryption_settings.xml b/app/src/main/res/menu/menu_etesync_encryption_settings.xml
new file mode 100644
index 000000000..4c186a162
--- /dev/null
+++ b/app/src/main/res/menu/menu_etesync_encryption_settings.xml
@@ -0,0 +1,11 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 05dbff7a2..b6dbf3ad3 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -379,6 +379,7 @@ File %1$s contained %2$s.\n\n
Username required
Password required
Encryption password required
+ Passwords do not match
URL required
Host name required
Must begin with http(s)://
@@ -448,6 +449,7 @@ File %1$s contained %2$s.\n\n
User
Password
Encryption password
+ Confirm encryption password
URL
Error: %s
Calendar settings
@@ -571,4 +573,5 @@ File %1$s contained %2$s.\n\n
Basic service that synchronizes with your Google account
Synchronization based on open internet standards
Open source, end-to-end encrypted synchronization
+ Show advanced settings