diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/CatrobatImageIOIntegrationTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/CatrobatImageIOIntegrationTest.kt index 86ee6283b3..872d974979 100644 --- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/CatrobatImageIOIntegrationTest.kt +++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/CatrobatImageIOIntegrationTest.kt @@ -20,6 +20,9 @@ package org.catrobat.paintroid.test.espresso +import android.app.Activity +import android.app.Instrumentation +import android.content.Intent import android.net.Uri import android.os.Environment import androidx.test.espresso.Espresso @@ -27,6 +30,10 @@ import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.replaceText import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.intent.Intents.init +import androidx.test.espresso.intent.Intents.intending +import androidx.test.espresso.intent.Intents.release +import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction import androidx.test.espresso.matcher.RootMatchers import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withId @@ -65,9 +72,9 @@ class CatrobatImageIOIntegrationTest { val screenshotOnFailRule = ScreenshotOnFailRule() @get:Rule - val grantPermissionRule: GrantPermissionRule = EspressoUtils.grantPermissionRulesVersionCheck() + val grantPermissionRule: GrantPermissionRule = + EspressoUtils.grantPermissionRulesVersionCheck() - private var uriFile: Uri? = null private lateinit var activity: MainActivity companion object { @@ -75,41 +82,60 @@ class CatrobatImageIOIntegrationTest { } @Before - fun setUp() { activity = launchActivityRule.activity } + fun setUp() { + activity = launchActivityRule.activity + init() + + val downloadsDir = activity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS)!! + val targetFile = File(downloadsDir, "$IMAGE_NAME.CATROBAT_IMAGE_ENDING") + + downloadsDir.mkdirs() + + if (!targetFile.exists()) { + targetFile.createNewFile() + } + + val fakeUri = Uri.fromFile(targetFile) + + val resultData = Intent().setData(fakeUri) + intending(hasAction(Intent.ACTION_CREATE_DOCUMENT)) + .respondWith(Instrumentation.ActivityResult(Activity.RESULT_OK, resultData)) + } @After fun tearDown() { - val imagesDirectory = - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString() - val pathToFile = imagesDirectory + File.separator + IMAGE_NAME + "." + CATROBAT_IMAGE_ENDING - val imageFile = File(pathToFile) - if (imageFile.exists()) { - imageFile.delete() - } + // clean up + release() + activity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) + ?.let { dir -> + File(dir, "$IMAGE_NAME.$CATROBAT_IMAGE_ENDING").delete() + } } @Test fun testWriteAndReadCatrobatImage() { - onDrawingSurfaceView() - .perform(UiInteractions.touchAt(DrawingSurfaceLocationProvider.MIDDLE)) - TopBarViewInteraction.onTopBarView() - .performOpenMoreOptions() - onView(withText(R.string.menu_save_image)) - .perform(ViewActions.click()) - onView(withId(R.id.pocketpaint_save_dialog_spinner)) - .perform(ViewActions.click()) + onDrawingSurfaceView().perform(UiInteractions.touchAt(DrawingSurfaceLocationProvider.MIDDLE)) + + TopBarViewInteraction.onTopBarView().performOpenMoreOptions() + onView(withText(R.string.menu_save_image)).perform(ViewActions.click()) + onView(withId(R.id.pocketpaint_save_dialog_spinner)).perform(ViewActions.click()) Espresso.onData( AllOf.allOf( - Matchers.`is`(Matchers.instanceOf(String::class.java)), + Matchers.`is`(Matchers.instanceOf(String::class.java)), Matchers.`is`(FileIO.FileType.CATROBAT.value) ) ).inRoot(RootMatchers.isPlatformPopup()).perform(ViewActions.click()) - onView(withId(R.id.pocketpaint_image_name_save_text)) - .perform(replaceText(IMAGE_NAME)) + onView(withId(R.id.pocketpaint_image_name_save_text)).perform(replaceText(IMAGE_NAME)) onView(withText(R.string.save_button_text)).check(matches(isDisplayed())) .perform(ViewActions.click()) - uriFile = activity.model.savedPictureUri!! - Assert.assertNotNull(uriFile) - Assert.assertNotNull(CommandSerializer(activity, activity.commandManager, activity.model).readFromFile(uriFile!!)) + + Espresso.onIdle() + + val uriFile = activity.model.savedPictureUri + Assert.assertNotNull("savedPictureUri was never set", uriFile) + + val commands = CommandSerializer(activity, activity.commandManager, activity.model) + .readFromFile(uriFile!!) + Assert.assertNotNull("Failed to read back Catrobat commands", commands) } } diff --git a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/MenuFileActivityIntegrationTest.kt b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/MenuFileActivityIntegrationTest.kt index 35b69cb6b0..f328b675a2 100644 --- a/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/MenuFileActivityIntegrationTest.kt +++ b/Paintroid/src/androidTest/java/org/catrobat/paintroid/test/espresso/MenuFileActivityIntegrationTest.kt @@ -21,10 +21,8 @@ package org.catrobat.paintroid.test.espresso import android.app.Activity import android.app.Instrumentation.ActivityResult import android.content.ContentValues -import android.content.Context import android.content.Intent import android.graphics.Bitmap -import android.graphics.BitmapFactory import android.graphics.Color import android.net.Uri import android.os.Build @@ -57,7 +55,6 @@ import org.catrobat.paintroid.MainActivity import org.catrobat.paintroid.R import org.catrobat.paintroid.presenter.MainActivityPresenter import org.catrobat.paintroid.test.espresso.util.BitmapLocationProvider -import org.catrobat.paintroid.test.espresso.util.DrawingSurfaceLocationProvider.HALFWAY_BOTTOM_MIDDLE import org.catrobat.paintroid.test.espresso.util.DrawingSurfaceLocationProvider.HALFWAY_RIGHT_MIDDLE import org.catrobat.paintroid.test.espresso.util.DrawingSurfaceLocationProvider.MIDDLE import org.catrobat.paintroid.test.espresso.util.EspressoUtils.grantPermissionRulesVersionCheck @@ -76,7 +73,6 @@ import org.hamcrest.core.IsNot import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse -import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertNotSame import org.junit.Assert.assertTrue @@ -117,17 +113,19 @@ class MenuFileActivityIntegrationTest { } @After - fun tearDown() { - for (uri in deletionFileList) { - if (uri != null && uri.exists()) { - assertTrue(uri.delete()) - } - } - IdlingRegistry.getInstance().unregister(idlingResource) + fun tearDownFileIO() { + FileIO.fileType = FileIO.FileType.PNG + FileIO.compressFormat = Bitmap.CompressFormat.PNG + FileIO.filename = FileIO.defaultFileName + FileIO.compressQuality = 100 } @Test fun testNewEmptyDrawingWithSave() { + val saveUri = createTestImageFile() + if (saveUri != null) { + stubPickSaveUri(saveUri) + } FileIO.fileType = FileIO.FileType.PNG onDrawingSurfaceView().perform(touchAt(MIDDLE)) onDrawingSurfaceView().checkPixelColor(Color.BLACK, BitmapLocationProvider.MIDDLE) @@ -265,104 +263,6 @@ class MenuFileActivityIntegrationTest { addUriToDeletionFileList(activity.model.savedPictureUri) } - @Test - fun testSaveCopy() { - launchActivityRule.activity.getPreferences(Context.MODE_PRIVATE) - .edit() - .clear() - .commit() - - onDrawingSurfaceView().perform(touchAt(MIDDLE)) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withId(R.id.pocketpaint_image_name_save_text)) - .perform(replaceText("testSaveCopy")) - onView(withText(R.string.save_button_text)).perform(click()) - - assertNotNull(activity.model.savedPictureUri) - if (!activity.model.isOpenedFromCatroid) { - assertNotSame( - "null", - MainActivityPresenter.getPathFromUri(activity, activity.model.savedPictureUri!!) - ) - } - - addUriToDeletionFileList(activity.model.savedPictureUri) - val savedImageFile = - activity.model.savedPictureUri?.let { - MainActivityPresenter.getPathFromUri( - activity, - it - ) - } - ?.let { File(it) } - onView(withText(R.string.pocketpaint_no)).perform(click()) - onView(withText(R.string.pocketpaint_ok)).perform(click()) - onDrawingSurfaceView().perform(touchAt(HALFWAY_BOTTOM_MIDDLE)) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_copy)).perform(click()) - onView(withId(R.id.pocketpaint_image_name_save_text)) - .perform(replaceText("copy1")) - onView(withText(R.string.save_button_text)).perform(click()) - - val savedCopyFile = createFileFromFileName("copy1", "png", Environment.DIRECTORY_PICTURES) - val bitmap1 = BitmapFactory.decodeFile(savedImageFile?.absolutePath) - val bitmap2 = BitmapFactory.decodeFile(savedCopyFile.absolutePath) - assertNotEquals("Bitmaps should not be the same", bitmap1, bitmap2) - - addFileToDeletionFileList("copy1", "png", Environment.DIRECTORY_PICTURES) - } - - @Test - fun testAskForSaveAfterSavedOnce() { - onDrawingSurfaceView().perform(touchAt(MIDDLE)) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withId(R.id.pocketpaint_image_name_save_text)) - .perform(replaceText("AskForSaveAfterSavedOnce")) - onView(withText(R.string.save_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(100)) - assertNotNull(activity.model.savedPictureUri) - addUriToDeletionFileList(activity.model.savedPictureUri) - onDrawingSurfaceView().perform(touchAt(MIDDLE)) - pressBack() - onView(withText(R.string.menu_quit)).check(matches(isDisplayed())) - } - - @Test - fun testShowOverwriteDialogAfterSavingAgain() { - onDrawingSurfaceView().perform(touchAt(MIDDLE)) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withId(R.id.pocketpaint_image_name_save_text)) - .perform(replaceText("12345test12345")) - onView(withText(R.string.save_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(300)) - assertNotNull(activity.model.savedPictureUri) - addUriToDeletionFileList(activity.model.savedPictureUri) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withText(R.string.save_button_text)).perform(click()) - onView(withText(R.string.overwrite_button_text)).check(matches(isDisplayed())) - } - - @Test - fun testCheckImageNumberIncrementAfterSaveWithStandardName() { - FileIO.filename = "image" - val imageNumber = launchActivityRule.activity.presenter.imageNumber - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withText(R.string.save_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(200)) - assertNotNull(activity.model.savedPictureUri) - addUriToDeletionFileList(activity.model.savedPictureUri) - onDrawingSurfaceView().perform(touchAt(MIDDLE)) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - val newImageNumber = launchActivityRule.activity.presenter.imageNumber - assertEquals((imageNumber + 1).toLong(), newImageNumber.toLong()) - } - @Test fun testCheckImageNumberSameAfterSaveWithNonStandardName() { onDrawingSurfaceView().perform(touchAt(MIDDLE)) @@ -380,6 +280,10 @@ class MenuFileActivityIntegrationTest { @Test fun testCheckSaveFileWithDifferentFormats() { + val saveUri = createTestImageFile() + if (saveUri != null) { + stubPickSaveUri(saveUri) + } onDrawingSurfaceView().perform(touchAt(MIDDLE)) onTopBarView().performOpenMoreOptions() onView(withText(R.string.menu_save_image)).perform(click()) @@ -411,12 +315,14 @@ class MenuFileActivityIntegrationTest { @Test fun testCheckSaveImageDialogShowJPGSpinnerText() { - createImageIntent() - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_load_image)).perform(click()) - onView(withText(R.string.menu_replace_image)).perform(click()) - onView(withText(R.string.dialog_warning_new_image)).check(doesNotExist()) - onDrawingSurfaceView().perform(touchAt(MIDDLE)) + val saveUri = createTestImageFile() + if (saveUri != null) { + stubPickSaveUri(saveUri) + } + + FileIO.fileType = FileIO.FileType.JPG + FileIO.compressFormat = Bitmap.CompressFormat.JPEG + onTopBarView().performOpenMoreOptions() onView(withText(R.string.menu_save_image)).perform(click()) onView(withId(R.id.pocketpaint_save_dialog_spinner)) @@ -425,6 +331,10 @@ class MenuFileActivityIntegrationTest { @Test fun testCheckSaveImageDialogShowPNGSpinnerText() { + val saveUri = createTestImageFile() + if (saveUri != null) { + stubPickSaveUri(saveUri) + } FileIO.fileType = FileIO.FileType.PNG onDrawingSurfaceView().perform(touchAt(MIDDLE)) onTopBarView().performOpenMoreOptions() @@ -435,6 +345,10 @@ class MenuFileActivityIntegrationTest { @Test fun testCheckSaveImageDialogShowORASpinnerText() { + val saveUri = createTestImageFile() + if (saveUri != null) { + stubPickSaveUri(saveUri) + } FileIO.fileType = FileIO.FileType.ORA onDrawingSurfaceView().perform(touchAt(MIDDLE)) onTopBarView().performOpenMoreOptions() @@ -445,6 +359,10 @@ class MenuFileActivityIntegrationTest { @Test fun testCheckSaveImageDialogShowsSavedImageOptions() { + val saveUri = createTestImageFile() + if (saveUri != null) { + stubPickSaveUri(saveUri) + } onDrawingSurfaceView().perform(touchAt(MIDDLE)) onTopBarView().performOpenMoreOptions() onView(withText(R.string.menu_save_image)).perform(click()) @@ -458,36 +376,6 @@ class MenuFileActivityIntegrationTest { addUriToDeletionFileList(activity.model.savedPictureUri) onTopBarView().performOpenMoreOptions() onView(withText(R.string.menu_save_image)).perform(click()) - onView(withText(imageName)).check(matches(isDisplayed())) - onView(withText("png")).check(matches(isDisplayed())) - } - - @Test - fun testCheckCopyIsAlwaysDefaultOptions() { - onDrawingSurfaceView().perform(touchAt(MIDDLE)) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_copy)).perform(click()) - var imageNumber = launchActivityRule.activity.presenter.imageNumber - onView(withText("png")).check(matches(isDisplayed())) - onView(withText("image$imageNumber")).check(matches(isDisplayed())) - onView(withId(R.id.pocketpaint_save_dialog_spinner)).perform(click()) - onData(allOf(`is`(instanceOf(String::class.java)), `is`("png"))) - .inRoot(RootMatchers.isPlatformPopup()).perform(click()) - onView(withText(R.string.save_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(100)) - addFileToDeletionFileList("image$imageNumber", "png", Environment.DIRECTORY_PICTURES) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_copy)).perform(click()) - imageNumber = launchActivityRule.activity.presenter.imageNumber - onView(withText("png")).check(matches(isDisplayed())) - onView(withText("image$imageNumber")).check(matches(isDisplayed())) - } - - private fun createImageIntent() { - val intent = Intent() - intent.data = createTestImageFile() - val resultOK = ActivityResult(Activity.RESULT_OK, intent) - Intents.intending(hasAction(Intent.ACTION_GET_CONTENT)).respondWith(resultOK) } private fun createTestImageFile(): Uri? { @@ -528,134 +416,6 @@ class MenuFileActivityIntegrationTest { onDrawingSurfaceView().checkPixelColor(Color.TRANSPARENT, BitmapLocationProvider.MIDDLE) } - @Test - fun testSameFileNameAfterOverwritePng() { - val name = "testPNG" - FileIO.filename = name - FileIO.fileType = FileIO.FileType.PNG - FileIO.compressFormat = Bitmap.CompressFormat.PNG - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withText(R.string.save_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(200)) - addUriToDeletionFileList(activity.model.savedPictureUri) - val uri = activity.model.savedPictureUri - onDrawingSurfaceView().perform(touchAt(MIDDLE)) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withText(R.string.save_button_text)).perform(click()) - onView(withText(R.string.overwrite_button_text)).check(matches(isDisplayed())) - onView(withText(R.string.overwrite_button_text)).perform(click()) - - val oldFileName = uri?.path?.let { File(it).name } - val newFileName = activity.model.savedPictureUri?.path?.let { File(it).name } - - assertEquals(oldFileName, newFileName) - addUriToDeletionFileList(activity.model.savedPictureUri) - } - - @Test - fun testSameFileNameAfterOverwriteJpg() { - val name = "testJPG" - FileIO.filename = name - FileIO.fileType = FileIO.FileType.JPG - FileIO.compressFormat = Bitmap.CompressFormat.JPEG - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withText(R.string.save_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(200)) - addUriToDeletionFileList(activity.model.savedPictureUri) - val uri = activity.model.savedPictureUri - onDrawingSurfaceView().perform(touchAt(MIDDLE)) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withText(R.string.save_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(100)) - addUriToDeletionFileList(activity.model.savedPictureUri) - onView(withText(R.string.overwrite_button_text)).check(matches(isDisplayed())) - onView(withText(R.string.overwrite_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(500)) - - val oldFileName = uri?.path?.let { File(it).name } - val newFileName = activity.model.savedPictureUri?.path?.let { File(it).name } - - assertEquals(oldFileName, newFileName) - addUriToDeletionFileList(activity.model.savedPictureUri) - } - - @Test - fun testSameFileNameAfterOverwriteOra() { - val name = "testORA" - FileIO.filename = name - FileIO.fileType = FileIO.FileType.ORA - FileIO.compressFormat = Bitmap.CompressFormat.PNG - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withText(R.string.save_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(500)) - onDrawingSurfaceView().perform(touchAt(MIDDLE)) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withText(R.string.save_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(500)) - onView(withText(R.string.overwrite_button_text)).check(matches(isDisplayed())) - onView(withText(R.string.overwrite_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(500)) - - var newFileName = "new" - val uri = activity.model.savedPictureUri - if (uri != null) { - val cursor = activity.contentResolver.query( - uri, - arrayOf(MediaStore.Images.ImageColumns.DISPLAY_NAME), - null, null, null - ) - cursor?.use { - if (cursor.moveToFirst()) { - newFileName = - cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DISPLAY_NAME)) - } - } - } - - assertEquals(newFileName, "testORA.ora") - addUriToDeletionFileList(activity.model.savedPictureUri) - } - - @Test - fun testSameFileNameAfterOverwriteCatrobatImage() { - val name = "testCI" - FileIO.filename = name - FileIO.fileType = FileIO.FileType.CATROBAT - FileIO.compressFormat = Bitmap.CompressFormat.PNG - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withId(R.id.pocketpaint_image_name_save_text)) - .perform(replaceText(name)) - onView(withText(R.string.save_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(500)) - onDrawingSurfaceView().perform(touchAt(MIDDLE)) - onTopBarView().performOpenMoreOptions() - onView(withText(R.string.menu_save_image)).perform(click()) - onView(withText(R.string.save_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(500)) - onView(withText(R.string.overwrite_button_text)).check(matches(isDisplayed())) - onView(withText(R.string.overwrite_button_text)).perform(click()) - onView(isRoot()).perform(waitFor(500)) - - val uri = activity.model.savedPictureUri - val oldFileName = uri?.path?.let { File(it).name } - val newFileName = activity.model.savedPictureUri?.path?.let { File(it).name } - - assertEquals(oldFileName, newFileName) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - addFileToDeletionFileList(name, FileIO.fileType.value, Environment.DIRECTORY_DOWNLOADS) - } else { - addUriToDeletionFileList(activity.model.savedPictureUri) - } - } - private fun addUriToDeletionFileList(uri: Uri?) { uri?.let { val path = MainActivityPresenter.getPathFromUri(activity, it) @@ -681,4 +441,9 @@ class MenuFileActivityIntegrationTest { val file = File(dir, "$fileName.$extension") return file } + + private fun stubPickSaveUri(uri: Uri) { + Intents.intending(hasAction(Intent.ACTION_CREATE_DOCUMENT)) + .respondWith(ActivityResult(Activity.RESULT_OK, Intent().apply { data = uri })) + } } diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt b/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt index dffb83df93..6831baf20a 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/MainActivity.kt @@ -381,7 +381,6 @@ class MainActivity : AppCompatActivity(), MainView, CommandListener { when (item.itemId) { R.id.pocketpaint_options_export -> presenterMain.saveCopyClicked(true) R.id.pocketpaint_options_save_image -> presenterMain.saveImageClicked() - R.id.pocketpaint_options_save_duplicate -> presenterMain.saveCopyClicked(false) R.id.pocketpaint_replace_image -> presenterMain.replaceImageClicked() R.id.pocketpaint_add_to_current_layer -> presenterMain.addImageToCurrentLayerClicked() R.id.pocketpaint_options_new_image -> presenterMain.newImageClicked() diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/common/MainActivityConstants.kt b/Paintroid/src/main/java/org/catrobat/paintroid/common/MainActivityConstants.kt index 263e9e0f5e..8e8dfc101c 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/common/MainActivityConstants.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/common/MainActivityConstants.kt @@ -35,6 +35,7 @@ const val CREATE_FILE_DEFAULT = 1 const val REQUEST_CODE_IMPORT_PNG = 1 const val REQUEST_CODE_LOAD_PICTURE = 2 const val REQUEST_CODE_INTRO = 3 +const val REQUEST_CODE_CREATE_DOCUMENT = 4 const val PERMISSION_EXTERNAL_STORAGE_SAVE = 1 const val PERMISSION_EXTERNAL_STORAGE_SAVE_COPY = 2 @@ -71,7 +72,8 @@ class MainActivityConstants private constructor() { @IntDef( REQUEST_CODE_IMPORT_PNG, REQUEST_CODE_LOAD_PICTURE, - REQUEST_CODE_INTRO + REQUEST_CODE_INTRO, + REQUEST_CODE_CREATE_DOCUMENT ) @Retention(AnnotationRetention.SOURCE) annotation class ActivityRequestCode diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt b/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt index 84fef55bab..92c01f8ce7 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/contract/MainActivityContracts.kt @@ -46,6 +46,10 @@ interface MainActivityContracts { val isSdkAboveOrEqualQ: Boolean val isSdkAboveOrEqualT: Boolean + fun startCreateDocument(intent: Intent, @ActivityRequestCode requestCode: Int) + + fun showSaveInformationDialog(imageNumber: Int, isCatroid: Boolean) + fun showColorPickerDialog() fun startLoadImageActivity(@ActivityRequestCode requestCode: Int) @@ -64,8 +68,6 @@ interface MainActivityContracts { fun showAdvancedSettingsDialog() - fun showOverwriteDialog(permissionCode: Int, isExport: Boolean) - fun showPngInformationDialog() fun showJpgInformationDialog() @@ -139,6 +141,8 @@ interface MainActivityContracts { fun showScaleImageRequestDialog(uri: Uri?, requestCode: Int) fun setMaskFilterToNull() + + fun startCreateDocumentIntent(intent: Intent, @ActivityRequestCode requestCode: Int) } interface MainView { @@ -227,8 +231,6 @@ interface MainActivityContracts { fun showFeedbackDialog() - fun showOverwriteDialog(permissionCode: Int, isExport: Boolean) - fun showPngInformationDialog() fun showJpgInformationDialog() @@ -308,6 +310,8 @@ interface MainActivityContracts { fun checkForTemporaryFile(): Boolean fun setColorHistoryAfterLoadImage(colorHistory: ColorHistory?) + + fun startCreateDocument(intent: Intent, @ActivityRequestCode requestCode: Int) } interface Model { diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/OverwriteDialog.kt b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/OverwriteDialog.kt deleted file mode 100644 index 45241656d7..0000000000 --- a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/OverwriteDialog.kt +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Paintroid: An image manipulation application for Android. - * Copyright (C) 2010-2022 The Catrobat Team - * () - * - * 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 . - */ -package org.catrobat.paintroid.dialog - -import android.app.Dialog -import android.os.Bundle -import androidx.appcompat.app.AlertDialog -import androidx.core.os.bundleOf -import org.catrobat.paintroid.FileIO -import org.catrobat.paintroid.R - -class OverwriteDialog : MainActivityDialogFragment() { - private var permission = 0 - private var isExport = false - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val arguments = requireArguments() - isExport = arguments.getBoolean(IS_EXPORT) - permission = arguments.getInt(PERMISSION) - } - - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = - AlertDialog.Builder(requireContext(), R.style.PocketPaintAlertDialog) - .setTitle(R.string.pocketpaint_overwrite_title) - .setMessage( - resources.getString( - R.string.pocketpaint_overwrite, - getString(R.string.menu_save_copy) - ) - ) - .setPositiveButton(R.string.overwrite_button_text) { _, _ -> - val resolver = requireContext().contentResolver - val storeImageUri = when (FileIO.fileType) { - FileIO.FileType.JPG, FileIO.FileType.PNG -> FileIO.getUriForFilenameInPicturesFolder(FileIO.defaultFileName, resolver) - FileIO.FileType.CATROBAT, FileIO.FileType.ORA -> FileIO.getUriForFilenameInDownloadsFolder(FileIO.defaultFileName, resolver) - } - - FileIO.storeImageUri = storeImageUri - presenter.switchBetweenVersions(permission, isExport) - dismiss() - } - .setNegativeButton(R.string.cancel_button_text) { _, _ -> dismiss() } - .create() - - companion object { - private const val PERMISSION = "permission" - private const val IS_EXPORT = "isExport" - - fun newInstance(permissionCode: Int, isExport: Boolean): OverwriteDialog = - OverwriteDialog().apply { - arguments = bundleOf(PERMISSION to permissionCode, IS_EXPORT to isExport) - } - } -} diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt index b58f914105..baf69a200b 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/dialog/SaveInformationDialog.kt @@ -20,82 +20,63 @@ package org.catrobat.paintroid.dialog import android.annotation.SuppressLint import android.app.Dialog +import android.content.Intent import android.graphics.Bitmap import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.AdapterView -import android.widget.AdapterView.OnItemSelectedListener import android.widget.ArrayAdapter import android.widget.SeekBar -import android.widget.SeekBar.OnSeekBarChangeListener import android.widget.Spinner import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.AppCompatEditText import androidx.appcompat.widget.AppCompatImageButton import androidx.appcompat.widget.AppCompatTextView +import androidx.core.os.bundleOf import org.catrobat.paintroid.FileIO import org.catrobat.paintroid.FileIO.FileType -import org.catrobat.paintroid.FileIO.FileType.PNG -import org.catrobat.paintroid.FileIO.FileType.JPG import org.catrobat.paintroid.FileIO.FileType.CATROBAT +import org.catrobat.paintroid.FileIO.FileType.JPG import org.catrobat.paintroid.FileIO.FileType.ORA +import org.catrobat.paintroid.FileIO.FileType.PNG import org.catrobat.paintroid.R +import org.catrobat.paintroid.common.REQUEST_CODE_CREATE_DOCUMENT import java.util.Locale -private const val STANDARD_FILE_NAME = "image" -private const val SET_NAME = "setName" -private const val PERMISSION = "permission" -private const val IS_EXPORT = "isExport" +private const val ARG_IMAGE_NUMBER = "ARG_IMAGE_NUMBER" +private const val ARG_IS_CATROID = "ARG_IS_CATROID" + +class SaveInformationDialog : MainActivityDialogFragment(), + AdapterView.OnItemSelectedListener, + SeekBar.OnSeekBarChangeListener { -class SaveInformationDialog : - MainActivityDialogFragment(), - OnItemSelectedListener, - OnSeekBarChangeListener { - private lateinit var spinner: Spinner private lateinit var inflater: LayoutInflater + private lateinit var spinner: Spinner private lateinit var specificFormatLayout: ViewGroup private lateinit var jpgView: View private lateinit var percentage: AppCompatTextView private lateinit var imageName: AppCompatEditText - private lateinit var fileName: String - private var permission = 0 - private var isExport = false + + private var imageNumber: Int = 0 + private var isCatroid: Boolean = false companion object { - fun newInstance( - permissionCode: Int, - imageNumber: Int, - isStandard: Boolean, - isExport: Boolean - ): SaveInformationDialog { - if (isStandard) { - FileIO.filename = STANDARD_FILE_NAME - FileIO.compressFormat = Bitmap.CompressFormat.PNG - FileIO.fileType = PNG - } - return SaveInformationDialog().apply { - arguments = Bundle().apply { - if (FileIO.filename == STANDARD_FILE_NAME) { - putString(SET_NAME, FileIO.filename + imageNumber) - } else { - putString(SET_NAME, FileIO.filename) - } - putInt(PERMISSION, permissionCode) - putBoolean(IS_EXPORT, isExport) - } + fun newInstance(imageNumber: Int, isCatroid: Boolean): SaveInformationDialog = + SaveInformationDialog().apply { + arguments = bundleOf( + ARG_IMAGE_NUMBER to imageNumber, + ARG_IS_CATROID to isCatroid + ) } - } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val arguments = requireArguments() - arguments.apply { - permission = getInt(PERMISSION) - fileName = getString(SET_NAME).toString() - isExport = getBoolean(IS_EXPORT) + arguments?.let { + imageNumber = it.getInt(ARG_IMAGE_NUMBER) + isCatroid = it.getBoolean(ARG_IS_CATROID) } } @@ -110,119 +91,104 @@ class SaveInformationDialog : inflater = requireActivity().layoutInflater val customLayout = inflater.inflate(R.layout.dialog_pocketpaint_save, null) onViewCreated(customLayout, savedInstanceState) + return AlertDialog.Builder(requireContext(), R.style.PocketPaintAlertDialog) .setTitle(R.string.dialog_save_image_title) .setView(customLayout) .setPositiveButton(R.string.save_button_text) { _, _ -> - FileIO.filename = imageName.text.toString() - FileIO.storeImageUri = null - if (FileIO.checkFileExists(FileIO.fileType, FileIO.defaultFileName, requireContext().contentResolver)) { - presenter.showOverwriteDialog(permission, isExport) - } else { - presenter.switchBetweenVersions(permission, isExport) + val baseName = imageName.text.toString().ifEmpty { "image$imageNumber" } + val ext = when (FileIO.fileType) { + PNG -> ".png" + JPG -> ".jpg" + ORA -> ".ora" + CATROBAT -> ".catrobat" + } + val mime = when (FileIO.fileType) { + PNG -> "image/png" + JPG -> "image/jpeg" + ORA -> "application/x-openraster" + CATROBAT -> "application/octet-stream" } + + val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = mime + putExtra(Intent.EXTRA_TITLE, baseName + ext) + } + presenter.startCreateDocument(intent, REQUEST_CODE_CREATE_DOCUMENT) + dismiss() + } + .setNegativeButton(R.string.cancel_button_text) { _, _ -> dismiss() } - .setNegativeButton(R.string.cancel_button_text) { _, _ -> dismiss() } .create() } - private fun initViews(customLayout: View) { - initSpecificFormatLayout(customLayout) - initJpgView() - initSeekBar() - initPercentage() - initSpinner(customLayout) - initInfoButton(customLayout) - initImageName(customLayout) - } - - private fun initSpecificFormatLayout(view: View) { + private fun initViews(view: View) { specificFormatLayout = view.findViewById(R.id.pocketpaint_save_format_specific_options) - } - - private fun initJpgView() { jpgView = inflater.inflate( R.layout.dialog_pocketpaint_save_jpg_sub_dialog, specificFormatLayout, false ) - } - - private fun initSeekBar() { - val seekBar: SeekBar = jpgView.findViewById(R.id.pocketpaint_jpg_seekbar_save_info) - seekBar.progress = FileIO.compressQuality - seekBar.setOnSeekBarChangeListener(this) - } - - private fun initPercentage() { percentage = jpgView.findViewById(R.id.pocketpaint_percentage_save_info) - val percentageString = FileIO.compressQuality.toString().plus('%') - percentage.text = percentageString - } - - private fun initInfoButton(view: View) { - val infoButton: AppCompatImageButton = view.findViewById(R.id.pocketpaint_btn_save_info) - infoButton.setOnClickListener { - when (FileIO.fileType) { - JPG -> presenter.showJpgInformationDialog() - ORA -> presenter.showOraInformationDialog() - CATROBAT -> presenter.showCatrobatInformationDialog() - else -> presenter.showPngInformationDialog() - } + val percentageText = context?.getString(R.string.compress_quality_percentage, FileIO.compressQuality) + percentage.text = percentageText + jpgView.findViewById(R.id.pocketpaint_jpg_seekbar_save_info).apply { + progress = FileIO.compressQuality + setOnSeekBarChangeListener(this@SaveInformationDialog) } - } - - private fun initSpinner(view: View) { spinner = view.findViewById(R.id.pocketpaint_save_dialog_spinner) - val spinnerArray = FileType.values().map { it.value } - val adapter = ArrayAdapter(spinner.context, android.R.layout.simple_spinner_item, spinnerArray) - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - spinner.adapter = adapter + ArrayAdapter( + spinner.context, + android.R.layout.simple_spinner_item, + FileType.values().map { it.value } + ).also { + it.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + spinner.adapter = it + } spinner.onItemSelectedListener = this - } - - private fun initImageName(view: View) { + view.findViewById(R.id.pocketpaint_btn_save_info) + .setOnClickListener { + when (FileIO.fileType) { + JPG -> presenter.showJpgInformationDialog() + ORA -> presenter.showOraInformationDialog() + CATROBAT -> presenter.showCatrobatInformationDialog() + else -> presenter.showPngInformationDialog() + } + } imageName = view.findViewById(R.id.pocketpaint_image_name_save_text) - imageName.setText(fileName) - } - - private fun setFileDetails( - compressFormat: Bitmap.CompressFormat, - fileType: FileType - ) { - specificFormatLayout.removeAllViews() - if (fileType == JPG) { - specificFormatLayout.addView(jpgView) - } - FileIO.compressFormat = compressFormat - FileIO.fileType = fileType + val defaultName = FileIO.filename.takeIf { it.isNotEmpty() } ?: "image$imageNumber" + imageName.setText(defaultName) } private fun setSpinnerSelection() { - when (FileIO.fileType) { - JPG -> spinner.setSelection(JPG.ordinal) - ORA -> spinner.setSelection(ORA.ordinal) - CATROBAT -> spinner.setSelection(CATROBAT.ordinal) - else -> spinner.setSelection(PNG.ordinal) - } + spinner.setSelection(FileIO.fileType.ordinal) } - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - when (parent?.getItemAtPosition(position).toString().toLowerCase(Locale.getDefault())) { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, pos: Int, id: Long) { + when (parent?.getItemAtPosition(pos).toString().lowercase(Locale.getDefault())) { JPG.value -> setFileDetails(Bitmap.CompressFormat.JPEG, JPG) PNG.value -> setFileDetails(Bitmap.CompressFormat.PNG, PNG) ORA.value -> setFileDetails(Bitmap.CompressFormat.PNG, ORA) CATROBAT.value -> setFileDetails(Bitmap.CompressFormat.PNG, CATROBAT) } } - override fun onNothingSelected(parent: AdapterView<*>?) = Unit + + private fun setFileDetails(format: Bitmap.CompressFormat, type: FileType) { + specificFormatLayout.removeAllViews() + if (type == JPG) { + specificFormatLayout.addView(jpgView) + } + FileIO.compressFormat = format + FileIO.fileType = type + } + override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { - percentage.text = progress.toString().plus('%') + percentage.text = seekBar.context.getString(R.string.compress_quality_percentage, progress) FileIO.compressQuality = progress } - override fun onStartTrackingTouch(seekBar: SeekBar) = Unit override fun onStopTrackingTouch(seekBar: SeekBar) = Unit } diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/presenter/MainActivityPresenter.kt b/Paintroid/src/main/java/org/catrobat/paintroid/presenter/MainActivityPresenter.kt index 5c8430bfc5..62d423d4ae 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/presenter/MainActivityPresenter.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/presenter/MainActivityPresenter.kt @@ -70,6 +70,7 @@ import org.catrobat.paintroid.common.PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_ import org.catrobat.paintroid.common.PERMISSION_EXTERNAL_STORAGE_SAVE_COPY import org.catrobat.paintroid.common.PERMISSION_REQUEST_CODE_IMPORT_PICTURE import org.catrobat.paintroid.common.PERMISSION_REQUEST_CODE_REPLACE_PICTURE +import org.catrobat.paintroid.common.REQUEST_CODE_CREATE_DOCUMENT import org.catrobat.paintroid.common.REQUEST_CODE_IMPORT_PNG import org.catrobat.paintroid.common.REQUEST_CODE_INTRO import org.catrobat.paintroid.common.REQUEST_CODE_LOAD_PICTURE @@ -128,6 +129,8 @@ open class MainActivityPresenter( private var resetPerspectiveAfterNextCommand = false private var isExport = false private var wasImageLoaded = false + private var pendingSaveRequestCode: Int? = null + private val isImageUnchanged: Boolean get() = !commandManager.isUndoAvailable @@ -153,6 +156,10 @@ open class MainActivityPresenter( var clippingToolPaint = Paint() var toolOptionsViewWasShown = false + override fun startCreateDocument(intent: Intent, requestCode: Int) { + navigator.startCreateDocument(intent, requestCode) + } + override fun replaceImageClicked() { checkIfClippingToolNeedsAdjustment() switchBetweenVersions(PERMISSION_REQUEST_CODE_REPLACE_PICTURE, false) @@ -196,6 +203,7 @@ open class MainActivityPresenter( override fun saveBeforeNewImage() { checkIfClippingToolNeedsAdjustment() + pendingSaveRequestCode = SAVE_IMAGE_NEW_EMPTY navigator.showSaveImageInformationDialogWhenStandalone( PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY, imageNumber, @@ -235,11 +243,26 @@ open class MainActivityPresenter( } override fun saveImageClicked() { - navigator.showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE, - imageNumber, - false - ) + prepareFileIOForExistingUri(model.savedPictureUri) + navigator.showSaveInformationDialog(imageNumber, model.isOpenedFromCatroid) + } + + private fun prepareFileIOForExistingUri(uri: Uri?) { + uri?.let { FileIO.parseFileName(it, view.myContentResolver) } + + if (model.isOpenedFromCatroid) { + val nameFromUri = uri?.let(::getFileName) + FileIO.filename = nameFromUri ?: "image$imageNumber" + if (nameFromUri?.endsWith(FileIO.FileType.JPG.value, true) == true || + nameFromUri?.endsWith("jpeg", true) == true + ) { + FileIO.compressFormat = Bitmap.CompressFormat.JPEG + FileIO.fileType = FileIO.FileType.JPG + } else { + FileIO.compressFormat = Bitmap.CompressFormat.PNG + FileIO.fileType = FileIO.FileType.PNG + } + } } override fun shareImageClicked() { @@ -301,10 +324,6 @@ open class MainActivityPresenter( navigator.showFeedbackDialog() } - override fun showOverwriteDialog(permissionCode: Int, isExport: Boolean) { - navigator.showOverwriteDialog(permissionCode, isExport) - } - override fun showPngInformationDialog() { navigator.showPngInformationDialog() } @@ -445,6 +464,17 @@ open class MainActivityPresenter( data: Intent? ) { val imageUri = data?.data + + if (requestCode == REQUEST_CODE_CREATE_DOCUMENT) { + if (resultCode == Activity.RESULT_OK) { + val uri = data?.data + val saveCode = pendingSaveRequestCode ?: SAVE_IMAGE_DEFAULT + pendingSaveRequestCode = null + saveImageConfirmClicked(saveCode, uri) + } + return + } + when (requestCode) { REQUEST_CODE_IMPORT_PNG -> { if (resultCode != Activity.RESULT_OK) { @@ -489,74 +519,37 @@ open class MainActivityPresenter( permissions: Array, grantResults: IntArray ) { - if (permissions.size == 1 && (permissions[0] == Manifest.permission.READ_EXTERNAL_STORAGE || - permissions[0] == Manifest.permission.WRITE_EXTERNAL_STORAGE || - permissions[0] == Manifest.permission.READ_MEDIA_IMAGES)) { - if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - when (requestCode) { - PERMISSION_EXTERNAL_STORAGE_SAVE -> { - saveImageConfirmClicked( - SAVE_IMAGE_DEFAULT, - FileIO.storeImageUri - ) - checkForDefaultFilename() - showLikeUsDialogIfFirstTimeSave() - } - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH -> { - saveImageConfirmClicked( - SAVE_IMAGE_FINISH, - FileIO.storeImageUri - ) - checkForDefaultFilename() - } - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_LOAD_NEW -> { - saveImageConfirmClicked( - SAVE_IMAGE_LOAD_NEW, - FileIO.storeImageUri - ) - checkForDefaultFilename() - } - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY -> { - saveImageConfirmClicked( - SAVE_IMAGE_NEW_EMPTY, - FileIO.storeImageUri - ) - checkForDefaultFilename() - } - PERMISSION_EXTERNAL_STORAGE_SAVE_COPY -> { - saveCopyConfirmClicked( - SAVE_IMAGE_DEFAULT, - FileIO.storeImageUri - ) - checkForDefaultFilename() + when (requestCode) { + PERMISSION_REQUEST_CODE_REPLACE_PICTURE -> + if (grantResults.firstOrNull() == PackageManager.PERMISSION_GRANTED) { + if (isImageUnchanged || model.isSaved) { + navigator.startLoadImageActivity(REQUEST_CODE_LOAD_PICTURE) + } else { + navigator.showSaveBeforeLoadImageDialog() } - PERMISSION_REQUEST_CODE_REPLACE_PICTURE -> - if (isImageUnchanged || model.isSaved) { - navigator.startLoadImageActivity(REQUEST_CODE_LOAD_PICTURE) - } else { - navigator.showSaveBeforeLoadImageDialog() - } - PERMISSION_REQUEST_CODE_IMPORT_PICTURE -> navigator.startImportImageActivity( - REQUEST_CODE_IMPORT_PNG - ) - else -> view.superHandleRequestPermissionsResult( - requestCode, - permissions, - grantResults - ) + } else { + showPermissionRationaleOrDenied(permissions) } - } else { - if (navigator.isPermissionPermanentlyDenied(permissions)) { - navigator.showRequestPermanentlyDeniedPermissionRationaleDialog() + PERMISSION_REQUEST_CODE_IMPORT_PICTURE -> + if (grantResults.firstOrNull() == PackageManager.PERMISSION_GRANTED) { + navigator.startImportImageActivity(REQUEST_CODE_IMPORT_PNG) } else { - navigator.showRequestPermissionRationaleDialog( - PermissionInfoDialog.PermissionType.EXTERNAL_STORAGE, - permissions, requestCode - ) + showPermissionRationaleOrDenied(permissions) } - } + else -> + view.superHandleRequestPermissionsResult(requestCode, permissions, grantResults) + } + } + + private fun showPermissionRationaleOrDenied(permissions: Array) { + if (navigator.isPermissionPermanentlyDenied(permissions)) { + navigator.showRequestPermanentlyDeniedPermissionRationaleDialog() } else { - view.superHandleRequestPermissionsResult(requestCode, permissions, grantResults) + navigator.showRequestPermissionRationaleDialog( + PermissionInfoDialog.PermissionType.EXTERNAL_STORAGE, + permissions, + PERMISSION_REQUEST_CODE_REPLACE_PICTURE + ) } } @@ -1012,18 +1005,19 @@ open class MainActivityPresenter( if (model.isOpenedFromCatroid && !isExport) { navigator.showToast(R.string.saved, Toast.LENGTH_LONG) } else { - var msg: String? = context.getString(R.string.saved_to) - fileActivity?.let { - msg += getPathFromUri(it, uri) - } - navigator.showToast(msg ?: "null", Toast.LENGTH_LONG) + val name = uri.displayNameOrFallback(contentResolver) + val msg = context.getString(R.string.saved_to) + name + navigator.showToast(msg, Toast.LENGTH_LONG) } + showLikeUsDialogIfFirstTimeSave() + model.savedPictureUri = uri model.isSaved = true } if (!model.isOpenedFromCatroid || saveAsCopy) { navigator.broadcastAddPictureToGallery(uri) } + when (requestCode) { SAVE_IMAGE_NEW_EMPTY -> onNewImage() SAVE_IMAGE_DEFAULT -> { @@ -1212,6 +1206,22 @@ open class MainActivityPresenter( return "" } + private fun Uri.displayNameOrFallback(resolver: ContentResolver?): String { + val fallback = lastPathSegment.orEmpty() + if (resolver == null) return fallback + return try { + resolver.query(this, null, null, null, null)?.use { cursor -> + val idx = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME) + if (idx >= 0 && cursor.moveToFirst()) { + return cursor.getString(idx) + } + } + fallback + } catch (_: Exception) { + fallback + } + } + @SuppressWarnings("SwallowedException") private fun getDataColumn( context: Context, diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/ui/MainActivityNavigator.kt b/Paintroid/src/main/java/org/catrobat/paintroid/ui/MainActivityNavigator.kt index 998176f5bd..f97e1eb72f 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/ui/MainActivityNavigator.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/ui/MainActivityNavigator.kt @@ -51,7 +51,6 @@ import org.catrobat.paintroid.common.RATE_US_DIALOG_FRAGMENT_TAG import org.catrobat.paintroid.common.FEEDBACK_DIALOG_FRAGMENT_TAG import org.catrobat.paintroid.common.ZOOM_WINDOW_SETTINGS_DIALOG_FRAGMENT_TAG import org.catrobat.paintroid.common.ADVANCED_SETTINGS_DIALOG_FRAGMENT_TAG -import org.catrobat.paintroid.common.OVERWRITE_INFORMATION_DIALOG_TAG import org.catrobat.paintroid.common.PNG_INFORMATION_DIALOG_TAG import org.catrobat.paintroid.common.JPG_INFORMATION_DIALOG_TAG import org.catrobat.paintroid.common.ORA_INFORMATION_DIALOG_TAG @@ -70,7 +69,6 @@ import org.catrobat.paintroid.contract.MainActivityContracts import org.catrobat.paintroid.dialog.FeedbackDialog import org.catrobat.paintroid.dialog.ZoomWindowSettingsDialog import org.catrobat.paintroid.dialog.AdvancedSettingsDialog -import org.catrobat.paintroid.dialog.OverwriteDialog import org.catrobat.paintroid.dialog.PngInfoDialog import org.catrobat.paintroid.dialog.JpgInfoDialog import org.catrobat.paintroid.dialog.OraInfoDialog @@ -322,16 +320,6 @@ class MainActivityNavigator( ) } - override fun showOverwriteDialog(permissionCode: Int, isExport: Boolean) { - mainActivity.idlingResource.increment() - val overwriteDialog = OverwriteDialog.newInstance(permissionCode, isExport) - overwriteDialog.show( - mainActivity.supportFragmentManager, - OVERWRITE_INFORMATION_DIALOG_TAG - ) - mainActivity.idlingResource.decrement() - } - override fun showPngInformationDialog() { val pngInfoDialog = PngInfoDialog() pngInfoDialog.show( @@ -473,6 +461,14 @@ class MainActivityNavigator( showDialogFragmentSafely(dialog, SCALE_IMAGE_FRAGMENT_TAG) } + override fun showSaveInformationDialog(imageNumber: Int, isCatroid: Boolean) { + val dialog = SaveInformationDialog.newInstance(imageNumber, isCatroid) + dialog.show( + mainActivity.supportFragmentManager, + SAVE_INFORMATION_DIALOG_TAG + ) + } + @SuppressLint("VisibleForTests") override fun showSaveImageInformationDialogWhenStandalone( permissionCode: Int, @@ -497,18 +493,18 @@ class MainActivityNavigator( mainActivity.presenter.switchBetweenVersions(permissionCode, isExport) return } - var isStandard = false - if (permissionCode == PERMISSION_EXTERNAL_STORAGE_SAVE_COPY) { - isStandard = true - } val saveInfoDialog = - SaveInformationDialog.newInstance(permissionCode, imageNumber, isStandard, isExport) + SaveInformationDialog.newInstance(imageNumber, mainActivity.model.isOpenedFromCatroid) saveInfoDialog.show( mainActivity.supportFragmentManager, SAVE_INFORMATION_DIALOG_TAG ) } + override fun startCreateDocument(intent: Intent, requestCode: Int) { + mainActivity.startActivityForResult(intent, requestCode) + } + override fun showToolChangeToast(offset: Int, idRes: Int) { var offset = offset val toolNameToast = ToastFactory.makeText(mainActivity, idRes, Toast.LENGTH_SHORT) @@ -551,4 +547,8 @@ class MainActivityNavigator( mainActivity.toolPaint.previewPaint.alpha = it.drawPaint.alpha } } + + override fun startCreateDocumentIntent(intent: Intent, requestCode: Int) { + mainActivity.startActivityForResult(intent, requestCode) + } } diff --git a/Paintroid/src/main/java/org/catrobat/paintroid/ui/viewholder/TopBarViewHolder.kt b/Paintroid/src/main/java/org/catrobat/paintroid/ui/viewholder/TopBarViewHolder.kt index 43bc42fbc4..5dd55a2f1c 100644 --- a/Paintroid/src/main/java/org/catrobat/paintroid/ui/viewholder/TopBarViewHolder.kt +++ b/Paintroid/src/main/java/org/catrobat/paintroid/ui/viewholder/TopBarViewHolder.kt @@ -71,7 +71,6 @@ class TopBarViewHolder(val layout: ViewGroup) : MainActivityContracts.TopBarView override fun removeStandaloneMenuItems(menu: Menu?) { menu?.apply { removeItem(R.id.pocketpaint_options_save_image) - removeItem(R.id.pocketpaint_options_save_duplicate) removeItem(R.id.pocketpaint_options_new_image) removeItem(R.id.pocketpaint_options_rate_us) } diff --git a/Paintroid/src/main/res/menu/menu_pocketpaint_more_options.xml b/Paintroid/src/main/res/menu/menu_pocketpaint_more_options.xml index 67934c43cc..c5b6c45073 100644 --- a/Paintroid/src/main/res/menu/menu_pocketpaint_more_options.xml +++ b/Paintroid/src/main/res/menu/menu_pocketpaint_more_options.xml @@ -5,9 +5,6 @@ - diff --git a/Paintroid/src/main/res/values/string.xml b/Paintroid/src/main/res/values/string.xml index de2ea72fb6..f7be91bbd3 100644 --- a/Paintroid/src/main/res/values/string.xml +++ b/Paintroid/src/main/res/values/string.xml @@ -104,7 +104,6 @@ Image saved Copy saved to\n Copy saved - Quit Save Discard Cancel @@ -220,7 +219,6 @@ Intro does not support split screen. Overwrite File? - You are about to overwrite an existing image (hint: To save it as a new image, use the \"%s\" option). Save anyway? Do you like Pocket Paint? Would you like to rate Pocket Paint? @@ -250,4 +248,6 @@ Used to display a zoomed in part of the drawing surface + %1$d%% + diff --git a/Paintroid/src/test/java/org/catrobat/paintroid/test/presenter/MainActivityPresenterTest.kt b/Paintroid/src/test/java/org/catrobat/paintroid/test/presenter/MainActivityPresenterTest.kt index 6043aeb352..8c3e737546 100644 --- a/Paintroid/src/test/java/org/catrobat/paintroid/test/presenter/MainActivityPresenterTest.kt +++ b/Paintroid/src/test/java/org/catrobat/paintroid/test/presenter/MainActivityPresenterTest.kt @@ -32,7 +32,6 @@ import android.view.Menu import android.widget.Toast import androidx.core.view.GravityCompat import com.nhaarman.mockitokotlin2.any -import org.catrobat.paintroid.FileIO import org.catrobat.paintroid.MainActivity import org.catrobat.paintroid.R import org.catrobat.paintroid.UserPreferences @@ -44,12 +43,8 @@ import org.catrobat.paintroid.common.CREATE_FILE_DEFAULT import org.catrobat.paintroid.common.LOAD_IMAGE_CATROID import org.catrobat.paintroid.common.LOAD_IMAGE_DEFAULT import org.catrobat.paintroid.common.LOAD_IMAGE_IMPORT_PNG -import org.catrobat.paintroid.common.PERMISSION_EXTERNAL_STORAGE_SAVE -import org.catrobat.paintroid.common.PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH -import org.catrobat.paintroid.common.PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_LOAD_NEW -import org.catrobat.paintroid.common.PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY -import org.catrobat.paintroid.common.PERMISSION_EXTERNAL_STORAGE_SAVE_COPY import org.catrobat.paintroid.common.PERMISSION_REQUEST_CODE_REPLACE_PICTURE +import org.catrobat.paintroid.common.REQUEST_CODE_CREATE_DOCUMENT import org.catrobat.paintroid.common.REQUEST_CODE_INTRO import org.catrobat.paintroid.common.REQUEST_CODE_LOAD_PICTURE import org.catrobat.paintroid.common.RESULT_INTRO_MW_NOT_SUPPORTED @@ -63,7 +58,6 @@ import org.catrobat.paintroid.contract.MainActivityContracts.MainView import org.catrobat.paintroid.controller.ToolController import org.catrobat.paintroid.dialog.PermissionInfoDialog import org.catrobat.paintroid.iotasks.BitmapReturnValue -import org.catrobat.paintroid.iotasks.SaveImage.SaveImageCallback import org.catrobat.paintroid.model.Layer import org.catrobat.paintroid.model.LayerModel import org.catrobat.paintroid.presenter.MainActivityPresenter @@ -293,42 +287,6 @@ class MainActivityPresenterTest { Mockito.verifyNoMoreInteractions(interactor) } - @Test - fun testSaveCopyClickedThenSaveImage() { - presenter!!.saveCopyClicked(false) - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE_COPY, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE_COPY) - Mockito.verify(interactor).saveCopy( - presenter!!, SAVE_IMAGE_DEFAULT, workspace!!.layerModel, - commandSerializer!!, null, - context!! - ) - Mockito.verifyNoMoreInteractions(interactor) - } - - @Test - fun testSaveImageClickedThenSaveImage() { - presenter!!.saveImageClicked() - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE) - Mockito.verify(interactor).saveImage( - presenter!!, SAVE_IMAGE_DEFAULT, workspace!!.layerModel, - commandSerializer!!, null, - context!! - ) - Mockito.verifyNoMoreInteractions(interactor) - } - @Test fun testEnterFullscreenClicked() { presenter!!.enterHideButtonsClicked() @@ -956,227 +914,6 @@ class MainActivityPresenterTest { ) } - @Test - fun testHandlePermissionResultSavePermissionGranted() { - Mockito.`when`(workspace!!.layerModel).thenReturn( - Mockito.mock( - LayerModel::class.java - ) - ) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE, arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), intArrayOf(PackageManager.PERMISSION_GRANTED) - ) - Mockito.verify(interactor).saveImage( - any(), - ArgumentMatchers.eq(SAVE_IMAGE_DEFAULT), - any(), - any(), - ArgumentMatchers.eq(null), - any(), - ) - } - - @Test - fun testHandlePermissionResultSavePermissionPermanentlyDenied() { - val permission = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - Mockito.`when`(navigator!!.isPermissionPermanentlyDenied(permission)).thenReturn(true) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE, - permission, intArrayOf(PackageManager.PERMISSION_DENIED) - ) - Mockito.verify(navigator).showRequestPermanentlyDeniedPermissionRationaleDialog() - } - - @Test - fun testHandlePermissionResultSavePermissionNotGranted() { - val permission = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - Mockito.`when`(navigator!!.isPermissionPermanentlyDenied(permission)).thenReturn(false) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE, - permission, intArrayOf(PackageManager.PERMISSION_DENIED) - ) - Mockito.verify(navigator) - .showRequestPermissionRationaleDialog( - PermissionInfoDialog.PermissionType.EXTERNAL_STORAGE, - permission, - PERMISSION_EXTERNAL_STORAGE_SAVE - ) - } - - @Test - fun testHandlePermissionResultSaveCopyPermissionGranted() { - Mockito.`when`(workspace!!.layerModel).thenReturn( - Mockito.mock( - LayerModel::class.java - ) - ) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_COPY, arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), intArrayOf(PackageManager.PERMISSION_GRANTED) - ) - Mockito.verify(interactor).saveCopy( - any(), - ArgumentMatchers.eq(SAVE_IMAGE_DEFAULT), - any(), - any(), - ArgumentMatchers.eq(null), - any(), - ) - } - - @Test - fun testHandlePermissionResultSaveCopyPermissionNotGranted() { - val permission = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - Mockito.`when`(navigator!!.isPermissionPermanentlyDenied(permission)).thenReturn(false) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_COPY, - permission, intArrayOf(PackageManager.PERMISSION_DENIED) - ) - Mockito.verify(navigator) - .showRequestPermissionRationaleDialog( - PermissionInfoDialog.PermissionType.EXTERNAL_STORAGE, - permission, - PERMISSION_EXTERNAL_STORAGE_SAVE_COPY - ) - } - - @Test - fun testHandlePermissionResultSaveCopyPermissionPermanentlyDenied() { - val permission = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - Mockito.`when`(navigator!!.isPermissionPermanentlyDenied(permission)).thenReturn(true) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_COPY, - permission, intArrayOf(PackageManager.PERMISSION_DENIED) - ) - Mockito.verify(navigator).showRequestPermanentlyDeniedPermissionRationaleDialog() - } - - @Test - fun testHandlePermissionResultSaveBeforeFinishPermissionGranted() { - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH, arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), intArrayOf(PackageManager.PERMISSION_GRANTED) - ) - Mockito.verify(interactor).saveImage( - presenter!!, SAVE_IMAGE_FINISH, workspace!!.layerModel, - commandSerializer!!, FileIO.storeImageUri, - context!! - ) - } - - @Test - fun testHandlePermissionResultSaveBeforeFinishPermissionNotGranted() { - val permission = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - Mockito.`when`(navigator!!.isPermissionPermanentlyDenied(permission)).thenReturn(false) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH, - permission, intArrayOf(PackageManager.PERMISSION_DENIED) - ) - Mockito.verify(navigator) - .showRequestPermissionRationaleDialog( - PermissionInfoDialog.PermissionType.EXTERNAL_STORAGE, - permission, - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH - ) - } - - @Test - fun testHandlePermissionResultSaveBeforeFinishPermissionPermanentlyDenied() { - val permission = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - Mockito.`when`(navigator!!.isPermissionPermanentlyDenied(permission)).thenReturn(true) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH, - permission, intArrayOf(PackageManager.PERMISSION_DENIED) - ) - Mockito.verify(navigator).showRequestPermanentlyDeniedPermissionRationaleDialog() - } - - @Test - fun testHandlePermissionResultSaveBeforeLoadNewPermissionNotGranted() { - val permission = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - Mockito.`when`(navigator!!.isPermissionPermanentlyDenied(permission)).thenReturn(false) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_LOAD_NEW, - permission, intArrayOf(PackageManager.PERMISSION_DENIED) - ) - Mockito.verify(navigator) - .showRequestPermissionRationaleDialog( - PermissionInfoDialog.PermissionType.EXTERNAL_STORAGE, - permission, - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_LOAD_NEW - ) - } - - @Test - fun testHandlePermissionResultSaveBeforeLoadNewPermissionPermanentlyDenied() { - val permission = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - Mockito.`when`(navigator!!.isPermissionPermanentlyDenied(permission)).thenReturn(true) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_LOAD_NEW, - permission, intArrayOf(PackageManager.PERMISSION_DENIED) - ) - Mockito.verify(navigator).showRequestPermanentlyDeniedPermissionRationaleDialog() - } - - @Test - fun testHandlePermissionResultSaveBeforeLoadNewPermissionGranted() { - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_LOAD_NEW, arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), intArrayOf(PackageManager.PERMISSION_GRANTED) - ) - Mockito.verify(interactor).saveImage( - presenter!!, SAVE_IMAGE_LOAD_NEW, workspace!!.layerModel, - commandSerializer!!, FileIO.storeImageUri, - context!! - ) - } - - @Test - fun testHandlePermissionResultSaveBeforeNewEmptyPermissionNotGranted() { - val permission = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - Mockito.`when`(navigator!!.isPermissionPermanentlyDenied(permission)).thenReturn(false) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY, - permission, intArrayOf(PackageManager.PERMISSION_DENIED) - ) - Mockito.verify(navigator) - .showRequestPermissionRationaleDialog( - PermissionInfoDialog.PermissionType.EXTERNAL_STORAGE, - permission, - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY - ) - } - - @Test - fun testHandlePermissionResultSaveBeforeNewEmptyPermissionPermanentlyDenied() { - val permission = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) - Mockito.`when`(navigator!!.isPermissionPermanentlyDenied(permission)).thenReturn(true) - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY, - permission, intArrayOf(PackageManager.PERMISSION_DENIED) - ) - Mockito.verify(navigator).showRequestPermanentlyDeniedPermissionRationaleDialog() - } - - @Test - fun testHandlePermissionResultSaveBeforeNewEmptyPermissionGranted() { - presenter!!.handleRequestPermissionsResult( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY, arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), intArrayOf(PackageManager.PERMISSION_GRANTED) - ) - Mockito.verify(interactor).saveImage( - presenter!!, SAVE_IMAGE_NEW_EMPTY, workspace!!.layerModel, - commandSerializer!!, FileIO.storeImageUri, - context!! - ) - } - @Test fun testHandlePermissionResultWhenStoragePermissionGrantedAndRequestCodeUnknownThenCallBaseHandle() { presenter!!.handleRequestPermissionsResult( @@ -1225,243 +962,6 @@ class MainActivityPresenterTest { ) } - @Test - fun testOnNavigationItemSelectedSaveCopyPermissionGranted() { - presenter!!.saveCopyClicked(false) - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE_COPY, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE_COPY) - Mockito.verify(interactor).saveCopy( - presenter!!, SAVE_IMAGE_DEFAULT, workspace!!.layerModel, - commandSerializer!!, null, - context!! - ) - } - - @Test - fun testOnNavigationItemSelectedSaveCopyPermissionNotGranted() { - Mockito.`when`(navigator!!.doIHavePermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) - .thenReturn(false) - Mockito.`when`(navigator.isSdkAboveOrEqualM).thenReturn(false).thenReturn(true) - presenter!!.saveCopyClicked(false) - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE_COPY, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE_COPY) - Mockito.verify(navigator).askForPermission( - arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), PERMISSION_EXTERNAL_STORAGE_SAVE_COPY - ) - } - - @Test - fun testNoPermissionCheckOnSaveBeforeFinishWhenOpenedFromCatroid() { - Mockito.`when`(workspace!!.layerModel).thenReturn( - Mockito.mock( - LayerModel::class.java - ) - ) - Mockito.`when`(navigator!!.doIHavePermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) - .thenReturn(false) - Mockito.`when`(navigator.isSdkAboveOrEqualM).thenReturn(true) - Mockito.`when`(model!!.isOpenedFromCatroid).thenReturn(true) - presenter!!.saveBeforeFinish() - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH) - - Mockito.verify(interactor)?.saveImage( - any(), - anyInt(), - any(), - any(), - ArgumentMatchers.eq(null as Uri?), - any() - ) - } - - @Test - fun testPermissionCheckOnExportWhenOpenedFromCatroid() { - Mockito.`when`(navigator!!.doIHavePermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) - .thenReturn(false) - Mockito.`when`(navigator.isSdkAboveOrEqualM).thenReturn(false).thenReturn(true) - Mockito.`when`(model!!.isOpenedFromCatroid).thenReturn(true) - presenter!!.saveCopyClicked(false) - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE_COPY, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE_COPY) - Mockito.verify(navigator).askForPermission( - arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), PERMISSION_EXTERNAL_STORAGE_SAVE_COPY - ) - } - - @Test - fun testOnNavigationItemSelectedSavePermissionGranted() { - presenter!!.saveImageClicked() - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE) - Mockito.verify(interactor).saveImage( - presenter!!, SAVE_IMAGE_DEFAULT, workspace!!.layerModel, - commandSerializer!!, FileIO.storeImageUri, - context!! - ) - } - - @Test - fun testOnNavigationItemSelectedSavePermissionNotGranted() { - Mockito.`when`(navigator!!.doIHavePermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) - .thenReturn(false) - Mockito.`when`(navigator.isSdkAboveOrEqualM).thenReturn(false).thenReturn(true) - presenter!!.saveImageClicked() - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE) - Mockito.verify(navigator).askForPermission( - arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), PERMISSION_EXTERNAL_STORAGE_SAVE - ) - } - - @Test - fun testSaveAndFinishPermissionGranted() { - presenter!!.saveBeforeFinish() - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH) - Mockito.verify(interactor).saveImage( - presenter!!, SAVE_IMAGE_FINISH, workspace!!.layerModel, - commandSerializer!!, FileIO.storeImageUri, - context!! - ) - } - - @Test - fun testSaveAndFinishPermissionNotGranted() { - Mockito.`when`(navigator!!.doIHavePermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) - .thenReturn(false) - Mockito.`when`(navigator.isSdkAboveOrEqualM).thenReturn(false).thenReturn(true) - presenter!!.saveBeforeFinish() - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH) - Mockito.verify(navigator).askForPermission( - arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_FINISH - ) - } - - @Test - fun testSaveAndNewImagePermissionGranted() { - presenter!!.saveBeforeNewImage() - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY) - Mockito.verify(interactor).saveImage( - presenter!!, SAVE_IMAGE_NEW_EMPTY, workspace!!.layerModel, - commandSerializer!!, FileIO.storeImageUri, - context!! - ) - } - - @Test - fun testSaveAndNewImagePermissionNotGranted() { - Mockito.`when`(navigator!!.doIHavePermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) - .thenReturn(false) - Mockito.`when`(navigator.isSdkAboveOrEqualM).thenReturn(false).thenReturn(true) - presenter!!.saveBeforeNewImage() - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY) - Mockito.verify(navigator).askForPermission( - arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_NEW_EMPTY - ) - } - - @Test - fun testSaveAndLoadImagePermissionGranted() { - presenter!!.saveBeforeLoadImage() - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_LOAD_NEW, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_LOAD_NEW) - - Mockito.verify(interactor).saveImage( - presenter!!, SAVE_IMAGE_LOAD_NEW, workspace!!.layerModel, - commandSerializer!!, FileIO.storeImageUri, - context!! - ) - } - - @Test - fun testSaveAndLoadImagePermissionNotGranted() { - Mockito.`when`(navigator!!.doIHavePermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) - .thenReturn(false) - Mockito.`when`(navigator.isSdkAboveOrEqualM).thenReturn(false).thenReturn(true) - presenter!!.saveBeforeLoadImage() - Mockito.verify(navigator) - .showSaveImageInformationDialogWhenStandalone( - PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_LOAD_NEW, - sharedPreferences!!.preferenceImageNumber, - false - ) - presenter!!.switchBetweenVersions(PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_LOAD_NEW) - Mockito.verify(navigator).askForPermission( - arrayOf( - Manifest.permission.WRITE_EXTERNAL_STORAGE - ), PERMISSION_EXTERNAL_STORAGE_SAVE_CONFIRMED_LOAD_NEW - ) - } - @Test fun testOnSaveImagePostExecuteThenDismissProgressDialog() { presenter!!.onSaveImagePostExecute(0, null, false) @@ -1636,4 +1136,53 @@ class MainActivityPresenterTest { Mockito.verify(navigator) .showScaleImageRequestDialog(null, LOAD_IMAGE_IMPORT_PNG) } + + @Test + fun testSaveImageClickedThenShowDialog() { + presenter!!.saveImageClicked() + Mockito.verify(navigator)?.showSaveInformationDialog( + sharedPreferences!!.preferenceImageNumber, + false + ) + Mockito.verifyNoMoreInteractions(interactor) + } + + @Test + fun testSaveImageClickedLaunchesSaveDialogAndPicker() { + presenter!!.saveImageClicked() + Mockito.verify(navigator)!!.showSaveInformationDialog( + sharedPreferences!!.preferenceImageNumber, + false + ) + } + + @Test + fun testStartCreateDocumentDelegatesToNavigator() { + val fakeIntent = Intent(Intent.ACTION_CREATE_DOCUMENT) + presenter!!.startCreateDocument(fakeIntent, REQUEST_CODE_CREATE_DOCUMENT) + Mockito.verify(navigator)!!.startCreateDocument(fakeIntent, REQUEST_CODE_CREATE_DOCUMENT) + } + + @Test + fun testHandleActivityResultCreateDocumentOkCallsSaveImage() { + val uri = Mockito.mock(Uri::class.java) + val intent = Mockito.mock(Intent::class.java).apply { + Mockito.`when`(this.data).thenReturn(uri) + } + + presenter!!.handleActivityResult( + REQUEST_CODE_CREATE_DOCUMENT, + Activity.RESULT_OK, + intent + ) + + Mockito.verify(interactor)!!.saveImage( + presenter!!, + SAVE_IMAGE_DEFAULT, + workspace!!.layerModel, + commandSerializer!!, + uri, + context!! + ) + } }