diff --git a/app/lint-baseline.xml b/app/lint-baseline.xml index f061426ec1..c039a046af 100644 --- a/app/lint-baseline.xml +++ b/app/lint-baseline.xml @@ -23,6 +23,28 @@ column="32"/> + + + + + + + + @@ -53,14 +75,14 @@ + message="Overriding `@layout/exo_player_control_view` which is marked as private in androidx.media3:media3-ui:1.6.1. If deliberate, use tools:override="true", otherwise pick a different name."> + + + + - - - - - - - - @@ -388,13 +399,6 @@ column="13"/> - - - - + + + + - - - - - - - - diff --git a/app/lint.xml b/app/lint.xml index 4092b89aca..7807399067 100644 --- a/app/lint.xml +++ b/app/lint.xml @@ -63,6 +63,9 @@ + + + @@ -70,12 +73,7 @@ - - - - - + diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt index 3c3ac2fd69..6a4c4fbf7c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt @@ -25,7 +25,6 @@ import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.Color import android.graphics.drawable.Animatable -import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.net.Uri import android.os.Build @@ -49,6 +48,7 @@ import androidx.appcompat.content.res.AppCompatResources import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.app.ActivityCompat import androidx.core.content.pm.ShortcutManagerCompat +import androidx.core.graphics.drawable.toDrawable import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.MenuProvider import androidx.core.view.ViewCompat @@ -1021,7 +1021,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider { transition: Transition? ) { activeToolbar.navigationIcon = FixedSizeDrawable( - BitmapDrawable(resources, resource), + resource.toDrawable(resources), navIconSize, navIconSize ) diff --git a/app/src/main/java/com/keylesspalace/tusky/MainViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/MainViewModel.kt index 0d48657547..69e9694764 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MainViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/MainViewModel.kt @@ -15,7 +15,6 @@ package com.keylesspalace.tusky -import android.content.Context import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -33,7 +32,6 @@ import com.keylesspalace.tusky.entity.Status import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.util.ShareShortcutHelper import dagger.hilt.android.lifecycle.HiltViewModel -import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -46,7 +44,6 @@ import kotlinx.coroutines.launch @HiltViewModel class MainViewModel @Inject constructor( - @ApplicationContext private val context: Context, private val api: MastodonApi, private val eventHub: EventHub, private val accountManager: AccountManager, diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java index 070adb6f0f..bd3102923c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java @@ -11,7 +11,6 @@ import android.text.TextUtils; import android.text.format.DateUtils; import android.view.Gravity; -import android.view.Menu; import android.view.View; import android.view.ViewGroup; import android.widget.Button; @@ -24,7 +23,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; -import androidx.appcompat.widget.PopupMenu; import androidx.appcompat.widget.TooltipCompat; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.text.HtmlCompat; @@ -45,10 +43,10 @@ import com.keylesspalace.tusky.entity.Attachment; import com.keylesspalace.tusky.entity.Attachment.Focus; import com.keylesspalace.tusky.entity.Attachment.MetaData; -import com.keylesspalace.tusky.entity.Filter; -import com.keylesspalace.tusky.entity.PreviewCard; import com.keylesspalace.tusky.entity.Emoji; +import com.keylesspalace.tusky.entity.Filter; import com.keylesspalace.tusky.entity.HashTag; +import com.keylesspalace.tusky.entity.PreviewCard; import com.keylesspalace.tusky.entity.Status; import com.keylesspalace.tusky.entity.TimelineAccount; import com.keylesspalace.tusky.entity.Translation; @@ -81,9 +79,7 @@ import at.connyduck.sparkbutton.SparkButton; import at.connyduck.sparkbutton.helpers.Utils; -import kotlin.Unit; import kotlin.collections.CollectionsKt; -import kotlin.jvm.functions.Function0; public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { public static class Key { @@ -534,7 +530,7 @@ protected void setMediaPreviews( final @NonNull StatusActionListener listener, boolean showingContent, boolean useBlurhash, - Filter filter + final @NonNull Filter filter ) { mediaPreview.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java index 3d0235e252..226a96152a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusViewHolder.java @@ -146,7 +146,7 @@ protected void hideStatusInfo() { statusInfo.setVisibility(View.GONE); } - protected TextView getStatusInfo() { + protected @NonNull TextView getStatusInfo() { return statusInfo; } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsViewModel.kt index 2077f39a18..efd751cd9a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsViewModel.kt @@ -112,9 +112,9 @@ class ConversationsViewModel @Inject constructor( fun showPollResults(conversation: ConversationViewData) = viewModelScope.launch { conversation.lastStatus.status.poll?.let { poll -> - conversation.toEntity(accountId = accountId, poll = poll.copy(voted = true)).let { - saveConversationToDb(it) - } + saveConversationToDb( + conversation.toEntity(accountId = accountId, poll = poll.copy(voted = true)) + ) } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt index 33c604755b..bea4d3d1a3 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginActivity.kt @@ -24,6 +24,7 @@ import android.util.Log import android.view.Menu import android.view.View import android.widget.TextView +import androidx.core.content.edit import androidx.core.net.toUri import androidx.core.view.WindowInsetsCompat.Type.ime import androidx.core.view.WindowInsetsCompat.Type.systemBars @@ -138,7 +139,7 @@ class LoginActivity : BaseActivity() { try { HttpUrl.Builder().host(domain).scheme("https").build() - } catch (e: IllegalArgumentException) { + } catch (_: IllegalArgumentException) { setLoading(false) binding.domainTextInputLayout.error = getString(R.string.error_invalid_domain) return @@ -161,11 +162,11 @@ class LoginActivity : BaseActivity() { ).fold( { credentials -> // Save credentials so we can access them after we opened another activity for auth. - preferences.edit() - .putString(DOMAIN, domain) - .putString(CLIENT_ID, credentials.clientId) - .putString(CLIENT_SECRET, credentials.clientSecret) - .apply() + preferences.edit { + putString(DOMAIN, domain) + putString(CLIENT_ID, credentials.clientId) + putString(CLIENT_SECRET, credentials.clientSecret) + } redirectUserToAuthorizeAndLogin(domain, credentials.clientId, openInWebView) }, diff --git a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt index 2661c21a42..6377960357 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/preference/PreferencesFragment.kt @@ -21,7 +21,6 @@ import androidx.annotation.DrawableRes import androidx.lifecycle.lifecycleScope import androidx.preference.Preference import com.keylesspalace.tusky.R -import com.keylesspalace.tusky.components.preference.PreferencesFragment.ReadingOrder.valueOf import com.keylesspalace.tusky.components.systemnotifications.NotificationChannelData import com.keylesspalace.tusky.db.AccountManager import com.keylesspalace.tusky.settings.AppTheme diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt index d656a387a4..5950d4908c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt @@ -19,7 +19,6 @@ import android.Manifest import android.app.DownloadManager import android.content.Intent import android.content.SharedPreferences -import android.net.Uri import android.os.Build import android.os.Bundle import android.os.Environment @@ -30,6 +29,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.widget.PopupMenu import androidx.core.app.ActivityOptionsCompat import androidx.core.content.getSystemService +import androidx.core.net.toUri import androidx.core.view.ViewCompat import androidx.lifecycle.lifecycleScope import androidx.paging.PagingData @@ -554,7 +554,7 @@ class SearchStatusesFragment : SearchFragment(), Status private fun accountIsInMentions(account: AccountEntity?, mentions: List): Boolean { return mentions.firstOrNull { - account?.username == it.username && account.domain == Uri.parse(it.url)?.host + account?.username == it.username && account.domain == it.url.toUri().host } != null } @@ -575,7 +575,7 @@ class SearchStatusesFragment : SearchFragment(), Status val downloadManager: DownloadManager = requireContext().getSystemService()!! for (url in mediaUrls) { - val uri = Uri.parse(url) + val uri = url.toUri() val request = DownloadManager.Request(uri) request.setDestinationInExternalPublicDir( Environment.DIRECTORY_DOWNLOADS, diff --git a/app/src/main/java/com/keylesspalace/tusky/components/systemnotifications/NotificationService.kt b/app/src/main/java/com/keylesspalace/tusky/components/systemnotifications/NotificationService.kt index 4282bcec98..9243ee0db1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/systemnotifications/NotificationService.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/systemnotifications/NotificationService.kt @@ -24,6 +24,7 @@ import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat.NotificationWithIdAndTag import androidx.core.app.RemoteInput import androidx.core.app.TaskStackBuilder +import androidx.core.content.edit import androidx.core.net.toUri import androidx.work.Constraints import androidx.work.Data @@ -783,9 +784,9 @@ class NotificationService @Inject constructor( Log.w(TAG, "Previous push provider ($lastUsedPushProvider) uninstalled. Resetting all accounts.") - val editor = preferences.edit() - editor.remove(PrefKeys.LAST_USED_PUSH_PROVDER) - editor.apply() + preferences.edit { + remove(PrefKeys.LAST_USED_PUSH_PROVDER) + } applicationScope.launch { accountManager.accounts.forEach { @@ -895,9 +896,9 @@ class NotificationService @Inject constructor( UnifiedPush.getAckDistributor(context)?.let { Log.d(TAG, "Saving distributor to preferences: $it") - val editor = preferences.edit() - editor.putString(PrefKeys.LAST_USED_PUSH_PROVDER, it) - editor.apply() + preferences.edit { + putString(PrefKeys.LAST_USED_PUSH_PROVDER, it) + } // TODO once this is selected it cannot be changed (except by wiping the application or uninstalling the provider) } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadViewModel.kt index b17dfe03bc..a4f555a433 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadViewModel.kt @@ -61,9 +61,9 @@ class ViewThreadViewModel @Inject constructor( private val api: MastodonApi, private val filterModel: FilterModel, private val timelineCases: TimelineCases, - eventHub: EventHub, - private val accountManager: AccountManager, private val db: AppDatabase, + eventHub: EventHub, + accountManager: AccountManager, ) : ViewModel() { private val activeAccount = accountManager.activeAccount!! diff --git a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsAdapter.kt index aef461e15b..3c48992e80 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/edits/ViewEditsAdapter.kt @@ -2,7 +2,6 @@ package com.keylesspalace.tusky.components.viewthread.edits import android.content.Context import android.graphics.Typeface.DEFAULT_BOLD -import android.graphics.drawable.ColorDrawable import android.graphics.drawable.Drawable import android.text.Editable import android.text.SpannableStringBuilder @@ -12,6 +11,7 @@ import android.util.TypedValue import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.graphics.drawable.toDrawable import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide @@ -188,7 +188,7 @@ class ViewEditsAdapter( val placeholder: Drawable = if (blurhash != null && useBlurhash) { BlurhashDrawable(context, blurhash) } else { - ColorDrawable(MaterialColors.getColor(imageView, R.attr.colorBackgroundAccent)) + MaterialColors.getColor(imageView, R.attr.colorBackgroundAccent).toDrawable() } if (attachment.previewUrl.isNullOrEmpty()) { diff --git a/app/src/main/java/com/keylesspalace/tusky/di/PlayerModule.kt b/app/src/main/java/com/keylesspalace/tusky/di/PlayerModule.kt index ac5cf7bab9..fc6ce60b53 100644 --- a/app/src/main/java/com/keylesspalace/tusky/di/PlayerModule.kt +++ b/app/src/main/java/com/keylesspalace/tusky/di/PlayerModule.kt @@ -79,16 +79,14 @@ object PlayerModule { textRendererOutput, metadataRendererOutput -> arrayOf( - MediaCodecVideoRenderer( - context, - MediaCodecSelector.DEFAULT, - DefaultRenderersFactory.DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS, - // enableDecoderFallback = true, helps playing videos even if one decoder fails - true, - eventHandler, - videoRendererEventListener, - DefaultRenderersFactory.MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY - ), + MediaCodecVideoRenderer.Builder(context) + .setMediaCodecSelector(MediaCodecSelector.DEFAULT) + .setAllowedJoiningTimeMs(DefaultRenderersFactory.DEFAULT_ALLOWED_VIDEO_JOINING_TIME_MS) + .setEnableDecoderFallback(true) + .setEventHandler(eventHandler) + .setEventListener(videoRendererEventListener) + .setMaxDroppedFramesToNotify(DefaultRenderersFactory.MAX_DROPPED_VIDEO_FRAME_COUNT_TO_NOTIFY) + .build(), MediaCodecAudioRenderer( context, MediaCodecSelector.DEFAULT, diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt index 865eca3dd2..1da0bdde90 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt @@ -18,7 +18,6 @@ import android.Manifest import android.app.DownloadManager import android.content.DialogInterface import android.content.Intent -import android.net.Uri import android.os.Build import android.os.Bundle import android.os.Environment @@ -31,6 +30,7 @@ import androidx.annotation.LayoutRes import androidx.appcompat.widget.PopupMenu import androidx.core.app.ActivityOptionsCompat import androidx.core.content.getSystemService +import androidx.core.net.toUri import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import at.connyduck.calladapter.networkresult.fold @@ -543,7 +543,7 @@ abstract class SFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayo val downloadManager: DownloadManager = requireContext().getSystemService()!! for (url in mediaUrls) { - val uri = Uri.parse(url) + val uri = url.toUri() downloadManager.enqueue( DownloadManager.Request(uri).apply { setDestinationInExternalPublicDir( @@ -569,7 +569,6 @@ abstract class SFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayo } companion object { - private const val TAG = "SFragment" private const val PENDING_MEDIA_DOWNLOADS_STATE_KEY = "pending_media_downloads" private fun accountIsInMentions( @@ -577,7 +576,7 @@ abstract class SFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayo mentions: List ): Boolean { return mentions.any { mention -> - account?.username == mention.username && account.domain == Uri.parse(mention.url)?.host + account?.username == mention.username && account.domain == mention.url.toUri().host } } } diff --git a/app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt b/app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt index 8d61330e69..f4f83259d4 100644 --- a/app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt +++ b/app/src/main/java/com/keylesspalace/tusky/service/SendStatusService.kt @@ -127,7 +127,7 @@ class SendStatusService : Service() { cancelSendingIntent(sendingNotificationId) ) - if (statusesToSend.size == 0 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (statusesToSend.isEmpty() || Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH) startForeground(sendingNotificationId, builder.build()) } else { diff --git a/app/src/main/java/com/keylesspalace/tusky/util/CustomEmojiHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/CustomEmojiHelper.kt index 53290d0757..9f30e54ebc 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/CustomEmojiHelper.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/CustomEmojiHelper.kt @@ -24,6 +24,7 @@ import android.graphics.drawable.Drawable import android.text.style.ReplacementSpan import android.view.View import android.widget.TextView +import androidx.core.graphics.withSave import androidx.core.text.toSpannable import com.bumptech.glide.Glide import com.bumptech.glide.request.target.CustomTarget @@ -155,32 +156,31 @@ class EmojiSpan(view: View) : ReplacementSpan() { paint: Paint ) { imageDrawable?.let { drawable -> - canvas.save() - - // start with a width relative to the text size - var emojiWidth = paint.textSize * 1.1 - - // calculate the height, keeping the aspect ratio correct - val drawableWidth = drawable.intrinsicWidth - val drawableHeight = drawable.intrinsicHeight - var emojiHeight = emojiWidth / drawableWidth * drawableHeight + canvas.withSave { + // start with a width relative to the text size + var emojiWidth = paint.textSize * 1.1 + + // calculate the height, keeping the aspect ratio correct + val drawableWidth = drawable.intrinsicWidth + val drawableHeight = drawable.intrinsicHeight + var emojiHeight = emojiWidth / drawableWidth * drawableHeight + + // how much vertical space there is draw the emoji + val drawableSpace = (bottom - top).toDouble() + + // in case the calculated height is bigger than the available space, scale the emoji down, preserving aspect ratio + if (emojiHeight > drawableSpace) { + emojiWidth *= drawableSpace / emojiHeight + emojiHeight = drawableSpace + } + drawable.setBounds(0, 0, emojiWidth.toInt(), emojiHeight.toInt()) - // how much vertical space there is draw the emoji - val drawableSpace = (bottom - top).toDouble() + // vertically center the emoji in the line + val transY = top + (drawableSpace / 2 - emojiHeight / 2) - // in case the calculated height is bigger than the available space, scale the emoji down, preserving aspect ratio - if (emojiHeight > drawableSpace) { - emojiWidth *= drawableSpace / emojiHeight - emojiHeight = drawableSpace + translate(x, transY.toFloat()) + drawable.draw(this) } - drawable.setBounds(0, 0, emojiWidth.toInt(), emojiHeight.toInt()) - - // vertically center the emoji in the line - val transY = top + (drawableSpace / 2 - emojiHeight / 2) - - canvas.translate(x, transY.toFloat()) - drawable.draw(canvas) - canvas.restore() } } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt index e45a52fa99..224025322a 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/LinkHelper.kt @@ -413,7 +413,7 @@ private fun openLinkInBrowser(uri: Uri?, context: Context) { try { context.startActivity(intent) } catch (e: ActivityNotFoundException) { - Log.w(TAG, "Activity was not found for intent, $intent") + Log.w(TAG, "Activity was not found for intent, $intent", e) } } @@ -430,6 +430,8 @@ fun openLinkInCustomTab(uri: Uri, context: Context) { materialR.attr.colorSurface, Color.BLACK ) + + @Suppress("DEPRECATION") val navigationbarColor = MaterialColors.getColor( context, android.R.attr.navigationBarColor, @@ -454,7 +456,7 @@ fun openLinkInCustomTab(uri: Uri, context: Context) { try { customTabsIntent.launchUrl(context, uri) } catch (e: ActivityNotFoundException) { - Log.w(TAG, "Activity was not found for intent $customTabsIntent") + Log.w(TAG, "Activity was not found for intent $customTabsIntent", e) openLinkInBrowser(uri, context) } } @@ -480,7 +482,7 @@ fun looksLikeMastodonUrl(urlString: String): Boolean { val uri: URI try { uri = URI(urlString) - } catch (e: URISyntaxException) { + } catch (_: URISyntaxException) { return false } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ListUtils.kt b/app/src/main/java/com/keylesspalace/tusky/util/ListUtils.kt index 12e5b73d10..0bde074877 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ListUtils.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/ListUtils.kt @@ -17,13 +17,6 @@ package com.keylesspalace.tusky.util -/** - * Copies elements to destination, removing duplicates and preserving original order. - */ -fun > Iterable.removeDuplicatesTo(destination: C): C { - return filterTo(destination, HashSet()::add) -} - inline fun List.withoutFirstWhich(predicate: (T) -> Boolean): List { val index = indexOfFirst(predicate) if (index == -1) { diff --git a/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt b/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt index 8f3d2a7c97..05fa86a254 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/LocaleManager.kt @@ -19,6 +19,7 @@ import android.content.Context import android.content.SharedPreferences import android.os.Build import androidx.appcompat.app.AppCompatDelegate +import androidx.core.content.edit import androidx.core.os.LocaleListCompat import androidx.preference.PreferenceDataStore import com.keylesspalace.tusky.R @@ -44,9 +45,9 @@ class LocaleManager @Inject constructor( // hand over the old setting to the system and save a dummy value in Shared Preferences applyLanguageToApp(language) - preferences.edit() - .putString(PrefKeys.LANGUAGE, HANDLED_BY_SYSTEM) - .apply() + preferences.edit { + putString(PrefKeys.LANGUAGE, HANDLED_BY_SYSTEM) + } } } else { // on Android < 13 we have to apply the language at every app start @@ -58,9 +59,9 @@ class LocaleManager @Inject constructor( // if we are on Android < 13 we have to save the selected language so we can apply it at appstart // on Android 13+ the system handles it for us if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { - preferences.edit() - .putString(PrefKeys.LANGUAGE, value) - .apply() + preferences.edit { + putString(PrefKeys.LANGUAGE, value) + } } applyLanguageToApp(value) } diff --git a/app/src/main/java/com/keylesspalace/tusky/util/RickRoll.kt b/app/src/main/java/com/keylesspalace/tusky/util/RickRoll.kt index 788786ed09..5df784d94b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/RickRoll.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/RickRoll.kt @@ -2,7 +2,7 @@ package com.keylesspalace.tusky.util import android.content.Context import android.content.Intent -import android.net.Uri +import androidx.core.net.toUri import com.keylesspalace.tusky.R fun shouldRickRoll(context: Context, domain: String) = @@ -11,7 +11,7 @@ fun shouldRickRoll(context: Context, domain: String) = } fun rickRoll(context: Context) { - val uri = Uri.parse(context.getString(R.string.rick_roll_url)) + val uri = context.getString(R.string.rick_roll_url).toUri() val intent = Intent(Intent.ACTION_VIEW, uri).apply { addCategory(Intent.CATEGORY_BROWSABLE) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt index d92df6fe97..271930d476 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/ShareShortcutHelper.kt @@ -19,13 +19,13 @@ package com.keylesspalace.tusky.util import android.content.Context import android.content.Intent -import android.graphics.Bitmap import android.graphics.Canvas import android.util.Log import androidx.appcompat.content.res.AppCompatResources import androidx.core.app.Person import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat +import androidx.core.graphics.createBitmap import androidx.core.graphics.drawable.IconCompat import com.bumptech.glide.Glide import com.bumptech.glide.load.engine.GlideException @@ -67,7 +67,7 @@ class ShareShortcutHelper @Inject constructor( } // inset the loaded bitmap inside a 108dp transparent canvas so it looks good as adaptive icon - val outBmp = Bitmap.createBitmap(outerSize, outerSize, Bitmap.Config.ARGB_8888) + val outBmp = createBitmap(outerSize, outerSize) val canvas = Canvas(outBmp) val borderSize = (outerSize - innerSize) / 2 diff --git a/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt b/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt index fdf8480239..fe66bc64e9 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/StatusViewHelper.kt @@ -17,13 +17,13 @@ package com.keylesspalace.tusky.util import android.content.Context import android.graphics.Color -import android.graphics.drawable.ColorDrawable import android.text.InputFilter import android.text.TextUtils import android.view.View import android.widget.ImageView import android.widget.TextView import androidx.annotation.DrawableRes +import androidx.core.graphics.drawable.toDrawable import com.bumptech.glide.Glide import com.google.android.material.color.MaterialColors import com.keylesspalace.tusky.R @@ -89,9 +89,8 @@ class StatusViewHelper(private val itemView: View) { } val mediaPreviewUnloaded = - ColorDrawable( - MaterialColors.getColor(context, R.attr.colorBackgroundAccent, Color.BLACK) - ) + MaterialColors.getColor(context, R.attr.colorBackgroundAccent, Color.BLACK) + .toDrawable() val n = min(attachments.size, Status.MAX_MEDIA_ATTACHMENTS) diff --git a/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.kt b/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.kt index 01aff3e001..18ac108e0d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/StringUtils.kt @@ -9,7 +9,7 @@ import kotlin.random.Random private const val POSSIBLE_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" const val HASHTAG_EXPRESSION = "([\\w_]*[\\p{Alpha}_][\\w_]*)" -val hashtagPattern = Pattern.compile(HASHTAG_EXPRESSION, Pattern.CASE_INSENSITIVE or Pattern.MULTILINE) +val hashtagPattern: Pattern = Pattern.compile(HASHTAG_EXPRESSION, Pattern.CASE_INSENSITIVE or Pattern.MULTILINE) fun randomAlphanumericString(count: Int): String { val chars = CharArray(count) diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.kt b/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.kt index 08aa992c7e..06a3087146 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/ThemeUtils.kt @@ -22,7 +22,6 @@ import android.graphics.Color import android.graphics.drawable.Drawable import androidx.annotation.AttrRes import androidx.appcompat.app.AppCompatDelegate -import androidx.core.content.res.use import com.google.android.material.color.MaterialColors import com.keylesspalace.tusky.settings.AppTheme @@ -31,12 +30,6 @@ import com.keylesspalace.tusky.settings.AppTheme * the ability to do so is not supported in resource files. */ -fun getDimension(context: Context, @AttrRes attribute: Int): Int { - return context.obtainStyledAttributes(intArrayOf(attribute)).use { array -> - array.getDimensionPixelSize(0, -1) - } -} - fun setDrawableTint(context: Context, drawable: Drawable, @AttrRes attribute: Int) { drawable.setTint(MaterialColors.getColor(context, attribute, Color.BLACK)) } diff --git a/app/src/main/java/com/keylesspalace/tusky/view/ClickableSpanTextView.kt b/app/src/main/java/com/keylesspalace/tusky/view/ClickableSpanTextView.kt index 1fc01c9995..46cc5b18a3 100644 --- a/app/src/main/java/com/keylesspalace/tusky/view/ClickableSpanTextView.kt +++ b/app/src/main/java/com/keylesspalace/tusky/view/ClickableSpanTextView.kt @@ -39,6 +39,7 @@ import android.view.MotionEvent.ACTION_DOWN import android.view.MotionEvent.ACTION_UP import android.view.ViewConfiguration import androidx.appcompat.widget.AppCompatTextView +import androidx.core.graphics.withSave import androidx.core.view.doOnLayout import com.keylesspalace.tusky.BuildConfig import com.keylesspalace.tusky.R @@ -379,15 +380,15 @@ class ClickableSpanTextView @JvmOverloads constructor( // Paint span boundaries. Optimised out on release builds, or debug builds where // showSpanBoundaries is false. if (BuildConfig.DEBUG && showSpanBoundaries) { - canvas.save() - for (entry in delegateRects) { - canvas.drawRect(entry.key, paddingDebugPaint) - } + canvas.withSave { + for (entry in delegateRects) { + drawRect(entry.key, paddingDebugPaint) + } - for (entry in spanRects) { - canvas.drawRect(entry.key, spanDebugPaint) + for (entry in spanRects) { + drawRect(entry.key, spanDebugPaint) + } } - canvas.restore() } } diff --git a/app/src/main/java/com/keylesspalace/tusky/view/GraphView.kt b/app/src/main/java/com/keylesspalace/tusky/view/GraphView.kt index dab8716fb9..8924eb91cc 100644 --- a/app/src/main/java/com/keylesspalace/tusky/view/GraphView.kt +++ b/app/src/main/java/com/keylesspalace/tusky/view/GraphView.kt @@ -21,12 +21,12 @@ import android.graphics.Paint import android.graphics.Path import android.graphics.PathMeasure import android.graphics.Rect -import android.text.TextUtils import android.util.AttributeSet import android.view.View import androidx.annotation.ColorInt import androidx.annotation.Dimension import androidx.core.content.res.use +import androidx.core.text.layoutDirection import com.google.android.material.R as materialR import com.google.android.material.color.MaterialColors import com.keylesspalace.tusky.R @@ -103,7 +103,7 @@ class GraphView @JvmOverloads constructor( init { initFromXML(attrs) - isRtlLayout = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == LAYOUT_DIRECTION_RTL + isRtlLayout = Locale.getDefault().layoutDirection == LAYOUT_DIRECTION_RTL } private fun initFromXML(attr: AttributeSet?) { diff --git a/app/src/main/java/com/keylesspalace/tusky/viewdata/PollViewData.kt b/app/src/main/java/com/keylesspalace/tusky/viewdata/PollViewData.kt index 40995804d3..395ba82222 100644 --- a/app/src/main/java/com/keylesspalace/tusky/viewdata/PollViewData.kt +++ b/app/src/main/java/com/keylesspalace/tusky/viewdata/PollViewData.kt @@ -24,7 +24,6 @@ import android.text.style.ImageSpan import android.widget.TextView import androidx.appcompat.content.res.AppCompatResources import androidx.core.text.parseAsHtml -import androidx.core.text.set import com.google.android.material.color.MaterialColors import com.keylesspalace.tusky.R import com.keylesspalace.tusky.entity.Poll diff --git a/app/src/main/res/values-en-rGB/strings.xml b/app/src/main/res/values-en-rGB/strings.xml index 87ae45e6d1..b685b6dc87 100644 --- a/app/src/main/res/values-en-rGB/strings.xml +++ b/app/src/main/res/values-en-rGB/strings.xml @@ -95,9 +95,6 @@ Home %1$s just posted Upload failed - Your post failed to upload and has been saved to drafts. -\n -\nEither the server could not be contacted, or it rejected the post. Additional comments? Quick Reply Boost @@ -105,4 +102,4 @@ Remove boost Are you sure you want to log out of %1$s? This will delete all local data of the account, including drafts and preferences. Share a link to this account - \ No newline at end of file + diff --git a/app/src/test/java/com/keylesspalace/tusky/MainActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/MainActivityTest.kt index ddb7d34c52..f9058f2fb0 100644 --- a/app/src/test/java/com/keylesspalace/tusky/MainActivityTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/MainActivityTest.kt @@ -3,7 +3,6 @@ package com.keylesspalace.tusky import android.app.Activity import android.app.NotificationManager import android.content.ComponentName -import android.content.Context import android.content.Intent import androidx.lifecycle.viewmodel.initializer import androidx.lifecycle.viewmodel.viewModelFactory @@ -164,9 +163,6 @@ class MainActivityTest { } }) val viewModel = MainViewModel( - context = mock { - on { getSystemService(Context.NOTIFICATION_SERVICE) } doReturn mock() - }, api = api, eventHub = eventHub, accountManager = accountManager, diff --git a/app/src/test/java/com/keylesspalace/tusky/components/compose/ComposeActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/components/compose/ComposeActivityTest.kt index c25860e5f6..d343402f29 100644 --- a/app/src/test/java/com/keylesspalace/tusky/components/compose/ComposeActivityTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/components/compose/ComposeActivityTest.kt @@ -137,7 +137,7 @@ class ComposeActivityTest { val instanceDaoMock: InstanceDao = mock { onBlocking { getInstanceInfo(any()) } doReturn - InstanceInfoEntity(instanceDomain, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,) + InstanceInfoEntity(instanceDomain, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null) onBlocking { getEmojiInfo(any()) } doReturn EmojisEntity(instanceDomain, emptyList()) } diff --git a/app/src/test/java/com/keylesspalace/tusky/components/viewthread/ViewThreadViewModelTest.kt b/app/src/test/java/com/keylesspalace/tusky/components/viewthread/ViewThreadViewModelTest.kt index e1bab013f1..6a1ffbee19 100644 --- a/app/src/test/java/com/keylesspalace/tusky/components/viewthread/ViewThreadViewModelTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/components/viewthread/ViewThreadViewModelTest.kt @@ -104,7 +104,7 @@ class ViewThreadViewModelTest { .allowMainThreadQueries() .build() - viewModel = ViewThreadViewModel(api, filterModel, timelineCases, eventHub, accountManager, db) + viewModel = ViewThreadViewModel(api, filterModel, timelineCases, db, eventHub, accountManager) } @After