From 50ca44a5f6fa0a4733b5500376ed8ef4ff723189 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Tue, 10 Sep 2024 19:50:09 +0200 Subject: [PATCH] Material Design 3 (#4637) I tried to find a balance between going fully M3 and keeping some of the original Tusky feeling. For example, I removed the "allCaps" setting we had on most buttons, which is recommended for M3. On the other hand, I made them less rounded than the M3 default. --- .../com/keylesspalace/tusky/BaseActivity.java | 3 +- .../tusky/EditProfileActivity.kt | 8 +- .../com/keylesspalace/tusky/ListsActivity.kt | 17 ++-- .../com/keylesspalace/tusky/MainActivity.kt | 5 +- .../tusky/TabPreferenceActivity.kt | 3 +- .../components/account/AccountActivity.kt | 40 +++------- .../account/list/ListSelectionFragment.kt | 4 +- .../announcements/AnnouncementAdapter.kt | 5 +- .../components/compose/ComposeActivity.kt | 31 +++---- .../components/compose/ComposeViewModel.kt | 7 -- .../compose/dialog/AddPollDialog.kt | 20 ++--- .../components/compose/dialog/FocusDialog.kt | 4 +- .../conversation/ConversationsFragment.kt | 4 +- .../components/filters/EditFilterActivity.kt | 48 +++++------ .../components/filters/FilterExtensions.kt | 16 ++-- .../followedtags/FollowedTagsActivity.kt | 4 +- .../tusky/components/login/LoginActivity.kt | 4 +- .../components/login/LoginWebViewActivity.kt | 5 +- .../notifications/NotificationsFragment.kt | 4 +- .../scheduled/ScheduledStatusActivity.kt | 4 +- .../fragments/SearchStatusesFragment.kt | 8 +- .../PushNotificationHelper.kt | 4 +- .../viewthread/ViewThreadActivity.kt | 2 +- .../com/keylesspalace/tusky/db/DraftsAlert.kt | 4 +- .../keylesspalace/tusky/fragment/SFragment.kt | 8 +- .../tusky/settings/SettingsDSL.kt | 8 +- .../util/ListStatusAccessibilityDelegate.kt | 8 +- .../keylesspalace/tusky/view/LicenseCard.kt | 12 +-- .../tusky/view/MuteAccountDialog.kt | 17 +++- .../res/color/selectable_chip_background.xml | 11 +++ .../drawable/background_dialog_activity.xml | 4 +- .../res/layout-land/fragment_report_done.xml | 11 +-- .../res/layout-sw640dp/fragment_timeline.xml | 3 +- .../fragment_timeline_notifications.xml | 13 +-- .../layout-sw640dp/fragment_view_thread.xml | 2 +- app/src/main/res/layout/activity_about.xml | 12 ++- app/src/main/res/layout/activity_account.xml | 8 +- .../res/layout/activity_announcements.xml | 5 +- app/src/main/res/layout/activity_compose.xml | 11 ++- .../main/res/layout/activity_edit_filter.xml | 45 ++++++----- .../main/res/layout/activity_edit_profile.xml | 5 +- app/src/main/res/layout/activity_filters.xml | 3 +- .../res/layout/activity_followed_tags.xml | 3 +- app/src/main/res/layout/activity_license.xml | 36 ++++----- app/src/main/res/layout/activity_lists.xml | 3 +- app/src/main/res/layout/activity_login.xml | 7 +- .../res/layout/activity_login_webview.xml | 13 +-- app/src/main/res/layout/activity_main.xml | 35 ++++---- .../res/layout/activity_scheduled_status.xml | 3 +- app/src/main/res/layout/activity_search.xml | 13 ++- .../res/layout/activity_tab_preference.xml | 1 + .../main/res/layout/activity_view_media.xml | 8 +- .../main/res/layout/activity_view_thread.xml | 19 +---- app/src/main/res/layout/card_license.xml | 3 +- app/src/main/res/layout/dialog_add_poll.xml | 23 ++++-- app/src/main/res/layout/dialog_list.xml | 80 +++++++++---------- .../main/res/layout/dialog_mute_account.xml | 60 +++++++------- .../res/layout/fragment_domain_blocks.xml | 5 +- .../main/res/layout/fragment_lists_list.xml | 7 +- .../main/res/layout/fragment_report_done.xml | 14 ++-- .../main/res/layout/fragment_report_note.xml | 13 +-- .../res/layout/fragment_report_statuses.xml | 9 +-- app/src/main/res/layout/fragment_search.xml | 5 +- app/src/main/res/layout/fragment_timeline.xml | 7 +- .../fragment_timeline_notifications.xml | 15 +--- .../res/layout/fragment_trending_tags.xml | 3 +- .../main/res/layout/fragment_view_edits.xml | 2 +- .../main/res/layout/fragment_view_image.xml | 3 +- .../main/res/layout/fragment_view_thread.xml | 2 +- .../main/res/layout/fragment_view_video.xml | 9 ++- app/src/main/res/layout/item_announcement.xml | 6 +- app/src/main/res/layout/item_conversation.xml | 2 - app/src/main/res/layout/item_edit_field.xml | 5 +- app/src/main/res/layout/item_footer.xml | 4 +- app/src/main/res/layout/item_muted_user.xml | 4 +- .../main/res/layout/item_network_state.xml | 10 ++- ...m_notifications_load_state_footer_view.xml | 4 + .../main/res/layout/item_report_status.xml | 2 - app/src/main/res/layout/item_status.xml | 2 - .../main/res/layout/item_status_detailed.xml | 1 - .../res/layout/item_status_notification.xml | 2 - .../main/res/layout/item_tab_preference.xml | 6 +- app/src/main/res/layout/pref_slider.xml | 5 +- .../res/layout/preference_material_switch.xml | 9 +++ app/src/main/res/layout/toolbar_basic.xml | 11 ++- .../main/res/values-night/theme_colors.xml | 4 +- app/src/main/res/values/attrs.xml | 2 + app/src/main/res/values/colors.xml | 3 + app/src/main/res/values/dimens.xml | 2 - app/src/main/res/values/strings.xml | 13 +-- app/src/main/res/values/styles.xml | 72 ++++++++++++----- app/src/main/res/values/theme_colors.xml | 2 + gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 48 +++++++++++ 94 files changed, 575 insertions(+), 487 deletions(-) create mode 100644 app/src/main/res/color/selectable_chip_background.xml create mode 100644 app/src/main/res/layout/preference_material_switch.xml diff --git a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java index 2bbcf2858..c8cab13d6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java +++ b/app/src/main/java/com/keylesspalace/tusky/BaseActivity.java @@ -36,6 +36,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.lifecycle.ViewModelProvider; import com.google.android.material.color.MaterialColors; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.snackbar.Snackbar; import com.keylesspalace.tusky.adapter.AccountSelectionAdapter; import com.keylesspalace.tusky.components.login.LoginActivity; @@ -260,7 +261,7 @@ public abstract class BaseActivity extends AppCompatActivity { ); adapter.addAll(accounts); - new AlertDialog.Builder(this) + new MaterialAlertDialogBuilder(this) .setTitle(dialogTitle) .setAdapter(adapter, (dialogInterface, index) -> listener.onAccountSelected(accounts.get(index))) .show(); diff --git a/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt b/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt index ab459ae09..d0a342622 100644 --- a/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/EditProfileActivity.kt @@ -17,7 +17,6 @@ package com.keylesspalace.tusky import android.content.Intent import android.graphics.Bitmap -import android.graphics.Color import android.net.Uri import android.os.Bundle import android.util.Log @@ -39,6 +38,9 @@ import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.canhub.cropper.CropImage import com.canhub.cropper.CropImageContract import com.canhub.cropper.options +import com.google.android.material.R as materialR +import com.google.android.material.color.MaterialColors +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.adapter.AccountFieldEditAdapter import com.keylesspalace.tusky.components.instanceinfo.InstanceInfoRepository @@ -125,7 +127,7 @@ class EditProfileActivity : BaseActivity() { val plusDrawable = IconicsDrawable(this, GoogleMaterial.Icon.gmd_add).apply { sizeDp = 12 - colorInt = Color.WHITE + colorInt = MaterialColors.getColor(binding.addFieldButton, materialR.attr.colorOnPrimary) } binding.addFieldButton.setCompoundDrawablesRelativeWithIntrinsicBounds( @@ -365,7 +367,7 @@ class EditProfileActivity : BaseActivity() { } } - private suspend fun launchSaveDialog() = AlertDialog.Builder(this) + private suspend fun launchSaveDialog() = MaterialAlertDialogBuilder(this) .setMessage(getString(R.string.dialog_save_profile_changes_message)) .create() .await(R.string.action_save, R.string.action_discard) diff --git a/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt b/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt index 0323c2920..eb2cb7a13 100644 --- a/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/ListsActivity.kt @@ -26,13 +26,13 @@ import android.view.ViewGroup import android.widget.PopupMenu import androidx.activity.viewModels import androidx.annotation.StringRes -import androidx.appcompat.app.AlertDialog import androidx.core.widget.doOnTextChanged import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.ListAdapter +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.databinding.ActivityListsBinding import com.keylesspalace.tusky.databinding.DialogListBinding @@ -107,10 +107,17 @@ class ListsActivity : BaseActivity() { } private fun showlistNameDialog(list: MastoList?) { + var selectedReplyPolicyIndex = 0 + + val replyPolicies = resources.getStringArray(R.array.list_reply_policies_display) val binding = DialogListBinding.inflate(layoutInflater).apply { - replyPolicySpinner.setSelection(MastoList.ReplyPolicy.from(list?.repliesPolicy).ordinal) + replyPolicyDropDown.setText(replyPolicies[MastoList.ReplyPolicy.from(list?.repliesPolicy).ordinal]) + replyPolicyDropDown.setSimpleItems(replyPolicies) + replyPolicyDropDown.setOnItemClickListener { _, _, position, _ -> + selectedReplyPolicyIndex = position + } } - val dialog = AlertDialog.Builder(this) + val dialog = MaterialAlertDialogBuilder(this) .setView(binding.root) .setPositiveButton( if (list == null) { @@ -123,7 +130,7 @@ class ListsActivity : BaseActivity() { binding.nameText.text.toString(), list?.id, binding.exclusiveCheckbox.isChecked, - MastoList.ReplyPolicy.entries[binding.replyPolicySpinner.selectedItemPosition].policy + MastoList.ReplyPolicy.entries[selectedReplyPolicyIndex].policy ) } .setNegativeButton(android.R.string.cancel, null) @@ -147,7 +154,7 @@ class ListsActivity : BaseActivity() { } private fun showListDeleteDialog(list: MastoList) { - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setMessage(getString(R.string.dialog_delete_list_warning, list.title)) .setPositiveButton(R.string.action_delete) { _, _ -> viewModel.deleteList(list.id) diff --git a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt index c9e25da29..1e6c1e4b6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/MainActivity.kt @@ -60,6 +60,7 @@ import com.bumptech.glide.request.target.FixedSizeDrawable import com.bumptech.glide.request.transition.Transition import com.google.android.material.R as materialR import com.google.android.material.color.MaterialColors +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout.OnTabSelectedListener import com.google.android.material.tabs.TabLayoutMediator @@ -822,7 +823,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider { } private fun buildDeveloperToolsDialog(): AlertDialog { - return AlertDialog.Builder(this) + return MaterialAlertDialogBuilder(this) .setTitle("Developer Tools") .setItems( arrayOf("Create \"Load more\" gap") @@ -1003,7 +1004,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider { } private fun logout() { - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setTitle(R.string.action_logout) .setMessage(getString(R.string.action_logout_confirm, activeAccount.fullName)) .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> diff --git a/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt b/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt index 2fddb882f..24c6ce8dd 100644 --- a/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/TabPreferenceActivity.kt @@ -31,6 +31,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.transition.TransitionManager import at.connyduck.sparkbutton.helpers.Utils +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.transition.MaterialArcMotion import com.google.android.material.transition.MaterialContainerTransform import com.keylesspalace.tusky.adapter.ItemInteractionListener @@ -238,7 +239,7 @@ class TabPreferenceActivity : BaseActivity(), ItemInteractionListener, ListSelec editText.setText("") frameLayout.addView(editText) - val dialog = AlertDialog.Builder(this) + val dialog = MaterialAlertDialogBuilder(this) .setTitle(R.string.add_hashtag_title) .setView(frameLayout) .setNegativeButton(android.R.string.cancel, null) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt index 5ea9dc7ab..dc813fe01 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/account/AccountActivity.kt @@ -34,7 +34,6 @@ import androidx.activity.viewModels import androidx.annotation.ColorInt import androidx.annotation.DrawableRes import androidx.annotation.Px -import androidx.appcompat.app.AlertDialog import androidx.appcompat.content.res.AppCompatResources import androidx.core.app.ActivityOptionsCompat import androidx.core.graphics.ColorUtils @@ -53,6 +52,7 @@ import com.google.android.material.R as materialR import com.google.android.material.appbar.AppBarLayout import com.google.android.material.chip.Chip import com.google.android.material.color.MaterialColors +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.ShapeAppearanceModel @@ -190,9 +190,9 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide * Load colors and dimensions from resources */ private fun loadResources() { - toolbarColor = MaterialColors.getColor(this, materialR.attr.colorSurface, Color.BLACK) + toolbarColor = MaterialColors.getColor(binding.accountToolbar, materialR.attr.colorSurface) statusBarColorTransparent = getColor(R.color.transparent_statusbar_background) - statusBarColorOpaque = MaterialColors.getColor(this, materialR.attr.colorPrimaryDark, Color.BLACK) + statusBarColorOpaque = MaterialColors.getColor(binding.accountToolbar, materialR.attr.colorPrimaryDark) avatarSize = resources.getDimension(R.dimen.account_activity_avatar_size) titleVisibleHeight = resources.getDimensionPixelSize(R.dimen.account_activity_scroll_title_visible_height) } @@ -320,28 +320,13 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide setDisplayShowTitleEnabled(false) } - val appBarElevation = resources.getDimension(R.dimen.actionbar_elevation) - - val toolbarBackground = MaterialShapeDrawable.createWithElevationOverlay( - this, - appBarElevation - ) - toolbarBackground.fillColor = ColorStateList.valueOf(Color.TRANSPARENT) - binding.accountToolbar.background = toolbarBackground + binding.accountToolbar.setBackgroundColor(Color.TRANSPARENT) binding.accountToolbar.setNavigationIcon(R.drawable.ic_arrow_back_with_background) - binding.accountToolbar.setOverflowIcon( - AppCompatResources.getDrawable(this, R.drawable.ic_more_with_background) - ) + binding.accountToolbar.overflowIcon = AppCompatResources.getDrawable(this, R.drawable.ic_more_with_background) - binding.accountHeaderInfoContainer.background = MaterialShapeDrawable.createWithElevationOverlay(this, appBarElevation) - - val avatarBackground = MaterialShapeDrawable.createWithElevationOverlay( - this, - appBarElevation - ).apply { + val avatarBackground = MaterialShapeDrawable().apply { fillColor = ColorStateList.valueOf(toolbarColor) - elevation = appBarElevation shapeAppearanceModel = ShapeAppearanceModel.builder() .setAllCornerSizes(resources.getDimension(R.dimen.account_avatar_background_radius)) .build() @@ -382,7 +367,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide toolbarColor ) as Int - toolbarBackground.fillColor = ColorStateList.valueOf(evaluatedToolbarColor) + binding.accountToolbar.setBackgroundColor(evaluatedToolbarColor) binding.swipeToRefreshLayout.isEnabled = verticalOffset == 0 } @@ -874,7 +859,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide } private fun showFollowRequestPendingDialog() { - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setMessage(R.string.dialog_message_cancel_follow_request) .setPositiveButton(android.R.string.ok) { _, _ -> viewModel.changeFollowState() } .setNegativeButton(android.R.string.cancel, null) @@ -882,7 +867,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide } private fun showUnfollowWarningDialog() { - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setMessage(R.string.dialog_unfollow_warning) .setPositiveButton(android.R.string.ok) { _, _ -> viewModel.changeFollowState() } .setNegativeButton(android.R.string.cancel, null) @@ -890,7 +875,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide } private fun showFollowWarningDialog() { - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setMessage(R.string.dialog_follow_warning) .setPositiveButton(android.R.string.ok) { _, _ -> viewModel.changeFollowState() } .setNegativeButton(android.R.string.cancel, null) @@ -901,7 +886,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide if (blockingDomain) { viewModel.unblockDomain(instance) } else { - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setMessage(getString(R.string.mute_domain_warning, instance)) .setPositiveButton( getString(R.string.mute_domain_warning_dialog_ok) @@ -913,7 +898,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide private fun toggleBlock() { if (viewModel.relationshipData.value?.data?.blocking != true) { - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setMessage(getString(R.string.dialog_block_warning, loadedAccount?.username)) .setPositiveButton(android.R.string.ok) { _, _ -> viewModel.changeBlockState() } .setNegativeButton(android.R.string.cancel, null) @@ -1115,6 +1100,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvide badge.isClickable = false badge.isFocusable = false badge.setEnsureMinTouchTargetSize(false) + badge.isCloseIconVisible = false // reset some chip defaults so it looks better for our badge usecase badge.iconStartPadding = resources.getDimension(R.dimen.profile_badge_icon_start_padding) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/account/list/ListSelectionFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/account/list/ListSelectionFragment.kt index 9d1b4e4b7..383771496 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/account/list/ListSelectionFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/account/list/ListSelectionFragment.kt @@ -24,12 +24,12 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.ListsActivity import com.keylesspalace.tusky.R @@ -77,7 +77,7 @@ class ListSelectionFragment : DialogFragment() { val adapter = Adapter() binding.listsView.adapter = adapter - val dialogBuilder = AlertDialog.Builder(context) + val dialogBuilder = MaterialAlertDialogBuilder(context) .setView(binding.root) .setTitle(R.string.select_list_title) .setNeutralButton(R.string.select_list_manage) { _, _ -> diff --git a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementAdapter.kt index 2cdb1db55..68d4e98bc 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/announcements/AnnouncementAdapter.kt @@ -19,7 +19,6 @@ import android.annotation.SuppressLint import android.graphics.drawable.Drawable import android.os.Build import android.text.SpannableString -import android.view.ContextThemeWrapper import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -106,9 +105,11 @@ class AnnouncementAdapter( item.reactions.forEachIndexed { i, reaction -> ( chips.getChildAt(i)?.takeUnless { it.id == R.id.addReactionChip } as Chip? - ?: Chip(ContextThemeWrapper(chips.context, com.google.android.material.R.style.Widget_MaterialComponents_Chip_Choice)).apply { + ?: Chip(chips.context).apply { isCheckable = true checkedIcon = null + isCloseIconVisible = false + setChipBackgroundColorResource(R.color.selectable_chip_background) chips.addView(this, i) } ) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt index 2b26d3300..8e2910bb8 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeActivity.kt @@ -16,7 +16,6 @@ package com.keylesspalace.tusky.components.compose import android.Manifest -import android.app.ProgressDialog import android.content.ClipData import android.content.Context import android.content.Intent @@ -47,7 +46,6 @@ import androidx.annotation.AttrRes import androidx.annotation.ColorInt import androidx.annotation.StringRes import androidx.annotation.VisibleForTesting -import androidx.appcompat.app.AlertDialog import androidx.core.content.FileProvider import androidx.core.content.res.use import androidx.core.view.ContentInfoCompat @@ -66,6 +64,7 @@ import com.google.android.material.R as materialR import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback import com.google.android.material.color.MaterialColors +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.BuildConfig @@ -1319,14 +1318,14 @@ class ComposeActivity : private fun getSaveAsDraftOrDiscardDialog( contentText: String, contentWarning: String - ): AlertDialog.Builder { + ): MaterialAlertDialogBuilder { val warning = if (viewModel.media.value.isNotEmpty()) { R.string.compose_save_draft_loses_media } else { R.string.compose_save_draft } - return AlertDialog.Builder(this) + return MaterialAlertDialogBuilder(this) .setMessage(warning) .setPositiveButton(R.string.action_save) { _, _ -> viewModel.stopUploads() @@ -1345,14 +1344,14 @@ class ComposeActivity : private fun getUpdateDraftOrDiscardDialog( contentText: String, contentWarning: String - ): AlertDialog.Builder { + ): MaterialAlertDialogBuilder { val warning = if (viewModel.media.value.isNotEmpty()) { R.string.compose_save_draft_loses_media } else { R.string.compose_save_draft } - return AlertDialog.Builder(this) + return MaterialAlertDialogBuilder(this) .setMessage(warning) .setPositiveButton(R.string.action_save) { _, _ -> viewModel.stopUploads() @@ -1368,8 +1367,8 @@ class ComposeActivity : * User is editing a post (scheduled, or posted), and can either go back to editing, or * discard the changes. */ - private fun getContinueEditingOrDiscardDialog(): AlertDialog.Builder { - return AlertDialog.Builder(this) + private fun getContinueEditingOrDiscardDialog(): MaterialAlertDialogBuilder { + return MaterialAlertDialogBuilder(this) .setMessage(R.string.compose_unsaved_changes) .setPositiveButton(R.string.action_continue_edit) { _, _ -> // Do nothing, dialog will dismiss, user can continue editing @@ -1384,8 +1383,8 @@ class ComposeActivity : * User is editing an existing draft and making it empty. * The user can either delete the empty draft or go back to editing. */ - private fun getDeleteEmptyDraftOrContinueEditing(): AlertDialog.Builder { - return AlertDialog.Builder(this) + private fun getDeleteEmptyDraftOrContinueEditing(): MaterialAlertDialogBuilder { + return MaterialAlertDialogBuilder(this) .setMessage(R.string.compose_delete_draft) .setPositiveButton(R.string.action_delete) { _, _ -> viewModel.deleteDraft() @@ -1404,19 +1403,7 @@ class ComposeActivity : private fun saveDraftAndFinish(contentText: String, contentWarning: String) { lifecycleScope.launch { - val dialog = if (viewModel.shouldShowSaveDraftDialog()) { - ProgressDialog.show( - this@ComposeActivity, - null, - getString(R.string.saving_draft), - true, - false - ) - } else { - null - } viewModel.saveDraft(contentText, contentWarning) - dialog?.cancel() finish() } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt index 6b15b1e50..d0befe868 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/ComposeViewModel.kt @@ -331,13 +331,6 @@ class ComposeViewModel @Inject constructor( mediaUploader.cancelUploadScope(*_media.value.map { it.localId }.toIntArray()) } - fun shouldShowSaveDraftDialog(): Boolean { - // if any of the media files need to be downloaded first it could take a while, so show a loading dialog - return _media.value.any { mediaValue -> - mediaValue.uri.scheme == "https" - } - } - suspend fun saveDraft(content: String, contentWarning: String) { val mediaUris: MutableList = mutableListOf() val mediaDescriptions: MutableList = mutableListOf() diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/AddPollDialog.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/AddPollDialog.kt index 1d8168db6..3cd4b9e52 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/AddPollDialog.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/AddPollDialog.kt @@ -20,8 +20,8 @@ package com.keylesspalace.tusky.components.compose.dialog import android.content.Context import android.view.LayoutInflater import android.view.WindowManager -import android.widget.ArrayAdapter import androidx.appcompat.app.AlertDialog +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.keylesspalace.tusky.R import com.keylesspalace.tusky.databinding.DialogAddPollBinding import com.keylesspalace.tusky.entity.NewPoll @@ -37,7 +37,7 @@ fun showAddPollDialog( ) { val binding = DialogAddPollBinding.inflate(LayoutInflater.from(context)) - val dialog = AlertDialog.Builder(context) + val dialog = MaterialAlertDialogBuilder(context) .setIcon(R.drawable.ic_poll_24dp) .setTitle(R.string.create_poll_title) .setView(binding.root) @@ -63,9 +63,8 @@ fun showAddPollDialog( val durationLabels = context.resources.getStringArray( R.array.poll_duration_names ).filterIndexed { index, _ -> durations[index] in minDuration..maxDuration } - binding.pollDurationSpinner.adapter = ArrayAdapter(context, android.R.layout.simple_spinner_item, durationLabels).apply { - setDropDownViewResource(androidx.appcompat.R.layout.support_simple_spinner_dropdown_item) - } + + binding.pollDurationDropDown.setSimpleItems(durationLabels.toTypedArray()) durations = durations.filter { it in minDuration..maxDuration } binding.addChoiceButton.setOnClickListener { @@ -79,23 +78,24 @@ fun showAddPollDialog( val secondsInADay = 60 * 60 * 24 val desiredDuration = poll?.expiresIn ?: secondsInADay - val pollDurationId = durations.indexOfLast { + var selectedDurationIndex = durations.indexOfLast { it <= desiredDuration } - binding.pollDurationSpinner.setSelection(pollDurationId) + binding.pollDurationDropDown.setText(durationLabels[selectedDurationIndex], false) + binding.pollDurationDropDown.setOnItemClickListener { _, _, position, _ -> + selectedDurationIndex = position + } binding.multipleChoicesCheckBox.isChecked = poll?.multiple ?: false dialog.setOnShowListener { val button = dialog.getButton(AlertDialog.BUTTON_POSITIVE) button.setOnClickListener { - val selectedPollDurationId = binding.pollDurationSpinner.selectedItemPosition - onUpdatePoll( NewPoll( options = adapter.pollOptions, - expiresIn = durations[selectedPollDurationId], + expiresIn = durations[selectedDurationIndex], multiple = binding.multipleChoicesCheckBox.isChecked ) ) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/FocusDialog.kt b/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/FocusDialog.kt index d4c0848e7..2e013066c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/FocusDialog.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/compose/dialog/FocusDialog.kt @@ -20,7 +20,6 @@ import android.graphics.drawable.Drawable import android.net.Uri import android.view.WindowManager import android.widget.FrameLayout -import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope @@ -30,6 +29,7 @@ import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.target.Target +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.keylesspalace.tusky.databinding.DialogFocusBinding import com.keylesspalace.tusky.entity.Attachment.Focus import kotlinx.coroutines.launch @@ -98,7 +98,7 @@ fun T.makeFocusDialog( dialog.dismiss() } - val dialog = AlertDialog.Builder(this) + val dialog = MaterialAlertDialogBuilder(this) .setView(dialogBinding.root) .setPositiveButton(android.R.string.ok, okListener) .setNegativeButton(android.R.string.cancel, null) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt index c97cacccd..08f912b2c 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationsFragment.kt @@ -21,7 +21,6 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View -import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.PopupMenu import androidx.core.view.MenuProvider import androidx.fragment.app.viewModels @@ -35,6 +34,7 @@ import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.SimpleItemAnimator import at.connyduck.sparkbutton.helpers.Utils import com.google.android.material.color.MaterialColors +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.keylesspalace.tusky.R import com.keylesspalace.tusky.StatusListActivity import com.keylesspalace.tusky.adapter.StatusBaseViewHolder @@ -370,7 +370,7 @@ class ConversationsFragment : } private fun deleteConversation(conversation: ConversationViewData) { - AlertDialog.Builder(requireContext()) + MaterialAlertDialogBuilder(requireContext()) .setMessage(R.string.dialog_delete_conversation_warning) .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(android.R.string.ok) { _, _ -> diff --git a/app/src/main/java/com/keylesspalace/tusky/components/filters/EditFilterActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/filters/EditFilterActivity.kt index 7a0f9ddc4..c61765bea 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/filters/EditFilterActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/filters/EditFilterActivity.kt @@ -3,18 +3,16 @@ package com.keylesspalace.tusky.components.filters import android.content.Context import android.content.DialogInterface.BUTTON_POSITIVE import android.os.Bundle -import android.view.View import android.widget.AdapterView -import android.widget.ArrayAdapter import androidx.activity.viewModels -import androidx.appcompat.app.AlertDialog import androidx.core.view.size import androidx.core.widget.doAfterTextChanged import androidx.lifecycle.lifecycleScope import at.connyduck.calladapter.networkresult.fold import com.google.android.material.chip.Chip +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.google.android.material.materialswitch.MaterialSwitch import com.google.android.material.snackbar.Snackbar -import com.google.android.material.switchmaterial.SwitchMaterial import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.R import com.keylesspalace.tusky.appstore.EventHub @@ -46,7 +44,7 @@ class EditFilterActivity : BaseActivity() { private lateinit var filter: Filter private var originalFilter: Filter? = null - private lateinit var contextSwitches: Map + private lateinit var contextSwitches: Map override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -112,25 +110,14 @@ class EditFilterActivity : BaseActivity() { } ) } - binding.filterDurationSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected( - parent: AdapterView<*>?, - view: View?, - position: Int, - id: Long - ) { - viewModel.setDuration( - if (originalFilter?.expiresAt == null) { - position - } else { - position - 1 - } - ) - } - - override fun onNothingSelected(parent: AdapterView<*>?) { - viewModel.setDuration(0) - } + binding.filterDurationDropDown.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ -> + viewModel.setDuration( + if (originalFilter?.expiresAt == null) { + position + } else { + position - 1 + } + ) } validateSaveButton() @@ -177,10 +164,13 @@ class EditFilterActivity : BaseActivity() { // Populate the UI from the filter's members private fun loadFilter() { viewModel.load(filter) - if (filter.expiresAt != null) { - val durationNames = listOf(getString(R.string.duration_no_change)) + resources.getStringArray(R.array.filter_duration_names) - binding.filterDurationSpinner.adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, durationNames) + val durationNames = if (filter.expiresAt != null) { + arrayOf(getString(R.string.duration_no_change)) + resources.getStringArray(R.array.filter_duration_names) + } else { + resources.getStringArray(R.array.filter_duration_names) } + binding.filterDurationDropDown.setSimpleItems(durationNames) + binding.filterDurationDropDown.setText(durationNames[0], false) } private fun updateKeywords(newKeywords: List) { @@ -221,7 +211,7 @@ class EditFilterActivity : BaseActivity() { private fun showAddKeywordDialog() { val binding = DialogFilterBinding.inflate(layoutInflater) binding.phraseWholeWord.isChecked = true - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setTitle(R.string.filter_keyword_addition_title) .setView(binding.root) .setPositiveButton(android.R.string.ok) { _, _ -> @@ -242,7 +232,7 @@ class EditFilterActivity : BaseActivity() { binding.phraseEditText.setText(keyword.keyword) binding.phraseWholeWord.isChecked = keyword.wholeWord - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setTitle(R.string.filter_edit_keyword_title) .setView(binding.root) .setPositiveButton(R.string.filter_dialog_update_button) { _, _ -> diff --git a/app/src/main/java/com/keylesspalace/tusky/components/filters/FilterExtensions.kt b/app/src/main/java/com/keylesspalace/tusky/components/filters/FilterExtensions.kt index 0f14bc5fd..e2c0b589b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/filters/FilterExtensions.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/filters/FilterExtensions.kt @@ -18,14 +18,14 @@ package com.keylesspalace.tusky.components.filters import android.app.Activity -import androidx.appcompat.app.AlertDialog +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.keylesspalace.tusky.R import com.keylesspalace.tusky.util.await -internal suspend fun Activity.showDeleteFilterDialog(filterTitle: String) = AlertDialog.Builder( - this -) - .setMessage(getString(R.string.dialog_delete_filter_text, filterTitle)) - .setCancelable(true) - .create() - .await(R.string.dialog_delete_filter_positive_action, android.R.string.cancel) +internal suspend fun Activity.showDeleteFilterDialog(filterTitle: String): Int { + return MaterialAlertDialogBuilder(this) + .setMessage(getString(R.string.dialog_delete_filter_text, filterTitle)) + .setCancelable(true) + .create() + .await(R.string.dialog_delete_filter_positive_action, android.R.string.cancel) +} diff --git a/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt index 2be476067..6c64048ec 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/followedtags/FollowedTagsActivity.kt @@ -7,7 +7,6 @@ import android.os.Bundle import android.util.Log import android.widget.AutoCompleteTextView import androidx.activity.viewModels -import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import androidx.lifecycle.lifecycleScope import androidx.paging.LoadState @@ -15,6 +14,7 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.SimpleItemAnimator import at.connyduck.calladapter.networkresult.fold +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.R @@ -195,7 +195,7 @@ class FollowedTagsActivity : ) ) - return AlertDialog.Builder(requireActivity()) + return MaterialAlertDialogBuilder(requireActivity()) .setTitle(R.string.dialog_follow_hashtag_title) .setView(layout) .setPositiveButton(android.R.string.ok) { _, _ -> 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 83f1558f7..014893e59 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,11 +24,11 @@ import android.util.Log import android.view.Menu import android.view.View import android.widget.TextView -import androidx.appcompat.app.AlertDialog import androidx.core.net.toUri import androidx.lifecycle.lifecycleScope import at.connyduck.calladapter.networkresult.fold import com.bumptech.glide.Glide +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.BuildConfig import com.keylesspalace.tusky.MainActivity @@ -110,7 +110,7 @@ class LoginActivity : BaseActivity() { binding.loginButton.setOnClickListener { onLoginClick(true) } binding.whatsAnInstanceTextView.setOnClickListener { - val dialog = AlertDialog.Builder(this) + val dialog = MaterialAlertDialogBuilder(this) .setMessage(R.string.dialog_whats_an_instance) .setPositiveButton(R.string.action_close, null) .show() diff --git a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt index c2ea86b3b..3eb271f4e 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/login/LoginWebViewActivity.kt @@ -32,15 +32,14 @@ import android.webkit.WebView import android.webkit.WebViewClient import androidx.activity.result.contract.ActivityResultContract import androidx.activity.viewModels -import androidx.appcompat.app.AlertDialog import androidx.core.net.toUri import androidx.lifecycle.lifecycleScope +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.BuildConfig import com.keylesspalace.tusky.R import com.keylesspalace.tusky.databinding.ActivityLoginWebviewBinding import com.keylesspalace.tusky.util.getParcelableExtraCompat -import com.keylesspalace.tusky.util.hide import com.keylesspalace.tusky.util.viewBinding import com.keylesspalace.tusky.util.visible import dagger.hilt.android.AndroidEntryPoint @@ -196,7 +195,7 @@ class LoginWebViewActivity : BaseActivity() { viewModel.instanceRules.collect { instanceRules -> binding.loginRules.visible(instanceRules.isNotEmpty()) binding.loginRules.setOnClickListener { - AlertDialog.Builder(this@LoginWebViewActivity) + MaterialAlertDialogBuilder(this@LoginWebViewActivity) .setTitle(getString(R.string.instance_rule_title, data.domain)) .setMessage( instanceRules.joinToString(separator = "\n\n") { "• $it" } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt index 5d2e191d4..c2001422d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/notifications/NotificationsFragment.kt @@ -27,7 +27,6 @@ import android.view.ViewGroup import android.widget.ArrayAdapter import android.widget.ListView import android.widget.PopupWindow -import androidx.appcompat.app.AlertDialog import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.MenuProvider import androidx.fragment.app.viewModels @@ -43,6 +42,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import at.connyduck.calladapter.networkresult.onFailure import at.connyduck.sparkbutton.helpers.Utils import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.R import com.keylesspalace.tusky.adapter.StatusBaseViewHolder @@ -416,7 +416,7 @@ class NotificationsFragment : } private fun confirmClearNotifications() { - AlertDialog.Builder(requireContext()) + MaterialAlertDialogBuilder(requireContext()) .setMessage(R.string.notification_clear_text) .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> clearNotifications() } .setNegativeButton(android.R.string.cancel, null) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt index d2289d411..aa59a59a9 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/scheduled/ScheduledStatusActivity.kt @@ -22,13 +22,13 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import androidx.activity.viewModels -import androidx.appcompat.app.AlertDialog import androidx.core.view.MenuProvider import androidx.lifecycle.lifecycleScope import androidx.paging.LoadState import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.color.MaterialColors +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.R import com.keylesspalace.tusky.appstore.EventHub @@ -168,7 +168,7 @@ class ScheduledStatusActivity : } override fun delete(item: ScheduledStatus) { - AlertDialog.Builder(this) + MaterialAlertDialogBuilder(this) .setMessage(R.string.delete_scheduled_post_warning) .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(android.R.string.ok) { _, _ -> 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 85d7c406d..effe20a73 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 @@ -27,7 +27,6 @@ import android.util.Log import android.view.View import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.PopupMenu import androidx.core.app.ActivityOptionsCompat import androidx.core.content.getSystemService @@ -39,6 +38,7 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import at.connyduck.calladapter.networkresult.fold import at.connyduck.calladapter.networkresult.onFailure +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.R import com.keylesspalace.tusky.ViewMediaActivity @@ -485,7 +485,7 @@ class SearchStatusesFragment : SearchFragment(), Status } private fun onBlock(accountId: String, accountUsername: String) { - AlertDialog.Builder(requireContext()) + MaterialAlertDialogBuilder(requireContext()) .setMessage(getString(R.string.dialog_block_warning, accountUsername)) .setPositiveButton(android.R.string.ok) { _, _ -> viewModel.blockAccount(accountId) } .setNegativeButton(android.R.string.cancel, null) @@ -555,7 +555,7 @@ class SearchStatusesFragment : SearchFragment(), Status private fun showConfirmDeleteDialog(id: String, position: Int) { context?.let { - AlertDialog.Builder(it) + MaterialAlertDialogBuilder(it) .setMessage(R.string.dialog_delete_post_warning) .setPositiveButton(android.R.string.ok) { _, _ -> viewModel.deleteStatusAsync(id) @@ -568,7 +568,7 @@ class SearchStatusesFragment : SearchFragment(), Status private fun showConfirmEditDialog(id: String, position: Int, status: Status) { context?.let { context -> - AlertDialog.Builder(context) + MaterialAlertDialogBuilder(context) .setMessage(R.string.dialog_redraft_post_warning) .setPositiveButton(android.R.string.ok) { _, _ -> viewLifecycleOwner.lifecycleScope.launch { diff --git a/app/src/main/java/com/keylesspalace/tusky/components/systemnotifications/PushNotificationHelper.kt b/app/src/main/java/com/keylesspalace/tusky/components/systemnotifications/PushNotificationHelper.kt index 4e7c1a682..de9bce269 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/systemnotifications/PushNotificationHelper.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/systemnotifications/PushNotificationHelper.kt @@ -22,10 +22,10 @@ import android.content.Context import android.os.Build import android.util.Log import android.view.View -import androidx.appcompat.app.AlertDialog import androidx.preference.PreferenceManager import at.connyduck.calladapter.networkresult.onFailure import at.connyduck.calladapter.networkresult.onSuccess +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.R import com.keylesspalace.tusky.components.login.LoginActivity @@ -73,7 +73,7 @@ fun showMigrationNoticeIfNecessary( } private fun showMigrationExplanationDialog(context: Context, accountManager: AccountManager) { - AlertDialog.Builder(context).apply { + MaterialAlertDialogBuilder(context).apply { if (currentAccountNeedsMigration(accountManager)) { setMessage(R.string.dialog_push_notification_migration) setPositiveButton(R.string.title_migration_relogin) { _, _ -> diff --git a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadActivity.kt b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadActivity.kt index 5227fb293..4db214de6 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/viewthread/ViewThreadActivity.kt @@ -33,7 +33,7 @@ class ViewThreadActivity : BottomSheetActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(binding.root) - setSupportActionBar(binding.toolbar) + setSupportActionBar(binding.includedToolbar.toolbar) supportActionBar?.run { setDisplayHomeAsUpEnabled(true) setDisplayShowHomeEnabled(true) diff --git a/app/src/main/java/com/keylesspalace/tusky/db/DraftsAlert.kt b/app/src/main/java/com/keylesspalace/tusky/db/DraftsAlert.kt index 39f46e9a6..1f9508622 100644 --- a/app/src/main/java/com/keylesspalace/tusky/db/DraftsAlert.kt +++ b/app/src/main/java/com/keylesspalace/tusky/db/DraftsAlert.kt @@ -18,10 +18,10 @@ package com.keylesspalace.tusky.db import android.content.Context import android.content.DialogInterface import android.util.Log -import androidx.appcompat.app.AlertDialog import androidx.lifecycle.LifecycleCoroutineScope import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.keylesspalace.tusky.R import com.keylesspalace.tusky.components.drafts.DraftsActivity import com.keylesspalace.tusky.db.dao.DraftDao @@ -61,7 +61,7 @@ class DraftsAlert @Inject constructor(db: AppDatabase) { draftsNeedUserAlert.collect { count -> Log.d(TAG, "User id $activeAccountId changed: Notification-worthy draft count $count") if (count > 0) { - AlertDialog.Builder(context) + MaterialAlertDialogBuilder(context) .setTitle(R.string.action_post_failed) .setMessage( context.resources.getQuantityString(R.plurals.action_post_failed_detail, count) 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 4f728dc5e..c901ebff4 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.kt @@ -28,7 +28,6 @@ import android.view.View import android.widget.Toast import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.LayoutRes -import androidx.appcompat.app.AlertDialog import androidx.appcompat.widget.PopupMenu import androidx.core.app.ActivityOptionsCompat import androidx.core.content.getSystemService @@ -36,6 +35,7 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import at.connyduck.calladapter.networkresult.fold import at.connyduck.calladapter.networkresult.onFailure +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.BottomSheetActivity @@ -383,7 +383,7 @@ abstract class SFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayo } private fun onBlock(accountId: String, accountUsername: String) { - AlertDialog.Builder(requireContext()) + MaterialAlertDialogBuilder(requireContext()) .setMessage(getString(R.string.dialog_block_warning, accountUsername)) .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> lifecycleScope.launch { @@ -428,7 +428,7 @@ abstract class SFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayo } private fun showConfirmDeleteDialog(id: String, position: Int) { - AlertDialog.Builder(requireActivity()) + MaterialAlertDialogBuilder(requireActivity()) .setMessage(R.string.dialog_delete_post_warning) .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> viewLifecycleOwner.lifecycleScope.launch { @@ -452,7 +452,7 @@ abstract class SFragment(@LayoutRes contentLayoutId: Int) : Fragment(contentLayo private fun showConfirmEditDialog(id: String, position: Int, status: Status) { val context = context ?: return - AlertDialog.Builder(context) + MaterialAlertDialogBuilder(context) .setMessage(R.string.dialog_redraft_post_warning) .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> viewLifecycleOwner.lifecycleScope.launch { diff --git a/app/src/main/java/com/keylesspalace/tusky/settings/SettingsDSL.kt b/app/src/main/java/com/keylesspalace/tusky/settings/SettingsDSL.kt index c1b57427d..08de72791 100644 --- a/app/src/main/java/com/keylesspalace/tusky/settings/SettingsDSL.kt +++ b/app/src/main/java/com/keylesspalace/tusky/settings/SettingsDSL.kt @@ -12,7 +12,7 @@ import androidx.preference.Preference import androidx.preference.PreferenceCategory import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceScreen -import androidx.preference.SwitchPreference +import androidx.preference.SwitchPreferenceCompat import com.keylesspalace.tusky.view.SliderPreference import de.c1710.filemojicompat_ui.views.picker.preference.EmojiPickerPreference @@ -56,9 +56,9 @@ inline fun PreferenceParent.sliderPreference( } inline fun PreferenceParent.switchPreference( - builder: SwitchPreference.() -> Unit -): SwitchPreference { - val pref = SwitchPreference(context) + builder: SwitchPreferenceCompat.() -> Unit +): SwitchPreferenceCompat { + val pref = SwitchPreferenceCompat(context) builder(pref) addPref(pref) return pref diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ListStatusAccessibilityDelegate.kt b/app/src/main/java/com/keylesspalace/tusky/util/ListStatusAccessibilityDelegate.kt index 537c7acdc..82f43bf59 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ListStatusAccessibilityDelegate.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/ListStatusAccessibilityDelegate.kt @@ -8,12 +8,12 @@ import android.view.View import android.view.accessibility.AccessibilityEvent import android.view.accessibility.AccessibilityManager import android.widget.ArrayAdapter -import androidx.appcompat.app.AlertDialog import androidx.core.view.AccessibilityDelegateCompat import androidx.core.view.accessibility.AccessibilityNodeInfoCompat import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerViewAccessibilityDelegate +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.keylesspalace.tusky.R import com.keylesspalace.tusky.adapter.StatusBaseViewHolder import com.keylesspalace.tusky.entity.Status.Companion.MAX_MEDIA_ATTACHMENTS @@ -174,7 +174,7 @@ class ListStatusAccessibilityDelegate( val status = getStatus(host) as? StatusViewData.Concrete ?: return val links = getLinks(status).toList() val textLinks = links.map { item -> item.link } - AlertDialog.Builder(host.context) + MaterialAlertDialogBuilder(host.context) .setTitle(R.string.title_links_dialog) .setAdapter( ArrayAdapter( @@ -191,7 +191,7 @@ class ListStatusAccessibilityDelegate( val status = getStatus(host) as? StatusViewData.Concrete ?: return val mentions = status.actionable.mentions val stringMentions = mentions.map { it.username } - AlertDialog.Builder(host.context) + MaterialAlertDialogBuilder(host.context) .setTitle(R.string.title_mentions_dialog) .setAdapter( ArrayAdapter( @@ -209,7 +209,7 @@ class ListStatusAccessibilityDelegate( private fun showHashtagsDialog(host: View) { val status = getStatus(host) as? StatusViewData.Concrete ?: return val tags = getHashtags(status).map { it.subSequence(1, it.length) }.toList() - AlertDialog.Builder(host.context) + MaterialAlertDialogBuilder(host.context) .setTitle(R.string.title_hashtags_dialog) .setAdapter( ArrayAdapter( diff --git a/app/src/main/java/com/keylesspalace/tusky/view/LicenseCard.kt b/app/src/main/java/com/keylesspalace/tusky/view/LicenseCard.kt index 04d689e1e..e6eb5de04 100644 --- a/app/src/main/java/com/keylesspalace/tusky/view/LicenseCard.kt +++ b/app/src/main/java/com/keylesspalace/tusky/view/LicenseCard.kt @@ -16,7 +16,7 @@ package com.keylesspalace.tusky.view import android.content.Context -import android.graphics.Color +import android.content.res.ColorStateList import android.util.AttributeSet import android.view.LayoutInflater import androidx.core.content.res.use @@ -32,19 +32,13 @@ class LicenseCard @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = 0 + defStyleAttr: Int = R.attr.licenseCardStyle ) : MaterialCardView(context, attrs, defStyleAttr) { init { val binding = CardLicenseBinding.inflate(LayoutInflater.from(context), this) - setCardBackgroundColor( - MaterialColors.getColor( - context, - materialR.attr.colorSurface, - Color.BLACK - ) - ) + setStrokeColor(ColorStateList.valueOf(MaterialColors.getColor(this, materialR.attr.colorOutline))) val (name, license, link) = context.theme.obtainStyledAttributes( attrs, diff --git a/app/src/main/java/com/keylesspalace/tusky/view/MuteAccountDialog.kt b/app/src/main/java/com/keylesspalace/tusky/view/MuteAccountDialog.kt index 715fa6033..43b7ed5d3 100644 --- a/app/src/main/java/com/keylesspalace/tusky/view/MuteAccountDialog.kt +++ b/app/src/main/java/com/keylesspalace/tusky/view/MuteAccountDialog.kt @@ -3,7 +3,7 @@ package com.keylesspalace.tusky.view import android.app.Activity -import androidx.appcompat.app.AlertDialog +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.keylesspalace.tusky.R import com.keylesspalace.tusky.databinding.DialogMuteAccountBinding @@ -16,17 +16,26 @@ fun showMuteAccountDialog( binding.warning.text = activity.getString(R.string.dialog_mute_warning, accountUsername) binding.checkbox.isChecked = true - AlertDialog.Builder(activity) + val durationLabels = activity.resources.getStringArray(R.array.mute_duration_names) + binding.durationDropDown.setSimpleItems(durationLabels) + + var selectedDurationIndex = 0 + binding.durationDropDown.setOnItemClickListener { _, _, position, _ -> + selectedDurationIndex = position + } + binding.durationDropDown.setText(durationLabels[selectedDurationIndex], false) + + MaterialAlertDialogBuilder(activity) .setView(binding.root) .setPositiveButton(android.R.string.ok) { _, _ -> val durationValues = activity.resources.getIntArray(R.array.mute_duration_values) // workaround to make indefinite muting work with Mastodon 3.3.0 // https://github.com/tuskyapp/Tusky/issues/2107 - val duration = if (binding.duration.selectedItemPosition == 0) { + val duration = if (selectedDurationIndex == 0) { null } else { - durationValues[binding.duration.selectedItemPosition] + durationValues[selectedDurationIndex] } onOk(binding.checkbox.isChecked, duration) diff --git a/app/src/main/res/color/selectable_chip_background.xml b/app/src/main/res/color/selectable_chip_background.xml new file mode 100644 index 000000000..2469cdac5 --- /dev/null +++ b/app/src/main/res/color/selectable_chip_background.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/background_dialog_activity.xml b/app/src/main/res/drawable/background_dialog_activity.xml index 80cff382e..7af1b9869 100644 --- a/app/src/main/res/drawable/background_dialog_activity.xml +++ b/app/src/main/res/drawable/background_dialog_activity.xml @@ -1,5 +1,5 @@ - + - \ No newline at end of file + diff --git a/app/src/main/res/layout-land/fragment_report_done.xml b/app/src/main/res/layout-land/fragment_report_done.xml index 6263758a3..567449b8e 100644 --- a/app/src/main/res/layout-land/fragment_report_done.xml +++ b/app/src/main/res/layout-land/fragment_report_done.xml @@ -59,10 +59,11 @@ app:layout_constraintTop_toBottomOf="@id/textReported" app:layout_constraintVertical_chainStyle="packed" /> - - - \ No newline at end of file + diff --git a/app/src/main/res/layout-sw640dp/fragment_timeline.xml b/app/src/main/res/layout-sw640dp/fragment_timeline.xml index 511b4f3b6..415695912 100644 --- a/app/src/main/res/layout-sw640dp/fragment_timeline.xml +++ b/app/src/main/res/layout-sw640dp/fragment_timeline.xml @@ -12,13 +12,14 @@ android:layout_gravity="center_horizontal" android:background="?android:attr/colorBackground"> - + app:liftOnScroll="false"> - - - diff --git a/app/src/main/res/layout-sw640dp/fragment_view_thread.xml b/app/src/main/res/layout-sw640dp/fragment_view_thread.xml index 3001e4d83..59acf5b97 100644 --- a/app/src/main/res/layout-sw640dp/fragment_view_thread.xml +++ b/app/src/main/res/layout-sw640dp/fragment_view_thread.xml @@ -46,7 +46,7 @@ - @@ -178,12 +178,11 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="24dp" + android:layout_marginEnd="@dimen/text_content_margin" android:lineSpacingMultiplier="1.2" android:maxWidth="320dp" android:text="@string/about_tusky_account" - android:textAllCaps="false" android:textSize="16sp" - android:layout_marginEnd="@dimen/text_content_margin" app:layout_constraintEnd_toStartOf="@+id/aboutLicensesButton" app:layout_constraintStart_toStartOf="@+id/aboutBugsFeaturesInfoTextView" app:layout_constraintTop_toBottomOf="@id/aboutBugsFeaturesInfoTextView" /> @@ -193,13 +192,12 @@ style="@style/TuskyButton.Outlined" android:layout_width="0dp" android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/text_content_margin" android:lineSpacingMultiplier="1.2" android:maxWidth="320dp" android:text="@string/title_licenses" android:textAlignment="center" - android:textAllCaps="false" android:textSize="16sp" - android:layout_marginEnd="@dimen/text_content_margin" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/tuskyProfileButton" app:layout_constraintTop_toTopOf="@+id/tuskyProfileButton" /> diff --git a/app/src/main/res/layout/activity_account.xml b/app/src/main/res/layout/activity_account.xml index e424a5f58..2b34e4490 100644 --- a/app/src/main/res/layout/activity_account.xml +++ b/app/src/main/res/layout/activity_account.xml @@ -17,7 +17,7 @@ android:id="@+id/accountAppBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:elevation="@dimen/actionbar_elevation"> + app:liftOnScroll="false"> - diff --git a/app/src/main/res/layout/activity_announcements.xml b/app/src/main/res/layout/activity_announcements.xml index 6a18bf131..1094d5e0e 100644 --- a/app/src/main/res/layout/activity_announcements.xml +++ b/app/src/main/res/layout/activity_announcements.xml @@ -9,11 +9,12 @@ android:id="@+id/includedToolbar" layout="@layout/toolbar_basic" /> - + android:layout_gravity="center" + android:indeterminate="true" /> - - - - - + diff --git a/app/src/main/res/layout/activity_edit_filter.xml b/app/src/main/res/layout/activity_edit_filter.xml index 2a56297b1..9b3182e33 100644 --- a/app/src/main/res/layout/activity_edit_filter.xml +++ b/app/src/main/res/layout/activity_edit_filter.xml @@ -34,6 +34,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textNoSuggestions" /> + + app:chipStrokeWidth="0dp" + app:closeIconEnabled="false" /> + + - + android:hint="@string/label_expires_after"> - + + + - - - - -