diff --git a/app/build.gradle b/app/build.gradle index a64e262..e36a594 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,7 +46,7 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.3.1' - + implementation 'androidx.documentfile:documentfile:1.0.1' implementation platform("org.jetbrains.kotlin:kotlin-bom:1.8.0") diff --git a/app/src/main/java/com/maxistar/textpad/activities/EditorActivity.java b/app/src/main/java/com/maxistar/textpad/activities/EditorActivity.java index 6cca5d6..fb19e5b 100644 --- a/app/src/main/java/com/maxistar/textpad/activities/EditorActivity.java +++ b/app/src/main/java/com/maxistar/textpad/activities/EditorActivity.java @@ -26,6 +26,8 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.ParcelFileDescriptor; import android.print.PrintAttributes; import android.print.PrintDocumentAdapter; import android.print.PrintJob; @@ -65,6 +67,16 @@ import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.view.menu.MenuBuilder; +import androidx.documentfile.provider.DocumentFile; + + +import android.content.DialogInterface; +import android.text.SpannableString; +import android.text.method.LinkMovementMethod; +import android.text.style.UnderlineSpan; +import android.text.style.ClickableSpan; +import android.view.View; +import android.widget.TextView; public class EditorActivity extends AppCompatActivity { @@ -74,11 +86,17 @@ public class EditorActivity extends AppCompatActivity { private static final int REQUEST_OPEN = 1; private static final int REQUEST_SAVE = 2; + private static final int REQUEST_SETTINGS = 3; + + private static final int ACTION_CREATE_FILE = 4; private static final int ACTION_OPEN_FILE = 5; + private static final int REQUEST_AUTHORIZE_FOLDER = 6; + + private static final int DO_NOTHING = 0; private static final int DO_OPEN = 1; private static final int DO_NEW = 2; @@ -1081,6 +1099,33 @@ protected void openNamedFileLegacy(String filename) { protected void openNamedFile(final Uri uri) { try { ContentResolver contentResolver = getContentResolver(); + + boolean isReadOnly = false; + + //DocumentFile file = DocumentFile.fromSingleUri(getApplicationContext(), uri); + //isReadOnly = !file.canWrite(); + + + try { + // Try opening the file with write mode + ParcelFileDescriptor pfdWrite = getContentResolver().openFileDescriptor(uri, "rw"); + if (pfdWrite == null) { + isReadOnly = true; + } else { + pfdWrite.close(); // Close it if opened successfully + } + } catch (Exception e) { + isReadOnly = true; + } + + if (isReadOnly) { + // Inform the user that the file is read-only + //Toast.makeText(this, "The file is opened for reading only. Please open it for writing or save it with a different name.", Toast.LENGTH_LONG).show(); + new Handler().postDelayed(this::showReadOnlyDialog, 1000); + } + + + InputStream inputStream = contentResolver.openInputStream(uri); if (inputStream == null) { throw new IOException(); @@ -1124,6 +1169,58 @@ protected void openNamedFile(final Uri uri) { } } + public void showReadOnlyDialog() { + Context context = this; + // Message text with a clickable link + SpannableString spannableMessage = new SpannableString("This file is in read only mode. You can save it with a different name, or you can open it again using 'Open' command from the application menu. Alternatively, you can allow the parent folder for write access, so next time this file will be writable. Click 'authorize folder' to allow all files in the folder to be writable. Click here to read more."); + + // Set the clickable part + ClickableSpan clickableSpan = new ClickableSpan() { + @Override + public void onClick(View textView) { + // Open the link in an external browser + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://your-link.com")); + context.startActivity(browserIntent); + } + }; + spannableMessage.setSpan(clickableSpan, spannableMessage.length() - "Click here to read more.".length(), spannableMessage.length(), 0); + spannableMessage.setSpan(new UnderlineSpan(), spannableMessage.length() - "Click here to read more.".length(), spannableMessage.length(), 0); + + // Creating the AlertDialog + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle("File Access"); + + // Including the message and link in the dialog + builder.setMessage(spannableMessage); + builder.setCancelable(true); + + // Setting the dialog buttons + builder.setPositiveButton("Authorize Folder", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + authorizeFolder(); + } + }); + + builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }); + + AlertDialog dialog = builder.create(); + dialog.show(); + + // Make the link clickable + ((TextView)dialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); + } + + void authorizeFolder() { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + startActivityForResult(intent, REQUEST_AUTHORIZE_FOLDER); + } + private void showAlternativeFileDialog(final Uri uri) { new AlertDialog.Builder(this) .setTitle(R.string.AlternativeFileAccessTitle) @@ -1233,6 +1330,13 @@ public synchronized void onActivityResult( this.saveFileWithConfirmation(); } } + } else if (requestCode == REQUEST_AUTHORIZE_FOLDER) { + Uri folderUri = data.getData(); + if (folderUri != null) { + getContentResolver().takePersistableUriPermission(folderUri, + Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + } + persistUriPermissions(data); } super.onActivityResult(requestCode, resultCode, data); }