diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ControllableTabLayout.java b/app/src/main/java/org/thoughtcrime/securesms/components/ControllableTabLayout.java index 8c32a1737..854244b5d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/ControllableTabLayout.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/ControllableTabLayout.java @@ -4,6 +4,9 @@ import android.content.Context; import android.util.AttributeSet; import android.view.View; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.google.android.material.tabs.TabLayout; import java.util.List; @@ -15,6 +18,8 @@ public class ControllableTabLayout extends TabLayout { private List touchables; + private NewTabListener newTabListener; + public ControllableTabLayout(Context context) { super(context); } @@ -39,4 +44,28 @@ public class ControllableTabLayout extends TabLayout { super.setEnabled(enabled); } + + public void setNewTabListener(@Nullable NewTabListener newTabListener) { + this.newTabListener = newTabListener; + } + + @Override + public @NonNull Tab newTab() { + Tab tab = super.newTab(); + + if (newTabListener != null) { + newTabListener.onNewTab(tab); + } + + return tab; + } + + /** + * Allows implementor to modify tabs when they are created, before they are added to the tab layout. + * This is useful for loading custom views, to ensure that time is not spent inflating these views + * as the user is switching between pages. + */ + public interface NewTabListener { + void onNewTab(@NonNull Tab tab); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewActivity.java b/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewActivity.java index b257d70fd..872916a9f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewActivity.java @@ -18,7 +18,6 @@ package org.thoughtcrime.securesms.mediaoverview; import android.content.Context; import android.content.Intent; -import android.graphics.Typeface; import android.os.Bundle; import android.view.MenuItem; import android.view.View; @@ -27,19 +26,19 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.StringRes; -import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.Toolbar; -import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.viewpager.widget.ViewPager; +import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.tabs.TabLayout; import org.thoughtcrime.securesms.PassphraseRequiredActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.components.AnimatingToggle; +import org.thoughtcrime.securesms.components.ControllableTabLayout; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MediaDatabase; import org.thoughtcrime.securesms.database.MediaDatabase.Sorting; @@ -51,6 +50,7 @@ import org.whispersystems.libsignal.util.Pair; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Activity for displaying media attachments in-app @@ -62,7 +62,7 @@ public final class MediaOverviewActivity extends PassphraseRequiredActivity { private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme(); private Toolbar toolbar; - private TabLayout tabLayout; + private ControllableTabLayout tabLayout; private ViewPager viewPager; private TextView sortOrder; private View sortOrderArrow; @@ -98,6 +98,7 @@ public final class MediaOverviewActivity extends PassphraseRequiredActivity { boolean allThreads = threadId == MediaDatabase.ALL_THREADS; + tabLayout.setNewTabListener(new NewTabListener()); tabLayout.addOnTabSelectedListener(new OnTabSelectedListener()); fillTabLayoutIfFits(tabLayout); tabLayout.setupWithViewPager(viewPager); @@ -221,7 +222,7 @@ public final class MediaOverviewActivity extends PassphraseRequiredActivity { } private void showSortOrderDialog(View v) { - new AlertDialog.Builder(MediaOverviewActivity.this) + new MaterialAlertDialogBuilder(MediaOverviewActivity.this) .setTitle(R.string.MediaOverviewActivity_Sort_by) .setSingleChoiceItems(R.array.MediaOverviewActivity_Sort_by, currentSorting.ordinal(), @@ -286,39 +287,33 @@ public final class MediaOverviewActivity extends PassphraseRequiredActivity { } } - private static final class OnTabSelectedListener implements TabLayout.OnTabSelectedListener { + private static final class NewTabListener implements ControllableTabLayout.NewTabListener { + @Override + public void onNewTab(@NonNull TabLayout.Tab tab) { + View customView = tab.getCustomView(); + if (customView == null) { + tab.setCustomView(R.layout.media_overview_tab_item); + } + } + } - private final Typeface tabUnselected = Typeface.create("sans-serif", Typeface.NORMAL); - private final Typeface tabSelected = Typeface.create("sans-serif-medium", Typeface.NORMAL); + private static final class OnTabSelectedListener implements TabLayout.OnTabSelectedListener { @Override public void onTabSelected(@NonNull TabLayout.Tab tab) { - View view = getCustomView(tab); - TextView title = view.findViewById(android.R.id.text1); - title.setTypeface(tabSelected); - title.setTextColor(ContextCompat.getColor(view.getContext(), R.color.signal_inverse_primary)); + MediaOverviewTabItem view = (MediaOverviewTabItem) Objects.requireNonNull(tab.getCustomView()); + view.select(); } @Override public void onTabUnselected(@NonNull TabLayout.Tab tab) { - View view = getCustomView(tab); - TextView title = view.findViewById(android.R.id.text1); - title.setTypeface(tabUnselected); - title.setTextColor(ContextCompat.getColor(view.getContext(), R.color.signal_text_secondary)); + MediaOverviewTabItem view = (MediaOverviewTabItem) Objects.requireNonNull(tab.getCustomView()); + view.unselect(); } @Override public void onTabReselected(@NonNull TabLayout.Tab tab) { // Intentionally Blank. } - - private @NonNull View getCustomView(@NonNull TabLayout.Tab tab) { - View customView = tab.getCustomView(); - if (customView == null) { - tab.setCustomView(R.layout.custom_tab_layout_text); - } - - return tab.getCustomView(); - } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewTabItem.kt b/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewTabItem.kt new file mode 100644 index 000000000..b885a89a5 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewTabItem.kt @@ -0,0 +1,39 @@ +package org.thoughtcrime.securesms.mediaoverview + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout +import android.widget.TextView +import androidx.core.widget.doAfterTextChanged +import org.thoughtcrime.securesms.R + +class MediaOverviewTabItem @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr) { + + private lateinit var unselectedTextView: TextView + private lateinit var selectedTextView: TextView + + override fun onFinishInflate() { + super.onFinishInflate() + + unselectedTextView = findViewById(android.R.id.text1) + selectedTextView = findViewById(R.id.text1_bold) + + unselectedTextView.doAfterTextChanged { + selectedTextView.text = it + } + } + + fun select() { + unselectedTextView.alpha = 0f + selectedTextView.alpha = 1f + } + + fun unselect() { + unselectedTextView.alpha = 1f + selectedTextView.alpha = 0f + } +} diff --git a/app/src/main/res/layout/custom_tab_layout_text.xml b/app/src/main/res/layout/custom_tab_layout_text.xml deleted file mode 100644 index e5a66b3b8..000000000 --- a/app/src/main/res/layout/custom_tab_layout_text.xml +++ /dev/null @@ -1,10 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/layout/media_overview_tab_item.xml b/app/src/main/res/layout/media_overview_tab_item.xml new file mode 100644 index 000000000..82725dedb --- /dev/null +++ b/app/src/main/res/layout/media_overview_tab_item.xml @@ -0,0 +1,30 @@ + + + + + + + +