That fuck shit the fascists are using
at master 292 lines 10 kB view raw
1/* 2 * Copyright (C) 2015 Open Whisper Systems 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 3 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17package org.tm.archive.mediaoverview; 18 19import android.content.Context; 20import android.content.Intent; 21import android.os.Bundle; 22import android.view.MenuItem; 23import android.view.View; 24import android.view.ViewGroup; 25import android.widget.TextView; 26 27import androidx.annotation.NonNull; 28import androidx.annotation.StringRes; 29import androidx.appcompat.widget.Toolbar; 30import androidx.fragment.app.Fragment; 31import androidx.fragment.app.FragmentManager; 32import androidx.fragment.app.FragmentStatePagerAdapter; 33import androidx.viewpager.widget.ViewPager; 34 35import com.google.android.material.dialog.MaterialAlertDialogBuilder; 36import com.google.android.material.tabs.TabLayout; 37import com.google.android.material.transition.platform.MaterialContainerTransformSharedElementCallback; 38 39import org.signal.libsignal.protocol.util.Pair; 40import org.tm.archive.PassphraseRequiredActivity; 41import org.tm.archive.R; 42import org.tm.archive.components.AnimatingToggle; 43import org.tm.archive.components.BoldSelectionTabItem; 44import org.tm.archive.components.ControllableTabLayout; 45import org.tm.archive.database.MediaTable; 46import org.tm.archive.database.MediaTable.Sorting; 47import org.tm.archive.database.SignalDatabase; 48import org.tm.archive.database.loaders.MediaLoader; 49import org.tm.archive.util.DynamicNoActionBarTheme; 50import org.tm.archive.util.DynamicTheme; 51import org.signal.core.util.concurrent.SimpleTask; 52 53import java.util.ArrayList; 54import java.util.List; 55 56/** 57 * Activity for displaying media attachments in-app 58 */ 59public final class MediaOverviewActivity extends PassphraseRequiredActivity { 60 61 private static final String THREAD_ID_EXTRA = "thread_id"; 62 63 private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme(); 64 65 private Toolbar toolbar; 66 private ControllableTabLayout tabLayout; 67 private ViewPager viewPager; 68 private TextView sortOrder; 69 private View sortOrderArrow; 70 private Sorting currentSorting; 71 private Boolean currentDetailLayout; 72 private MediaOverviewViewModel model; 73 private AnimatingToggle displayToggle; 74 private View viewGrid; 75 private View viewDetail; 76 private long threadId; 77 78 public static Intent forThread(@NonNull Context context, long threadId) { 79 Intent intent = new Intent(context, MediaOverviewActivity.class); 80 intent.putExtra(MediaOverviewActivity.THREAD_ID_EXTRA, threadId); 81 return intent; 82 } 83 84 public static Intent forAll(@NonNull Context context) { 85 return forThread(context, MediaTable.ALL_THREADS); 86 } 87 88 @Override 89 protected void onPreCreate() { 90 dynamicTheme.onCreate(this); 91 } 92 93 @Override 94 protected void onCreate(Bundle bundle, boolean ready) { 95 setExitSharedElementCallback(new MaterialContainerTransformSharedElementCallback()); 96 setContentView(R.layout.media_overview_activity); 97 98 initializeResources(); 99 initializeToolbar(); 100 101 boolean allThreads = threadId == MediaTable.ALL_THREADS; 102 103 BoldSelectionTabItem.registerListeners(tabLayout); 104 fillTabLayoutIfFits(tabLayout); 105 tabLayout.setupWithViewPager(viewPager); 106 viewPager.setAdapter(new MediaOverviewPagerAdapter(getSupportFragmentManager())); 107 108 model = MediaOverviewViewModel.getMediaOverviewViewModel(this); 109 model.setSortOrder(allThreads ? Sorting.Largest : Sorting.Newest); 110 model.setDetailLayout(allThreads); 111 model.getSortOrder().observe(this, this::setSorting); 112 model.getDetailLayout().observe(this, this::setDetailLayout); 113 114 sortOrder.setOnClickListener(this::showSortOrderDialog); 115 sortOrderArrow.setOnClickListener(this::showSortOrderDialog); 116 117 displayToggle.setOnClickListener(v -> setDetailLayout(!currentDetailLayout)); 118 119 viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { 120 @Override 121 public void onPageSelected(int position) { 122 boolean gridToggleEnabled = allowGridSelectionOnPage(position); 123 displayToggle.animate() 124 .alpha(gridToggleEnabled ? 1 : 0) 125 .start(); 126 displayToggle.setEnabled(gridToggleEnabled); 127 } 128 }); 129 130 viewPager.setCurrentItem(allThreads ? 3 : 0); 131 } 132 133 private static boolean allowGridSelectionOnPage(int page) { 134 return page == 0; 135 } 136 137 private void setSorting(@NonNull Sorting sorting) { 138 if (currentSorting == sorting) return; 139 140 sortOrder.setText(sortingToString(sorting)); 141 currentSorting = sorting; 142 model.setSortOrder(sorting); 143 } 144 145 private static @StringRes int sortingToString(@NonNull Sorting sorting) { 146 switch (sorting) { 147 case Oldest : return R.string.MediaOverviewActivity_Oldest; 148 case Newest : return R.string.MediaOverviewActivity_Newest; 149 case Largest : return R.string.MediaOverviewActivity_Storage_used; 150 default : throw new AssertionError(); 151 } 152 } 153 154 private void setDetailLayout(@NonNull Boolean detailLayout) { 155 if (currentDetailLayout == detailLayout) return; 156 157 currentDetailLayout = detailLayout; 158 model.setDetailLayout(detailLayout); 159 displayToggle.display(detailLayout ? viewGrid : viewDetail); 160 } 161 162 @Override 163 public void onResume() { 164 super.onResume(); 165 dynamicTheme.onResume(this); 166 } 167 168 @Override 169 public boolean onOptionsItemSelected(MenuItem item) { 170 super.onOptionsItemSelected(item); 171 172 if (item.getItemId() == android.R.id.home) { 173 finish(); 174 return true; 175 } 176 177 return false; 178 } 179 180 private void initializeResources() { 181 Intent intent = getIntent(); 182 long threadId = intent.getLongExtra(THREAD_ID_EXTRA, Long.MIN_VALUE); 183 184 if (threadId == Long.MIN_VALUE) throw new AssertionError(); 185 186 this.viewPager = findViewById(R.id.pager); 187 this.toolbar = findViewById(R.id.toolbar); 188 this.tabLayout = findViewById(R.id.tab_layout); 189 this.sortOrder = findViewById(R.id.sort_order); 190 this.sortOrderArrow = findViewById(R.id.sort_order_arrow); 191 this.displayToggle = findViewById(R.id.grid_list_toggle); 192 this.viewDetail = findViewById(R.id.view_detail); 193 this.viewGrid = findViewById(R.id.view_grid); 194 this.threadId = threadId; 195 } 196 197 private void initializeToolbar() { 198 setSupportActionBar(toolbar); 199 getSupportActionBar().setDisplayHomeAsUpEnabled(true); 200 201 if (threadId == MediaTable.ALL_THREADS) { 202 getSupportActionBar().setTitle(R.string.MediaOverviewActivity_All_storage_use); 203 } else { 204 SimpleTask.run(() -> SignalDatabase.threads().getRecipientForThreadId(threadId), 205 (recipient) -> { 206 if (recipient != null) { 207 getSupportActionBar().setTitle(recipient.getDisplayName(this)); 208 recipient.live().observe(this, r -> getSupportActionBar().setTitle(r.getDisplayName(this))); 209 } 210 } 211 ); 212 } 213 } 214 215 public void onEnterMultiSelect() { 216 tabLayout.setEnabled(false); 217 viewPager.setEnabled(false); 218 toolbar.setVisibility(View.INVISIBLE); 219 } 220 221 public void onExitMultiSelect() { 222 tabLayout.setEnabled(true); 223 viewPager.setEnabled(true); 224 toolbar.setVisibility(View.VISIBLE); 225 } 226 227 private void showSortOrderDialog(View v) { 228 new MaterialAlertDialogBuilder(MediaOverviewActivity.this) 229 .setTitle(R.string.MediaOverviewActivity_Sort_by) 230 .setSingleChoiceItems(R.array.MediaOverviewActivity_Sort_by, 231 currentSorting.ordinal(), 232 (dialog, item) -> { 233 setSorting(Sorting.values()[item]); 234 dialog.dismiss(); 235 }) 236 .create() 237 .show(); 238 } 239 240 private static void fillTabLayoutIfFits(@NonNull TabLayout tabLayout) { 241 tabLayout.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { 242 int totalWidth = 0; 243 int maxWidth = 0; 244 ViewGroup tabs = (ViewGroup) tabLayout.getChildAt(0); 245 246 for (int i = 0; i < tabLayout.getTabCount(); i++) { 247 int tabWidth = tabs.getChildAt(i).getWidth(); 248 totalWidth += tabWidth; 249 maxWidth = Math.max(maxWidth, tabWidth); 250 } 251 252 int viewWidth = right - left; 253 if (totalWidth < viewWidth) { 254 tabLayout.setTabMode(TabLayout.MODE_FIXED); 255 } 256 }); 257 } 258 259 private class MediaOverviewPagerAdapter extends FragmentStatePagerAdapter { 260 261 private final List<Pair<MediaLoader.MediaType, CharSequence>> pages; 262 263 MediaOverviewPagerAdapter(FragmentManager fragmentManager) { 264 super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); 265 266 pages = new ArrayList<>(4); 267 pages.add(new Pair<>(MediaLoader.MediaType.GALLERY, getString(R.string.MediaOverviewActivity_Media))); 268 pages.add(new Pair<>(MediaLoader.MediaType.DOCUMENT, getString(R.string.MediaOverviewActivity_Files))); 269 pages.add(new Pair<>(MediaLoader.MediaType.AUDIO, getString(R.string.MediaOverviewActivity_Audio))); 270 pages.add(new Pair<>(MediaLoader.MediaType.ALL, getString(R.string.MediaOverviewActivity_All))); 271 } 272 273 @Override 274 public @NonNull Fragment getItem(int position) { 275 MediaOverviewPageFragment.GridMode gridMode = allowGridSelectionOnPage(position) 276 ? MediaOverviewPageFragment.GridMode.FOLLOW_MODEL 277 : MediaOverviewPageFragment.GridMode.FIXED_DETAIL; 278 279 return MediaOverviewPageFragment.newInstance(threadId, pages.get(position).first(), gridMode); 280 } 281 282 @Override 283 public int getCount() { 284 return pages.size(); 285 } 286 287 @Override 288 public CharSequence getPageTitle(int position) { 289 return pages.get(position).second(); 290 } 291 } 292}