Add Two Action Dialog button

Signed-off-by: alperozturk <alper_ozturk@proton.me>
This commit is contained in:
alperozturk 2023-12-06 14:02:09 +01:00
parent 34881cebbc
commit 5f99e4379d
No known key found for this signature in database
GPG key ID: 4E577DC593B59BDF
7 changed files with 224 additions and 18 deletions

View file

@ -104,6 +104,7 @@ import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
import com.owncloud.android.ui.dialog.StoragePermissionDialogFragment;
import com.owncloud.android.ui.dialog.SyncFileNotEnoughSpaceDialogFragment;
import com.owncloud.android.ui.dialog.SyncedFolderPreferencesDialogFragment;
import com.owncloud.android.ui.dialog.TwoActionDialogFragment;
import com.owncloud.android.ui.fragment.ExtendedListFragment;
import com.owncloud.android.ui.fragment.FeatureFragment;
import com.owncloud.android.ui.fragment.FileDetailActivitiesFragment;
@ -269,6 +270,9 @@ abstract class ComponentsModule {
@ContributesAndroidInjector
abstract ChooseTemplateDialogFragment chooseTemplateDialogFragment();
@ContributesAndroidInjector
abstract TwoActionDialogFragment twoActionDialogFragment();
@ContributesAndroidInjector
abstract AccountRemovalDialog accountRemovalDialog();

View file

@ -0,0 +1,26 @@
/*
* Nextcloud Android client application
*
* @author Alper Ozturk
* Copyright (C) 2023 Alper Ozturk
* Copyright (C) 2023 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.nextcloud.model
enum class HTTPStatusCodes(val code: Int) {
NOT_FOUND(404)
}

View file

@ -20,7 +20,9 @@ import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.nextcloud.client.account.User
import com.nextcloud.model.HTTPStatusCodes
import com.nextcloud.utils.extensions.getParcelableArgument
import com.owncloud.android.R
import com.owncloud.android.datamodel.OCFile
@ -164,7 +166,7 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener
startDialog()
} else {
Log_OC.e(TAG, "ReadFileRemoteOp returned failure with code: " + result.httpCode)
showErrorAndFinish()
showErrorAndFinish(result.httpCode)
}
} catch (e: Exception) {
Log_OC.e(TAG, "Error when trying to fetch remote file", e)
@ -203,9 +205,30 @@ class ConflictsResolveActivity : FileActivity(), OnConflictDecisionMadeListener
}
}
private fun showErrorAndFinish() {
runOnUiThread { Toast.makeText(this, R.string.conflict_dialog_error, Toast.LENGTH_LONG).show() }
finish()
private fun showErrorAndFinish(code: Int? = null) {
val message = parseErrorMessage(code)
runOnUiThread {
if (code != null) {
sendHandleFileExistenceEventBroadcast()
} else {
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
}
finish()
}
}
private fun sendHandleFileExistenceEventBroadcast() {
val intent = Intent(UploadListActivity.HANDLE_FILE_EXISTENCE_RECEIVER)
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
}
private fun parseErrorMessage(code: Int?): String {
return if (code == HTTPStatusCodes.NOT_FOUND.code) {
getString(R.string.uploader_file_not_found_on_server_message)
} else {
getString(R.string.conflict_dialog_error)
}
}
/**

View file

@ -56,6 +56,7 @@ import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.operations.CheckCurrentCredentialsOperation;
import com.owncloud.android.ui.adapter.UploadListAdapter;
import com.owncloud.android.ui.decoration.MediaGridItemDecoration;
import com.owncloud.android.ui.dialog.TwoActionDialogFragment;
import com.owncloud.android.utils.FilesSyncHelper;
import com.owncloud.android.utils.theme.ViewThemeUtils;
@ -66,13 +67,13 @@ import androidx.recyclerview.widget.GridLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
/**
* Activity listing pending, active, and completed uploads. User can delete
* completed uploads from view. Content of this list of coming from
* {@link UploadsStorageManager}.
* Activity listing pending, active, and completed uploads. User can delete completed uploads from view. Content of this
* list of coming from {@link UploadsStorageManager}.
*/
public class UploadListActivity extends FileActivity {
public class UploadListActivity extends FileActivity implements TwoActionDialogFragment.TwoActionDialogActionListener {
private static final String TAG = UploadListActivity.class.getSimpleName();
public static final String HANDLE_FILE_EXISTENCE_RECEIVER = "HANDLE_FILE_EXISTENCE_RECEIVER";
private UploadMessagesReceiver uploadMessagesReceiver;
@ -144,6 +145,44 @@ public class UploadListActivity extends FileActivity {
setupDrawer(R.id.nav_uploads);
setupContent();
registerHandleFileExistenceDialogReceiver();
}
private void registerHandleFileExistenceDialogReceiver() {
IntentFilter filter = new IntentFilter(HANDLE_FILE_EXISTENCE_RECEIVER);
LocalBroadcastManager.getInstance(this).registerReceiver(handleFileExistenceReceiver, filter);
}
private final BroadcastReceiver handleFileExistenceReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
showHandleFileExistenceDialog();
}
};
private void showHandleFileExistenceDialog() {
TwoActionDialogFragment dialog = TwoActionDialogFragment.Companion.newInstance(R.string.uploader_handle_not_existed_file_dialog_title,
R.string.uploader_handle_not_existed_file_dialog_message,
R.string.common_cancel,
R.string.common_ok,
this);
dialog.show(this.getSupportFragmentManager(), null);
}
@Override
public void positiveAction() {
}
@Override
public void negativeAction() {
}
@Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(handleFileExistenceReceiver);
super.onDestroy();
}
private void setupContent() {
@ -178,6 +217,7 @@ public class UploadListActivity extends FileActivity {
swipeListRefreshLayout.setOnRefreshListener(this::refresh);
loadItems();
}
private void loadItems() {
@ -327,14 +367,14 @@ public class UploadListActivity extends FileActivity {
if (mUploaderBinder == null) {
mUploaderBinder = (FileUploaderBinder) service;
Log_OC.d(TAG, "UploadListActivity connected to Upload service. component: " +
component + " service: " + service);
component + " service: " + service);
} else {
Log_OC.d(TAG, "mUploaderBinder already set. mUploaderBinder: " +
mUploaderBinder + " service:" + service);
mUploaderBinder + " service:" + service);
}
} else {
Log_OC.d(TAG, "UploadListActivity not connected to Upload service. component: " +
component + " service: " + service);
component + " service: " + service);
}
}

View file

@ -503,9 +503,9 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
OCUpload item,
String status) {
String remotePath = item.getRemotePath();
OCFile ocFile = storageManager.getFileByEncryptedRemotePath(remotePath);
OCFile localFile = storageManager.getFileByEncryptedRemotePath(remotePath);
if (ocFile == null) {
if (localFile == null) {
// Remote file doesn't exist, try to refresh folder
OCFile folder = storageManager.getFileByEncryptedRemotePath(new File(remotePath).getParent() + "/");
@ -517,8 +517,8 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
// Destination folder doesn't exist anymore
}
if (ocFile != null) {
this.openConflictActivity(ocFile, item);
if (localFile != null) {
this.openConflictActivity(localFile, item);
return true;
}
@ -533,10 +533,10 @@ public class UploadListAdapter extends SectionedRecyclerViewAdapter<SectionedVie
holder.binding.uploadStatus.setText(status);
if (result.isSuccess()) {
OCFile file = storageManager.getFileByEncryptedRemotePath(remotePath);
OCFile fileOnServer = storageManager.getFileByEncryptedRemotePath(remotePath);
if (file != null) {
openConflictActivity(file, item);
if (fileOnServer != null) {
openConflictActivity(fileOnServer, item);
} else {
displayFileNotFoundError(holder.itemView, context);
}

View file

@ -0,0 +1,110 @@
/*
* Nextcloud Android client application
*
* @author Alper Ozturk
* Copyright (C) 2023 Alper Ozturk
* Copyright (C) 2023 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.dialog
import android.app.Dialog
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.nextcloud.client.di.Injectable
import com.owncloud.android.utils.theme.ViewThemeUtils
import javax.inject.Inject
class TwoActionDialogFragment(val listener: TwoActionDialogActionListener) : DialogFragment(), Injectable {
@Inject
lateinit var viewThemeUtils: ViewThemeUtils
interface TwoActionDialogActionListener {
fun positiveAction()
fun negativeAction()
}
companion object {
const val titleArgument = "titleArgument"
const val messageArgument = "messageArgument"
const val negativeButtonArgument = "negativeButtonArgument"
const val positiveButtonArgument = "positiveButtonArgument"
fun newInstance(
titleId: Int,
messageId: Int?,
negativeButtonTextId: Int,
positiveButtonTextId: Int,
listener: TwoActionDialogActionListener
): TwoActionDialogFragment {
return TwoActionDialogFragment(listener).apply {
arguments = Bundle().apply {
putInt(titleArgument, titleId)
messageId?.let { putInt(messageArgument, it) }
putInt(positiveButtonArgument, positiveButtonTextId)
putInt(negativeButtonArgument, negativeButtonTextId)
}
}
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val title = requireContext().getString(requireArguments().getInt(titleArgument))
val messageId: Int? = arguments?.getInt(messageArgument)
val positiveButtonText = requireContext().getString(requireArguments().getInt(positiveButtonArgument))
val negativeButtonText = requireContext().getString(requireArguments().getInt(negativeButtonArgument))
val builder = MaterialAlertDialogBuilder(requireContext())
.setTitle(title)
.setNegativeButton(negativeButtonText) { dialog, _ ->
dialog.dismiss()
listener.negativeAction()
}
.setPositiveButton(positiveButtonText) { dialog, _ ->
dialog.dismiss()
listener.positiveAction()
}
messageId?.let {
builder.setMessage(requireContext().getString(messageId))
}
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(requireContext(), builder)
return builder.create()
}
override fun onStart() {
super.onStart()
val alertDialog = dialog as AlertDialog?
alertDialog?.let {
val positiveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE) as MaterialButton?
if (positiveButton != null) {
viewThemeUtils.material.colorMaterialButtonPrimaryTonal(positiveButton)
}
val negativeButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) as MaterialButton?
if (negativeButton != null) {
viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(negativeButton)
}
}
}
}

View file

@ -912,6 +912,9 @@
<string name="failed_to_start_editor">Failed to start editor</string>
<string name="create_rich_workspace">Add folder info</string>
<string name="creates_rich_workspace">creates folder info</string>
<string name="uploader_handle_not_existed_file_dialog_title">File Not Found</string>
<string name="uploader_handle_not_existed_file_dialog_message">This file does not longer exist in server still want to upload?</string>
<string name="uploader_file_not_found_on_server_message">We couldnt locate the file on server. Another user may have deleted the file</string>
<string name="uploader_file_not_found_message">File not found. Are you sure this file exist or conflict not solved before?</string>
<string name="uploader_upload_failed_sync_conflict_error">File upload conflict</string>
<string name="uploader_upload_failed_sync_conflict_error_content">Pick which version to keep of %1$s</string>