diff --git a/commons/detekt-baseline.xml b/commons/detekt-baseline.xml index ea5a6eddb..e6561c733 100644 --- a/commons/detekt-baseline.xml +++ b/commons/detekt-baseline.xml @@ -6,8 +6,8 @@ ComplexCondition:Activity.kt$!isRPlus() || (isRPlus() && (hasProperStoredDocumentUriSdk30(path) || Environment.isExternalStorageManager())) ComplexCondition:Activity.kt$(!isRPlus() && isPathOnSD(path) && !isSDCardSetAsDefaultStorage() && (baseConfig.sdTreeUri.isEmpty() || !hasProperStoredTreeUri(false))) ComplexCondition:Activity.kt$startIntentForUriAction( uri, "android.intent.action.VIEW", ComponentName("com.google.android.documentsui", "com.android.documentsui.files.FilesActivity") ) || startIntentForUriAction( uri, "android.intent.action.VIEW", ComponentName("com.android.documentsui", "com.android.documentsui.files.FilesActivity") ) || startIntentForUriAction( uri, "android.intent.action.VIEW", ComponentName("com.android.documentsui", "com.android.documentsui.FilesActivity") ) || startIntentForUriAction(uri, "android.intent.action.VIEW", null) || startIntentForUriAction(uri, "android.provider.action.BROWSE", null) || startIntentForUriAction(uri, "android.provider.action.BROWSE_DOCUMENT_ROOT", null) - ComplexCondition:BaseSimpleActivity.kt$BaseSimpleActivity$isPathOnOTG(source) || isPathOnOTG(destination) || isPathOnSD(source) || isPathOnSD(destination) || isRestrictedSAFOnlyRoot(source) || isRestrictedSAFOnlyRoot(destination) || isAccessibleWithSAFSdk30(source) || isAccessibleWithSAFSdk30(destination) || fileDirItems.first().isDirectory - ComplexCondition:BaseSimpleActivity.kt$BaseSimpleActivity$requestCode == SELECT_EXPORT_SETTINGS_FILE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null + ComplexCondition:BaseSimpleActivity.kt$BaseSimpleActivity$isPathOnOTG(source) || isPathOnOTG(destination) || isPathOnSD(source) || isPathOnSD( destination ) || isRestrictedSAFOnlyRoot(source) || isRestrictedSAFOnlyRoot(destination) || isAccessibleWithSAFSdk30(source) || isAccessibleWithSAFSdk30(destination) || fileDirItems.first().isDirectory + ComplexCondition:BaseSimpleActivity.kt$BaseSimpleActivity$requestCode == SELECT_EXPORT_SETTINGS_FILE_INTENT && resultCode == RESULT_OK && resultData != null && resultData.data != null ComplexCondition:Contact.kt$Contact$firstValue.isEmpty() && firstName.isEmpty() && middleName.isEmpty() && surname.isEmpty() ComplexCondition:Contact.kt$Contact$secondValue.isEmpty() && other.firstName.isEmpty() && other.middleName.isEmpty() && other.surname.isEmpty() ComplexCondition:CustomizationActivity.kt$CustomizationActivity$curTextColor == getColor(value.textColorId) && curBackgroundColor == getColor(value.backgroundColorId) && curPrimaryColor == getColor(value.primaryColorId) && curAppIconColor == getColor(value.appIconColorId) @@ -124,11 +124,12 @@ LambdaParameterEventTrailing:ManageBlockedNumbersScreen.kt$onCopy LambdaParameterEventTrailing:ManageBlockedNumbersScreen.kt$onSelectAll LambdaParameterEventTrailing:SimpleDropDownMenuItem.kt$onClick - LargeClass:BaseSimpleActivity.kt$BaseSimpleActivity : AppCompatActivity + LargeClass:BaseSimpleActivity.kt$BaseSimpleActivity : EdgeToEdgeActivity LargeClass:ContactsHelper.kt$ContactsHelper LargeClass:CustomizationActivity.kt$CustomizationActivity : BaseSimpleActivity LongMethod:Activity-themes.kt$fun Activity.getThemeId(color: Int = baseConfig.primaryColor, showTransparentTop: Boolean = false) LongMethod:Activity.kt$private fun BaseSimpleActivity.renameCasually( oldPath: String, newPath: String, isRenamingMultipleFiles: Boolean, callback: ((success: Boolean, android30RenameFormat: Android30RenameFormat) -> Unit)? ) + LongMethod:BaseSimpleActivity.kt$BaseSimpleActivity$fun copyMoveFilesTo( fileDirItems: ArrayList<FileDirItem>, source: String, destination: String, isCopyOperation: Boolean, copyPhotoVideoOnly: Boolean, copyHidden: Boolean, callback: (destinationPath: String) -> Unit, ) LongMethod:BaseSimpleActivity.kt$BaseSimpleActivity$override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) LongMethod:ContactsHelper.kt$ContactsHelper$fun insertContact(contact: Contact): Boolean LongMethod:ContactsHelper.kt$ContactsHelper$fun updateContact(contact: Contact, photoUpdateStatus: Int): Boolean @@ -327,11 +328,6 @@ MagicNumber:BaseSimpleActivity.kt$BaseSimpleActivity$10 MagicNumber:BaseSimpleActivity.kt$BaseSimpleActivity$100 MagicNumber:BaseSimpleActivity.kt$BaseSimpleActivity$18 - MagicNumber:BaseSimpleActivity.kt$BaseSimpleActivity$300 - MagicNumber:BaseSimpleActivity.kt$BaseSimpleActivity$301 - MagicNumber:BaseSimpleActivity.kt$BaseSimpleActivity$302 - MagicNumber:BaseSimpleActivity.kt$BaseSimpleActivity$303 - MagicNumber:BaseSimpleActivity.kt$BaseSimpleActivity$304 MagicNumber:BaseSimpleActivity.kt$BaseSimpleActivity$50 MagicNumber:BaseSimpleActivity.kt$BaseSimpleActivity$9 MagicNumber:Bitmap.kt$80 @@ -938,7 +934,6 @@ MagicNumber:LineColorPickerDialog.kt$LineColorPickerDialog$16 MagicNumber:LineColorPickerDialog.kt$LineColorPickerDialog$17 MagicNumber:LineColorPickerDialog.kt$LineColorPickerDialog$18 - MagicNumber:LineColorPickerDialog.kt$LineColorPickerDialog$19 MagicNumber:LineColorPickerDialog.kt$LineColorPickerDialog$3 MagicNumber:LineColorPickerDialog.kt$LineColorPickerDialog$4 MagicNumber:LineColorPickerDialog.kt$LineColorPickerDialog$5 @@ -1034,30 +1029,9 @@ MaxLineLength:BaseSecurityTab.kt$BaseSecurityTab$updateTitle(context.getString(R.string.too_many_incorrect_attempts, count), context.getColor(R.color.md_red)) MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$// synchronous return value determines only if we are showing the SAF dialog, callback result tells if the SD or OTG permission has been granted MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$// this file is guaranteed to be on the internal storage, so just delete it this way - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$ActivityCompat.requestPermissions(this, permissionIds.map { getPermissionString(it) }.toTypedArray(), GENERIC_PERM_HANDLER) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER).putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$baseConfig.OTGPartition = baseConfig.OTGTreeUri.removeSuffix("%3A").substringAfterLast('/').trimEnd('/') - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$copyMoveListener.copySucceeded(false, fileCountToCopy <= updatedPaths.size, destination, updatedPaths.size == 1) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$copyMoveListener.copySucceeded(false, fileCountToCopy == 0, destination, false) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$fun MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$getConflictResolution(it, newFile.absolutePath) == CONFLICT_KEEP_BOTH -> newFile = getAlternativeFile(newFile) MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$getConflictResolution(it, newFile.absolutePath) == CONFLICT_SKIP -> fileCountToCopy-- MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$if - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$private fun isAndroidDir(uri: Uri) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$private fun isInternalStorage(uri: Uri) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$private fun isProperOTGRootFolder(uri: Uri) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$private fun isProperSDRootFolder(uri: Uri) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$putExtra(DocumentsContract.EXTRA_INITIAL_URI, createAndroidDataOrObbUri(checkedDocumentPath)) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$return - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$startCopyMove(fileDirItems, destination, isCopyOperation, copyPhotoVideoOnly, copyHidden) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$val - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$val drawableId = if (toolbarNavigationIcon == NavigationIcon.Cross) R.drawable.ic_cross_vector else R.drawable.ic_arrow_left_vector - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$val label = "You are using a fake version of the app. For your own safety download the original one from www.fossify.org. Thanks" - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$val recoverableSecurityException = securityException as? RecoverableSecurityException ?: throw securityException - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$var isMaterialActivity = false // by material activity we mean translucent navigation bar and opaque status and action bars - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$window.decorView.systemUiVisibility = window.decorView.systemUiVisibility.addBit(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$window.decorView.systemUiVisibility = window.decorView.systemUiVisibility.removeBit(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) - MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) MaxLineLength:BaseSimpleActivity.kt$BaseSimpleActivity$} MaxLineLength:BaseSplashActivity.kt$BaseSplashActivity$resources.getColor(if (isUsingSystemDarkTheme) R.color.theme_dark_background_color else R.color.theme_light_background_color) MaxLineLength:BaseSplashActivity.kt$BaseSplashActivity$textColor = resources.getColor(if (isUsingSystemDarkTheme) R.color.theme_dark_text_color else R.color.theme_light_text_color) @@ -1229,8 +1203,6 @@ MaxLineLength:LicenseScreen.kt$License(LICENSE_RTL, R.string.rtl_viewpager_title, R.string.rtl_viewpager_text, R.string.rtl_viewpager_url) MaxLineLength:LicenseScreen.kt$License(LICENSE_SUBSAMPLING, R.string.subsampling_title, R.string.subsampling_text, R.string.subsampling_url) MaxLineLength:LicenseScreen.kt$} - MaxLineLength:LineColorPickerDialog.kt$LineColorPickerDialog$val activity: BaseSimpleActivity - MaxLineLength:LineColorPickerDialog.kt$LineColorPickerDialog$val appIconIDs: ArrayList<Int>? = null MaxLineLength:LineColorPickerDialog.kt$if (isPrimaryColorPicker) dialogLineColorPickerBinding!!.secondaryLineColorPicker else dialogLineColorPickerBinding!!.primaryLineColorPicker MaxLineLength:LocalContactsHelper.kt$LocalContactsHelper$fun MaxLineLength:LocalContactsHelper.kt$LocalContactsHelper$return (contacts.map { convertLocalContactToContact(it, storedGroups) }.toMutableList() as? ArrayList<Contact>) ?: arrayListOf() @@ -1285,7 +1257,6 @@ MaxLineLength:MyRecyclerViewListAdapter.kt$MyRecyclerViewListAdapter.<no name provided>$override MaxLineLength:MyRecyclerViewListAdapter.kt$MyRecyclerViewListAdapter.<no name provided>$val backArrow = activity.findViewById<ImageView>(androidx.appcompat.R.id.action_mode_close_button) MaxLineLength:MyRecyclerViewListAdapter.kt$MyRecyclerViewListAdapter.ViewHolder$fun - MaxLineLength:MySearchMenu.kt$MySearchMenu$params.scrollFlags = params.scrollFlags.removeBit(LayoutParams.SCROLL_FLAG_SCROLL or LayoutParams.SCROLL_FLAG_ENTER_ALWAYS) MaxLineLength:PasswordTypesAdapter.kt$PasswordTypesAdapter$(view as SecurityTab).initTab(requiredHash, hashListener, scrollView, biometricPromptHost, showBiometricAuthentication) MaxLineLength:PreviewExtensions.kt$MyDevicesDarkOnly$@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_2, name = "5.0 inches dark", group = DARK) MaxLineLength:PreviewExtensions.kt$MyDevicesDarkOnly$@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, device = Devices.PIXEL_2_XL, name = "6.0 inches dark", group = DARK) @@ -1347,7 +1318,6 @@ MaxLineLength:VcfExporter.kt$VcfExporter$val MaxLineLength:VcfExporter.kt$VcfExporter$val photoByteArray = MediaStore.Images.Media.getBitmap(activity.contentResolver, Uri.parse(contact.thumbnailUri)).getByteArray() MaxLineLength:View.kt$fun View.performHapticFeedback() - MaxLineLength:Window.kt$decorView.systemUiVisibility = decorView.systemUiVisibility.removeBit(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) MaxLineLength:WritePermissionDialog.kt$. MaxLineLength:WritePermissionDialog.kt$WritePermissionDialog$Html.fromHtml(activity.getString(R.string.confirm_storage_access_android_text_specific, humanizedPath)) MaxLineLength:WritePermissionDialog.kt$WritePermissionDialog$class @@ -1507,7 +1477,7 @@ TooManyFunctions:Activity.kt$org.fossify.commons.extensions.Activity.kt TooManyFunctions:BaseConfig.kt$BaseConfig TooManyFunctions:BaseSecurityTab.kt$BaseSecurityTab : ConstraintLayoutSecurityTab - TooManyFunctions:BaseSimpleActivity.kt$BaseSimpleActivity : AppCompatActivity + TooManyFunctions:BaseSimpleActivity.kt$BaseSimpleActivity : EdgeToEdgeActivity TooManyFunctions:BottomActionMenuView.kt$BottomActionMenuView : LinearLayout TooManyFunctions:Breadcrumbs.kt$Breadcrumbs : HorizontalScrollView TooManyFunctions:ComposeExtensions.kt$org.fossify.commons.compose.extensions.ComposeExtensions.kt @@ -1609,12 +1579,6 @@ VariableNaming:BaseConfig.kt$BaseConfig$var OTGPartition: String get() = prefs.getString(OTG_PARTITION, "")!! set(OTGPartition) = prefs.edit().putString(OTG_PARTITION, OTGPartition).apply() VariableNaming:BaseConfig.kt$BaseConfig$var OTGPath: String get() = prefs.getString(OTG_REAL_PATH, "")!! set(OTGPath) = prefs.edit().putString(OTG_REAL_PATH, OTGPath).apply() VariableNaming:BaseConfig.kt$BaseConfig$var OTGTreeUri: String get() = prefs.getString(OTG_TREE_URI, "")!! set(OTGTreeUri) = prefs.edit().putString(OTG_TREE_URI, OTGTreeUri).apply() - VariableNaming:BaseSimpleActivity.kt$BaseSimpleActivity$private val DELETE_FILE_SDK_30_HANDLER = 300 - VariableNaming:BaseSimpleActivity.kt$BaseSimpleActivity$private val GENERIC_PERM_HANDLER = 100 - VariableNaming:BaseSimpleActivity.kt$BaseSimpleActivity$private val MANAGE_MEDIA_RC = 303 - VariableNaming:BaseSimpleActivity.kt$BaseSimpleActivity$private val RECOVERABLE_SECURITY_HANDLER = 301 - VariableNaming:BaseSimpleActivity.kt$BaseSimpleActivity$private val TRASH_FILE_SDK_30_HANDLER = 304 - VariableNaming:BaseSimpleActivity.kt$BaseSimpleActivity$private val UPDATE_FILE_SDK_30_HANDLER = 302 VariableNaming:ContactsHelper.kt$ContactsHelper$private val BATCH_SIZE = 50 VariableNaming:ContactsHelper.kt$ContactsHelper$val IDsString = TextUtils.join(",", relevantGroupIDs) VariableNaming:ContactsHelper.kt$ContactsHelper$val IM = cursor.getStringValue(CommonDataKinds.Im.DATA) ?: return@queryCursor @@ -1628,10 +1592,6 @@ VariableNaming:FingerprintTab.kt$FingerprintTab$private val RECHECK_PERIOD = 3000L VariableNaming:Int.kt$val DARK_FACTOR = factor VariableNaming:Int.kt$val LIGHT_FACTOR = factor - VariableNaming:LineColorPickerDialog.kt$LineColorPickerDialog$private val DEFAULT_COLOR_VALUE = activity.resources.getColor(R.color.color_primary) - VariableNaming:LineColorPickerDialog.kt$LineColorPickerDialog$private val DEFAULT_PRIMARY_COLOR_INDEX = 9 - VariableNaming:LineColorPickerDialog.kt$LineColorPickerDialog$private val DEFAULT_SECONDARY_COLOR_INDEX = 8 - VariableNaming:LineColorPickerDialog.kt$LineColorPickerDialog$private val PRIMARY_COLORS_COUNT = 19 VariableNaming:MyRecyclerView.kt$MyRecyclerView$private val AUTO_SCROLL_DELAY = 25L VariableNaming:MyRecyclerView.kt$MyRecyclerView.GestureListener$private val ZOOM_IN_THRESHOLD = -0.4f VariableNaming:MyRecyclerView.kt$MyRecyclerView.GestureListener$private val ZOOM_OUT_THRESHOLD = 0.15f @@ -1646,7 +1606,6 @@ WildcardImport:AddBlockedNumberDialog.kt$import androidx.compose.runtime.* WildcardImport:AddBlockedNumberDialog.kt$import org.fossify.commons.compose.alert_dialog.* WildcardImport:AlertDialogState.kt$import androidx.compose.runtime.* - WildcardImport:AppLockActivity.kt$import org.fossify.commons.extensions.* WildcardImport:AppSideloadedDialog.kt$import org.fossify.commons.compose.alert_dialog.* WildcardImport:AppSideloadedDialog.kt$import org.fossify.commons.extensions.* WildcardImport:AppTheme.kt$import androidx.compose.runtime.* @@ -1730,7 +1689,6 @@ WildcardImport:MyRecyclerViewAdapter.kt$import org.fossify.commons.extensions.* WildcardImport:MyRecyclerViewListAdapter.kt$import android.view.* WildcardImport:MyRecyclerViewListAdapter.kt$import org.fossify.commons.extensions.* - WildcardImport:MySearchMenu.kt$import org.fossify.commons.extensions.* WildcardImport:OpenDeviceSettingsDialog.kt$import org.fossify.commons.compose.alert_dialog.* WildcardImport:PermissionRequiredDialog.kt$import org.fossify.commons.compose.alert_dialog.* WildcardImport:PinTab.kt$import org.fossify.commons.extensions.* diff --git a/commons/lint-baseline.xml b/commons/lint-baseline.xml index 518d9790f..29e819b34 100644 --- a/commons/lint-baseline.xml +++ b/commons/lint-baseline.xml @@ -18,17 +18,6 @@ message="Reference from @style/PinNumberStyle.Base to style/PinNumberStyle here"/> - - - - @@ -69,7 +58,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -80,7 +69,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -91,7 +80,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -102,7 +91,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -113,7 +102,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -124,7 +113,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -216,17 +205,6 @@ column="15"/> - - - - @@ -300,7 +278,7 @@ errorLine2=" ~~~~"> @@ -354,7 +332,7 @@ errorLine1="distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip" errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -365,7 +343,7 @@ errorLine1="gradlePlugins-agp = "8.11.1"" errorLine2=" ~~~~~~~~"> @@ -376,7 +354,7 @@ errorLine1="gradlePlugins-agp = "8.11.1"" errorLine2=" ~~~~~~~~"> @@ -427,79 +405,13 @@ + message="A newer version of com.google.devtools.ksp than 2.2.20-2.0.3 is available: 2.2.20-2.0.4" + errorLine1="ksp = "2.2.20-2.0.3"" + errorLine2=" ~~~~~~~~~~~~~~"> - - - - - - - - - - - - - - - - - - - - - - - - + file="$HOME/Projects/Fossify/FossifyOrg/libs/Commons/gradle/libs.versions.toml" + line="7" + column="7"/> - - - - @@ -552,62 +453,62 @@ errorLine1="compose = "1.7.6"" errorLine2=" ~~~~~~~"> @@ -618,7 +519,7 @@ errorLine1="compose = "1.7.6"" errorLine2=" ~~~~~~~"> @@ -629,20 +530,86 @@ errorLine1="composeMaterial3 = "1.3.2"" errorLine2=" ~~~~~~~"> + message="A newer version of androidx.room:room-compiler than 2.8.1 is available: 2.8.3" + errorLine1="room = "2.8.1"" + errorLine2=" ~~~~~~~"> + file="$HOME/Projects/Fossify/FossifyOrg/libs/Commons/gradle/libs.versions.toml" + line="40" + column="8"/> + + + + + + + + + + + + + + + + + + + + + + + + @@ -662,22 +629,11 @@ errorLine1="reprint = "2cb206415d"" errorLine2=" ~~~~~~~~~~~~"> - - - - + + + + @@ -817,7 +784,7 @@ errorLine2=" ~~~~~~~~~~~~~"> @@ -828,7 +795,7 @@ errorLine2=" ~~~~~~~~~~~~~"> @@ -894,7 +861,7 @@ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -905,7 +872,7 @@ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -916,7 +883,7 @@ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -927,7 +894,7 @@ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -971,7 +938,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -982,7 +949,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -993,7 +960,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1004,7 +971,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1026,7 +993,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1037,7 +1004,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -2900,6 +2867,17 @@ column="5"/> + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + @@ -16156,7 +16200,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -16167,7 +16211,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -16178,7 +16222,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -16222,7 +16266,7 @@ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -16233,7 +16277,7 @@ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -16244,7 +16288,7 @@ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -16255,7 +16299,7 @@ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -16266,7 +16310,7 @@ errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -16303,17 +16347,6 @@ column="5"/> - - - - + errorLine1=" <EditText" + errorLine2=" ~~~~~~~~"> + line="35" + column="14"/> + errorLine1=" <EditText" + errorLine2=" ~~~~~~~~"> - - - - + line="35" + column="14"/> @@ -18530,7 +18552,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -18541,7 +18563,7 @@ errorLine2=" ~~~~~~~~~~~~~~~"> @@ -18552,7 +18574,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> @@ -18563,7 +18585,7 @@ errorLine2=" ~~~~~~~~~~~~~~~"> @@ -19047,7 +19069,7 @@ errorLine2=" ~~~~~~~~~"> @@ -19058,7 +19080,7 @@ errorLine2=" ~~~~~~~~~"> @@ -19069,7 +19091,7 @@ errorLine2=" ~~~~~~~~~"> @@ -19080,7 +19102,7 @@ errorLine2=" ~~~~~~~~~"> @@ -19245,7 +19267,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -19256,7 +19278,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -19267,7 +19289,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -19278,7 +19300,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -19289,7 +19311,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -19337,26 +19359,4 @@ column="5"/> - - - - - - - - diff --git a/commons/src/main/kotlin/org/fossify/commons/activities/AppLockActivity.kt b/commons/src/main/kotlin/org/fossify/commons/activities/AppLockActivity.kt index 6dc18661b..4b226fd6e 100644 --- a/commons/src/main/kotlin/org/fossify/commons/activities/AppLockActivity.kt +++ b/commons/src/main/kotlin/org/fossify/commons/activities/AppLockActivity.kt @@ -4,17 +4,23 @@ import android.app.Activity import android.content.Intent import android.os.Bundle import androidx.activity.addCallback -import androidx.appcompat.app.AppCompatActivity import androidx.biometric.auth.AuthPromptHost import org.fossify.commons.R import org.fossify.commons.adapters.AppLockAdapter import org.fossify.commons.databinding.ActivityAppLockBinding -import org.fossify.commons.extensions.* +import org.fossify.commons.extensions.appLockManager +import org.fossify.commons.extensions.baseConfig +import org.fossify.commons.extensions.getProperBackgroundColor +import org.fossify.commons.extensions.getThemeId +import org.fossify.commons.extensions.isBiometricAuthSupported +import org.fossify.commons.extensions.onGlobalLayout +import org.fossify.commons.extensions.overrideActivityTransition +import org.fossify.commons.extensions.viewBinding import org.fossify.commons.helpers.PROTECTION_FINGERPRINT import org.fossify.commons.helpers.isRPlus import org.fossify.commons.interfaces.HashListener -class AppLockActivity : AppCompatActivity(), HashListener { +class AppLockActivity : EdgeToEdgeActivity(), HashListener { private val binding by viewBinding(ActivityAppLockBinding::inflate) @@ -24,6 +30,7 @@ class AppLockActivity : AppCompatActivity(), HashListener { super.onCreate(savedInstanceState) setContentView(binding.root) + setupEdgeToEdge(padBottomSystem = listOf(binding.viewPager)) onBackPressedDispatcher.addCallback(owner = this) { appLockManager.lock() finishAffinity() @@ -77,8 +84,6 @@ class AppLockActivity : AppCompatActivity(), HashListener { private fun setupTheme() { setTheme(getThemeId(showTransparentTop = true)) with(getProperBackgroundColor()) { - window.updateStatusBarColors(this) - window.updateNavigationBarColors(this) window.decorView.setBackgroundColor(this) } } diff --git a/commons/src/main/kotlin/org/fossify/commons/activities/BaseSimpleActivity.kt b/commons/src/main/kotlin/org/fossify/commons/activities/BaseSimpleActivity.kt index 9a7086ced..34eb2722b 100644 --- a/commons/src/main/kotlin/org/fossify/commons/activities/BaseSimpleActivity.kt +++ b/commons/src/main/kotlin/org/fossify/commons/activities/BaseSimpleActivity.kt @@ -1,10 +1,6 @@ package org.fossify.commons.activities -import android.animation.ArgbEvaluator -import android.animation.ObjectAnimator -import android.animation.ValueAnimator import android.annotation.SuppressLint -import android.app.Activity import android.app.ActivityManager import android.app.RecoverableSecurityException import android.app.role.RoleManager @@ -25,35 +21,27 @@ import android.telecom.TelecomManager import android.view.Menu import android.view.MenuItem import android.view.View -import android.view.WindowManager import android.widget.EditText -import android.widget.FrameLayout import android.widget.ImageView import android.widget.Toast +import androidx.activity.OnBackPressedCallback +import androidx.activity.addCallback import androidx.annotation.RequiresApi -import androidx.appcompat.app.AppCompatActivity -import androidx.appcompat.widget.Toolbar -import androidx.coordinatorlayout.widget.CoordinatorLayout -import androidx.core.animation.doOnEnd import androidx.core.app.ActivityCompat import androidx.core.net.toUri import androidx.core.util.Pair -import androidx.core.view.ScrollingView -import androidx.core.view.WindowInsetsCompat +import androidx.core.view.ViewCompat +import androidx.core.view.WindowCompat import androidx.core.view.get import androidx.core.view.size -import androidx.core.widget.NestedScrollView -import androidx.recyclerview.widget.RecyclerView import org.fossify.commons.R import org.fossify.commons.asynctasks.CopyMoveTask -import org.fossify.commons.compose.extensions.DEVELOPER_PLAY_STORE_URL import org.fossify.commons.dialogs.ConfirmationDialog import org.fossify.commons.dialogs.ExportSettingsDialog import org.fossify.commons.dialogs.FileConflictDialog import org.fossify.commons.dialogs.PermissionRequiredDialog import org.fossify.commons.dialogs.WritePermissionDialog import org.fossify.commons.dialogs.WritePermissionDialog.WritePermissionDialogMode -import org.fossify.commons.extensions.addBit import org.fossify.commons.extensions.adjustAlpha import org.fossify.commons.extensions.applyColorFilter import org.fossify.commons.extensions.baseConfig @@ -67,7 +55,6 @@ import org.fossify.commons.extensions.formatSize import org.fossify.commons.extensions.getAppIconColors import org.fossify.commons.extensions.getAvailableStorageB import org.fossify.commons.extensions.getColoredDrawableWithColor -import org.fossify.commons.extensions.getColoredMaterialStatusBarColor import org.fossify.commons.extensions.getContrastColor import org.fossify.commons.extensions.getCurrentFormattedDateTime import org.fossify.commons.extensions.getDoesFilePathExist @@ -93,22 +80,14 @@ import org.fossify.commons.extensions.isShowingOTGDialog import org.fossify.commons.extensions.isShowingSAFCreateDocumentDialogSdk30 import org.fossify.commons.extensions.isShowingSAFDialog import org.fossify.commons.extensions.isShowingSAFDialogSdk30 -import org.fossify.commons.extensions.isUsingGestureNavigation -import org.fossify.commons.extensions.launchViewIntent -import org.fossify.commons.extensions.navigationBarHeight -import org.fossify.commons.extensions.onApplyWindowInsets import org.fossify.commons.extensions.openDeviceSettings import org.fossify.commons.extensions.openNotificationSettings import org.fossify.commons.extensions.random -import org.fossify.commons.extensions.removeBit import org.fossify.commons.extensions.showErrorToast -import org.fossify.commons.extensions.statusBarHeight +import org.fossify.commons.extensions.showModdedAppWarning import org.fossify.commons.extensions.storeAndroidTreeUri -import org.fossify.commons.extensions.toInt import org.fossify.commons.extensions.toast -import org.fossify.commons.extensions.updateNavigationBarColors import org.fossify.commons.extensions.updateOTGPathFromPartition -import org.fossify.commons.extensions.updateStatusBarColors import org.fossify.commons.extensions.writeLn import org.fossify.commons.helpers.APP_FAQ import org.fossify.commons.helpers.APP_ICON_IDS @@ -122,7 +101,6 @@ import org.fossify.commons.helpers.CONFLICT_KEEP_BOTH import org.fossify.commons.helpers.CONFLICT_SKIP import org.fossify.commons.helpers.CREATE_DOCUMENT_SDK_30 import org.fossify.commons.helpers.EXTERNAL_STORAGE_PROVIDER_AUTHORITY -import org.fossify.commons.helpers.HIGHER_ALPHA import org.fossify.commons.helpers.MEDIUM_ALPHA import org.fossify.commons.helpers.MyContextWrapper import org.fossify.commons.helpers.NavigationIcon @@ -148,36 +126,29 @@ import org.fossify.commons.helpers.sumByLong import org.fossify.commons.interfaces.CopyMoveListener import org.fossify.commons.models.FAQItem import org.fossify.commons.models.FileDirItem +import org.fossify.commons.views.MyAppBarLayout import java.io.File import java.io.OutputStream import java.util.regex.Pattern -abstract class BaseSimpleActivity : AppCompatActivity() { - var materialScrollColorAnimation: ValueAnimator? = null +abstract class BaseSimpleActivity : EdgeToEdgeActivity() { var copyMoveCallback: ((destinationPath: String) -> Unit)? = null var actionOnPermission: ((granted: Boolean) -> Unit)? = null var isAskingPermissions = false var useDynamicTheme = true - var showTransparentTop = false - var isMaterialActivity = false // by material activity we mean translucent navigation bar and opaque status and action bars var checkedDocumentPath = "" - var currentScrollY = 0 var configItemsToExport = LinkedHashMap() - private var mainCoordinatorLayout: CoordinatorLayout? = null - private var nestedView: View? = null - private var scrollingView: ScrollingView? = null - private var toolbar: Toolbar? = null - private var useTransparentNavigation = false - private var useTopSearchMenu = false - private val GENERIC_PERM_HANDLER = 100 - private val DELETE_FILE_SDK_30_HANDLER = 300 - private val RECOVERABLE_SECURITY_HANDLER = 301 - private val UPDATE_FILE_SDK_30_HANDLER = 302 - private val MANAGE_MEDIA_RC = 303 - private val TRASH_FILE_SDK_30_HANDLER = 304 + private lateinit var backCallback: OnBackPressedCallback companion object { + private const val GENERIC_PERM_HANDLER = 100 + private const val DELETE_FILE_SDK_30_HANDLER = 300 + private const val RECOVERABLE_SECURITY_HANDLER = 301 + private const val UPDATE_FILE_SDK_30_HANDLER = 302 + private const val MANAGE_MEDIA_RC = 303 + private const val TRASH_FILE_SDK_30_HANDLER = 304 + var funAfterSAFPermission: ((success: Boolean) -> Unit)? = null var funAfterSdk30Action: ((success: Boolean) -> Unit)? = null var funAfterUpdate30File: ((success: Boolean) -> Unit)? = null @@ -192,49 +163,45 @@ abstract class BaseSimpleActivity : AppCompatActivity() { abstract fun getRepositoryName(): String? + /** Return true if the back press was consumed. */ + protected open fun onBackPressedCompat(): Boolean = false + + /** Use when a screen needs to temporarily ignore back (e.g., during animations). */ + protected fun setBackHandlingEnabled(enabled: Boolean) { + backCallback.isEnabled = enabled + } + + /** If a subclass wants to explicitly trigger the default behaviour. */ + protected fun performDefaultBack() { + backCallback.isEnabled = false + onBackPressedDispatcher.onBackPressed() + backCallback.isEnabled = true + } + override fun onCreate(savedInstanceState: Bundle?) { if (useDynamicTheme) { - setTheme(getThemeId(showTransparentTop = showTransparentTop)) + setTheme(getThemeId(showTransparentTop = true)) } super.onCreate(savedInstanceState) + WindowCompat.enableEdgeToEdge(window) + registerBackPressedCallback() + if (!packageName.startsWith("org.fossify.", true)) { if ((0..50).random() == 10 || baseConfig.appRunCount % 100 == 0) { - val label = "You are using a fake version of the app. For your own safety download the original one from www.fossify.org. Thanks" - ConfirmationDialog( - activity = this, - message = label, - positive = R.string.ok, - negative = 0 - ) { - launchViewIntent(DEVELOPER_PLAY_STORE_URL) - } + showModdedAppWarning() } } } - @SuppressLint("NewApi") override fun onResume() { super.onResume() if (useDynamicTheme) { - setTheme(getThemeId(showTransparentTop = showTransparentTop)) + setTheme(getThemeId(showTransparentTop = true)) updateBackgroundColor(getProperBackgroundColor()) } - if (showTransparentTop) { - window.statusBarColor = Color.TRANSPARENT - } else if (!isMaterialActivity) { - updateActionbarColor(getProperStatusBarColor()) - } - updateRecentsAppIcon() - - var navBarColor = getProperBackgroundColor() - if (isMaterialActivity) { - navBarColor = navBarColor.adjustAlpha(HIGHER_ALPHA) - } - - updateNavigationBarColor(navBarColor) maybeLaunchAppUnlockActivity(requestCode = REQUEST_APP_UNLOCK) } @@ -246,7 +213,7 @@ abstract class BaseSimpleActivity : AppCompatActivity() { override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) - handleNavigationAndScrolling() + ViewCompat.requestApplyInsets(findViewById(android.R.id.content)) } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -269,211 +236,71 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } } - fun updateBackgroundColor(color: Int = baseConfig.backgroundColor) { - window.decorView.setBackgroundColor(color) - } - - fun updateStatusbarColor(color: Int) { - window.updateStatusBarColors(color) - } - - fun animateStatusBarColor(colorTo: Int, colorFrom: Int = window.statusBarColor, duration: Long = 300L) { - with(ObjectAnimator.ofInt(colorFrom, colorTo)) { - setEvaluator(ArgbEvaluator()) - setDuration(duration) - addUpdateListener { - window.statusBarColor = it.animatedValue.toInt() - } - - doOnEnd { updateStatusbarColor(window.statusBarColor) } - start() + fun registerBackPressedCallback() { + backCallback = onBackPressedDispatcher.addCallback(this) { + if (onBackPressedCompat()) return@addCallback + // fallback to system + isEnabled = false + onBackPressedDispatcher.onBackPressed() + isEnabled = true } } - fun updateActionbarColor(color: Int = getProperStatusBarColor()) { - updateStatusbarColor(color) - setTaskDescription(ActivityManager.TaskDescription(null, null, color)) - } - - fun updateNavigationBarColor(color: Int) { - window.updateNavigationBarColors(color) + fun updateBackgroundColor(color: Int = baseConfig.backgroundColor) { + window.decorView.setBackgroundColor(color) } - // use translucent navigation bar, set the background color to action and status bars - fun updateMaterialActivityViews( - mainCoordinatorLayout: CoordinatorLayout?, - nestedView: View?, - useTransparentNavigation: Boolean, - useTopSearchMenu: Boolean, + fun setupTopAppBar( + topAppBar: MyAppBarLayout, + navigationIcon: NavigationIcon = NavigationIcon.None, + topBarColor: Int = getRequiredTopBarColor(), + searchMenuItem: MenuItem? = null, ) { - this.mainCoordinatorLayout = mainCoordinatorLayout - this.nestedView = nestedView - this.useTransparentNavigation = useTransparentNavigation - this.useTopSearchMenu = useTopSearchMenu - handleNavigationAndScrolling() - - val backgroundColor = getProperBackgroundColor() - updateStatusbarColor(backgroundColor) - updateActionbarColor(backgroundColor) - } - - private fun handleNavigationAndScrolling() { - if (useTransparentNavigation) { - if (navigationBarHeight > 0 || isUsingGestureNavigation()) { - window.decorView.systemUiVisibility = window.decorView.systemUiVisibility.addBit(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) - updateTopBottomInsets(statusBarHeight, navigationBarHeight) - // Don't touch this. Window Inset API often has a domino effect and things will most likely break. - onApplyWindowInsets { - val insets = it.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.ime()) - updateTopBottomInsets(insets.top, insets.bottom) - } + val contrastColor = topBarColor.getContrastColor() + if (navigationIcon != NavigationIcon.None) { + val drawableId = if (navigationIcon == NavigationIcon.Cross) { + R.drawable.ic_cross_vector } else { - window.decorView.systemUiVisibility = window.decorView.systemUiVisibility.removeBit(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) - updateTopBottomInsets(0, 0) - } - } - } - - private fun updateTopBottomInsets(top: Int, bottom: Int) { - nestedView?.run { - setPadding(paddingLeft, paddingTop, paddingRight, bottom) - } - (mainCoordinatorLayout?.layoutParams as? FrameLayout.LayoutParams)?.topMargin = top - } - - // colorize the top toolbar and statusbar at scrolling down a bit - fun setupMaterialScrollListener(scrollingView: ScrollingView?, toolbar: Toolbar) { - this.scrollingView = scrollingView - this.toolbar = toolbar - if (scrollingView is RecyclerView) { - scrollingView.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY -> - val newScrollY = scrollingView.computeVerticalScrollOffset() - scrollingChanged(newScrollY, currentScrollY) - currentScrollY = newScrollY + R.drawable.ic_arrow_left_vector } - } else if (scrollingView is NestedScrollView) { - scrollingView.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY -> - scrollingChanged(scrollY, oldScrollY) - } - } - } - - private fun scrollingChanged(newScrollY: Int, oldScrollY: Int) { - if (newScrollY > 0 && oldScrollY == 0) { - val colorFrom = window.statusBarColor - val colorTo = getColoredMaterialStatusBarColor() - animateTopBarColors(colorFrom, colorTo) - } else if (newScrollY == 0 && oldScrollY > 0) { - val colorFrom = window.statusBarColor - val colorTo = getRequiredStatusBarColor() - animateTopBarColors(colorFrom, colorTo) - } - } - fun animateTopBarColors(colorFrom: Int, colorTo: Int) { - if (toolbar == null) { - return - } - - materialScrollColorAnimation?.end() - materialScrollColorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), colorFrom, colorTo) - materialScrollColorAnimation!!.addUpdateListener { animator -> - val color = animator.animatedValue as Int - if (toolbar != null) { - updateTopBarColors(toolbar!!, color) - } + topAppBar.toolbar?.navigationIcon = + resources.getColoredDrawableWithColor(drawableId, contrastColor) + topAppBar.toolbar?.setNavigationContentDescription(navigationIcon.accessibilityResId) } - materialScrollColorAnimation!!.start() - } - - fun getRequiredStatusBarColor(): Int { - return if ((scrollingView is RecyclerView || scrollingView is NestedScrollView) && scrollingView?.computeVerticalScrollOffset() == 0) { - getProperBackgroundColor() - } else { - getColoredMaterialStatusBarColor() - } - } - - fun updateTopBarColors(toolbar: Toolbar, color: Int) { - val contrastColor = if (useTopSearchMenu) { - getProperBackgroundColor().getContrastColor() - } else { - color.getContrastColor() - } - - if (!useTopSearchMenu) { - updateStatusbarColor(color) - toolbar.setBackgroundColor(color) - toolbar.setTitleTextColor(contrastColor) - toolbar.navigationIcon?.applyColorFilter(contrastColor) - toolbar.collapseIcon = resources.getColoredDrawableWithColor(R.drawable.ic_arrow_left_vector, contrastColor) - } - - toolbar.overflowIcon = resources.getColoredDrawableWithColor(R.drawable.ic_three_dots_vector, contrastColor) - - val menu = toolbar.menu - for (i in 0 until menu.size) { - try { - menu[i].icon?.setTint(contrastColor) - } catch (ignored: Exception) { - } - } - } - - fun updateStatusBarOnPageChange() { - if (scrollingView is RecyclerView || scrollingView is NestedScrollView) { - val scrollY = scrollingView!!.computeVerticalScrollOffset() - val colorFrom = window.statusBarColor - val colorTo = if (scrollY > 0) { - getColoredMaterialStatusBarColor() - } else { - getRequiredStatusBarColor() - } - animateTopBarColors(colorFrom, colorTo) - currentScrollY = scrollY - } - } - - fun setupToolbar( - toolbar: Toolbar, - toolbarNavigationIcon: NavigationIcon = NavigationIcon.None, - statusBarColor: Int = getRequiredStatusBarColor(), - searchMenuItem: MenuItem? = null, - ) { - val contrastColor = statusBarColor.getContrastColor() - if (toolbarNavigationIcon != NavigationIcon.None) { - val drawableId = if (toolbarNavigationIcon == NavigationIcon.Cross) R.drawable.ic_cross_vector else R.drawable.ic_arrow_left_vector - toolbar.navigationIcon = resources.getColoredDrawableWithColor(drawableId, contrastColor) - toolbar.setNavigationContentDescription(toolbarNavigationIcon.accessibilityResId) - } - - toolbar.setNavigationOnClickListener { + topAppBar.toolbar?.setNavigationOnClickListener { hideKeyboard() finish() } - updateTopBarColors(toolbar, statusBarColor) + updateTopBarColors(topAppBar, topBarColor) - if (!useTopSearchMenu) { - searchMenuItem?.actionView?.findViewById(androidx.appcompat.R.id.search_close_btn)?.apply { - applyColorFilter(contrastColor) - } + if (!isSearchBarEnabled) { + searchMenuItem?.actionView + ?.findViewById(androidx.appcompat.R.id.search_close_btn) + ?.apply { + applyColorFilter(contrastColor) + } - searchMenuItem?.actionView?.findViewById(androidx.appcompat.R.id.search_src_text)?.apply { - setTextColor(contrastColor) - setHintTextColor(contrastColor.adjustAlpha(MEDIUM_ALPHA)) - hint = "${getString(R.string.search)}…" + searchMenuItem?.actionView + ?.findViewById(androidx.appcompat.R.id.search_src_text) + ?.apply { + setTextColor(contrastColor) + setHintTextColor(contrastColor.adjustAlpha(MEDIUM_ALPHA)) + hint = "${getString(R.string.search)}…" - if (isQPlus()) { - textCursorDrawable = null + if (isQPlus()) { + textCursorDrawable = null + } } - } // search underline - searchMenuItem?.actionView?.findViewById(androidx.appcompat.R.id.search_plate)?.apply { - background.setColorFilter(contrastColor, PorterDuff.Mode.MULTIPLY) - } + searchMenuItem?.actionView + ?.findViewById(androidx.appcompat.R.id.search_plate) + ?.apply { + background.setColorFilter(contrastColor, PorterDuff.Mode.MULTIPLY) + } } } @@ -485,7 +312,8 @@ abstract class BaseSimpleActivity : AppCompatActivity() { return } - val recentsIcon = BitmapFactory.decodeResource(resources, appIconIDs[currentAppIconColorIndex]) + val recentsIcon = + BitmapFactory.decodeResource(resources, appIconIDs[currentAppIconColorIndex]) val title = getAppLauncherName() val color = baseConfig.primaryColor @@ -526,10 +354,6 @@ abstract class BaseSimpleActivity : AppCompatActivity() { return 0 } - fun setTranslucentNavigation() { - window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) - } - override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { super.onActivityResult(requestCode, resultCode, resultData) val partition = try { @@ -540,7 +364,7 @@ abstract class BaseSimpleActivity : AppCompatActivity() { val sdOtgPattern = Pattern.compile(SD_OTG_SHORT) if (requestCode == CREATE_DOCUMENT_SDK_30) { - if (resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) { + if (resultCode == RESULT_OK && resultData != null && resultData.data != null) { val treeUri = resultData.data val checkedUri = buildDocumentUriSdk30(checkedDocumentPath) @@ -550,7 +374,8 @@ abstract class BaseSimpleActivity : AppCompatActivity() { return } - val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + val takeFlags = + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION applicationContext.contentResolver.takePersistableUriPermission(treeUri, takeFlags) val funAfter = funAfterSdk30Action funAfterSdk30Action = null @@ -560,7 +385,7 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } } else if (requestCode == OPEN_DOCUMENT_TREE_FOR_SDK_30) { - if (resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) { + if (resultCode == RESULT_OK && resultData != null && resultData.data != null) { val treeUri = resultData.data val checkedUri = createFirstParentTreeUri(checkedDocumentPath) @@ -571,7 +396,8 @@ abstract class BaseSimpleActivity : AppCompatActivity() { return } - val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + val takeFlags = + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION applicationContext.contentResolver.takePersistableUriPermission(treeUri, takeFlags) val funAfter = funAfterSdk30Action funAfterSdk30Action = null @@ -581,7 +407,7 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } } else if (requestCode == OPEN_DOCUMENT_TREE_FOR_ANDROID_DATA_OR_OBB) { - if (resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) { + if (resultCode == RESULT_OK && resultData != null && resultData.data != null) { if (isProperAndroidRoot(checkedDocumentPath, resultData.data!!)) { if (resultData.dataString == baseConfig.OTGTreeUri || resultData.dataString == baseConfig.sdTreeUri) { val pathToSelect = createAndroidDataOrObbPath(checkedDocumentPath) @@ -592,15 +418,27 @@ abstract class BaseSimpleActivity : AppCompatActivity() { val treeUri = resultData.data storeAndroidTreeUri(checkedDocumentPath, treeUri.toString()) - val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - applicationContext.contentResolver.takePersistableUriPermission(treeUri!!, takeFlags) + val takeFlags = + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + applicationContext.contentResolver.takePersistableUriPermission( + treeUri!!, + takeFlags + ) funAfterSAFPermission?.invoke(true) funAfterSAFPermission = null } else { - toast(getString(R.string.wrong_folder_selected, createAndroidDataOrObbPath(checkedDocumentPath))) + toast( + getString( + R.string.wrong_folder_selected, + createAndroidDataOrObbPath(checkedDocumentPath) + ) + ) Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply { if (isRPlus()) { - putExtra(DocumentsContract.EXTRA_INITIAL_URI, createAndroidDataOrObbUri(checkedDocumentPath)) + putExtra( + DocumentsContract.EXTRA_INITIAL_URI, + createAndroidDataOrObbUri(checkedDocumentPath) + ) } try { @@ -614,8 +452,9 @@ abstract class BaseSimpleActivity : AppCompatActivity() { funAfterSAFPermission?.invoke(false) } } else if (requestCode == OPEN_DOCUMENT_TREE_SD) { - if (resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) { - val isProperPartition = partition.isEmpty() || !sdOtgPattern.matcher(partition).matches() || (sdOtgPattern.matcher(partition) + if (resultCode == RESULT_OK && resultData != null && resultData.data != null) { + val isProperPartition = partition.isEmpty() || !sdOtgPattern.matcher(partition) + .matches() || (sdOtgPattern.matcher(partition) .matches() && resultData.dataString!!.contains(partition)) if (isProperSDRootFolder(resultData.data!!) && isProperPartition) { if (resultData.dataString == baseConfig.OTGTreeUri) { @@ -640,8 +479,9 @@ abstract class BaseSimpleActivity : AppCompatActivity() { funAfterSAFPermission?.invoke(false) } } else if (requestCode == OPEN_DOCUMENT_TREE_OTG) { - if (resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) { - val isProperPartition = partition.isEmpty() || !sdOtgPattern.matcher(partition).matches() || (sdOtgPattern.matcher(partition) + if (resultCode == RESULT_OK && resultData != null && resultData.data != null) { + val isProperPartition = partition.isEmpty() || !sdOtgPattern.matcher(partition) + .matches() || (sdOtgPattern.matcher(partition) .matches() && resultData.dataString!!.contains(partition)) if (isProperOTGRootFolder(resultData.data!!) && isProperPartition) { if (resultData.dataString == baseConfig.sdTreeUri) { @@ -650,11 +490,17 @@ abstract class BaseSimpleActivity : AppCompatActivity() { return } baseConfig.OTGTreeUri = resultData.dataString!! - baseConfig.OTGPartition = baseConfig.OTGTreeUri.removeSuffix("%3A").substringAfterLast('/').trimEnd('/') + baseConfig.OTGPartition = + baseConfig.OTGTreeUri.removeSuffix("%3A").substringAfterLast('/') + .trimEnd('/') updateOTGPathFromPartition() - val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - applicationContext.contentResolver.takePersistableUriPermission(resultData.data!!, takeFlags) + val takeFlags = + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + applicationContext.contentResolver.takePersistableUriPermission( + resultData.data!!, + takeFlags + ) funAfterSAFPermission?.invoke(true) funAfterSAFPermission = null @@ -671,20 +517,20 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } else { funAfterSAFPermission?.invoke(false) } - } else if (requestCode == SELECT_EXPORT_SETTINGS_FILE_INTENT && resultCode == Activity.RESULT_OK && resultData != null && resultData.data != null) { + } else if (requestCode == SELECT_EXPORT_SETTINGS_FILE_INTENT && resultCode == RESULT_OK && resultData != null && resultData.data != null) { val outputStream = contentResolver.openOutputStream(resultData.data!!) exportSettingsTo(outputStream, configItemsToExport) } else if (requestCode == DELETE_FILE_SDK_30_HANDLER) { - funAfterSdk30Action?.invoke(resultCode == Activity.RESULT_OK) + funAfterSdk30Action?.invoke(resultCode == RESULT_OK) } else if (requestCode == RECOVERABLE_SECURITY_HANDLER) { - funRecoverableSecurity?.invoke(resultCode == Activity.RESULT_OK) + funRecoverableSecurity?.invoke(resultCode == RESULT_OK) funRecoverableSecurity = null } else if (requestCode == UPDATE_FILE_SDK_30_HANDLER) { - funAfterUpdate30File?.invoke(resultCode == Activity.RESULT_OK) + funAfterUpdate30File?.invoke(resultCode == RESULT_OK) } else if (requestCode == MANAGE_MEDIA_RC) { funAfterManageMediaPermission?.invoke() } else if (requestCode == TRASH_FILE_SDK_30_HANDLER) { - funAfterTrash30File?.invoke(resultCode == Activity.RESULT_OK) + funAfterTrash30File?.invoke(resultCode == RESULT_OK) } } @@ -692,24 +538,54 @@ abstract class BaseSimpleActivity : AppCompatActivity() { val treeUri = resultData.data baseConfig.sdTreeUri = treeUri.toString() - val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + val takeFlags = + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION applicationContext.contentResolver.takePersistableUriPermission(treeUri!!, takeFlags) } - private fun isProperSDRootFolder(uri: Uri) = isExternalStorageDocument(uri) && isRootUri(uri) && !isInternalStorage(uri) - private fun isProperSDFolder(uri: Uri) = isExternalStorageDocument(uri) && !isInternalStorage(uri) + private fun isProperSDRootFolder(uri: Uri): Boolean { + return isExternalStorageDocument(uri) && isRootUri(uri) && !isInternalStorage(uri) + } + + private fun isProperSDFolder(uri: Uri): Boolean { + return isExternalStorageDocument(uri) && !isInternalStorage(uri) + } - private fun isProperOTGRootFolder(uri: Uri) = isExternalStorageDocument(uri) && isRootUri(uri) && !isInternalStorage(uri) - private fun isProperOTGFolder(uri: Uri) = isExternalStorageDocument(uri) && !isInternalStorage(uri) + private fun isProperOTGRootFolder(uri: Uri): Boolean { + return isExternalStorageDocument(uri) && isRootUri(uri) && !isInternalStorage(uri) + } + + private fun isProperOTGFolder(uri: Uri): Boolean { + return isExternalStorageDocument(uri) && !isInternalStorage(uri) + } private fun isRootUri(uri: Uri) = uri.lastPathSegment?.endsWith(":") ?: false - private fun isInternalStorage(uri: Uri) = isExternalStorageDocument(uri) && DocumentsContract.getTreeDocumentId(uri).contains("primary") - private fun isAndroidDir(uri: Uri) = isExternalStorageDocument(uri) && DocumentsContract.getTreeDocumentId(uri).contains(":Android") - private fun isInternalStorageAndroidDir(uri: Uri) = isInternalStorage(uri) && isAndroidDir(uri) - private fun isOTGAndroidDir(uri: Uri) = isProperOTGFolder(uri) && isAndroidDir(uri) - private fun isSDAndroidDir(uri: Uri) = isProperSDFolder(uri) && isAndroidDir(uri) - private fun isExternalStorageDocument(uri: Uri) = EXTERNAL_STORAGE_PROVIDER_AUTHORITY == uri.authority + private fun isInternalStorage(uri: Uri): Boolean { + return isExternalStorageDocument(uri) && DocumentsContract.getTreeDocumentId(uri) + .contains("primary") + } + + private fun isAndroidDir(uri: Uri): Boolean { + return isExternalStorageDocument(uri) && DocumentsContract.getTreeDocumentId(uri) + .contains(":Android") + } + + private fun isInternalStorageAndroidDir(uri: Uri): Boolean { + return isInternalStorage(uri) && isAndroidDir(uri) + } + + private fun isOTGAndroidDir(uri: Uri): Boolean { + return isProperOTGFolder(uri) && isAndroidDir(uri) + } + + private fun isSDAndroidDir(uri: Uri): Boolean { + return isProperSDFolder(uri) && isAndroidDir(uri) + } + + private fun isExternalStorageDocument(uri: Uri): Boolean { + return EXTERNAL_STORAGE_PROVIDER_AUTHORITY == uri.authority + } private fun isProperAndroidRoot(path: String, uri: Uri): Boolean { return when { @@ -744,15 +620,7 @@ abstract class BaseSimpleActivity : AppCompatActivity() { fun startCustomizationActivity() { if (!packageName.contains("yfissof".reversed(), true)) { if (baseConfig.appRunCount > 100) { - val label = "You are using a fake version of the app. For your own safety download the original one from www.fossify.org. Thanks" - ConfirmationDialog( - activity = this, - message = label, - positive = R.string.ok, - negative = 0 - ) { - launchViewIntent(DEVELOPER_PLAY_STORE_URL) - } + showModdedAppWarning() return } } @@ -798,7 +666,11 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } } - fun handleSAFDialogSdk30(path: String, showRationale: Boolean = true, callback: (success: Boolean) -> Unit): Boolean { + fun handleSAFDialogSdk30( + path: String, + showRationale: Boolean = true, + callback: (success: Boolean) -> Unit + ): Boolean { hideKeyboard() return if (!packageName.startsWith("org.fossify")) { callback(true) @@ -812,7 +684,10 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } } - fun checkManageMediaOrHandleSAFDialogSdk30(path: String, callback: (success: Boolean) -> Unit): Boolean { + fun checkManageMediaOrHandleSAFDialogSdk30( + path: String, + callback: (success: Boolean) -> Unit + ): Boolean { hideKeyboard() return if (canManageMedia()) { callback(true) @@ -822,7 +697,10 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } } - fun handleSAFCreateDocumentDialogSdk30(path: String, callback: (success: Boolean) -> Unit): Boolean { + fun handleSAFCreateDocumentDialogSdk30( + path: String, + callback: (success: Boolean) -> Unit + ): Boolean { hideKeyboard() return if (!packageName.startsWith("org.fossify")) { callback(true) @@ -836,7 +714,11 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } } - fun handleAndroidSAFDialog(path: String, openInSystemAppAllowed: Boolean = false, callback: (success: Boolean) -> Unit): Boolean { + fun handleAndroidSAFDialog( + path: String, + openInSystemAppAllowed: Boolean = false, + callback: (success: Boolean) -> Unit + ): Boolean { hideKeyboard() return if (!packageName.startsWith("org.fossify")) { callback(true) @@ -884,7 +766,8 @@ abstract class BaseSimpleActivity : AppCompatActivity() { if (isRPlus()) { funAfterSdk30Action = callback try { - val deleteRequest = MediaStore.createDeleteRequest(contentResolver, uris).intentSender + val deleteRequest = + MediaStore.createDeleteRequest(contentResolver, uris).intentSender startIntentSenderForResult(deleteRequest, DELETE_FILE_SDK_30_HANDLER, null, 0, 0, 0) } catch (e: Exception) { showErrorToast(e) @@ -904,7 +787,8 @@ abstract class BaseSimpleActivity : AppCompatActivity() { if (isRPlus()) { funAfterTrash30File = callback try { - val trashRequest = MediaStore.createTrashRequest(contentResolver, uris, toTrash).intentSender + val trashRequest = + MediaStore.createTrashRequest(contentResolver, uris, toTrash).intentSender startIntentSenderForResult(trashRequest, TRASH_FILE_SDK_30_HANDLER, null, 0, 0, 0) } catch (e: Exception) { showErrorToast(e) @@ -940,9 +824,17 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } catch (securityException: SecurityException) { if (isQPlus()) { funRecoverableSecurity = callback - val recoverableSecurityException = securityException as? RecoverableSecurityException ?: throw securityException + val recoverableSecurityException = + securityException as? RecoverableSecurityException ?: throw securityException val intentSender = recoverableSecurityException.userAction.actionIntent.intentSender - startIntentSenderForResult(intentSender, RECOVERABLE_SECURITY_HANDLER, null, 0, 0, 0) + startIntentSenderForResult( + intent = intentSender, + requestCode = RECOVERABLE_SECURITY_HANDLER, + fillInIntent = null, + flagsMask = 0, + flagsValues = 0, + extraFlags = 0 + ) } else { callback(false) } @@ -1001,14 +893,28 @@ abstract class BaseSimpleActivity : AppCompatActivity() { val fileUris = getFileUrisFromFileDirItems(fileDirItems) updateSDK30Uris(fileUris) { sdk30UriSuccess -> if (sdk30UriSuccess) { - startCopyMove(fileDirItems, destination, isCopyOperation, copyPhotoVideoOnly, copyHidden) + startCopyMove( + files = fileDirItems, + destinationPath = destination, + isCopyOperation = isCopyOperation, + copyPhotoVideoOnly = copyPhotoVideoOnly, + copyHidden = copyHidden + ) } } } else { - startCopyMove(fileDirItems, destination, isCopyOperation, copyPhotoVideoOnly, copyHidden) + startCopyMove( + files = fileDirItems, + destinationPath = destination, + isCopyOperation = isCopyOperation, + copyPhotoVideoOnly = copyPhotoVideoOnly, + copyHidden = copyHidden + ) } } else { - if (isPathOnOTG(source) || isPathOnOTG(destination) || isPathOnSD(source) || isPathOnSD(destination) || + if (isPathOnOTG(source) || isPathOnOTG(destination) || isPathOnSD(source) || isPathOnSD( + destination + ) || isRestrictedSAFOnlyRoot(source) || isRestrictedSAFOnlyRoot(destination) || isAccessibleWithSAFSdk30(source) || isAccessibleWithSAFSdk30(destination) || fileDirItems.first().isDirectory @@ -1020,11 +926,23 @@ abstract class BaseSimpleActivity : AppCompatActivity() { val fileUris = getFileUrisFromFileDirItems(fileDirItems) updateSDK30Uris(fileUris) { sdk30UriSuccess -> if (sdk30UriSuccess) { - startCopyMove(fileDirItems, destination, isCopyOperation, copyPhotoVideoOnly, copyHidden) + startCopyMove( + files = fileDirItems, + destinationPath = destination, + isCopyOperation = isCopyOperation, + copyPhotoVideoOnly = copyPhotoVideoOnly, + copyHidden = copyHidden + ) } } } else { - startCopyMove(fileDirItems, destination, isCopyOperation, copyPhotoVideoOnly, copyHidden) + startCopyMove( + files = fileDirItems, + destinationPath = destination, + isCopyOperation = isCopyOperation, + copyPhotoVideoOnly = copyPhotoVideoOnly, + copyHidden = copyHidden + ) } } } @@ -1058,9 +976,19 @@ abstract class BaseSimpleActivity : AppCompatActivity() { runOnUiThread { if (updatedPaths.isEmpty()) { - copyMoveListener.copySucceeded(false, fileCountToCopy == 0, destination, false) + copyMoveListener.copySucceeded( + copyOnly = false, + copiedAll = fileCountToCopy == 0, + destinationPath = destination, + wasCopyingOneFileOnly = false + ) } else { - copyMoveListener.copySucceeded(false, fileCountToCopy <= updatedPaths.size, destination, updatedPaths.size == 1) + copyMoveListener.copySucceeded( + copyOnly = false, + copiedAll = fileCountToCopy <= updatedPaths.size, + destinationPath = destination, + wasCopyingOneFileOnly = updatedPaths.size == 1 + ) } } } @@ -1079,7 +1007,8 @@ abstract class BaseSimpleActivity : AppCompatActivity() { var fileIndex = 1 var newFile: File? do { - val newName = String.format("%s(%d).%s", file.nameWithoutExtension, fileIndex, file.extension) + val newName = + String.format("%s(%d).%s", file.nameWithoutExtension, fileIndex, file.extension) newFile = File(file.parent, newName) fileIndex++ } while (getDoesFilePathExist(newFile!!.absolutePath)) @@ -1118,7 +1047,11 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } } } else { - val text = String.format(getString(R.string.no_space), sumToCopy.formatSize(), availableSpace.formatSize()) + val text = String.format( + getString(R.string.no_space), + sumToCopy.formatSize(), + availableSpace.formatSize() + ) toast(text, Toast.LENGTH_LONG) } } @@ -1136,7 +1069,11 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } val file = files[index] - val newFileDirItem = FileDirItem("$destinationPath/${file.name}", file.name, file.isDirectory) + val newFileDirItem = FileDirItem( + path = "$destinationPath/${file.name}", + name = file.name, + isDirectory = file.isDirectory + ) ensureBackgroundThread { if (getDoesFilePathExist(newFileDirItem.path)) { runOnUiThread { @@ -1191,7 +1128,11 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } else { isAskingPermissions = true actionOnPermission = callback - ActivityCompat.requestPermissions(this, arrayOf(getPermissionString(permissionId)), GENERIC_PERM_HANDLER) + ActivityCompat.requestPermissions( + this, + arrayOf(getPermissionString(permissionId)), + GENERIC_PERM_HANDLER + ) } } @@ -1207,7 +1148,11 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } else { isAskingPermissions = true actionOnPermission = callback - ActivityCompat.requestPermissions(this, permissionIds.map { getPermissionString(it) }.toTypedArray(), GENERIC_PERM_HANDLER) + ActivityCompat.requestPermissions( + this, + permissionIds.map { getPermissionString(it) }.toTypedArray(), + GENERIC_PERM_HANDLER + ) } } else { if (hasAllPermissions(permissionIds)) { @@ -1215,7 +1160,11 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } else { isAskingPermissions = true actionOnPermission = callback - ActivityCompat.requestPermissions(this, permissionIds.map { getPermissionString(it) }.toTypedArray(), GENERIC_PERM_HANDLER) + ActivityCompat.requestPermissions( + this, + permissionIds.map { getPermissionString(it) }.toTypedArray(), + GENERIC_PERM_HANDLER + ) } } } @@ -1342,7 +1291,8 @@ abstract class BaseSimpleActivity : AppCompatActivity() { } private fun getExportSettingsFilename(): String { - val appName = baseConfig.appId.removeSuffix(".debug").removeSuffix(".pro").removePrefix("org.fossify.") + val appName = baseConfig.appId.removeSuffix(".debug").removeSuffix(".pro") + .removePrefix("org.fossify.") return "$appName-settings_${getCurrentFormattedDateTime()}" } @@ -1350,27 +1300,35 @@ abstract class BaseSimpleActivity : AppCompatActivity() { protected fun launchSetDefaultDialerIntent() { if (isQPlus()) { val roleManager = getSystemService(RoleManager::class.java) - if (roleManager!!.isRoleAvailable(RoleManager.ROLE_DIALER) && !roleManager.isRoleHeld(RoleManager.ROLE_DIALER)) { + if ( + roleManager!!.isRoleAvailable(RoleManager.ROLE_DIALER) + && !roleManager.isRoleHeld(RoleManager.ROLE_DIALER) + ) { val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER) startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_DIALER) } } else { - Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER).putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName).apply { - try { - startActivityForResult(this, REQUEST_CODE_SET_DEFAULT_DIALER) - } catch (e: ActivityNotFoundException) { - toast(R.string.no_app_found) - } catch (e: Exception) { - showErrorToast(e) + Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER) + .putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName) + .apply { + try { + startActivityForResult(this, REQUEST_CODE_SET_DEFAULT_DIALER) + } catch (e: ActivityNotFoundException) { + toast(R.string.no_app_found) + } catch (e: Exception) { + showErrorToast(e) + } } - } } } @RequiresApi(Build.VERSION_CODES.Q) fun setDefaultCallerIdApp() { val roleManager = getSystemService(RoleManager::class.java) - if (roleManager.isRoleAvailable(RoleManager.ROLE_CALL_SCREENING) && !roleManager.isRoleHeld(RoleManager.ROLE_CALL_SCREENING)) { + if ( + roleManager.isRoleAvailable(RoleManager.ROLE_CALL_SCREENING) + && !roleManager.isRoleHeld(RoleManager.ROLE_CALL_SCREENING) + ) { val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_SCREENING) startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_CALLER_ID) } diff --git a/commons/src/main/kotlin/org/fossify/commons/activities/CustomizationActivity.kt b/commons/src/main/kotlin/org/fossify/commons/activities/CustomizationActivity.kt index fda74bc0b..cfffccba9 100644 --- a/commons/src/main/kotlin/org/fossify/commons/activities/CustomizationActivity.kt +++ b/commons/src/main/kotlin/org/fossify/commons/activities/CustomizationActivity.kt @@ -84,18 +84,12 @@ class CustomizationActivity : BaseSimpleActivity() { private val binding by viewBinding(ActivityCustomizationBinding::inflate) override fun onCreate(savedInstanceState: Bundle?) { - isMaterialActivity = true super.onCreate(savedInstanceState) setContentView(binding.root) setupOptionsMenu() refreshMenuItems() - updateMaterialActivityViews( - mainCoordinatorLayout = binding.customizationCoordinator, - nestedView = binding.customizationHolder, - useTransparentNavigation = true, - useTopSearchMenu = false - ) + setupEdgeToEdge(padBottomSystem = listOf(binding.customizationHolder)) initColorVariables() if (canAccessGlobalConfig()) { @@ -124,18 +118,16 @@ class CustomizationActivity : BaseSimpleActivity() { if (!isDynamicTheme()) { updateBackgroundColor(getCurrentBackgroundColor()) - updateActionbarColor(getCurrentTopBarColor()) } curPrimaryLineColorPicker?.getSpecificColor()?.apply { - updateActionbarColor(this) setTheme(getThemeId(this)) } - setupToolbar( - toolbar = binding.customizationToolbar, - toolbarNavigationIcon = NavigationIcon.Cross, - statusBarColor = getColoredMaterialStatusBarColor() + setupTopAppBar( + topAppBar = binding.appBar, + navigationIcon = NavigationIcon.Arrow, + topBarColor = getColoredMaterialStatusBarColor() ) showOrHideThankYouFeatures() updateApplyToAllColors() @@ -158,11 +150,12 @@ class CustomizationActivity : BaseSimpleActivity() { } } - override fun onBackPressed() { - if (hasUnsavedChanges && System.currentTimeMillis() - lastSavePromptTS > SAVE_DISCARD_PROMPT_INTERVAL) { + override fun onBackPressedCompat(): Boolean { + return if (hasUnsavedChanges && System.currentTimeMillis() - lastSavePromptTS > SAVE_DISCARD_PROMPT_INTERVAL) { promptSaveDiscard() + true } else { - super.onBackPressed() + false } } @@ -274,10 +267,10 @@ class CustomizationActivity : BaseSimpleActivity() { } updateMenuItemColors(binding.customizationToolbar.menu, getCurrentTopBarColor()) - setupToolbar( - toolbar = binding.customizationToolbar, - toolbarNavigationIcon = NavigationIcon.Cross, - statusBarColor = getCurrentTopBarColor() + setupTopAppBar( + topAppBar = binding.appBar, + navigationIcon = NavigationIcon.Arrow, + topBarColor = getCurrentTopBarColor() ) } } @@ -295,7 +288,7 @@ class CustomizationActivity : BaseSimpleActivity() { curAppIconColor = baseConfig.customAppIconColor setTheme(getThemeId(curPrimaryColor)) updateMenuItemColors(binding.customizationToolbar.menu, curPrimaryColor) - setupToolbar(binding.customizationToolbar, NavigationIcon.Cross, curPrimaryColor) + setupTopAppBar(binding.appBar, NavigationIcon.Arrow, curPrimaryColor) setupColorsPickers() } else { baseConfig.customPrimaryColor = curPrimaryColor @@ -320,10 +313,10 @@ class CustomizationActivity : BaseSimpleActivity() { setTheme(getThemeId(getCurrentPrimaryColor())) colorChanged() updateMenuItemColors(binding.customizationToolbar.menu, getCurrentTopBarColor()) - setupToolbar( - toolbar = binding.customizationToolbar, - toolbarNavigationIcon = NavigationIcon.Cross, - statusBarColor = getCurrentTopBarColor() + setupTopAppBar( + topAppBar = binding.appBar, + navigationIcon = NavigationIcon.Arrow, + topBarColor = getCurrentTopBarColor() ) } @@ -332,7 +325,6 @@ class CustomizationActivity : BaseSimpleActivity() { updateLabelColors(getCurrentTextColor()) updateHeaderColors(getCurrentAccentOrPrimaryColor()) updateBackgroundColor(getCurrentBackgroundColor()) - updateActionbarColor(getCurrentTopBarColor()) updateAutoThemeFields() updateApplyToAllColors() handleAccentColorLayout() @@ -486,7 +478,6 @@ class CustomizationActivity : BaseSimpleActivity() { initColorVariables() setupColorsPickers() updateBackgroundColor() - updateActionbarColor() refreshMenuItems() updateLabelColors(getCurrentTextColor()) updateHeaderColors(getCurrentAccentOrPrimaryColor()) @@ -559,7 +550,6 @@ class CustomizationActivity : BaseSimpleActivity() { private fun setCurrentPrimaryColor(color: Int) { curPrimaryColor = color - updateActionbarColor(color) updateApplyToAllColors() updateHeaderColors(color) } @@ -626,7 +616,7 @@ class CustomizationActivity : BaseSimpleActivity() { activity = this, color = curPrimaryColor, isPrimaryColorPicker = true, - toolbar = binding.customizationToolbar + appBar = binding.appBar ) { wasPositivePressed, color -> curPrimaryLineColorPicker = null if (wasPositivePressed) { @@ -637,13 +627,12 @@ class CustomizationActivity : BaseSimpleActivity() { setTheme(getThemeId(color)) } updateMenuItemColors(binding.customizationToolbar.menu, color) - setupToolbar(binding.customizationToolbar, NavigationIcon.Cross, color) + setupTopAppBar(binding.appBar, NavigationIcon.Arrow, color) } else { - updateActionbarColor(curPrimaryColor) setTheme(getThemeId(curPrimaryColor)) updateMenuItemColors(binding.customizationToolbar.menu, curPrimaryColor) - setupToolbar(binding.customizationToolbar, NavigationIcon.Cross, curPrimaryColor) - updateTopBarColors(binding.customizationToolbar, curPrimaryColor) + setupTopAppBar(binding.appBar, NavigationIcon.Arrow, curPrimaryColor) + updateTopBarColors(binding.appBar, curPrimaryColor) } } } @@ -656,8 +645,7 @@ class CustomizationActivity : BaseSimpleActivity() { colorChanged() updateApplyToAllColors() updateHeaderColors(curAccentColor) - updateActionbarColor(getCurrentTopBarColor()) - updateTopBarColors(binding.customizationToolbar, getCurrentTopBarColor()) + updateTopBarColors(binding.appBar, getCurrentTopBarColor()) } } } diff --git a/commons/src/main/kotlin/org/fossify/commons/activities/EdgeToEdgeActivity.kt b/commons/src/main/kotlin/org/fossify/commons/activities/EdgeToEdgeActivity.kt new file mode 100644 index 000000000..3b5eb1b55 --- /dev/null +++ b/commons/src/main/kotlin/org/fossify/commons/activities/EdgeToEdgeActivity.kt @@ -0,0 +1,156 @@ +package org.fossify.commons.activities + +import android.animation.ArgbEvaluator +import android.animation.ValueAnimator +import android.os.Bundle +import android.view.View +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.ScrollingView +import androidx.core.view.WindowCompat +import androidx.core.view.WindowInsetsCompat.Type +import androidx.core.view.get +import androidx.core.view.size +import androidx.core.widget.NestedScrollView +import androidx.recyclerview.widget.RecyclerView +import org.fossify.commons.R +import org.fossify.commons.extensions.applyColorFilter +import org.fossify.commons.extensions.getColoredDrawableWithColor +import org.fossify.commons.extensions.getColoredMaterialStatusBarColor +import org.fossify.commons.extensions.getContrastColor +import org.fossify.commons.extensions.getProperBackgroundColor +import org.fossify.commons.extensions.onApplyWindowInsets +import org.fossify.commons.extensions.setSystemBarsAppearance +import org.fossify.commons.extensions.updatePaddingWithBase +import org.fossify.commons.views.MyAppBarLayout + +abstract class EdgeToEdgeActivity : AppCompatActivity() { + open var isSearchBarEnabled = false + open val padCutout: Boolean + get() = true + + private var topAppBar: MyAppBarLayout? = null + private var scrollingView: ScrollingView? = null + private var materialScrollColorAnimation: ValueAnimator? = null + private var currentScrollY = 0 + + private val contentRoot by lazy { findViewById(android.R.id.content) } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + WindowCompat.enableEdgeToEdge(window) + } + + /** + * Helper for views that need to be edge to edge compatible. + */ + fun setupEdgeToEdge( + padTopSystem: List = emptyList(), + padBottomSystem: List = emptyList(), + padBottomImeAndSystem: List = emptyList(), + ) { + onApplyWindowInsets { insets -> + val system = insets.getInsetsIgnoringVisibility(Type.systemBars()) + val imeAndSystem = insets.getInsets(Type.ime() or Type.systemBars()) + + padTopSystem.forEach { it.updatePaddingWithBase(top = system.top) } + padBottomSystem.forEach { it.updatePaddingWithBase(bottom = system.bottom) } + padBottomImeAndSystem.forEach { it.updatePaddingWithBase(bottom = imeAndSystem.bottom) } + + if (padCutout) { + val cutout = insets.getInsets(Type.displayCutout()) + val sideLeft = maxOf(system.left, cutout.left) + val sideRight = maxOf(system.right, cutout.right) + contentRoot.updatePaddingWithBase(left = sideLeft, right = sideRight) + } + } + } + + fun setupMaterialScrollListener(scrollingView: ScrollingView?, topAppBar: MyAppBarLayout) { + this.scrollingView = scrollingView + this.topAppBar = topAppBar + if (scrollingView is RecyclerView) { + scrollingView.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY -> + val newScrollY = scrollingView.computeVerticalScrollOffset() + scrollingChanged(newScrollY, currentScrollY) + currentScrollY = newScrollY + } + } else if (scrollingView is NestedScrollView) { + scrollingView.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY -> + scrollingChanged(scrollY, oldScrollY) + } + } + } + + private fun scrollingChanged(newScrollY: Int, oldScrollY: Int) { + if (newScrollY > 0 && oldScrollY == 0) { + animateTopBarColors(getProperBackgroundColor(), getColoredMaterialStatusBarColor()) + } else if (newScrollY == 0 && oldScrollY > 0) { + animateTopBarColors(getColoredMaterialStatusBarColor(), getRequiredTopBarColor()) + } + } + + fun animateTopBarColors(colorFrom: Int, colorTo: Int) { + if (topAppBar == null) { + return + } + + materialScrollColorAnimation?.end() + materialScrollColorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), colorFrom, colorTo) + materialScrollColorAnimation!!.addUpdateListener { animator -> + val color = animator.animatedValue as Int + if (topAppBar != null) { + updateTopBarColors(topAppBar!!, color) + } + } + + materialScrollColorAnimation!!.start() + } + + fun getRequiredTopBarColor(): Int { + return if ( + (scrollingView is RecyclerView || scrollingView is NestedScrollView) + && scrollingView?.computeVerticalScrollOffset() == 0 + ) { + getProperBackgroundColor() + } else { + getColoredMaterialStatusBarColor() + } + } + + fun updateTopBarColors(topAppBar: MyAppBarLayout, color: Int) { + val contrastColor = if (isSearchBarEnabled) { + getProperBackgroundColor().getContrastColor() + } else { + color.getContrastColor() + } + + window.setSystemBarsAppearance(color) + if (!isSearchBarEnabled) { + topAppBar.setBackgroundColor(color) + topAppBar.toolbar?.setBackgroundColor(color) + topAppBar.toolbar?.setTitleTextColor(contrastColor) + topAppBar.toolbar?.navigationIcon?.applyColorFilter(contrastColor) + topAppBar.toolbar?.collapseIcon = resources.getColoredDrawableWithColor( + drawableId = R.drawable.ic_arrow_left_vector, + color = contrastColor + ) + } + + topAppBar.toolbar?.overflowIcon = + resources.getColoredDrawableWithColor(R.drawable.ic_three_dots_vector, contrastColor) + + val menu = topAppBar.toolbar?.menu ?: return + for (i in 0 until menu.size) { + try { + menu[i].icon?.setTint(contrastColor) + } catch (ignored: Exception) { + } + } + } + + override fun onDestroy() { + materialScrollColorAnimation?.cancel() + materialScrollColorAnimation = null + super.onDestroy() + } +} diff --git a/commons/src/main/kotlin/org/fossify/commons/adapters/FilepickerItemsAdapter.kt b/commons/src/main/kotlin/org/fossify/commons/adapters/FilepickerItemsAdapter.kt index 5a0a9dd3d..f6de3c9bd 100644 --- a/commons/src/main/kotlin/org/fossify/commons/adapters/FilepickerItemsAdapter.kt +++ b/commons/src/main/kotlin/org/fossify/commons/adapters/FilepickerItemsAdapter.kt @@ -101,8 +101,8 @@ class FilepickerItemsAdapter( var itemToLoad = if (fileDirItem.name.endsWith(".apk", true)) { val packageInfo = root.context.packageManager.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES) - if (packageInfo != null) { - val appInfo = packageInfo.applicationInfo + val appInfo = packageInfo?.applicationInfo + if (appInfo != null) { appInfo.sourceDir = path appInfo.publicSourceDir = path appInfo.loadIcon(root.context.packageManager) diff --git a/commons/src/main/kotlin/org/fossify/commons/adapters/MyRecyclerViewAdapter.kt b/commons/src/main/kotlin/org/fossify/commons/adapters/MyRecyclerViewAdapter.kt index a2566c76d..ded508f5b 100644 --- a/commons/src/main/kotlin/org/fossify/commons/adapters/MyRecyclerViewAdapter.kt +++ b/commons/src/main/kotlin/org/fossify/commons/adapters/MyRecyclerViewAdapter.kt @@ -53,8 +53,6 @@ abstract class MyRecyclerViewAdapter(val activity: BaseSimpleActivity, val recyc init { actModeCallback = object : MyActionModeCallback() { - private var savedStatusBarColor = activity.getProperStatusBarColor() - override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { actionItemPressed(item.itemId) return true @@ -86,13 +84,6 @@ abstract class MyRecyclerViewAdapter(val activity: BaseSimpleActivity, val recyc resources.getColor(R.color.dark_grey, activity.theme) } - savedStatusBarColor = activity.window.statusBarColor - activity.animateStatusBarColor( - colorTo = bgColor, - colorFrom = savedStatusBarColor, - duration = 300L - ) - actBarTextView!!.setTextColor(bgColor.getContrastColor()) activity.updateMenuItemColors(menu, baseColor = bgColor) onActionModeCreated() @@ -120,12 +111,6 @@ abstract class MyRecyclerViewAdapter(val activity: BaseSimpleActivity, val recyc } } - activity.animateStatusBarColor( - colorTo = savedStatusBarColor, - colorFrom = activity.window.statusBarColor, - duration = 400L - ) - updateTitle() selectedKeys.clear() actBarTextView?.text = "" diff --git a/commons/src/main/kotlin/org/fossify/commons/adapters/MyRecyclerViewListAdapter.kt b/commons/src/main/kotlin/org/fossify/commons/adapters/MyRecyclerViewListAdapter.kt index 241c01bd3..0679f67f6 100644 --- a/commons/src/main/kotlin/org/fossify/commons/adapters/MyRecyclerViewListAdapter.kt +++ b/commons/src/main/kotlin/org/fossify/commons/adapters/MyRecyclerViewListAdapter.kt @@ -62,8 +62,6 @@ abstract class MyRecyclerViewListAdapter( init { actModeCallback = object : MyActionModeCallback() { - private var savedStatusBarColor = activity.getProperStatusBarColor() - override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean { actionItemPressed(item.itemId) return true @@ -94,13 +92,6 @@ abstract class MyRecyclerViewListAdapter( resources.getColor(R.color.dark_grey, activity.theme) } - savedStatusBarColor = activity.window.statusBarColor - activity.animateStatusBarColor( - colorTo = bgColor, - colorFrom = savedStatusBarColor, - duration = 300L - ) - actBarTextView!!.setTextColor(bgColor.getContrastColor()) activity.updateMenuItemColors(menu, baseColor = bgColor) onActionModeCreated() @@ -128,12 +119,6 @@ abstract class MyRecyclerViewListAdapter( } } - activity.animateStatusBarColor( - colorTo = savedStatusBarColor, - colorFrom = activity.window.statusBarColor, - duration = 400L - ) - updateTitle() selectedKeys.clear() actBarTextView?.text = "" diff --git a/commons/src/main/kotlin/org/fossify/commons/compose/alert_dialog/AlertDialogsExtensions.kt b/commons/src/main/kotlin/org/fossify/commons/compose/alert_dialog/AlertDialogsExtensions.kt index 937f52e7e..099f532b2 100644 --- a/commons/src/main/kotlin/org/fossify/commons/compose/alert_dialog/AlertDialogsExtensions.kt +++ b/commons/src/main/kotlin/org/fossify/commons/compose/alert_dialog/AlertDialogsExtensions.kt @@ -36,12 +36,12 @@ val dialogContainerColor } } -val Modifier.dialogBackgroundShapeAndBorder: Modifier - @ReadOnlyComposable - @Composable get() = this - .fillMaxWidth() - .background(dialogContainerColor, dialogShape) - .dialogBorder +@Composable +@ReadOnlyComposable +fun Modifier.dialogBackgroundShapeAndBorder(): Modifier = this + .fillMaxWidth() + .background(dialogContainerColor, dialogShape) + .dialogBorder() val dialogShape = Shapes.extraLarge @@ -49,13 +49,13 @@ val dialogElevation = 0.dp val dialogTextColor @Composable @ReadOnlyComposable get() = SimpleTheme.colorScheme.onSurface -val Modifier.dialogBorder: Modifier - @ReadOnlyComposable - @Composable get() = - when (LocalTheme.current) { - is Theme.BlackAndWhite -> this.border(1.dp, light_grey_stroke, dialogShape) - else -> this - } +@Composable +@ReadOnlyComposable +fun Modifier.dialogBorder(): Modifier = + when (LocalTheme.current) { + is Theme.BlackAndWhite -> this.border(1.dp, light_grey_stroke, dialogShape) + else -> this + } @Composable fun DialogSurface( @@ -64,7 +64,7 @@ fun DialogSurface( ) { Surface( modifier = modifier - .dialogBorder, + .dialogBorder(), shape = dialogShape, color = dialogContainerColor, tonalElevation = dialogElevation, diff --git a/commons/src/main/kotlin/org/fossify/commons/compose/bottom_sheet/BottomSheetDialogsExtensions.kt b/commons/src/main/kotlin/org/fossify/commons/compose/bottom_sheet/BottomSheetDialogsExtensions.kt index e59b1a109..073abc280 100644 --- a/commons/src/main/kotlin/org/fossify/commons/compose/bottom_sheet/BottomSheetDialogsExtensions.kt +++ b/commons/src/main/kotlin/org/fossify/commons/compose/bottom_sheet/BottomSheetDialogsExtensions.kt @@ -22,13 +22,13 @@ val bottomSheetDialogShape = Shapes.extraLarge.copy( bottomStart = CornerSize(0f) ) -val Modifier.bottomSheetDialogBorder: Modifier - @ReadOnlyComposable - @Composable get() = - when (LocalTheme.current) { - is Theme.BlackAndWhite -> this.border(2.dp, light_grey_stroke, bottomSheetDialogShape) - else -> this - } +@Composable +@ReadOnlyComposable +fun Modifier.bottomSheetDialogBorder(): Modifier = + when (LocalTheme.current) { + is Theme.BlackAndWhite -> this.border(2.dp, light_grey_stroke, bottomSheetDialogShape) + else -> this + } @Composable fun BottomSheetSpacerEdgeToEdge() { @@ -43,7 +43,7 @@ fun BottomSheetColumnDialogSurface( Surface( modifier = modifier .fillMaxSize() - .bottomSheetDialogBorder, + .bottomSheetDialogBorder(), shape = bottomSheetDialogShape, color = dialogContainerColor, tonalElevation = dialogElevation, @@ -62,7 +62,7 @@ fun BottomSheetBoxDialogSurface( Surface( modifier = modifier .fillMaxSize() - .bottomSheetDialogBorder, + .bottomSheetDialogBorder(), shape = bottomSheetDialogShape, color = dialogContainerColor, tonalElevation = dialogElevation, @@ -81,7 +81,7 @@ fun BottomSheetDialogSurface( Surface( modifier = modifier .fillMaxSize() - .bottomSheetDialogBorder, + .bottomSheetDialogBorder(), shape = bottomSheetDialogShape, color = dialogContainerColor, tonalElevation = dialogElevation, diff --git a/commons/src/main/kotlin/org/fossify/commons/compose/menus/ActionMenu.kt b/commons/src/main/kotlin/org/fossify/commons/compose/menus/ActionMenu.kt index 184155522..758abcdbf 100644 --- a/commons/src/main/kotlin/org/fossify/commons/compose/menus/ActionMenu.kt +++ b/commons/src/main/kotlin/org/fossify/commons/compose/menus/ActionMenu.kt @@ -144,7 +144,7 @@ fun ActionMenu( DropdownMenu( modifier = Modifier .background(dialogContainerColor) - .dialogBorder, + .dialogBorder(), expanded = isMenuVisible, onDismissRequest = { onMenuToggle(false) }, ) { diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/AddBlockedNumberDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/AddBlockedNumberDialog.kt index 8d25b05cc..731e8893a 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/AddBlockedNumberDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/AddBlockedNumberDialog.kt @@ -42,7 +42,7 @@ fun AddOrEditBlockedNumberAlertDialog( AlertDialog( containerColor = dialogContainerColor, modifier = modifier - .dialogBorder, + .dialogBorder(), onDismissRequest = alertDialogState::hide, confirmButton = { TextButton(onClick = { diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/AppSideloadedDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/AppSideloadedDialog.kt index 050160cd7..39665c38e 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/AppSideloadedDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/AppSideloadedDialog.kt @@ -70,7 +70,7 @@ fun AppSideLoadedAlertDialog( AlertDialog( containerColor = dialogContainerColor, modifier = modifier - .dialogBorder, + .dialogBorder(), onDismissRequest = alertDialogState::hide, confirmButton = { TextButton(onClick = { diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/CallConfirmationDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/CallConfirmationDialog.kt index bfa3ffa33..3f670dd1c 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/CallConfirmationDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/CallConfirmationDialog.kt @@ -68,7 +68,7 @@ fun CallConfirmationAlertDialog( androidx.compose.material3.AlertDialog( containerColor = dialogContainerColor, modifier = modifier - .dialogBorder, + .dialogBorder(), onDismissRequest = { alertDialogState.hide() callback() diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/ColorPickerDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/ColorPickerDialog.kt index cb1133316..5af6cc391 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/ColorPickerDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/ColorPickerDialog.kt @@ -159,7 +159,7 @@ fun ColorPickerAlertDialog( AlertDialog( modifier = modifier - .dialogBorder, + .dialogBorder(), onDismissRequest = alertDialogState::hide, properties = DialogProperties(usePlatformDefaultWidth = false) ) { diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/ConfirmationAdvancedDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/ConfirmationAdvancedDialog.kt index 80942b722..f46e6f71b 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/ConfirmationAdvancedDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/ConfirmationAdvancedDialog.kt @@ -73,7 +73,7 @@ fun ConfirmationAdvancedAlertDialog( androidx.compose.material3.AlertDialog( containerColor = dialogContainerColor, modifier = modifier - .dialogBorder, + .dialogBorder(), properties = DialogProperties(dismissOnClickOutside = cancelOnTouchOutside), onDismissRequest = { alertDialogState.hide() diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/ConfirmationDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/ConfirmationDialog.kt index 2c35c37c5..6e9265b1d 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/ConfirmationDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/ConfirmationDialog.kt @@ -80,7 +80,7 @@ fun ConfirmationAlertDialog( androidx.compose.material3.AlertDialog( containerColor = dialogContainerColor, modifier = modifier - .dialogBorder, + .dialogBorder(), properties = DialogProperties(dismissOnClickOutside = cancelOnTouchOutside), onDismissRequest = { alertDialogState.hide() diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/CreateNewFolderDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/CreateNewFolderDialog.kt index 170ef3633..3d4de0a47 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/CreateNewFolderDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/CreateNewFolderDialog.kt @@ -118,7 +118,7 @@ fun CreateNewFolderAlertDialog( var title by remember { mutableStateOf("") } AlertDialog( - modifier = modifier.dialogBorder, + modifier = modifier.dialogBorder(), shape = dialogShape, containerColor = dialogContainerColor, tonalElevation = dialogElevation, diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/DonateDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/DonateDialog.kt index 439fb6773..f63090aa9 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/DonateDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/DonateDialog.kt @@ -64,7 +64,7 @@ fun DonateAlertDialog( androidx.compose.material3.AlertDialog( containerColor = dialogContainerColor, modifier = modifier - .dialogBorder, + .dialogBorder(), properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = false), onDismissRequest = {}, shape = dialogShape, diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/EnterPasswordDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/EnterPasswordDialog.kt index afc8c7f8b..657994cb7 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/EnterPasswordDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/EnterPasswordDialog.kt @@ -91,7 +91,7 @@ fun EnterPasswordAlertDialog( } } AlertDialog( - modifier = modifier.dialogBorder, + modifier = modifier.dialogBorder(), shape = dialogShape, containerColor = dialogContainerColor, tonalElevation = dialogElevation, diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/FeatureLockedDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/FeatureLockedDialog.kt index fd71cf000..f9aa1907b 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/FeatureLockedDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/FeatureLockedDialog.kt @@ -72,7 +72,7 @@ fun FeatureLockedAlertDialog( androidx.compose.material3.AlertDialog( containerColor = dialogContainerColor, modifier = modifier - .dialogBorder, + .dialogBorder(), properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = false), onDismissRequest = cancelCallback, shape = dialogShape, diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/FilePickerDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/FilePickerDialog.kt index 10aeb896a..2fae35f98 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/FilePickerDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/FilePickerDialog.kt @@ -2,8 +2,8 @@ package org.fossify.commons.dialogs import android.os.Environment import android.os.Parcelable -import android.view.KeyEvent import android.widget.Toast +import androidx.activity.addCallback import androidx.appcompat.app.AlertDialog import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.documentfile.provider.DocumentFile @@ -13,7 +13,39 @@ import org.fossify.commons.activities.BaseSimpleActivity import org.fossify.commons.adapters.FilepickerFavoritesAdapter import org.fossify.commons.adapters.FilepickerItemsAdapter import org.fossify.commons.databinding.DialogFilepickerBinding -import org.fossify.commons.extensions.* +import org.fossify.commons.extensions.areSystemAnimationsEnabled +import org.fossify.commons.extensions.baseConfig +import org.fossify.commons.extensions.beGone +import org.fossify.commons.extensions.beVisible +import org.fossify.commons.extensions.beVisibleIf +import org.fossify.commons.extensions.getAlertDialogBuilder +import org.fossify.commons.extensions.getAndroidSAFFileItems +import org.fossify.commons.extensions.getColoredDrawableWithColor +import org.fossify.commons.extensions.getContrastColor +import org.fossify.commons.extensions.getDirectChildrenCount +import org.fossify.commons.extensions.getDoesFilePathExist +import org.fossify.commons.extensions.getFilenameFromPath +import org.fossify.commons.extensions.getFolderLastModifieds +import org.fossify.commons.extensions.getIsPathDirectory +import org.fossify.commons.extensions.getOTGItems +import org.fossify.commons.extensions.getParentPath +import org.fossify.commons.extensions.getProperPrimaryColor +import org.fossify.commons.extensions.getProperTextColor +import org.fossify.commons.extensions.getSomeAndroidSAFDocument +import org.fossify.commons.extensions.getSomeDocumentFile +import org.fossify.commons.extensions.getSomeDocumentSdk30 +import org.fossify.commons.extensions.getTextSize +import org.fossify.commons.extensions.handleHiddenFolderPasswordProtection +import org.fossify.commons.extensions.handleLockedFolderOpening +import org.fossify.commons.extensions.internalStoragePath +import org.fossify.commons.extensions.isAccessibleWithSAFSdk30 +import org.fossify.commons.extensions.isInDownloadDir +import org.fossify.commons.extensions.isPathOnOTG +import org.fossify.commons.extensions.isRestrictedSAFOnlyRoot +import org.fossify.commons.extensions.isRestrictedWithSAFSdk30 +import org.fossify.commons.extensions.isVisible +import org.fossify.commons.extensions.setupDialogStuff +import org.fossify.commons.extensions.toast import org.fossify.commons.helpers.ensureBackgroundThread import org.fossify.commons.models.FileDirItem import org.fossify.commons.views.Breadcrumbs @@ -75,19 +107,6 @@ class FilePickerDialog( val builder = activity.getAlertDialogBuilder() .setNegativeButton(R.string.cancel, null) - .setOnKeyListener { dialogInterface, i, keyEvent -> - if (keyEvent.action == KeyEvent.ACTION_UP && i == KeyEvent.KEYCODE_BACK) { - val breadcrumbs = mDialogView.filepickerBreadcrumbs - if (breadcrumbs.getItemCount() > 1) { - breadcrumbs.removeBreadcrumb() - currPath = breadcrumbs.getLastItem().path.trimEnd('/') - tryUpdateItems() - } else { - mDialog?.dismiss() - } - } - true - } if (!pickFile) { builder.setPositiveButton(R.string.ok, null) @@ -133,6 +152,17 @@ class FilePickerDialog( builder.apply { activity.setupDialogStuff(mDialogView.root, this, getTitle()) { alertDialog -> mDialog = alertDialog + alertDialog.onBackPressedDispatcher.addCallback(alertDialog) { + val breadcrumbs = mDialogView.filepickerBreadcrumbs + if (breadcrumbs.getItemCount() > 1) { + breadcrumbs.removeBreadcrumb() + currPath = breadcrumbs.getLastItem().path.trimEnd('/') + tryUpdateItems() + } else { + isEnabled = false + alertDialog.onBackPressedDispatcher.onBackPressed() + } + } } } diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/FolderLockingNoticeDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/FolderLockingNoticeDialog.kt index 3eae3a004..b9d6016a3 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/FolderLockingNoticeDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/FolderLockingNoticeDialog.kt @@ -46,7 +46,7 @@ fun FolderLockingNoticeAlertDialog( callback: () -> Unit ) { AlertDialog( - modifier = modifier.dialogBorder, + modifier = modifier.dialogBorder(), shape = dialogShape, containerColor = dialogContainerColor, tonalElevation = dialogElevation, diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/LineColorPickerDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/LineColorPickerDialog.kt index 7610ce3f3..5f94c1396 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/LineColorPickerDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/LineColorPickerDialog.kt @@ -1,6 +1,7 @@ package org.fossify.commons.dialogs import android.content.Context +import android.graphics.Color import android.view.WindowManager import android.widget.FrameLayout import androidx.annotation.ColorInt @@ -21,7 +22,6 @@ import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogWindowProvider import androidx.core.content.ContextCompat import androidx.core.view.updateLayoutParams -import com.google.android.material.appbar.MaterialToolbar import org.fossify.commons.R import org.fossify.commons.activities.BaseSimpleActivity import org.fossify.commons.compose.alert_dialog.AlertDialogState @@ -34,19 +34,27 @@ import org.fossify.commons.compose.theme.SimpleTheme import org.fossify.commons.databinding.DialogLineColorPickerBinding import org.fossify.commons.extensions.* import org.fossify.commons.interfaces.LineColorPickerListener +import org.fossify.commons.views.MyAppBarLayout class LineColorPickerDialog( - val activity: BaseSimpleActivity, val color: Int, val isPrimaryColorPicker: Boolean, val primaryColors: Int = R.array.md_primary_colors, - val appIconIDs: ArrayList? = null, val toolbar: MaterialToolbar? = null, val callback: (wasPositivePressed: Boolean, color: Int) -> Unit + val activity: BaseSimpleActivity, + val color: Int, + val isPrimaryColorPicker: Boolean, + val primaryColors: Int = R.array.md_primary_colors, + val appIconIDs: ArrayList? = null, + val appBar: MyAppBarLayout? = null, + val callback: (wasPositivePressed: Boolean, color: Int) -> Unit ) { - private val PRIMARY_COLORS_COUNT = 19 - private val DEFAULT_PRIMARY_COLOR_INDEX = 9 - private val DEFAULT_SECONDARY_COLOR_INDEX = 8 - private val DEFAULT_COLOR_VALUE = activity.resources.getColor(R.color.color_primary) + companion object { + private const val PRIMARY_COLORS_COUNT = 19 + private const val DEFAULT_PRIMARY_COLOR_INDEX = 9 + private const val DEFAULT_SECONDARY_COLOR_INDEX = 8 + } private var wasDimmedBackgroundRemoved = false private var dialog: AlertDialog? = null private var view = DialogLineColorPickerBinding.inflate(activity.layoutInflater, null, false) + private val defaultColorValue = activity.resources.getColor(R.color.color_primary) init { view.apply { @@ -96,8 +104,8 @@ class LineColorPickerDialog( view.hexCode.text = color.toHex() if (isPrimaryColorPicker) { - if (toolbar != null) { - activity.updateTopBarColors(toolbar, color) + if (appBar != null) { + activity.updateTopBarColors(appBar, color) } if (!wasDimmedBackgroundRemoved) { @@ -108,7 +116,7 @@ class LineColorPickerDialog( } private fun getColorIndexes(color: Int): Pair { - if (color == DEFAULT_COLOR_VALUE) { + if (color == defaultColorValue) { return getDefaultColorPair() } @@ -328,7 +336,7 @@ private fun Context.getColors(id: Int) = resources.getIntArray(id).toCollection( private fun LineColorPickerAlertDialogPreview() { AppThemeSurface { LineColorPickerAlertDialog(alertDialogState = rememberAlertDialogState(), - color = R.color.color_primary, + color = Color.GREEN, isPrimaryColorPicker = true, onActiveColorChange = {} ) { _, _ -> } diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/OpenDeviceSettingsDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/OpenDeviceSettingsDialog.kt index 127114d78..6cde77286 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/OpenDeviceSettingsDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/OpenDeviceSettingsDialog.kt @@ -46,7 +46,7 @@ fun OpenDeviceSettingsAlertDialog( AlertDialog( containerColor = dialogContainerColor, modifier = modifier - .dialogBorder, + .dialogBorder(), onDismissRequest = alertDialogState::hide, shape = dialogShape, tonalElevation = dialogElevation, diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/PermissionRequiredDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/PermissionRequiredDialog.kt index dda7d92f7..b0fcf257c 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/PermissionRequiredDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/PermissionRequiredDialog.kt @@ -52,7 +52,7 @@ fun PermissionRequiredAlertDialog( AlertDialog( containerColor = dialogContainerColor, modifier = modifier - .dialogBorder, + .dialogBorder(), onDismissRequest = alertDialogState::hide, shape = dialogShape, tonalElevation = dialogElevation, diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/PurchaseThankYouDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/PurchaseThankYouDialog.kt index 1c6a7c5bc..1f6f00cff 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/PurchaseThankYouDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/PurchaseThankYouDialog.kt @@ -58,7 +58,7 @@ fun PurchaseThankYouAlertDialog( androidx.compose.material3.AlertDialog( containerColor = dialogContainerColor, modifier = modifier - .dialogBorder, + .dialogBorder(), properties = DialogProperties(dismissOnClickOutside = false, dismissOnBackPress = false), onDismissRequest = {}, shape = dialogShape, diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/UpgradeToProDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/UpgradeToProDialog.kt index 6fe63e04d..31efa88f3 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/UpgradeToProDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/UpgradeToProDialog.kt @@ -109,7 +109,7 @@ fun UpgradeToProAlertDialog( } } }, - modifier = modifier.dialogBorder, + modifier = modifier.dialogBorder(), properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) ) } diff --git a/commons/src/main/kotlin/org/fossify/commons/dialogs/WhatsNewDialog.kt b/commons/src/main/kotlin/org/fossify/commons/dialogs/WhatsNewDialog.kt index 64b58e02c..1516a96d2 100644 --- a/commons/src/main/kotlin/org/fossify/commons/dialogs/WhatsNewDialog.kt +++ b/commons/src/main/kotlin/org/fossify/commons/dialogs/WhatsNewDialog.kt @@ -72,7 +72,7 @@ fun WhatsNewAlertDialog( containerColor = dialogContainerColor, shape = dialogShape, tonalElevation = dialogElevation, - modifier = modifier.dialogBorder, + modifier = modifier.dialogBorder(), title = { Text( text = stringResource(id = R.string.whats_new), diff --git a/commons/src/main/kotlin/org/fossify/commons/extensions/Activity-themes.kt b/commons/src/main/kotlin/org/fossify/commons/extensions/Activity-themes.kt index 4fd6d6f5c..4684886c1 100644 --- a/commons/src/main/kotlin/org/fossify/commons/extensions/Activity-themes.kt +++ b/commons/src/main/kotlin/org/fossify/commons/extensions/Activity-themes.kt @@ -19,7 +19,7 @@ fun Activity.getThemeId(color: Int = baseConfig.primaryColor, showTransparentTop else -> R.style.AppTheme_White } - showTransparentTop -> { + else -> { when (color) { -12846 -> R.style.AppTheme_Red_100_core -1074534 -> R.style.AppTheme_Red_200_core @@ -214,200 +214,4 @@ fun Activity.getThemeId(color: Int = baseConfig.primaryColor, showTransparentTop else -> R.style.AppTheme_Green_900_core } } - - else -> { - when (color) { - -12846 -> R.style.AppTheme_Red_100 - -1074534 -> R.style.AppTheme_Red_200 - -1739917 -> R.style.AppTheme_Red_300 - -1092784 -> R.style.AppTheme_Red_400 - -769226 -> R.style.AppTheme_Red_500 - -1754827 -> R.style.AppTheme_Red_600 - -2937041 -> R.style.AppTheme_Red_700 - -3790808 -> R.style.AppTheme_Red_800 - -4776932 -> R.style.AppTheme_Red_900 - - -476208 -> R.style.AppTheme_Pink_100 - -749647 -> R.style.AppTheme_Pink_200 - -1023342 -> R.style.AppTheme_Pink_300 - -1294214 -> R.style.AppTheme_Pink_400 - -1499549 -> R.style.AppTheme_Pink_500 - -2614432 -> R.style.AppTheme_Pink_600 - -4056997 -> R.style.AppTheme_Pink_700 - -5434281 -> R.style.AppTheme_Pink_800 - -7860657 -> R.style.AppTheme_Pink_900 - - -1982745 -> R.style.AppTheme_Purple_100 - -3238952 -> R.style.AppTheme_Purple_200 - -4560696 -> R.style.AppTheme_Purple_300 - -5552196 -> R.style.AppTheme_Purple_400 - -6543440 -> R.style.AppTheme_Purple_500 - -7461718 -> R.style.AppTheme_Purple_600 - -8708190 -> R.style.AppTheme_Purple_700 - -9823334 -> R.style.AppTheme_Purple_800 - -11922292 -> R.style.AppTheme_Purple_900 - - -3029783 -> R.style.AppTheme_Deep_Purple_100 - -5005861 -> R.style.AppTheme_Deep_Purple_200 - -6982195 -> R.style.AppTheme_Deep_Purple_300 - -8497214 -> R.style.AppTheme_Deep_Purple_400 - -10011977 -> R.style.AppTheme_Deep_Purple_500 - -10603087 -> R.style.AppTheme_Deep_Purple_600 - -11457112 -> R.style.AppTheme_Deep_Purple_700 - -12245088 -> R.style.AppTheme_Deep_Purple_800 - -13558894 -> R.style.AppTheme_Deep_Purple_900 - - -3814679 -> R.style.AppTheme_Indigo_100 - -6313766 -> R.style.AppTheme_Indigo_200 - -8812853 -> R.style.AppTheme_Indigo_300 - -10720320 -> R.style.AppTheme_Indigo_400 - -12627531 -> R.style.AppTheme_Indigo_500 - -13022805 -> R.style.AppTheme_Indigo_600 - -13615201 -> R.style.AppTheme_Indigo_700 - -14142061 -> R.style.AppTheme_Indigo_800 - -15064194 -> R.style.AppTheme_Indigo_900 - - -4464901 -> R.style.AppTheme_Blue_100 - -7288071 -> R.style.AppTheme_Blue_200 - -10177034 -> R.style.AppTheme_Blue_300 - -12409355 -> R.style.AppTheme_Blue_400 - -14575885 -> R.style.AppTheme_Blue_500 - -14776091 -> R.style.AppTheme_Blue_600 - -15108398 -> R.style.AppTheme_Blue_700 - -15374912 -> R.style.AppTheme_Blue_800 - -15906911 -> R.style.AppTheme_Blue_900 - - -4987396 -> R.style.AppTheme_Light_Blue_100 - -8268550 -> R.style.AppTheme_Light_Blue_200 - -11549705 -> R.style.AppTheme_Light_Blue_300 - -14043396 -> R.style.AppTheme_Light_Blue_400 - -16537100 -> R.style.AppTheme_Light_Blue_500 - -16540699 -> R.style.AppTheme_Light_Blue_600 - -16611119 -> R.style.AppTheme_Light_Blue_700 - -16615491 -> R.style.AppTheme_Light_Blue_800 - -16689253 -> R.style.AppTheme_Light_Blue_900 - - -5051406 -> R.style.AppTheme_Cyan_100 - -8331542 -> R.style.AppTheme_Cyan_200 - -11677471 -> R.style.AppTheme_Cyan_300 - -14235942 -> R.style.AppTheme_Cyan_400 - -16728876 -> R.style.AppTheme_Cyan_500 - -16732991 -> R.style.AppTheme_Cyan_600 - -16738393 -> R.style.AppTheme_Cyan_700 - -16743537 -> R.style.AppTheme_Cyan_800 - -16752540 -> R.style.AppTheme_Cyan_900 - - -5054501 -> R.style.AppTheme_Teal_100 - -8336444 -> R.style.AppTheme_Teal_200 - -11684180 -> R.style.AppTheme_Teal_300 - -14244198 -> R.style.AppTheme_Teal_400 - -16738680 -> R.style.AppTheme_Teal_500 - -16742021 -> R.style.AppTheme_Teal_600 - -16746133 -> R.style.AppTheme_Teal_700 - -16750244 -> R.style.AppTheme_Teal_800 - -16757440 -> R.style.AppTheme_Teal_900 - - -2691126 -> R.style.AppTheme_Green_100 - -4528984 -> R.style.AppTheme_Green_200 - -6366844 -> R.style.AppTheme_Green_300 - -7810712 -> R.style.AppTheme_Green_400 - -9254834 -> R.style.AppTheme_Green_500 - -10176442 -> R.style.AppTheme_Green_600 - -11492293 -> R.style.AppTheme_Green_700 - -12808398 -> R.style.AppTheme_Green_800 - -15700705 -> R.style.AppTheme_Green_900 - - -2298424 -> R.style.AppTheme_Light_Green_100 - -3808859 -> R.style.AppTheme_Light_Green_200 - -5319295 -> R.style.AppTheme_Light_Green_300 - -6501275 -> R.style.AppTheme_Light_Green_400 - -7617718 -> R.style.AppTheme_Light_Green_500 - -8604862 -> R.style.AppTheme_Light_Green_600 - -9920712 -> R.style.AppTheme_Light_Green_700 - -11171025 -> R.style.AppTheme_Light_Green_800 - -13407970 -> R.style.AppTheme_Light_Green_900 - - -985917 -> R.style.AppTheme_Lime_100 - -1642852 -> R.style.AppTheme_Lime_200 - -2300043 -> R.style.AppTheme_Lime_300 - -2825897 -> R.style.AppTheme_Lime_400 - -3285959 -> R.style.AppTheme_Lime_500 - -4142541 -> R.style.AppTheme_Lime_600 - -5983189 -> R.style.AppTheme_Lime_700 - -6382300 -> R.style.AppTheme_Lime_800 - -8227049 -> R.style.AppTheme_Lime_900 - - -1596 -> R.style.AppTheme_Yellow_100 - -2672 -> R.style.AppTheme_Yellow_200 - -3722 -> R.style.AppTheme_Yellow_300 - -4520 -> R.style.AppTheme_Yellow_400 - -5317 -> R.style.AppTheme_Yellow_500 - -141259 -> R.style.AppTheme_Yellow_600 - -278483 -> R.style.AppTheme_Yellow_700 - -415707 -> R.style.AppTheme_Yellow_800 - -688361 -> R.style.AppTheme_Yellow_900 - - -4941 -> R.style.AppTheme_Amber_100 - -8062 -> R.style.AppTheme_Amber_200 - -10929 -> R.style.AppTheme_Amber_300 - -13784 -> R.style.AppTheme_Amber_400 - -16121 -> R.style.AppTheme_Amber_500 - -19712 -> R.style.AppTheme_Amber_600 - -24576 -> R.style.AppTheme_Amber_700 - -28928 -> R.style.AppTheme_Amber_800 - -37120 -> R.style.AppTheme_Amber_900 - - -8014 -> R.style.AppTheme_Orange_100 - -13184 -> R.style.AppTheme_Orange_200 - -18611 -> R.style.AppTheme_Orange_300 - -22746 -> R.style.AppTheme_Orange_400 - -26624 -> R.style.AppTheme_Orange_500 - -291840 -> R.style.AppTheme_Orange_600 - -689152 -> R.style.AppTheme_Orange_700 - -1086464 -> R.style.AppTheme_Orange_800 - -1683200 -> R.style.AppTheme_Orange_900 - - -13124 -> R.style.AppTheme_Deep_Orange_100 - -21615 -> R.style.AppTheme_Deep_Orange_200 - -30107 -> R.style.AppTheme_Deep_Orange_300 - -36797 -> R.style.AppTheme_Deep_Orange_400 - -43230 -> R.style.AppTheme_Deep_Orange_500 - -765666 -> R.style.AppTheme_Deep_Orange_600 - -1684967 -> R.style.AppTheme_Deep_Orange_700 - -2604267 -> R.style.AppTheme_Deep_Orange_800 - -4246004 -> R.style.AppTheme_Deep_Orange_900 - - -2634552 -> R.style.AppTheme_Brown_100 - -4412764 -> R.style.AppTheme_Brown_200 - -6190977 -> R.style.AppTheme_Brown_300 - -7508381 -> R.style.AppTheme_Brown_400 - -8825528 -> R.style.AppTheme_Brown_500 - -9614271 -> R.style.AppTheme_Brown_600 - -10665929 -> R.style.AppTheme_Brown_700 - -11652050 -> R.style.AppTheme_Brown_800 - -12703965 -> R.style.AppTheme_Brown_900 - - -3155748 -> R.style.AppTheme_Blue_Grey_100 - -5194811 -> R.style.AppTheme_Blue_Grey_200 - -7297874 -> R.style.AppTheme_Blue_Grey_300 - -8875876 -> R.style.AppTheme_Blue_Grey_400 - -10453621 -> R.style.AppTheme_Blue_Grey_500 - -11243910 -> R.style.AppTheme_Blue_Grey_600 - -12232092 -> R.style.AppTheme_Blue_Grey_700 - -13154481 -> R.style.AppTheme_Blue_Grey_800 - -14273992 -> R.style.AppTheme_Blue_Grey_900 - - -1 -> R.style.AppTheme_Grey_100 - -1118482 -> R.style.AppTheme_Grey_200 - -2039584 -> R.style.AppTheme_Grey_300 - -4342339 -> R.style.AppTheme_Grey_400 - -6381922 -> R.style.AppTheme_Grey_500 - -9079435 -> R.style.AppTheme_Grey_600 - -10395295 -> R.style.AppTheme_Grey_700 - -12434878 -> R.style.AppTheme_Grey_800 - -16777216 -> R.style.AppTheme_Grey_900 - - else -> R.style.AppTheme_Green_900 - } - } } diff --git a/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt b/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt index bd198911c..e195fb626 100644 --- a/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt +++ b/commons/src/main/kotlin/org/fossify/commons/extensions/Activity.kt @@ -143,8 +143,12 @@ fun Activity.showDonateOrUpgradeDialog() { } fun Activity.isAppInstalledOnSDCard(): Boolean = try { - val applicationInfo = packageManager.getPackageInfo(packageName, 0).applicationInfo - (applicationInfo.flags and ApplicationInfo.FLAG_EXTERNAL_STORAGE) == ApplicationInfo.FLAG_EXTERNAL_STORAGE + val appInfo = packageManager.getPackageInfo(packageName, 0).applicationInfo + if (appInfo != null) { + (appInfo.flags and ApplicationInfo.FLAG_EXTERNAL_STORAGE) == ApplicationInfo.FLAG_EXTERNAL_STORAGE + } else { + false + } } catch (e: Exception) { false } @@ -1720,6 +1724,20 @@ fun BaseSimpleActivity.getAlarmSounds(type: Int, callback: (ArrayList true diff --git a/commons/src/main/kotlin/org/fossify/commons/extensions/Context.kt b/commons/src/main/kotlin/org/fossify/commons/extensions/Context.kt index 2621334da..9f3033dc1 100644 --- a/commons/src/main/kotlin/org/fossify/commons/extensions/Context.kt +++ b/commons/src/main/kotlin/org/fossify/commons/extensions/Context.kt @@ -1,7 +1,6 @@ package org.fossify.commons.extensions import android.Manifest -import android.annotation.TargetApi import android.app.Activity import android.app.Application import android.app.NotificationManager @@ -116,7 +115,6 @@ import org.fossify.commons.helpers.YOUR_ALARM_SOUNDS_MIN_ID import org.fossify.commons.helpers.ensureBackgroundThread import org.fossify.commons.helpers.isNougatPlus import org.fossify.commons.helpers.isOnMainThread -import org.fossify.commons.helpers.isOreoPlus import org.fossify.commons.helpers.isQPlus import org.fossify.commons.helpers.isRPlus import org.fossify.commons.helpers.isSPlus @@ -129,6 +127,8 @@ import java.io.File import java.text.SimpleDateFormat import java.util.Date import java.util.Locale +import androidx.core.net.toUri +import kotlin.math.roundToInt fun Context.getSharedPrefs() = getSharedPreferences(PREFS_KEY, Context.MODE_PRIVATE) @@ -480,7 +480,7 @@ fun Context.ensurePublicUri(path: String, applicationId: String): Uri? { } else -> { - val uri = Uri.parse(path) + val uri = path.toUri() if (uri.scheme == "content") { uri } else { @@ -758,7 +758,11 @@ fun Context.getDefaultAlarmSound(type: Int) = AlarmSound(0, getDefaultAlarmTitle fun Context.grantReadUriPermission(uriString: String) { try { // ensure custom reminder sounds play well - grantUriPermission("com.android.systemui", Uri.parse(uriString), Intent.FLAG_GRANT_READ_URI_PERMISSION) + grantUriPermission( + "com.android.systemui", + uriString.toUri(), + Intent.FLAG_GRANT_READ_URI_PERMISSION + ) } catch (ignored: Exception) { } } @@ -874,7 +878,7 @@ fun Context.getVideoResolution(path: String): Point? { if (point == null && path.startsWith("content://", true)) { try { - val fd = contentResolver.openFileDescriptor(Uri.parse(path), "r")?.fileDescriptor + val fd = contentResolver.openFileDescriptor(path.toUri(), "r")?.fileDescriptor val retriever = MediaMetadataRetriever() retriever.setDataSource(fd) val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)!!.toInt() @@ -900,7 +904,7 @@ fun Context.getDuration(path: String): Int? { val cursor = contentResolver.query(uri, projection, selection, selectionArgs, null) cursor?.use { if (cursor.moveToFirst()) { - return Math.round(cursor.getIntValue(MediaColumns.DURATION) / 1000.toDouble()).toInt() + return (cursor.getIntValue(MediaColumns.DURATION) / 1000.toDouble()).roundToInt() } } } catch (ignored: Exception) { @@ -909,7 +913,8 @@ fun Context.getDuration(path: String): Int? { return try { val retriever = MediaMetadataRetriever() retriever.setDataSource(path) - Math.round(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)!!.toInt() / 1000f) + (retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)!! + .toInt() / 1000f).roundToInt() } catch (ignored: Exception) { null } @@ -1044,45 +1049,6 @@ val Context.notificationManager: NotificationManager get() = getSystemService(Co val Context.shortcutManager: ShortcutManager get() = getSystemService(ShortcutManager::class.java) as ShortcutManager val Context.portrait get() = resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT -val Context.navigationBarOnSide: Boolean get() = usableScreenSize.x < realScreenSize.x && usableScreenSize.x > usableScreenSize.y -val Context.navigationBarOnBottom: Boolean get() = usableScreenSize.y < realScreenSize.y -val Context.navigationBarHeight: Int get() = if (navigationBarOnBottom && navigationBarSize.y != usableScreenSize.y) navigationBarSize.y else 0 -val Context.navigationBarWidth: Int get() = if (navigationBarOnSide) navigationBarSize.x else 0 - -val Context.navigationBarSize: Point - get() = when { - navigationBarOnSide -> Point(newNavigationBarHeight, usableScreenSize.y) - navigationBarOnBottom -> Point(usableScreenSize.x, newNavigationBarHeight) - else -> Point() - } - -val Context.newNavigationBarHeight: Int - get() { - var navigationBarHeight = 0 - val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android") - if (resourceId > 0) { - navigationBarHeight = resources.getDimensionPixelSize(resourceId) - } - return navigationBarHeight - } - -val Context.statusBarHeight: Int - get() { - var statusBarHeight = 0 - val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android") - if (resourceId > 0) { - statusBarHeight = resources.getDimensionPixelSize(resourceId) - } - return statusBarHeight - } - -val Context.actionBarHeight: Int - get() { - val styledAttributes = theme.obtainStyledAttributes(intArrayOf(android.R.attr.actionBarSize)) - val actionBarHeight = styledAttributes.getDimension(0, 0f) - styledAttributes.recycle() - return actionBarHeight.toInt() - } val Context.usableScreenSize: Point get() { @@ -1098,19 +1064,6 @@ val Context.realScreenSize: Point return size } -fun Context.isUsingGestureNavigation(): Boolean { - return try { - val resourceId = resources.getIdentifier("config_navBarInteractionMode", "integer", "android") - if (resourceId > 0) { - resources.getInteger(resourceId) == 2 - } else { - false - } - } catch (e: Exception) { - false - } -} - fun Context.getCornerRadius() = resources.getDimension(R.dimen.rounded_corner_radius_small) // we need the Default Dialer functionality only in Simple Dialer and in Simple Contacts for now @@ -1142,7 +1095,6 @@ fun Context.getContactsHasMap(withComparableNumbers: Boolean = false, callback: } } -@TargetApi(Build.VERSION_CODES.N) fun Context.getBlockedNumbersWithContact(callback: (ArrayList) -> Unit) { getContactsHasMap(true) { contacts -> val blockedNumbers = ArrayList() @@ -1176,7 +1128,6 @@ fun Context.getBlockedNumbersWithContact(callback: (ArrayList) -> } } -@TargetApi(Build.VERSION_CODES.N) fun Context.getBlockedNumbers(): ArrayList { val blockedNumbers = ArrayList() if (!isNougatPlus() || !isDefaultDialer()) { @@ -1202,7 +1153,6 @@ fun Context.getBlockedNumbers(): ArrayList { return blockedNumbers } -@TargetApi(Build.VERSION_CODES.N) fun Context.addBlockedNumber(number: String): Boolean { ContentValues().apply { put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, number) @@ -1219,7 +1169,6 @@ fun Context.addBlockedNumber(number: String): Boolean { return true } -@TargetApi(Build.VERSION_CODES.N) fun Context.deleteBlockedNumber(number: String): Boolean { val selection = "${BlockedNumbers.COLUMN_ORIGINAL_NUMBER} = ?" val selectionArgs = arrayOf(number) diff --git a/commons/src/main/kotlin/org/fossify/commons/extensions/Fossify.kt b/commons/src/main/kotlin/org/fossify/commons/extensions/Fossify.kt index 36e9480e9..f3a00da38 100644 --- a/commons/src/main/kotlin/org/fossify/commons/extensions/Fossify.kt +++ b/commons/src/main/kotlin/org/fossify/commons/extensions/Fossify.kt @@ -36,7 +36,7 @@ fun PackageManager.checkSignature(packageName: String?): Boolean { fun PackageManager.getSignatures(packageName: String): Array? { @Suppress("DEPRECATION") return if (isPiePlus()) { - getPackageInfo(packageName, GET_SIGNING_CERTIFICATES).signingInfo.apkContentsSigners + getPackageInfo(packageName, GET_SIGNING_CERTIFICATES).signingInfo?.apkContentsSigners } else { getPackageInfo(packageName, GET_SIGNATURES).signatures } diff --git a/commons/src/main/kotlin/org/fossify/commons/extensions/View.kt b/commons/src/main/kotlin/org/fossify/commons/extensions/View.kt index 938429186..16464671d 100644 --- a/commons/src/main/kotlin/org/fossify/commons/extensions/View.kt +++ b/commons/src/main/kotlin/org/fossify/commons/extensions/View.kt @@ -4,6 +4,9 @@ import android.content.Context import android.view.HapticFeedbackConstants import android.view.View import android.view.ViewTreeObserver +import androidx.annotation.Px +import androidx.core.view.updatePadding +import androidx.core.view.updatePaddingRelative import org.fossify.commons.R import org.fossify.commons.helpers.SHORT_ANIMATION_DURATION @@ -76,3 +79,27 @@ fun View.setDebouncedClickListener( } } } + +fun View.ensureBasePadding(): IntArray { + val key = R.id.tag_base_padding + val base = getTag(key) as? IntArray + if (base != null) return base + val arr = intArrayOf(paddingLeft, paddingTop, paddingRight, paddingBottom) + setTag(key, arr) + return arr +} + +fun View.updatePaddingWithBase( + @Px left: Int = 0, + @Px top: Int = 0, + @Px right: Int = 0, + @Px bottom: Int = 0, +) { + val base = ensureBasePadding() + updatePadding( + left = base[0] + left, + top = base[1] + top, + right = base[2] + right, + bottom = base[3] + bottom + ) +} diff --git a/commons/src/main/kotlin/org/fossify/commons/extensions/Window.kt b/commons/src/main/kotlin/org/fossify/commons/extensions/Window.kt index 1d2b55d8e..4b91bd758 100644 --- a/commons/src/main/kotlin/org/fossify/commons/extensions/Window.kt +++ b/commons/src/main/kotlin/org/fossify/commons/extensions/Window.kt @@ -2,33 +2,33 @@ package org.fossify.commons.extensions import android.view.View import android.view.Window +import androidx.core.view.WindowInsetsCompat +import androidx.core.view.WindowInsetsControllerCompat import org.fossify.commons.helpers.DARK_GREY -import org.fossify.commons.helpers.isOreoPlus -fun Window.updateStatusBarColors(backgroundColor: Int) { - statusBarColor = backgroundColor - updateStatusBarForegroundColor(backgroundColor) +fun Window.insetsController(view: View? = null): WindowInsetsControllerCompat { + return WindowInsetsControllerCompat(this, view ?: decorView) } -fun Window.updateStatusBarForegroundColor(backgroundColor: Int) { - if (backgroundColor.getContrastColor() == DARK_GREY) { - decorView.systemUiVisibility = decorView.systemUiVisibility.addBit(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) - } else { - decorView.systemUiVisibility = decorView.systemUiVisibility.removeBit(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) +fun Window.setSystemBarsAppearance(backgroundColor: Int) { + val isLightBackground = backgroundColor.getContrastColor() == DARK_GREY + insetsController().apply { + isAppearanceLightStatusBars = isLightBackground + isAppearanceLightNavigationBars = isLightBackground } } -fun Window.updateNavigationBarColors(backgroundColor: Int) { - navigationBarColor = backgroundColor - updateNavigationBarForegroundColor(backgroundColor) +fun Window.showBars() = insetsController().apply { + systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_DEFAULT + show(WindowInsetsCompat.Type.systemBars()) } -fun Window.updateNavigationBarForegroundColor(backgroundColor: Int) { - if (isOreoPlus()) { - if (backgroundColor.getContrastColor() == DARK_GREY) { - decorView.systemUiVisibility = decorView.systemUiVisibility.addBit(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) - } else { - decorView.systemUiVisibility = decorView.systemUiVisibility.removeBit(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) - } +fun Window.hideBars(transient: Boolean = true) = insetsController().apply { + systemBarsBehavior = if (transient) { + WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } else { + WindowInsetsControllerCompat.BEHAVIOR_DEFAULT } + + hide(WindowInsetsCompat.Type.systemBars()) } diff --git a/commons/src/main/kotlin/org/fossify/commons/helpers/Constants.kt b/commons/src/main/kotlin/org/fossify/commons/helpers/Constants.kt index 21587fccf..e2816b4cb 100644 --- a/commons/src/main/kotlin/org/fossify/commons/helpers/Constants.kt +++ b/commons/src/main/kotlin/org/fossify/commons/helpers/Constants.kt @@ -50,6 +50,7 @@ const val MD5 = "MD5" const val SHA1 = "SHA-1" const val SHA256 = "SHA-256" const val SHORT_ANIMATION_DURATION = 150L +const val DEFAULT_ANIMATION_DURATION = 300L val DARK_GREY = 0xFF333333.toInt() const val LOWER_ALPHA = 0.25f @@ -552,6 +553,12 @@ fun isTiramisuPlus() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) fun isUpsideDownCakePlus() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE +@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.VANILLA_ICE_CREAM) +fun isVanillaIceCreamPlus() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM + +@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.BAKLAVA) +fun isBaklavaPlus() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA + fun getDateFormats() = arrayListOf( "--MM-dd", "yyyy-MM-dd", diff --git a/commons/src/main/kotlin/org/fossify/commons/views/MyAppBarLayout.kt b/commons/src/main/kotlin/org/fossify/commons/views/MyAppBarLayout.kt new file mode 100644 index 000000000..40af25985 --- /dev/null +++ b/commons/src/main/kotlin/org/fossify/commons/views/MyAppBarLayout.kt @@ -0,0 +1,62 @@ +package org.fossify.commons.views + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat.Type +import androidx.core.view.updatePadding +import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.appbar.MaterialToolbar + +open class MyAppBarLayout @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : AppBarLayout(context, attrs, defStyleAttr) { + private var cachedToolbar: MaterialToolbar? = null + + init { + elevation = 0f + ViewCompat.setElevation(this, 0f) + stateListAnimator = null + isLiftOnScroll = false + isLifted = false + + ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets -> + val system = insets.getInsetsIgnoringVisibility(Type.systemBars()) + view.updatePadding(top = system.top, left = system.left, right = system.right) + insets + } + } + + open val toolbar: MaterialToolbar? + get() { + for (i in 0 until childCount) { + val child = getChildAt(i) + if (child is MaterialToolbar) { + return child.also { cachedToolbar = it } + } + } + + return null + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + ViewCompat.requestApplyInsets(this) + } + + override fun onViewAdded(child: View) { + super.onViewAdded(child) + cachedToolbar = null + } + + override fun onViewRemoved(child: View) { + super.onViewRemoved(child) + cachedToolbar = null + } + + fun requireToolbar(): MaterialToolbar = + toolbar ?: error("MyAppBarLayout requires a Toolbar/MaterialToolbar child") +} diff --git a/commons/src/main/kotlin/org/fossify/commons/views/MyFloatingActionButton.kt b/commons/src/main/kotlin/org/fossify/commons/views/MyFloatingActionButton.kt index c9ffc24aa..9a7a2d475 100644 --- a/commons/src/main/kotlin/org/fossify/commons/views/MyFloatingActionButton.kt +++ b/commons/src/main/kotlin/org/fossify/commons/views/MyFloatingActionButton.kt @@ -3,6 +3,8 @@ package org.fossify.commons.views import android.content.Context import android.content.res.ColorStateList import android.util.AttributeSet +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat import com.google.android.material.floatingactionbutton.FloatingActionButton import org.fossify.commons.extensions.applyColorFilter import org.fossify.commons.extensions.getContrastColor @@ -12,7 +14,19 @@ open class MyFloatingActionButton : FloatingActionButton { constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) + constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super( + context, + attrs, + defStyle + ) + + init { + ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets -> + val system = insets.getInsetsIgnoringVisibility(WindowInsetsCompat.Type.systemBars()) + translationY = -system.bottom.toFloat() + insets + } + } fun setColors(textColor: Int, accentColor: Int, backgroundColor: Int) { backgroundTintList = ColorStateList.valueOf(accentColor) diff --git a/commons/src/main/kotlin/org/fossify/commons/views/MySearchMenu.kt b/commons/src/main/kotlin/org/fossify/commons/views/MySearchMenu.kt index cd7cdd45f..1e1da6e3d 100644 --- a/commons/src/main/kotlin/org/fossify/commons/views/MySearchMenu.kt +++ b/commons/src/main/kotlin/org/fossify/commons/views/MySearchMenu.kt @@ -4,15 +4,23 @@ import android.app.Activity import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater -import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.appbar.MaterialToolbar import org.fossify.commons.R import org.fossify.commons.activities.BaseSimpleActivity import org.fossify.commons.databinding.MenuSearchBinding -import org.fossify.commons.extensions.* +import org.fossify.commons.extensions.adjustAlpha +import org.fossify.commons.extensions.applyColorFilter +import org.fossify.commons.extensions.getContrastColor +import org.fossify.commons.extensions.getProperBackgroundColor +import org.fossify.commons.extensions.getProperPrimaryColor +import org.fossify.commons.extensions.hideKeyboard +import org.fossify.commons.extensions.onTextChangeListener +import org.fossify.commons.extensions.removeBit +import org.fossify.commons.extensions.showKeyboard import org.fossify.commons.helpers.LOWER_ALPHA import org.fossify.commons.helpers.MEDIUM_ALPHA -open class MySearchMenu(context: Context, attrs: AttributeSet) : AppBarLayout(context, attrs) { +open class MySearchMenu(context: Context, attrs: AttributeSet) : MyAppBarLayout(context, attrs) { var isSearchOpen = false var useArrowIcon = false var onSearchOpenListener: (() -> Unit)? = null @@ -20,9 +28,10 @@ open class MySearchMenu(context: Context, attrs: AttributeSet) : AppBarLayout(co var onSearchTextChangedListener: ((text: String) -> Unit)? = null var onNavigateBackClickListener: (() -> Unit)? = null - val binding = MenuSearchBinding.inflate(LayoutInflater.from(context), this, true) + val binding = MenuSearchBinding.inflate(LayoutInflater.from(context), this) - fun getToolbar() = binding.topToolbar + override val toolbar: MaterialToolbar? + get() = binding.topToolbar fun setupMenu() { binding.topToolbarSearchIcon.setOnClickListener { @@ -77,14 +86,9 @@ open class MySearchMenu(context: Context, attrs: AttributeSet) : AppBarLayout(co binding.topToolbarSearch.hint = text } - fun toggleHideOnScroll(hideOnScroll: Boolean) { - val params = binding.topAppBarLayout.layoutParams as LayoutParams - if (hideOnScroll) { - params.scrollFlags = LayoutParams.SCROLL_FLAG_SCROLL or LayoutParams.SCROLL_FLAG_ENTER_ALWAYS - } else { - params.scrollFlags = params.scrollFlags.removeBit(LayoutParams.SCROLL_FLAG_SCROLL or LayoutParams.SCROLL_FLAG_ENTER_ALWAYS) - } - } + @Suppress("unused", "EmptyFunctionBlock") + @Deprecated("This feature is broken for now.") + fun toggleHideOnScroll(hideOnScroll: Boolean) {} fun toggleForceArrowBackIcon(useArrowBack: Boolean) { this.useArrowIcon = useArrowBack @@ -103,11 +107,12 @@ open class MySearchMenu(context: Context, attrs: AttributeSet) : AppBarLayout(co val contrastColor = backgroundColor.getContrastColor() setBackgroundColor(backgroundColor) - binding.topAppBarLayout.setBackgroundColor(backgroundColor) binding.topToolbarSearchIcon.applyColorFilter(contrastColor) - binding.topToolbarHolder.background?.applyColorFilter(context.getProperPrimaryColor().adjustAlpha(LOWER_ALPHA)) + binding.toolbarContainer.background?.applyColorFilter( + color = context.getProperPrimaryColor().adjustAlpha(LOWER_ALPHA) + ) binding.topToolbarSearch.setTextColor(contrastColor) binding.topToolbarSearch.setHintTextColor(contrastColor.adjustAlpha(MEDIUM_ALPHA)) - (context as? BaseSimpleActivity)?.updateTopBarColors(binding.topToolbar, backgroundColor) + (context as? BaseSimpleActivity)?.updateTopBarColors(this, backgroundColor) } } diff --git a/commons/src/main/res/layout/activity_customization.xml b/commons/src/main/res/layout/activity_customization.xml index 1a478aec2..db495e7e6 100644 --- a/commons/src/main/res/layout/activity_customization.xml +++ b/commons/src/main/res/layout/activity_customization.xml @@ -6,22 +6,29 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:layout_height="wrap_content"> + + + + + android:scrollbars="none" + app:layout_behavior="@string/appbar_scrolling_view_behavior"> - + android:layout_height="wrap_content"> - + android:layout_height="?attr/actionBarSize" + android:paddingStart="@dimen/activity_margin" + android:paddingTop="@dimen/medium_margin" + android:paddingEnd="@dimen/activity_margin" + android:paddingBottom="@dimen/medium_margin"> - - - + android:layout_height="wrap_content" + android:background="@drawable/search_menu_background" + android:focusableInTouchMode="true" + tools:ignore="UselessParent"> + + + + + + - + - - + + diff --git a/commons/src/main/res/values/ids.xml b/commons/src/main/res/values/ids.xml index a581e879d..3fdb40bfa 100644 --- a/commons/src/main/res/values/ids.xml +++ b/commons/src/main/res/values/ids.xml @@ -1,10 +1,11 @@ - - - - - - - + + + + + + + + diff --git a/commons/src/main/res/values/styles.xml b/commons/src/main/res/values/styles.xml index c852d6987..dc1beefc3 100644 --- a/commons/src/main/res/values/styles.xml +++ b/commons/src/main/res/values/styles.xml @@ -563,1545 +563,6 @@ @style/ActionMenuOverflowIcon - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -