From 992977d27ea24786d4262d7230b6c534b88d315c Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Jun 2024 14:37:44 +0200 Subject: [PATCH 1/9] Convert to M3 Signed-off-by: alperozturk --- .../ui/fragment/OCFileListFragment.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 6746c152352a..cab8ac45bd8e 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -37,6 +37,7 @@ import com.google.android.material.behavior.HideBottomViewOnScrollBehavior; import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; import com.nextcloud.android.lib.resources.files.ToggleFileLockRemoteOperation; @@ -539,15 +540,16 @@ public void directCameraUpload() { } private void showDirectCameraUploadAlertDialog(FileDisplayActivity fileDisplayActivity) { - AlertDialog.Builder builder = new AlertDialog.Builder(fileDisplayActivity); - AlertDialog dialog = builder.setIcon(R.mipmap.ic_launcher) + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(fileDisplayActivity) .setTitle(R.string.upload_direct_camera_promt) - .setNegativeButton(R.string.upload_direct_camera_video, (iface, id) -> - fileDisplayActivity.getFileOperationsHelper().uploadFromCamera(fileDisplayActivity,FileDisplayActivity.REQUEST_CODE__UPLOAD_FROM_VIDEO_CAMERA, true)) - .setPositiveButton(R.string.upload_direct_camera_photo, (iface, id) -> - fileDisplayActivity.getFileOperationsHelper().uploadFromCamera(fileDisplayActivity, FileDisplayActivity.REQUEST_CODE__UPLOAD_FROM_CAMERA, false)) - .create(); - dialog.show(); + .setIcon(R.mipmap.ic_launcher) + .setPositiveButton(R.string.upload_direct_camera_video, (dialog, which) -> fileDisplayActivity.getFileOperationsHelper().uploadFromCamera(fileDisplayActivity, FileDisplayActivity.REQUEST_CODE__UPLOAD_FROM_VIDEO_CAMERA, true)) + .setNegativeButton(R.string.upload_direct_camera_photo, (dialog, which) -> fileDisplayActivity.getFileOperationsHelper().uploadFromCamera(fileDisplayActivity, FileDisplayActivity.REQUEST_CODE__UPLOAD_FROM_CAMERA, false)); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(fileDisplayActivity, builder); + + builder.create(); + builder.show(); } @Override From 28eac70a07768e52cad192317d728a40e5a5c7ba Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Jun 2024 14:37:58 +0200 Subject: [PATCH 2/9] Optimize imports Signed-off-by: alperozturk --- .../com/owncloud/android/ui/fragment/OCFileListFragment.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index cab8ac45bd8e..3043c8b91488 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -135,7 +135,6 @@ import androidx.annotation.OptIn; import androidx.annotation.StringRes; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AlertDialog; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.core.content.ContextCompat; import androidx.drawerlayout.widget.DrawerLayout; From 3429e43b846776d04a49ac35822a50b2269e3de8 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Jun 2024 14:57:59 +0200 Subject: [PATCH 3/9] Use M3 alert dialog Signed-off-by: alperozturk --- .../java/com/owncloud/android/MainApp.java | 29 +++--- .../ui/activity/FileDisplayActivity.java | 35 +++---- .../ReceiveExternalFilesActivity.java | 4 +- .../android/ui/activity/SettingsActivity.java | 5 +- .../android/ui/activity/StorageMigration.java | 94 ++++++++----------- .../ui/activity/SyncedFoldersActivity.kt | 5 +- .../sufficientlysecure/SaveCalendar.java | 37 +++----- 7 files changed, 91 insertions(+), 118 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/MainApp.java b/app/src/main/java/com/owncloud/android/MainApp.java index 2f2b17e9d044..f10307ef257c 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.java +++ b/app/src/main/java/com/owncloud/android/MainApp.java @@ -38,6 +38,7 @@ import android.text.TextUtils; import android.view.WindowManager; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.appReview.InAppReviewHelper; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; @@ -109,7 +110,6 @@ import androidx.annotation.NonNull; import androidx.annotation.StringRes; -import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatDelegate; import androidx.core.util.Pair; import androidx.lifecycle.Lifecycle; @@ -806,24 +806,27 @@ private static void updateToAutoUpload() { // show info pop-up try { - new AlertDialog.Builder(context, R.style.Theme_ownCloud_Dialog) - .setTitle(R.string.drawer_synced_folders) - .setMessage(R.string.synced_folders_new_info) - .setPositiveButton(R.string.drawer_open, (dialog, which) -> { - // show Auto Upload - Intent folderSyncIntent = new Intent(context, SyncedFoldersActivity.class); - dialog.dismiss(); - context.startActivity(folderSyncIntent); - }) - .setNegativeButton(R.string.drawer_close, (dialog, which) -> dialog.dismiss()) - .setIcon(R.drawable.nav_synced_folders) - .show(); + showAutoUploadAlertDialog(); } catch (WindowManager.BadTokenException e) { Log_OC.i(TAG, "Error showing Auto Upload Update dialog, so skipping it: " + e.getMessage()); } } } + private static void showAutoUploadAlertDialog() { + new MaterialAlertDialogBuilder(appContext.get()) + .setTitle(R.string.drawer_synced_folders) + .setMessage(R.string.synced_folders_new_info) + .setPositiveButton(R.string.drawer_open, (dialog, which) -> { + Intent folderSyncIntent = new Intent(appContext.get(), SyncedFoldersActivity.class); + dialog.dismiss(); + appContext.get().startActivity(folderSyncIntent); + }) + .setNegativeButton(R.string.drawer_close, (dialog, which) -> dialog.dismiss()) + .setIcon(R.drawable.nav_synced_folders) + .show(); + } + private static void updateAutoUploadEntries(Clock clock) { // updates entries to reflect their true paths Context context = getAppContext(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 1b8c280c2606..6e102ac70f78 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -45,6 +45,7 @@ import android.view.WindowManager; import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.snackbar.Snackbar; import com.nextcloud.appReview.InAppReviewHelper; import com.nextcloud.client.account.User; @@ -328,10 +329,18 @@ private void checkStoragePath() { MainApp.setStoragePath(newStorage); try { - AlertDialog alertDialog = new AlertDialog.Builder(this, R.style.Theme_ownCloud_Dialog).setTitle(R.string.wrong_storage_path).setMessage(R.string.wrong_storage_path_desc).setPositiveButton(R.string.dialog_close, (dialog, which) -> dialog.dismiss()).setIcon(R.drawable.ic_settings).create(); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.Theme_ownCloud_Dialog) + .setTitle(R.string.wrong_storage_path) + .setMessage(R.string.wrong_storage_path_desc) + .setPositiveButton(R.string.dialog_close, (dialog, which) -> dialog.dismiss()) + .setIcon(R.drawable.ic_settings); - alertDialog.show(); - viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)); + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(getApplicationContext(), builder); + + AlertDialog dialog = builder.create(); + builder.show(); + + viewThemeUtils.platform.colorTextButtons(dialog.getButton(AlertDialog.BUTTON_POSITIVE)); } catch (WindowManager.BadTokenException e) { Log_OC.e(TAG, "Error showing wrong storage info, so skipping it: " + e.getMessage()); } @@ -405,18 +414,12 @@ private void upgradeNotificationForInstantUpload() { if (preferences.instantPictureUploadEnabled() || preferences.instantVideoUploadEnabled()) { preferences.removeLegacyPreferences(); // show info pop-up - new AlertDialog.Builder(this, R.style.Theme_ownCloud_Dialog).setTitle(R.string.drawer_synced_folders).setMessage(R.string.synced_folders_new_info).setPositiveButton(R.string.drawer_open, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - // show instant upload - Intent syncedFoldersIntent = new Intent(getApplicationContext(), SyncedFoldersActivity.class); - dialog.dismiss(); - startActivity(syncedFoldersIntent); - } - }).setNegativeButton(R.string.drawer_close, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }).setIcon(R.drawable.nav_synced_folders).show(); + new MaterialAlertDialogBuilder(this, R.style.Theme_ownCloud_Dialog).setTitle(R.string.drawer_synced_folders).setMessage(R.string.synced_folders_new_info).setPositiveButton(R.string.drawer_open, (dialog, which) -> { + // show instant upload + Intent syncedFoldersIntent = new Intent(getApplicationContext(), SyncedFoldersActivity.class); + dialog.dismiss(); + startActivity(syncedFoldersIntent); + }).setNegativeButton(R.string.drawer_close, (dialog, which) -> dialog.dismiss()).setIcon(R.drawable.nav_synced_folders).show(); } } @@ -2400,7 +2403,7 @@ private void selectUserAndOpenFile(List users, String fileId) { for (int i = 0; i < userNames.length; i++) { userNames[i] = users.get(i).getAccountName(); } - final AlertDialog.Builder builder = new AlertDialog.Builder(this); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this); builder.setTitle(R.string.common_choose_account).setItems(userNames, (dialog, which) -> { User user = users.get(which); openFile(user, fileId); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java index 4d69dcf4ae30..2699119f853d 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java @@ -46,6 +46,7 @@ import android.widget.Toast; import com.google.android.material.button.MaterialButton; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.account.User; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.jobs.upload.FileUploadHelper; @@ -104,7 +105,6 @@ import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog.Builder; import androidx.appcompat.widget.SearchView; import androidx.core.view.MenuItemCompat; @@ -311,7 +311,7 @@ public static class DialogNoAccount extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder builder = new Builder(getActivity()); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity()); builder.setIcon(R.drawable.ic_warning); builder.setTitle(R.string.uploader_wrn_no_account_title); builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index 5e68f2900edc..e05ebaf08b34 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -38,6 +38,7 @@ import android.view.ViewGroup; import android.webkit.URLUtil; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; @@ -493,7 +494,7 @@ private void removeE2E(PreferenceCategory preferenceCategoryMore) { preferenceCategoryMore.removePreference(preference); } else { preference.setOnPreferenceClickListener(p -> { - AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.FallbackTheming_Dialog); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.FallbackTheming_Dialog); AlertDialog alertDialog = builder.setTitle(R.string.prefs_e2e_mnemonic) .setMessage(getString(R.string.remove_e2e_message)) .setCancelable(true) @@ -980,7 +981,7 @@ public void handleMnemonicRequest(Intent data) { ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(this); String mnemonic = arbitraryDataProvider.getValue(user.getAccountName(), EncryptionUtils.MNEMONIC).trim(); - AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.FallbackTheming_Dialog); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.FallbackTheming_Dialog); AlertDialog alertDialog = builder.setTitle(R.string.prefs_e2e_mnemonic) .setMessage(mnemonic) .setNegativeButton(R.string.common_cancel, (dialog, i) -> dialog.dismiss()) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java b/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java index 995894029137..3f46e0748dda 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java @@ -19,6 +19,7 @@ import android.os.AsyncTask; import android.view.View; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.account.User; import com.owncloud.android.MainApp; import com.owncloud.android.R; @@ -84,58 +85,45 @@ private boolean storageFolderAlreadyExists() { } private void askToOverride() { - - new AlertDialog.Builder(mContext) + new MaterialAlertDialogBuilder(mContext) .setMessage(R.string.file_migration_directory_already_exists) .setCancelable(true) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialogInterface) { - if (mListener != null) { - mListener.onCancelMigration(); - } + .setOnCancelListener(dialogInterface -> { + if (mListener != null) { + mListener.onCancelMigration(); } }) - .setNegativeButton(R.string.common_cancel, new OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (mListener != null) { - mListener.onCancelMigration(); - } + .setNegativeButton(R.string.common_cancel, (dialogInterface, i) -> { + if (mListener != null) { + mListener.onCancelMigration(); } }) - .setNeutralButton(R.string.file_migration_use_data_folder, new OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - ProgressDialog progressDialog = createMigrationProgressDialog(); - progressDialog.show(); - new StoragePathSwitchTask( - mContext, - user, - mSourceStoragePath, - mTargetStoragePath, - progressDialog, - mListener).execute(); - - progressDialog.getButton(ProgressDialog.BUTTON_POSITIVE).setVisibility(View.GONE); + .setNeutralButton(R.string.file_migration_use_data_folder, (dialogInterface, i) -> { + ProgressDialog progressDialog = createMigrationProgressDialog(); + progressDialog.show(); + new StoragePathSwitchTask( + mContext, + user, + mSourceStoragePath, + mTargetStoragePath, + progressDialog, + mListener).execute(); + + progressDialog.getButton(ProgressDialog.BUTTON_POSITIVE).setVisibility(View.GONE); - } }) - .setPositiveButton(R.string.file_migration_override_data_folder, new OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - ProgressDialog progressDialog = createMigrationProgressDialog(); - progressDialog.show(); - new FileMigrationTask( - mContext, - user, - mSourceStoragePath, - mTargetStoragePath, - progressDialog, - mListener).execute(); - - progressDialog.getButton(ProgressDialog.BUTTON_POSITIVE).setVisibility(View.GONE); - } + .setPositiveButton(R.string.file_migration_override_data_folder, (dialogInterface, i) -> { + ProgressDialog progressDialog = createMigrationProgressDialog(); + progressDialog.show(); + new FileMigrationTask( + mContext, + user, + mSourceStoragePath, + mTargetStoragePath, + progressDialog, + mListener).execute(); + + progressDialog.getButton(ProgressDialog.BUTTON_POSITIVE).setVisibility(View.GONE); }) .create() .show(); @@ -223,21 +211,13 @@ protected void onPostExecute(Integer code) { } private void askToStillMove() { - new AlertDialog.Builder(mContext) + new MaterialAlertDialogBuilder(mContext) .setTitle(R.string.file_migration_source_not_readable_title) .setMessage(mContext.getString(R.string.file_migration_source_not_readable, mStorageTarget)) - .setNegativeButton(R.string.common_no, new OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.dismiss(); - } - }) - .setPositiveButton(R.string.common_yes, new OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (mListener != null) { - mListener.onStorageMigrationFinished(mStorageTarget, true); - } + .setNegativeButton(R.string.common_no, (dialogInterface, i) -> dialogInterface.dismiss()) + .setPositiveButton(R.string.common_yes, (dialogInterface, i) -> { + if (mListener != null) { + mListener.onStorageMigrationFinished(mStorageTarget, true); } }) .create() diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt index 53758c329d38..4e873fa3c656 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt @@ -24,6 +24,7 @@ import androidx.appcompat.app.AlertDialog import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.Lifecycle import androidx.recyclerview.widget.GridLayoutManager +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.nextcloud.client.core.Clock import com.nextcloud.client.device.PowerManagementService import com.nextcloud.client.di.Injectable @@ -221,7 +222,7 @@ class SyncedFoldersActivity : } private fun showPowerCheckDialog() { - val alertDialog = AlertDialog.Builder(this) + val alertDialog = MaterialAlertDialogBuilder(this) .setView(R.id.root_layout) .setPositiveButton(R.string.common_ok) { dialog, _ -> dialog.dismiss() } .setTitle(R.string.autoupload_disable_power_save_check) @@ -819,7 +820,7 @@ class SyncedFoldersActivity : private fun showBatteryOptimizationInfo() { if (powerManagementService.isPowerSavingExclusionAvailable || checkIfBatteryOptimizationEnabled()) { - val alertDialogBuilder = AlertDialog.Builder(this, R.style.Theme_ownCloud_Dialog) + val alertDialogBuilder = MaterialAlertDialogBuilder(this, R.style.Theme_ownCloud_Dialog) .setTitle(getString(R.string.battery_optimization_title)) .setMessage(getString(R.string.battery_optimization_message)) .setPositiveButton(getString(R.string.battery_optimization_disable)) { _, _ -> diff --git a/app/src/main/java/third_parties/sufficientlysecure/SaveCalendar.java b/app/src/main/java/third_parties/sufficientlysecure/SaveCalendar.java index 60f9d7a5f63c..660065793b10 100644 --- a/app/src/main/java/third_parties/sufficientlysecure/SaveCalendar.java +++ b/app/src/main/java/third_parties/sufficientlysecure/SaveCalendar.java @@ -9,7 +9,6 @@ package third_parties.sufficientlysecure; import android.annotation.SuppressLint; -import android.app.AlertDialog; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; @@ -30,6 +29,7 @@ import android.view.WindowManager; import android.widget.EditText; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.nextcloud.client.account.User; import com.nextcloud.client.files.Request; import com.nextcloud.client.files.UploadRequest; @@ -89,6 +89,8 @@ import java.util.Set; import java.util.UUID; +import androidx.appcompat.app.AlertDialog; + @SuppressLint("NewApi") public class SaveCalendar { private static final String TAG = "ICS_SaveCalendar"; @@ -270,40 +272,23 @@ private void getFileImpl(final String previousFile, final String suggestedFile, final int ok = android.R.string.ok; final int cancel = android.R.string.cancel; final int suggest = R.string.suggest; - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - AlertDialog dlg = builder.setIcon(R.mipmap.ic_launcher) + AlertDialog dlg = new MaterialAlertDialogBuilder(activity).setIcon(R.mipmap.ic_launcher) .setTitle(R.string.enter_destination_filename) .setView(input) - .setPositiveButton(ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface iface, int id) { - result[0] = input.getText().toString(); - } - }) - .setNeutralButton(suggest, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface iface, int id) { - } - }) - .setNegativeButton(cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface iface, int id) { - result[0] = ""; - } - }) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface iface) { - result[0] = ""; - } + .setPositiveButton(ok, (iface, id) -> result[0] = input.getText().toString()) + .setNeutralButton(suggest, (iface, id) -> { }) + .setNegativeButton(cancel, (iface, id) -> result[0] = "") + .setOnCancelListener(iface -> result[0] = "") .create(); int state = WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE; dlg.getWindow().setSoftInputMode(state); dlg.show(); // Overriding 'Suggest' here prevents it from closing the dialog dlg.getButton(DialogInterface.BUTTON_NEUTRAL) - .setOnClickListener(new View.OnClickListener() { - public void onClick(View onClick) { - input.setText(suggestedFile); - input.setSelection(input.getText().length()); - } + .setOnClickListener(onClick -> { + input.setText(suggestedFile); + input.setSelection(input.getText().length()); }); } From 6bc5c4e945cc6bfd73fdfc13745d3eb9ad561588 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Jun 2024 15:16:27 +0200 Subject: [PATCH 4/9] Use view theme utils Signed-off-by: alperozturk --- .../ui/activity/FileDisplayActivity.java | 3 + .../ReceiveExternalFilesActivity.java | 17 ++++-- .../android/ui/activity/SettingsActivity.java | 2 +- .../android/ui/activity/StorageMigration.java | 58 ++++++++++++------- .../ui/activity/SyncedFoldersActivity.kt | 7 ++- 5 files changed, 58 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index 6e102ac70f78..ddd42a811e9b 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -2409,6 +2409,9 @@ private void selectUserAndOpenFile(List users, String fileId) { openFile(user, fileId); showLoadingDialog(getString(R.string.retrieving_file)); }); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(getApplicationContext(), builder); + final AlertDialog dialog = builder.create(); dismissLoadingDialog(); dialog.show(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java index 2699119f853d..89dca49cc721 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java @@ -135,6 +135,8 @@ public class ReceiveExternalFilesActivity extends FileActivity @Inject AppPreferences preferences; @Inject LocalBroadcastManager localBroadcastManager; @Inject SyncedFolderProvider syncedFolderProvider; + @Inject ViewThemeUtils viewThemeUtils; + private AccountManager mAccountManager; private Stack mParents = new Stack<>(); private List mStreamsToUpload; @@ -205,7 +207,7 @@ protected void setAccount(Account account, boolean savedAccount) { Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAccountType(this)); if (accounts.length == 0) { Log_OC.i(TAG, "No ownCloud account is available"); - DialogNoAccount dialog = new DialogNoAccount(); + DialogNoAccount dialog = new DialogNoAccount(viewThemeUtils); dialog.show(getSupportFragmentManager(), null); } @@ -308,10 +310,16 @@ public void selectFile(OCFile file) { } public static class DialogNoAccount extends DialogFragment { + private final ViewThemeUtils viewThemeUtils; + + public DialogNoAccount(ViewThemeUtils viewThemeUtils) { + this.viewThemeUtils = viewThemeUtils; + } + @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity()); + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext()); builder.setIcon(R.drawable.ic_warning); builder.setTitle(R.string.uploader_wrn_no_account_title); builder.setMessage(String.format(getString(R.string.uploader_wrn_no_account_text), @@ -328,7 +336,8 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { startActivityForResult(intent, REQUEST_CODE__SETUP_ACCOUNT); }); builder.setNeutralButton(R.string.uploader_wrn_no_account_quit_btn_text, - (dialog, which) -> getActivity().finish()); + (dialog, which) -> requireActivity().finish()); + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireContext(), builder); return builder.create(); } } @@ -681,7 +690,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAuthTokenType()); if (accounts.length == 0) { - DialogNoAccount dialog = new DialogNoAccount(); + DialogNoAccount dialog = new DialogNoAccount(viewThemeUtils); dialog.show(getSupportFragmentManager(), null); } else { // there is no need for checking for is there more then one diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index e05ebaf08b34..79cd47b0ea96 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -792,7 +792,7 @@ private void setupGeneralCategory() { if (storagePath.equals(newPath)) { return true; } - StorageMigration storageMigration = new StorageMigration(this, user, storagePath, newPath); + StorageMigration storageMigration = new StorageMigration(this, user, storagePath, newPath, viewThemeUtils); storageMigration.setStorageMigrationProgressListener(this); storageMigration.migrate(); diff --git a/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java b/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java index 3f46e0748dda..452c98224da2 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/StorageMigration.java @@ -26,6 +26,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.utils.FileStorageUtils; +import com.owncloud.android.utils.theme.ViewThemeUtils; import java.io.File; @@ -38,10 +39,11 @@ public class StorageMigration { private static final String TAG = StorageMigration.class.getName(); - private Context mContext; - private User user; - private String mSourceStoragePath; - private String mTargetStoragePath; + private final Context mContext; + private final User user; + private final String mSourceStoragePath; + private final String mTargetStoragePath; + private final ViewThemeUtils viewThemeUtils; private StorageMigrationProgressListener mListener; @@ -50,11 +52,12 @@ public interface StorageMigrationProgressListener { void onCancelMigration(); } - public StorageMigration(Context context, User user, String sourcePath, String targetPath) { + public StorageMigration(Context context, User user, String sourcePath, String targetPath, ViewThemeUtils viewThemeUtils) { mContext = context; this.user = user; mSourceStoragePath = sourcePath; mTargetStoragePath = targetPath; + this.viewThemeUtils = viewThemeUtils; } public void setStorageMigrationProgressListener(StorageMigrationProgressListener listener) { @@ -73,7 +76,8 @@ public void migrate() { mSourceStoragePath, mTargetStoragePath, progressDialog, - mListener).execute(); + mListener, + viewThemeUtils).execute(); progressDialog.getButton(ProgressDialog.BUTTON_POSITIVE).setVisibility(View.GONE); } @@ -85,7 +89,7 @@ private boolean storageFolderAlreadyExists() { } private void askToOverride() { - new MaterialAlertDialogBuilder(mContext) + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(mContext) .setMessage(R.string.file_migration_directory_already_exists) .setCancelable(true) .setOnCancelListener(dialogInterface -> { @@ -107,7 +111,8 @@ private void askToOverride() { mSourceStoragePath, mTargetStoragePath, progressDialog, - mListener).execute(); + mListener, + viewThemeUtils).execute(); progressDialog.getButton(ProgressDialog.BUTTON_POSITIVE).setVisibility(View.GONE); @@ -121,12 +126,15 @@ private void askToOverride() { mSourceStoragePath, mTargetStoragePath, progressDialog, - mListener).execute(); + mListener, + viewThemeUtils).execute(); progressDialog.getButton(ProgressDialog.BUTTON_POSITIVE).setVisibility(View.GONE); - }) - .create() - .show(); + }); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(mContext, builder); + builder.create(); + builder.show(); } private ProgressDialog createMigrationProgressDialog() { @@ -156,20 +164,22 @@ private static abstract class FileMigrationTaskBase extends AsyncTask dialogInterface.dismiss()) @@ -219,9 +229,11 @@ private void askToStillMove() { if (mListener != null) { mListener.onStorageMigrationFinished(mStorageTarget, true); } - }) - .create() - .show(); + }); + + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(mContext, builder); + builder.create(); + builder.show(); } protected boolean[] saveAccountsSyncStatus() { @@ -272,8 +284,9 @@ public StoragePathSwitchTask(Context context, String source, String target, ProgressDialog progressDialog, - StorageMigrationProgressListener listener) { - super(context, user, source, target, progressDialog, listener); + StorageMigrationProgressListener listener, + ViewThemeUtils viewThemeUtils) { + super(context, user, source, target, progressDialog, listener, viewThemeUtils); } @Override @@ -320,8 +333,9 @@ public FileMigrationTask(Context context, String source, String target, ProgressDialog progressDialog, - StorageMigrationProgressListener listener) { - super(context, user, source, target, progressDialog, listener); + StorageMigrationProgressListener listener, + ViewThemeUtils viewThemeUtils) { + super(context, user, source, target, progressDialog, listener, viewThemeUtils); } @Override diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt index 4e873fa3c656..08a80bd7dd1d 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/activity/SyncedFoldersActivity.kt @@ -222,13 +222,16 @@ class SyncedFoldersActivity : } private fun showPowerCheckDialog() { - val alertDialog = MaterialAlertDialogBuilder(this) + val builder = MaterialAlertDialogBuilder(this) .setView(R.id.root_layout) .setPositiveButton(R.string.common_ok) { dialog, _ -> dialog.dismiss() } .setTitle(R.string.autoupload_disable_power_save_check) .setMessage(getString(R.string.power_save_check_dialog_message)) - .show() + viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this, builder) + + val alertDialog = builder.create() + builder.show() viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)) } From 7a177b79c26b352ddc5bc52ca8acca3ce1c83dd7 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Jun 2024 15:59:15 +0200 Subject: [PATCH 5/9] Fixes Signed-off-by: alperozturk --- .../java/com/owncloud/android/MainApp.java | 42 +++++++++++-------- .../files/BootupBroadcastReceiver.java | 3 +- .../ui/activity/FileDisplayActivity.java | 6 +-- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/MainApp.java b/app/src/main/java/com/owncloud/android/MainApp.java index f10307ef257c..2881b6465b7c 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.java +++ b/app/src/main/java/com/owncloud/android/MainApp.java @@ -353,8 +353,8 @@ public void onCreate() { } catch (Exception e) { Log_OC.d("Debug", "Failed to disable uri exposure"); } - - initSyncOperations(preferences, + initSyncOperations(this, + preferences, uploadsStorageManager, accountManager, connectivityService, @@ -367,10 +367,11 @@ public void onCreate() { initContactsBackup(accountManager, backgroundJobManager); notificationChannels(); - backgroundJobManager.scheduleMediaFoldersDetectionJob(); - backgroundJobManager.startMediaFoldersDetectionJob(); - - backgroundJobManager.schedulePeriodicHealthStatus(); + if (backgroundJobManager != null) { + backgroundJobManager.scheduleMediaFoldersDetectionJob(); + backgroundJobManager.startMediaFoldersDetectionJob(); + backgroundJobManager.schedulePeriodicHealthStatus(); + } registerGlobalPassCodeProtection(); } @@ -492,11 +493,14 @@ private void initSecurityKeyManager() { public static void initContactsBackup(UserAccountManager accountManager, BackgroundJobManager backgroundJobManager) { ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(appContext.get()); + if (accountManager == null) { + return; + } + List users = accountManager.getAllUsers(); for (User user : users) { - if (arbitraryDataProvider.getBooleanValue(user, PREFERENCE_CONTACTS_AUTOMATIC_BACKUP)) { + if (backgroundJobManager != null && arbitraryDataProvider.getBooleanValue(user, PREFERENCE_CONTACTS_AUTOMATIC_BACKUP)) { backgroundJobManager.schedulePeriodicContactsBackup(user); - } } } @@ -582,6 +586,7 @@ private void enableStrictMode() { } public static void initSyncOperations( + final Context context, final AppPreferences preferences, final UploadsStorageManager uploadsStorageManager, final UserAccountManager accountManager, @@ -592,7 +597,7 @@ public static void initSyncOperations( final ViewThemeUtils viewThemeUtils, final WalledCheckCache walledCheckCache, final SyncedFolderProvider syncedFolderProvider) { - updateToAutoUpload(); + updateToAutoUpload(context); cleanOldEntries(clock); updateAutoUploadEntries(clock); @@ -798,33 +803,34 @@ private static String getUserAgent(@StringRes int agent) { return String.format(appString, version, brandedName); } - private static void updateToAutoUpload() { - Context context = getAppContext(); + private static void updateToAutoUpload(Context context) { AppPreferences preferences = AppPreferencesImpl.fromContext(context); if (preferences.instantPictureUploadEnabled() || preferences.instantVideoUploadEnabled()) { preferences.removeLegacyPreferences(); // show info pop-up try { - showAutoUploadAlertDialog(); + showAutoUploadAlertDialog(context); } catch (WindowManager.BadTokenException e) { Log_OC.i(TAG, "Error showing Auto Upload Update dialog, so skipping it: " + e.getMessage()); } } } - private static void showAutoUploadAlertDialog() { - new MaterialAlertDialogBuilder(appContext.get()) + private static void showAutoUploadAlertDialog(Context context) { + final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(context, R.style.Theme_ownCloud_Dialog) .setTitle(R.string.drawer_synced_folders) .setMessage(R.string.synced_folders_new_info) .setPositiveButton(R.string.drawer_open, (dialog, which) -> { - Intent folderSyncIntent = new Intent(appContext.get(), SyncedFoldersActivity.class); + Intent folderSyncIntent = new Intent(context, SyncedFoldersActivity.class); dialog.dismiss(); - appContext.get().startActivity(folderSyncIntent); + context.startActivity(folderSyncIntent); }) .setNegativeButton(R.string.drawer_close, (dialog, which) -> dialog.dismiss()) - .setIcon(R.drawable.nav_synced_folders) - .show(); + .setIcon(R.drawable.nav_synced_folders); + + builder.create(); + builder.show(); } private static void updateAutoUploadEntries(Clock clock) { diff --git a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java index 381b32053cfa..0e367ca7665e 100644 --- a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java +++ b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java @@ -62,7 +62,8 @@ public void onReceive(Context context, Intent intent) { AndroidInjection.inject(this, context); if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { - MainApp.initSyncOperations(preferences, + MainApp.initSyncOperations(context, + preferences, uploadsStorageManager, accountManager, connectivityService, diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index ddd42a811e9b..b9105cb833f9 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -21,7 +21,6 @@ import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; @@ -337,10 +336,7 @@ private void checkStoragePath() { viewThemeUtils.dialog.colorMaterialAlertDialogBackground(getApplicationContext(), builder); - AlertDialog dialog = builder.create(); - builder.show(); - - viewThemeUtils.platform.colorTextButtons(dialog.getButton(AlertDialog.BUTTON_POSITIVE)); + builder.create().show(); } catch (WindowManager.BadTokenException e) { Log_OC.e(TAG, "Error showing wrong storage info, so skipping it: " + e.getMessage()); } From 0ca310b3e169f154689cd89a06a52ca519de08b2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 27 Jun 2024 16:17:21 +0200 Subject: [PATCH 6/9] Reduce lint Signed-off-by: alperozturk --- .../android/ui/activity/ReceiveExternalFilesActivity.java | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java index 89dca49cc721..96119519fd40 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java @@ -135,7 +135,6 @@ public class ReceiveExternalFilesActivity extends FileActivity @Inject AppPreferences preferences; @Inject LocalBroadcastManager localBroadcastManager; @Inject SyncedFolderProvider syncedFolderProvider; - @Inject ViewThemeUtils viewThemeUtils; private AccountManager mAccountManager; private Stack mParents = new Stack<>(); From 0ee64921973f3b5bf1066e1fae6cb5c43e7739ed Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 1 Jul 2024 15:07:14 +0200 Subject: [PATCH 7/9] Use M3 for SettingsActivity Signed-off-by: alperozturk --- .../android/ui/activity/SettingsActivity.java | 70 ++++++++++--------- app/src/main/res/values/styles.xml | 11 ++- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index 79cd47b0ea96..98ef6b4a2294 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -37,8 +37,11 @@ import android.view.View; import android.view.ViewGroup; import android.webkit.URLUtil; +import android.widget.Button; +import com.google.android.material.button.MaterialButton; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import com.nextcloud.android.common.ui.theme.utils.ColorRole; import com.nextcloud.client.account.User; import com.nextcloud.client.account.UserAccountManager; import com.nextcloud.client.di.Injectable; @@ -494,32 +497,34 @@ private void removeE2E(PreferenceCategory preferenceCategoryMore) { preferenceCategoryMore.removePreference(preference); } else { preference.setOnPreferenceClickListener(p -> { - final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.FallbackTheming_Dialog); - AlertDialog alertDialog = builder.setTitle(R.string.prefs_e2e_mnemonic) - .setMessage(getString(R.string.remove_e2e_message)) - .setCancelable(true) - .setNegativeButton(R.string.common_cancel, ((dialog, i) -> dialog.dismiss())) - .setPositiveButton(R.string.confirm_removal, (dialog, which) -> { - EncryptionUtils.removeE2E(arbitraryDataProvider, user); - preferenceCategoryMore.removePreference(preference); - - Preference pMnemonic = findPreference("mnemonic"); - if (pMnemonic != null) { - preferenceCategoryMore.removePreference(pMnemonic); - } - - dialog.dismiss(); - }) - .create(); - - alertDialog.show(); - + showRemoveE2EAlertDialog(preferenceCategoryMore, preference); return true; }); } } } + private void showRemoveE2EAlertDialog(PreferenceCategory preferenceCategoryMore, Preference preference) { + new MaterialAlertDialogBuilder(this, R.style.FallbackTheming_Dialog) + .setTitle(R.string.prefs_e2e_mnemonic) + .setMessage(getString(R.string.remove_e2e_message)) + .setCancelable(true) + .setNegativeButton(R.string.common_cancel, ((dialog, i) -> dialog.dismiss())) + .setPositiveButton(R.string.confirm_removal, (dialog, which) -> { + EncryptionUtils.removeE2E(arbitraryDataProvider, user); + preferenceCategoryMore.removePreference(preference); + + Preference pMnemonic = findPreference("mnemonic"); + if (pMnemonic != null) { + preferenceCategoryMore.removePreference(pMnemonic); + } + + dialog.dismiss(); + }) + .create() + .show(); + } + private void setupHelpPreference(PreferenceCategory preferenceCategoryMore) { boolean helpEnabled = getResources().getBoolean(R.bool.help_enabled); Preference pHelp = findPreference("help"); @@ -980,22 +985,23 @@ public void handleMnemonicRequest(Intent data) { ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(this); String mnemonic = arbitraryDataProvider.getValue(user.getAccountName(), EncryptionUtils.MNEMONIC).trim(); - - final MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.FallbackTheming_Dialog); - AlertDialog alertDialog = builder.setTitle(R.string.prefs_e2e_mnemonic) - .setMessage(mnemonic) - .setNegativeButton(R.string.common_cancel, (dialog, i) -> dialog.dismiss()) - .setNeutralButton(R.string.common_copy, (dialog, i) -> - ClipboardUtil.copyToClipboard(this, mnemonic, false)) - .setPositiveButton(R.string.common_ok, (dialog, which) -> dialog.dismiss()) - .create(); - - alertDialog.show(); - viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)); + showMnemonicAlertDialogDialog(mnemonic); } } } + private void showMnemonicAlertDialogDialog(String mnemonic) { + new MaterialAlertDialogBuilder(this, R.style.FallbackTheming_Dialog) + .setTitle(R.string.prefs_e2e_mnemonic) + .setMessage(mnemonic) + .setPositiveButton(R.string.common_ok, (dialog, which) -> dialog.dismiss()) + .setNegativeButton(R.string.common_cancel, (dialog, i) -> dialog.dismiss()) + .setNeutralButton(R.string.common_copy, (dialog, i) -> + ClipboardUtil.copyToClipboard(this, mnemonic, false)) + .create() + .show(); + } + @Override @NonNull public MenuInflater getMenuInflater() { diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 13c9a15b63a6..4c1563085156 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -84,19 +84,18 @@ calendar - - -