Loading build.gradle +1 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ buildscript { propMinSdkVersion = 16 propTargetSdkVersion = propCompileSdkVersion propVersionCode = 1 propVersionName = '3.11.3' propVersionName = '3.13.11' kotlin_version = '1.2.21' support_libs = '27.0.2' } Loading commons/src/main/kotlin/com/simplemobiletools/commons/activities/AboutActivity.kt +18 −6 Original line number Diff line number Diff line Loading @@ -2,20 +2,18 @@ package com.simplemobiletools.commons.activities import android.content.ActivityNotFoundException import android.content.Intent import android.graphics.Color import android.os.Build import android.os.Bundle import android.text.Html import android.text.method.LinkMovementMethod import android.view.View import com.simplemobiletools.commons.R import com.simplemobiletools.commons.extensions.baseConfig import com.simplemobiletools.commons.extensions.isBlackAndWhiteTheme import com.simplemobiletools.commons.extensions.launchViewIntent import com.simplemobiletools.commons.extensions.updateTextColors import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.APP_FAQ import com.simplemobiletools.commons.helpers.APP_LICENSES import com.simplemobiletools.commons.helpers.APP_NAME import com.simplemobiletools.commons.helpers.APP_VERSION_NAME import com.simplemobiletools.commons.models.FAQItem import kotlinx.android.synthetic.main.activity_about.* import java.util.* Loading @@ -27,7 +25,7 @@ class AboutActivity : BaseSimpleActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_about) appName = intent.getStringExtra(APP_NAME) ?: "" linkColor = if (isBlackAndWhiteTheme()) Color.WHITE else baseConfig.primaryColor linkColor = getAdjustedPrimaryColor() } override fun onResume() { Loading @@ -36,6 +34,7 @@ class AboutActivity : BaseSimpleActivity() { setupWebsite() setupEmail() setupFAQ() setupMoreApps() setupRateUs() setupInvite() Loading Loading @@ -65,6 +64,19 @@ class AboutActivity : BaseSimpleActivity() { about_email.movementMethod = LinkMovementMethod.getInstance() } private fun setupFAQ() { val faqItems = intent.getSerializableExtra(APP_FAQ) as ArrayList<FAQItem> about_faq.beVisibleIf(faqItems.isNotEmpty()) about_faq.setOnClickListener { Intent(applicationContext, FAQActivity::class.java).apply { putExtra(APP_FAQ, faqItems) startActivity(this) } } about_faq.setTextColor(linkColor) about_faq.underlineText() } private fun setupMoreApps() { about_more_apps.setOnClickListener { launchViewIntent("https://play.google.com/store/apps/dev?id=9070296388022589266") Loading commons/src/main/kotlin/com/simplemobiletools/commons/activities/BaseSimpleActivity.kt +89 −39 Original line number Diff line number Diff line Loading @@ -20,12 +20,12 @@ import com.simplemobiletools.commons.R import com.simplemobiletools.commons.asynctasks.CopyMoveTask import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.FileConflictDialog import com.simplemobiletools.commons.dialogs.WritePermissionDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.APP_LICENSES import com.simplemobiletools.commons.helpers.APP_NAME import com.simplemobiletools.commons.helpers.APP_VERSION_NAME import com.simplemobiletools.commons.helpers.OPEN_DOCUMENT_TREE import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.interfaces.CopyMoveListener import com.simplemobiletools.commons.models.FAQItem import com.simplemobiletools.commons.models.FileDirItem import java.io.File import java.util.* Loading @@ -34,10 +34,12 @@ open class BaseSimpleActivity : AppCompatActivity() { var actionOnPermission: ((granted: Boolean) -> Unit)? = null var isAskingPermissions = false var useDynamicTheme = true private val GENERIC_PERM_HANDLER = 100 companion object { var funAfterSAFPermission: (() -> Unit)? = null var funAfterOTGPermission: ((success: Boolean) -> Unit)? = null } override fun onCreate(savedInstanceState: Bundle?) { Loading Loading @@ -73,6 +75,7 @@ open class BaseSimpleActivity : AppCompatActivity() { override fun onDestroy() { super.onDestroy() funAfterSAFPermission = null funAfterOTGPermission = null } override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { Loading Loading @@ -112,14 +115,34 @@ open class BaseSimpleActivity : AppCompatActivity() { override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { super.onActivityResult(requestCode, resultCode, resultData) if (requestCode == OPEN_DOCUMENT_TREE && resultCode == Activity.RESULT_OK && resultData != null) { if (isProperFolder(resultData.data)) { if (isProperSDFolder(resultData.data)) { if (resultData.dataString == baseConfig.OTGTreeUri) { toast(R.string.sd_card_otg_same) return } saveTreeUri(resultData) funAfterSAFPermission?.invoke() funAfterSAFPermission = null } else { toast(R.string.wrong_root_selected) val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) startActivityForResult(intent, requestCode) } } else if (requestCode == OPEN_DOCUMENT_TREE_OTG && resultCode == Activity.RESULT_OK && resultData != null) { if (isProperOTGFolder(resultData.data)) { if (resultData.dataString == baseConfig.treeUri) { funAfterOTGPermission?.invoke(false) toast(R.string.sd_card_otg_same) return } baseConfig.OTGTreeUri = resultData.dataString funAfterOTGPermission?.invoke(true) funAfterOTGPermission = null } else { toast(R.string.wrong_root_selected_otg) val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) startActivityForResult(intent, requestCode) } } } Loading @@ -132,7 +155,9 @@ open class BaseSimpleActivity : AppCompatActivity() { applicationContext.contentResolver.takePersistableUriPermission(treeUri, takeFlags) } private fun isProperFolder(uri: Uri) = isExternalStorageDocument(uri) && isRootUri(uri) && !isInternalStorage(uri) private fun isProperSDFolder(uri: Uri) = isExternalStorageDocument(uri) && isRootUri(uri) && !isInternalStorage(uri) private fun isProperOTGFolder(uri: Uri) = isExternalStorageDocument(uri) && isRootUri(uri) && !isInternalStorage(uri) @SuppressLint("NewApi") private fun isRootUri(uri: Uri) = DocumentsContract.getTreeDocumentId(uri).endsWith(":") Loading @@ -142,19 +167,20 @@ open class BaseSimpleActivity : AppCompatActivity() { private fun isExternalStorageDocument(uri: Uri) = "com.android.externalstorage.documents" == uri.authority fun startAboutActivity(appNameId: Int, licenseMask: Int, versionName: String) { fun startAboutActivity(appNameId: Int, licenseMask: Int, versionName: String, faqItems: ArrayList<FAQItem> = arrayListOf()) { Intent(applicationContext, AboutActivity::class.java).apply { putExtra(APP_NAME, getString(appNameId)) putExtra(APP_LICENSES, licenseMask) putExtra(APP_VERSION_NAME, versionName) putExtra(APP_FAQ, faqItems) startActivity(this) } } fun startCustomizationActivity() = startActivity(Intent(this, CustomizationActivity::class.java)) fun handleSAFDialog(file: File, callback: () -> Unit): Boolean { return if (isShowingSAFDialog(file, baseConfig.treeUri, OPEN_DOCUMENT_TREE)) { fun handleSAFDialog(path: String, callback: () -> Unit): Boolean { return if (!path.startsWith(OTG_PATH) && isShowingSAFDialog(path, baseConfig.treeUri, OPEN_DOCUMENT_TREE)) { funAfterSAFPermission = callback true } else { Loading @@ -163,46 +189,48 @@ open class BaseSimpleActivity : AppCompatActivity() { } } fun copyMoveFilesTo(files: ArrayList<File>, source: String, destination: String, isCopyOperation: Boolean, copyPhotoVideoOnly: Boolean, callback: () -> Unit) { fun copyMoveFilesTo(fileDirItems: ArrayList<FileDirItem>, source: String, destination: String, isCopyOperation: Boolean, copyPhotoVideoOnly: Boolean, copyHidden: Boolean, callback: () -> Unit) { if (source == destination) { toast(R.string.source_and_destination_same) return } val destinationFolder = File(destination) if (!destinationFolder.exists()) { if (!getDoesFilePathExist(destination)) { toast(R.string.invalid_destination) return } handleSAFDialog(destinationFolder) { handleSAFDialog(destination) { copyMoveCallback = callback if (isCopyOperation) { startCopyMove(files, destinationFolder, isCopyOperation, copyPhotoVideoOnly) startCopyMove(fileDirItems, destination, isCopyOperation, copyPhotoVideoOnly, copyHidden) } else { if (isPathOnSD(source) || isPathOnSD(destination) || files.first().isDirectory || isNougatPlus()) { handleSAFDialog(File(source)) { startCopyMove(files, destinationFolder, isCopyOperation, copyPhotoVideoOnly) if (source.startsWith(OTG_PATH) || destination.startsWith(OTG_PATH) || isPathOnSD(source) || isPathOnSD(destination) || fileDirItems.first().isDirectory || isNougatPlus()) { handleSAFDialog(source) { startCopyMove(fileDirItems, destination, isCopyOperation, copyPhotoVideoOnly, copyHidden) } } else { toast(R.string.moving) val updatedFiles = ArrayList<File>(files.size * 2) updatedFiles.addAll(files) val updatedFiles = ArrayList<FileDirItem>(fileDirItems.size * 2) updatedFiles.addAll(fileDirItems) try { for (oldFile in files) { val newFile = File(destinationFolder, oldFile.name) if (!newFile.exists() && oldFile.renameTo(newFile)) { val destinationFolder = File(destination) for (oldFileDirItem in fileDirItems) { val newFile = File(destinationFolder, oldFileDirItem.name) if (!newFile.exists() && File(oldFileDirItem.path).renameTo(newFile)) { if (!baseConfig.keepLastModified) { newFile.setLastModified(System.currentTimeMillis()) } updateInMediaStore(oldFile, newFile) updatedFiles.add(newFile) updateInMediaStore(oldFileDirItem.path, newFile.absolutePath) updatedFiles.add(newFile.toFileDirItem(applicationContext)) } } scanFiles(updatedFiles) { val updatedPaths = updatedFiles.map { it.path } as ArrayList<String> scanPaths(updatedPaths) { runOnUiThread { copyMoveListener.copySucceeded(false, files.size * 2 == updatedFiles.size) copyMoveListener.copySucceeded(false, fileDirItems.size * 2 == updatedFiles.size) } } } catch (e: Exception) { Loading @@ -213,15 +241,15 @@ open class BaseSimpleActivity : AppCompatActivity() { } } private fun startCopyMove(files: ArrayList<File>, destinationFolder: File, isCopyOperation: Boolean, copyPhotoVideoOnly: Boolean) { checkConflict(files, destinationFolder, 0, LinkedHashMap()) { private fun startCopyMove(files: ArrayList<FileDirItem>, destinationPath: String, isCopyOperation: Boolean, copyPhotoVideoOnly: Boolean, copyHidden: Boolean) { checkConflicts(files, destinationPath, 0, LinkedHashMap()) { toast(if (isCopyOperation) R.string.copying else R.string.moving) val pair = Pair(files, destinationFolder) CopyMoveTask(this, isCopyOperation, copyPhotoVideoOnly, it, copyMoveListener).execute(pair) val pair = Pair(files, destinationPath) CopyMoveTask(this, isCopyOperation, copyPhotoVideoOnly, it, copyMoveListener, copyHidden).execute(pair) } } private fun checkConflict(files: ArrayList<File>, destinationFolder: File, index: Int, conflictResolutions: LinkedHashMap<String, Int>, fun checkConflicts(files: ArrayList<FileDirItem>, destinationPath: String, index: Int, conflictResolutions: LinkedHashMap<String, Int>, callback: (resolutions: LinkedHashMap<String, Int>) -> Unit) { if (index == files.size) { callback(conflictResolutions) Loading @@ -229,20 +257,20 @@ open class BaseSimpleActivity : AppCompatActivity() { } val file = files[index] val newFile = File(destinationFolder, file.name) if (newFile.exists()) { FileConflictDialog(this, newFile) { resolution, applyForAll -> val newFileDirItem = FileDirItem("$destinationPath/${file.name}", file.name, file.isDirectory) if (getDoesFilePathExist(newFileDirItem.path)) { FileConflictDialog(this, newFileDirItem) { resolution, applyForAll -> if (applyForAll) { conflictResolutions.clear() conflictResolutions[""] = resolution checkConflict(files, destinationFolder, files.size, conflictResolutions, callback) checkConflicts(files, destinationPath, files.size, conflictResolutions, callback) } else { conflictResolutions[newFile.absolutePath] = resolution checkConflict(files, destinationFolder, index + 1, conflictResolutions, callback) conflictResolutions[newFileDirItem.path] = resolution checkConflicts(files, destinationPath, index + 1, conflictResolutions, callback) } } } else { checkConflict(files, destinationFolder, index + 1, conflictResolutions, callback) checkConflicts(files, destinationPath, index + 1, conflictResolutions, callback) } } Loading Loading @@ -281,4 +309,26 @@ open class BaseSimpleActivity : AppCompatActivity() { copyMoveCallback = null } } fun handleOTGPermission(callback: (success: Boolean) -> Unit) { if (baseConfig.OTGTreeUri.isNotEmpty()) { callback(true) return } funAfterOTGPermission = callback WritePermissionDialog(this, true) { Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { if (resolveActivity(packageManager) == null) { type = "*/*" } if (resolveActivity(packageManager) != null) { startActivityForResult(this, OPEN_DOCUMENT_TREE_OTG) } else { toast(R.string.unknown_error_occurred) } } } } } commons/src/main/kotlin/com/simplemobiletools/commons/activities/FAQActivity.kt 0 → 100644 +42 −0 Original line number Diff line number Diff line package com.simplemobiletools.commons.activities import android.os.Bundle import android.view.LayoutInflater import com.simplemobiletools.commons.R import com.simplemobiletools.commons.extensions.baseConfig import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor import com.simplemobiletools.commons.extensions.underlineText import com.simplemobiletools.commons.helpers.APP_FAQ import com.simplemobiletools.commons.models.FAQItem import kotlinx.android.synthetic.main.activity_faq.* import kotlinx.android.synthetic.main.license_faq_item.view.* import java.util.* class FAQActivity : BaseSimpleActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_faq) val titleColor = getAdjustedPrimaryColor() val textColor = baseConfig.textColor val inflater = LayoutInflater.from(this) val faqItems = intent.getSerializableExtra(APP_FAQ) as ArrayList<FAQItem> faqItems.forEach { val faqItem = it inflater.inflate(R.layout.license_faq_item, null).apply { license_faq_title.apply { text = if (faqItem.title is Int) getString(faqItem.title) else faqItem.title as String underlineText() setTextColor(titleColor) } license_faq_text.apply { text = if (faqItem.text is Int) getString(faqItem.text) else faqItem.text as String setTextColor(textColor) } faq_holder.addView(this) } } } } commons/src/main/kotlin/com/simplemobiletools/commons/activities/LicenseActivity.kt +16 −22 Original line number Diff line number Diff line package com.simplemobiletools.commons.activities import android.graphics.Color import android.os.Bundle import android.text.SpannableString import android.text.style.UnderlineSpan import android.view.LayoutInflater import com.simplemobiletools.commons.R import com.simplemobiletools.commons.extensions.baseConfig import com.simplemobiletools.commons.extensions.isBlackAndWhiteTheme import com.simplemobiletools.commons.extensions.launchViewIntent import com.simplemobiletools.commons.extensions.updateTextColors import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.models.License import kotlinx.android.synthetic.main.activity_license.* import kotlinx.android.synthetic.main.license_item.view.* import kotlinx.android.synthetic.main.license_faq_item.view.* class LicenseActivity : BaseSimpleActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_license) val linkColor = if (isBlackAndWhiteTheme()) Color.WHITE else baseConfig.primaryColor val linkColor = getAdjustedPrimaryColor() val textColor = baseConfig.textColor updateTextColors(licenses_holder) val inflater = LayoutInflater.from(this) Loading @@ -28,22 +23,21 @@ class LicenseActivity : BaseSimpleActivity() { val licenseMask = intent.getIntExtra(APP_LICENSES, 0) licenses.filter { licenseMask and it.id != 0 }.forEach { val license = it val view = inflater.inflate(R.layout.license_item, null) view.apply { license_title.text = getUnderlinedTitle(getString(license.titleId)) license_title.setOnClickListener { launchViewIntent(license.urlId) } license_title.setTextColor(linkColor) license_text.text = getString(license.textId) license_text.setTextColor(baseConfig.textColor) licenses_holder.addView(this) } inflater.inflate(R.layout.license_faq_item, null).apply { license_faq_title.apply { text = getString(license.titleId) underlineText() setTextColor(linkColor) setOnClickListener { launchViewIntent(license.urlId) } } private fun getUnderlinedTitle(title: String): SpannableString { val underlined = SpannableString(title) underlined.setSpan(UnderlineSpan(), 0, title.length, 0) return underlined license_faq_text.text = getString(license.textId) license_faq_text.setTextColor(textColor) licenses_holder.addView(this) } } } private fun initLicenses() = Loading Loading
build.gradle +1 −1 Original line number Diff line number Diff line Loading @@ -6,7 +6,7 @@ buildscript { propMinSdkVersion = 16 propTargetSdkVersion = propCompileSdkVersion propVersionCode = 1 propVersionName = '3.11.3' propVersionName = '3.13.11' kotlin_version = '1.2.21' support_libs = '27.0.2' } Loading
commons/src/main/kotlin/com/simplemobiletools/commons/activities/AboutActivity.kt +18 −6 Original line number Diff line number Diff line Loading @@ -2,20 +2,18 @@ package com.simplemobiletools.commons.activities import android.content.ActivityNotFoundException import android.content.Intent import android.graphics.Color import android.os.Build import android.os.Bundle import android.text.Html import android.text.method.LinkMovementMethod import android.view.View import com.simplemobiletools.commons.R import com.simplemobiletools.commons.extensions.baseConfig import com.simplemobiletools.commons.extensions.isBlackAndWhiteTheme import com.simplemobiletools.commons.extensions.launchViewIntent import com.simplemobiletools.commons.extensions.updateTextColors import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.APP_FAQ import com.simplemobiletools.commons.helpers.APP_LICENSES import com.simplemobiletools.commons.helpers.APP_NAME import com.simplemobiletools.commons.helpers.APP_VERSION_NAME import com.simplemobiletools.commons.models.FAQItem import kotlinx.android.synthetic.main.activity_about.* import java.util.* Loading @@ -27,7 +25,7 @@ class AboutActivity : BaseSimpleActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_about) appName = intent.getStringExtra(APP_NAME) ?: "" linkColor = if (isBlackAndWhiteTheme()) Color.WHITE else baseConfig.primaryColor linkColor = getAdjustedPrimaryColor() } override fun onResume() { Loading @@ -36,6 +34,7 @@ class AboutActivity : BaseSimpleActivity() { setupWebsite() setupEmail() setupFAQ() setupMoreApps() setupRateUs() setupInvite() Loading Loading @@ -65,6 +64,19 @@ class AboutActivity : BaseSimpleActivity() { about_email.movementMethod = LinkMovementMethod.getInstance() } private fun setupFAQ() { val faqItems = intent.getSerializableExtra(APP_FAQ) as ArrayList<FAQItem> about_faq.beVisibleIf(faqItems.isNotEmpty()) about_faq.setOnClickListener { Intent(applicationContext, FAQActivity::class.java).apply { putExtra(APP_FAQ, faqItems) startActivity(this) } } about_faq.setTextColor(linkColor) about_faq.underlineText() } private fun setupMoreApps() { about_more_apps.setOnClickListener { launchViewIntent("https://play.google.com/store/apps/dev?id=9070296388022589266") Loading
commons/src/main/kotlin/com/simplemobiletools/commons/activities/BaseSimpleActivity.kt +89 −39 Original line number Diff line number Diff line Loading @@ -20,12 +20,12 @@ import com.simplemobiletools.commons.R import com.simplemobiletools.commons.asynctasks.CopyMoveTask import com.simplemobiletools.commons.dialogs.ConfirmationDialog import com.simplemobiletools.commons.dialogs.FileConflictDialog import com.simplemobiletools.commons.dialogs.WritePermissionDialog import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.APP_LICENSES import com.simplemobiletools.commons.helpers.APP_NAME import com.simplemobiletools.commons.helpers.APP_VERSION_NAME import com.simplemobiletools.commons.helpers.OPEN_DOCUMENT_TREE import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.interfaces.CopyMoveListener import com.simplemobiletools.commons.models.FAQItem import com.simplemobiletools.commons.models.FileDirItem import java.io.File import java.util.* Loading @@ -34,10 +34,12 @@ open class BaseSimpleActivity : AppCompatActivity() { var actionOnPermission: ((granted: Boolean) -> Unit)? = null var isAskingPermissions = false var useDynamicTheme = true private val GENERIC_PERM_HANDLER = 100 companion object { var funAfterSAFPermission: (() -> Unit)? = null var funAfterOTGPermission: ((success: Boolean) -> Unit)? = null } override fun onCreate(savedInstanceState: Bundle?) { Loading Loading @@ -73,6 +75,7 @@ open class BaseSimpleActivity : AppCompatActivity() { override fun onDestroy() { super.onDestroy() funAfterSAFPermission = null funAfterOTGPermission = null } override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { Loading Loading @@ -112,14 +115,34 @@ open class BaseSimpleActivity : AppCompatActivity() { override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { super.onActivityResult(requestCode, resultCode, resultData) if (requestCode == OPEN_DOCUMENT_TREE && resultCode == Activity.RESULT_OK && resultData != null) { if (isProperFolder(resultData.data)) { if (isProperSDFolder(resultData.data)) { if (resultData.dataString == baseConfig.OTGTreeUri) { toast(R.string.sd_card_otg_same) return } saveTreeUri(resultData) funAfterSAFPermission?.invoke() funAfterSAFPermission = null } else { toast(R.string.wrong_root_selected) val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) startActivityForResult(intent, requestCode) } } else if (requestCode == OPEN_DOCUMENT_TREE_OTG && resultCode == Activity.RESULT_OK && resultData != null) { if (isProperOTGFolder(resultData.data)) { if (resultData.dataString == baseConfig.treeUri) { funAfterOTGPermission?.invoke(false) toast(R.string.sd_card_otg_same) return } baseConfig.OTGTreeUri = resultData.dataString funAfterOTGPermission?.invoke(true) funAfterOTGPermission = null } else { toast(R.string.wrong_root_selected_otg) val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) startActivityForResult(intent, requestCode) } } } Loading @@ -132,7 +155,9 @@ open class BaseSimpleActivity : AppCompatActivity() { applicationContext.contentResolver.takePersistableUriPermission(treeUri, takeFlags) } private fun isProperFolder(uri: Uri) = isExternalStorageDocument(uri) && isRootUri(uri) && !isInternalStorage(uri) private fun isProperSDFolder(uri: Uri) = isExternalStorageDocument(uri) && isRootUri(uri) && !isInternalStorage(uri) private fun isProperOTGFolder(uri: Uri) = isExternalStorageDocument(uri) && isRootUri(uri) && !isInternalStorage(uri) @SuppressLint("NewApi") private fun isRootUri(uri: Uri) = DocumentsContract.getTreeDocumentId(uri).endsWith(":") Loading @@ -142,19 +167,20 @@ open class BaseSimpleActivity : AppCompatActivity() { private fun isExternalStorageDocument(uri: Uri) = "com.android.externalstorage.documents" == uri.authority fun startAboutActivity(appNameId: Int, licenseMask: Int, versionName: String) { fun startAboutActivity(appNameId: Int, licenseMask: Int, versionName: String, faqItems: ArrayList<FAQItem> = arrayListOf()) { Intent(applicationContext, AboutActivity::class.java).apply { putExtra(APP_NAME, getString(appNameId)) putExtra(APP_LICENSES, licenseMask) putExtra(APP_VERSION_NAME, versionName) putExtra(APP_FAQ, faqItems) startActivity(this) } } fun startCustomizationActivity() = startActivity(Intent(this, CustomizationActivity::class.java)) fun handleSAFDialog(file: File, callback: () -> Unit): Boolean { return if (isShowingSAFDialog(file, baseConfig.treeUri, OPEN_DOCUMENT_TREE)) { fun handleSAFDialog(path: String, callback: () -> Unit): Boolean { return if (!path.startsWith(OTG_PATH) && isShowingSAFDialog(path, baseConfig.treeUri, OPEN_DOCUMENT_TREE)) { funAfterSAFPermission = callback true } else { Loading @@ -163,46 +189,48 @@ open class BaseSimpleActivity : AppCompatActivity() { } } fun copyMoveFilesTo(files: ArrayList<File>, source: String, destination: String, isCopyOperation: Boolean, copyPhotoVideoOnly: Boolean, callback: () -> Unit) { fun copyMoveFilesTo(fileDirItems: ArrayList<FileDirItem>, source: String, destination: String, isCopyOperation: Boolean, copyPhotoVideoOnly: Boolean, copyHidden: Boolean, callback: () -> Unit) { if (source == destination) { toast(R.string.source_and_destination_same) return } val destinationFolder = File(destination) if (!destinationFolder.exists()) { if (!getDoesFilePathExist(destination)) { toast(R.string.invalid_destination) return } handleSAFDialog(destinationFolder) { handleSAFDialog(destination) { copyMoveCallback = callback if (isCopyOperation) { startCopyMove(files, destinationFolder, isCopyOperation, copyPhotoVideoOnly) startCopyMove(fileDirItems, destination, isCopyOperation, copyPhotoVideoOnly, copyHidden) } else { if (isPathOnSD(source) || isPathOnSD(destination) || files.first().isDirectory || isNougatPlus()) { handleSAFDialog(File(source)) { startCopyMove(files, destinationFolder, isCopyOperation, copyPhotoVideoOnly) if (source.startsWith(OTG_PATH) || destination.startsWith(OTG_PATH) || isPathOnSD(source) || isPathOnSD(destination) || fileDirItems.first().isDirectory || isNougatPlus()) { handleSAFDialog(source) { startCopyMove(fileDirItems, destination, isCopyOperation, copyPhotoVideoOnly, copyHidden) } } else { toast(R.string.moving) val updatedFiles = ArrayList<File>(files.size * 2) updatedFiles.addAll(files) val updatedFiles = ArrayList<FileDirItem>(fileDirItems.size * 2) updatedFiles.addAll(fileDirItems) try { for (oldFile in files) { val newFile = File(destinationFolder, oldFile.name) if (!newFile.exists() && oldFile.renameTo(newFile)) { val destinationFolder = File(destination) for (oldFileDirItem in fileDirItems) { val newFile = File(destinationFolder, oldFileDirItem.name) if (!newFile.exists() && File(oldFileDirItem.path).renameTo(newFile)) { if (!baseConfig.keepLastModified) { newFile.setLastModified(System.currentTimeMillis()) } updateInMediaStore(oldFile, newFile) updatedFiles.add(newFile) updateInMediaStore(oldFileDirItem.path, newFile.absolutePath) updatedFiles.add(newFile.toFileDirItem(applicationContext)) } } scanFiles(updatedFiles) { val updatedPaths = updatedFiles.map { it.path } as ArrayList<String> scanPaths(updatedPaths) { runOnUiThread { copyMoveListener.copySucceeded(false, files.size * 2 == updatedFiles.size) copyMoveListener.copySucceeded(false, fileDirItems.size * 2 == updatedFiles.size) } } } catch (e: Exception) { Loading @@ -213,15 +241,15 @@ open class BaseSimpleActivity : AppCompatActivity() { } } private fun startCopyMove(files: ArrayList<File>, destinationFolder: File, isCopyOperation: Boolean, copyPhotoVideoOnly: Boolean) { checkConflict(files, destinationFolder, 0, LinkedHashMap()) { private fun startCopyMove(files: ArrayList<FileDirItem>, destinationPath: String, isCopyOperation: Boolean, copyPhotoVideoOnly: Boolean, copyHidden: Boolean) { checkConflicts(files, destinationPath, 0, LinkedHashMap()) { toast(if (isCopyOperation) R.string.copying else R.string.moving) val pair = Pair(files, destinationFolder) CopyMoveTask(this, isCopyOperation, copyPhotoVideoOnly, it, copyMoveListener).execute(pair) val pair = Pair(files, destinationPath) CopyMoveTask(this, isCopyOperation, copyPhotoVideoOnly, it, copyMoveListener, copyHidden).execute(pair) } } private fun checkConflict(files: ArrayList<File>, destinationFolder: File, index: Int, conflictResolutions: LinkedHashMap<String, Int>, fun checkConflicts(files: ArrayList<FileDirItem>, destinationPath: String, index: Int, conflictResolutions: LinkedHashMap<String, Int>, callback: (resolutions: LinkedHashMap<String, Int>) -> Unit) { if (index == files.size) { callback(conflictResolutions) Loading @@ -229,20 +257,20 @@ open class BaseSimpleActivity : AppCompatActivity() { } val file = files[index] val newFile = File(destinationFolder, file.name) if (newFile.exists()) { FileConflictDialog(this, newFile) { resolution, applyForAll -> val newFileDirItem = FileDirItem("$destinationPath/${file.name}", file.name, file.isDirectory) if (getDoesFilePathExist(newFileDirItem.path)) { FileConflictDialog(this, newFileDirItem) { resolution, applyForAll -> if (applyForAll) { conflictResolutions.clear() conflictResolutions[""] = resolution checkConflict(files, destinationFolder, files.size, conflictResolutions, callback) checkConflicts(files, destinationPath, files.size, conflictResolutions, callback) } else { conflictResolutions[newFile.absolutePath] = resolution checkConflict(files, destinationFolder, index + 1, conflictResolutions, callback) conflictResolutions[newFileDirItem.path] = resolution checkConflicts(files, destinationPath, index + 1, conflictResolutions, callback) } } } else { checkConflict(files, destinationFolder, index + 1, conflictResolutions, callback) checkConflicts(files, destinationPath, index + 1, conflictResolutions, callback) } } Loading Loading @@ -281,4 +309,26 @@ open class BaseSimpleActivity : AppCompatActivity() { copyMoveCallback = null } } fun handleOTGPermission(callback: (success: Boolean) -> Unit) { if (baseConfig.OTGTreeUri.isNotEmpty()) { callback(true) return } funAfterOTGPermission = callback WritePermissionDialog(this, true) { Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { if (resolveActivity(packageManager) == null) { type = "*/*" } if (resolveActivity(packageManager) != null) { startActivityForResult(this, OPEN_DOCUMENT_TREE_OTG) } else { toast(R.string.unknown_error_occurred) } } } } }
commons/src/main/kotlin/com/simplemobiletools/commons/activities/FAQActivity.kt 0 → 100644 +42 −0 Original line number Diff line number Diff line package com.simplemobiletools.commons.activities import android.os.Bundle import android.view.LayoutInflater import com.simplemobiletools.commons.R import com.simplemobiletools.commons.extensions.baseConfig import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor import com.simplemobiletools.commons.extensions.underlineText import com.simplemobiletools.commons.helpers.APP_FAQ import com.simplemobiletools.commons.models.FAQItem import kotlinx.android.synthetic.main.activity_faq.* import kotlinx.android.synthetic.main.license_faq_item.view.* import java.util.* class FAQActivity : BaseSimpleActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_faq) val titleColor = getAdjustedPrimaryColor() val textColor = baseConfig.textColor val inflater = LayoutInflater.from(this) val faqItems = intent.getSerializableExtra(APP_FAQ) as ArrayList<FAQItem> faqItems.forEach { val faqItem = it inflater.inflate(R.layout.license_faq_item, null).apply { license_faq_title.apply { text = if (faqItem.title is Int) getString(faqItem.title) else faqItem.title as String underlineText() setTextColor(titleColor) } license_faq_text.apply { text = if (faqItem.text is Int) getString(faqItem.text) else faqItem.text as String setTextColor(textColor) } faq_holder.addView(this) } } } }
commons/src/main/kotlin/com/simplemobiletools/commons/activities/LicenseActivity.kt +16 −22 Original line number Diff line number Diff line package com.simplemobiletools.commons.activities import android.graphics.Color import android.os.Bundle import android.text.SpannableString import android.text.style.UnderlineSpan import android.view.LayoutInflater import com.simplemobiletools.commons.R import com.simplemobiletools.commons.extensions.baseConfig import com.simplemobiletools.commons.extensions.isBlackAndWhiteTheme import com.simplemobiletools.commons.extensions.launchViewIntent import com.simplemobiletools.commons.extensions.updateTextColors import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.models.License import kotlinx.android.synthetic.main.activity_license.* import kotlinx.android.synthetic.main.license_item.view.* import kotlinx.android.synthetic.main.license_faq_item.view.* class LicenseActivity : BaseSimpleActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_license) val linkColor = if (isBlackAndWhiteTheme()) Color.WHITE else baseConfig.primaryColor val linkColor = getAdjustedPrimaryColor() val textColor = baseConfig.textColor updateTextColors(licenses_holder) val inflater = LayoutInflater.from(this) Loading @@ -28,22 +23,21 @@ class LicenseActivity : BaseSimpleActivity() { val licenseMask = intent.getIntExtra(APP_LICENSES, 0) licenses.filter { licenseMask and it.id != 0 }.forEach { val license = it val view = inflater.inflate(R.layout.license_item, null) view.apply { license_title.text = getUnderlinedTitle(getString(license.titleId)) license_title.setOnClickListener { launchViewIntent(license.urlId) } license_title.setTextColor(linkColor) license_text.text = getString(license.textId) license_text.setTextColor(baseConfig.textColor) licenses_holder.addView(this) } inflater.inflate(R.layout.license_faq_item, null).apply { license_faq_title.apply { text = getString(license.titleId) underlineText() setTextColor(linkColor) setOnClickListener { launchViewIntent(license.urlId) } } private fun getUnderlinedTitle(title: String): SpannableString { val underlined = SpannableString(title) underlined.setSpan(UnderlineSpan(), 0, title.length, 0) return underlined license_faq_text.text = getString(license.textId) license_faq_text.setTextColor(textColor) licenses_holder.addView(this) } } } private fun initLicenses() = Loading