mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 15:23:00 +00:00 
			
		
		
		
	Merge branch 'refactor' into Compose-theme-improvements
# Conflicts: # app/src/main/java/org/schabi/newpipe/ui/components/common/NoItemsMessage.kt # app/src/main/java/org/schabi/newpipe/ui/components/video/comment/CommentRepliesDialog.kt
This commit is contained in:
		| @@ -6,9 +6,11 @@ import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
|  | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.compose.ui.platform.ComposeView; | ||||
|  | ||||
| import org.schabi.newpipe.BaseFragment; | ||||
| import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateUtil; | ||||
|  | ||||
| public class EmptyFragment extends BaseFragment { | ||||
|     private static final String SHOW_MESSAGE = "SHOW_MESSAGE"; | ||||
| @@ -26,8 +28,10 @@ public class EmptyFragment extends BaseFragment { | ||||
|                              final Bundle savedInstanceState) { | ||||
|         final boolean showMessage = getArguments().getBoolean(SHOW_MESSAGE); | ||||
|         final View view = inflater.inflate(R.layout.fragment_empty, container, false); | ||||
|         view.findViewById(R.id.empty_state_view).setVisibility( | ||||
|                 showMessage ? View.VISIBLE : View.GONE); | ||||
|  | ||||
|         final ComposeView composeView = view.findViewById(R.id.empty_state_view); | ||||
|         EmptyStateUtil.setEmptyStateComposable(composeView); | ||||
|         composeView.setVisibility(showMessage ? View.VISIBLE : View.GONE); | ||||
|         return view; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -10,7 +10,6 @@ import android.graphics.Color; | ||||
| import android.os.Bundle; | ||||
| import android.text.TextUtils; | ||||
| import android.util.Log; | ||||
| import android.util.TypedValue; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuInflater; | ||||
| @@ -45,6 +44,8 @@ import org.schabi.newpipe.fragments.detail.TabAdapter; | ||||
| import org.schabi.newpipe.ktx.AnimationType; | ||||
| import org.schabi.newpipe.local.feed.notifications.NotificationHelper; | ||||
| import org.schabi.newpipe.local.subscription.SubscriptionManager; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateSpec; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateUtil; | ||||
| import org.schabi.newpipe.util.ChannelTabHelper; | ||||
| import org.schabi.newpipe.util.Constants; | ||||
| import org.schabi.newpipe.util.ExtractorHelper; | ||||
| @@ -199,6 +200,11 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo> | ||||
|     protected void initViews(final View rootView, final Bundle savedInstanceState) { | ||||
|         super.initViews(rootView, savedInstanceState); | ||||
|  | ||||
|         EmptyStateUtil.setEmptyStateComposable( | ||||
|                 binding.emptyStateView, | ||||
|                 EmptyStateSpec.Companion.getContentNotSupported() | ||||
|         ); | ||||
|  | ||||
|         tabAdapter = new TabAdapter(getChildFragmentManager()); | ||||
|         binding.viewPager.setAdapter(tabAdapter); | ||||
|         binding.tabLayout.setupWithViewPager(binding.viewPager); | ||||
| @@ -645,8 +651,6 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo> | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         binding.errorContentNotSupported.setVisibility(View.VISIBLE); | ||||
|         binding.channelKaomoji.setText("(︶︹︺)"); | ||||
|         binding.channelKaomoji.setTextSize(TypedValue.COMPLEX_UNIT_SP, 45f); | ||||
|         binding.emptyStateView.setVisibility(View.VISIBLE); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -26,6 +26,7 @@ import org.schabi.newpipe.fragments.list.BaseListInfoFragment; | ||||
| import org.schabi.newpipe.fragments.list.playlist.PlaylistControlViewHolder; | ||||
| import org.schabi.newpipe.player.playqueue.ChannelTabPlayQueue; | ||||
| import org.schabi.newpipe.player.playqueue.PlayQueue; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateUtil; | ||||
| import org.schabi.newpipe.util.ChannelTabHelper; | ||||
| import org.schabi.newpipe.util.ExtractorHelper; | ||||
| import org.schabi.newpipe.util.PlayButtonHelper; | ||||
| @@ -79,6 +80,12 @@ public class ChannelTabFragment extends BaseListInfoFragment<InfoItem, ChannelTa | ||||
|         return inflater.inflate(R.layout.fragment_channel_tab, container, false); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) { | ||||
|         super.onViewCreated(rootView, savedInstanceState); | ||||
|         EmptyStateUtil.setEmptyStateComposable(rootView.findViewById(R.id.empty_state_view)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroyView() { | ||||
|         super.onDestroyView(); | ||||
|   | ||||
| @@ -64,6 +64,8 @@ import org.schabi.newpipe.ktx.AnimationType; | ||||
| import org.schabi.newpipe.ktx.ExceptionUtils; | ||||
| import org.schabi.newpipe.local.history.HistoryRecordManager; | ||||
| import org.schabi.newpipe.settings.NewPipeSettings; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateSpec; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateUtil; | ||||
| import org.schabi.newpipe.util.Constants; | ||||
| import org.schabi.newpipe.util.DeviceUtils; | ||||
| import org.schabi.newpipe.util.ExtractorHelper; | ||||
| @@ -344,6 +346,10 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I | ||||
|     protected void initViews(final View rootView, final Bundle savedInstanceState) { | ||||
|         super.initViews(rootView, savedInstanceState); | ||||
|  | ||||
|         EmptyStateUtil.setEmptyStateComposable( | ||||
|                 searchBinding.emptyStateView, | ||||
|                 EmptyStateSpec.Companion.getNoSearchResult()); | ||||
|  | ||||
|         searchBinding.suggestionsList.setAdapter(suggestionListAdapter); | ||||
|         // animations are just strange and useless, since the suggestions keep changing too much | ||||
|         searchBinding.suggestionsList.setItemAnimator(null); | ||||
|   | ||||
| @@ -38,6 +38,8 @@ import org.schabi.newpipe.local.holder.LocalBookmarkPlaylistItemHolder; | ||||
| import org.schabi.newpipe.local.holder.RemoteBookmarkPlaylistItemHolder; | ||||
| import org.schabi.newpipe.local.playlist.LocalPlaylistManager; | ||||
| import org.schabi.newpipe.local.playlist.RemotePlaylistManager; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateSpec; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateUtil; | ||||
| import org.schabi.newpipe.util.NavigationHelper; | ||||
| import org.schabi.newpipe.util.OnClickGesture; | ||||
| import org.schabi.newpipe.util.debounce.DebounceSavable; | ||||
| @@ -123,6 +125,10 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL | ||||
|         super.initViews(rootView, savedInstanceState); | ||||
|  | ||||
|         itemListAdapter.setUseItemHandle(true); | ||||
|         EmptyStateUtil.setEmptyStateComposable( | ||||
|                 rootView.findViewById(R.id.empty_state_view), | ||||
|                 EmptyStateSpec.Companion.getNoBookmarkedPlaylist() | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -74,6 +74,7 @@ import org.schabi.newpipe.ktx.slideUp | ||||
| import org.schabi.newpipe.local.feed.item.StreamItem | ||||
| import org.schabi.newpipe.local.feed.service.FeedLoadService | ||||
| import org.schabi.newpipe.local.subscription.SubscriptionManager | ||||
| import org.schabi.newpipe.ui.emptystate.setEmptyStateComposable | ||||
| import org.schabi.newpipe.util.DeviceUtils | ||||
| import org.schabi.newpipe.util.Localization | ||||
| import org.schabi.newpipe.util.NavigationHelper | ||||
| @@ -132,6 +133,7 @@ class FeedFragment : BaseStateFragment<FeedState>() { | ||||
|     override fun onViewCreated(rootView: View, savedInstanceState: Bundle?) { | ||||
|         // super.onViewCreated() calls initListeners() which require the binding to be initialized | ||||
|         _feedBinding = FragmentFeedBinding.bind(rootView) | ||||
|         feedBinding.emptyStateView.setEmptyStateComposable() | ||||
|         super.onViewCreated(rootView, savedInstanceState) | ||||
|  | ||||
|         val factory = FeedViewModel.getFactory(requireContext(), groupId) | ||||
|   | ||||
| @@ -56,6 +56,7 @@ import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService | ||||
| import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService.PREVIOUS_EXPORT_MODE | ||||
| import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard | ||||
| import org.schabi.newpipe.streams.io.StoredFileHelper | ||||
| import org.schabi.newpipe.ui.emptystate.setEmptyStateComposable | ||||
| import org.schabi.newpipe.util.NavigationHelper | ||||
| import org.schabi.newpipe.util.OnClickGesture | ||||
| import org.schabi.newpipe.util.ServiceHelper | ||||
| @@ -257,6 +258,8 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() { | ||||
|         binding.itemsList.adapter = groupAdapter | ||||
|         binding.itemsList.itemAnimator = null | ||||
|  | ||||
|         binding.emptyStateView.setEmptyStateComposable() | ||||
|  | ||||
|         viewModel = ViewModelProvider(this)[SubscriptionViewModel::class.java] | ||||
|         viewModel.stateLiveData.observe(viewLifecycleOwner) { it?.let(this::handleResult) } | ||||
|         viewModel.feedGroupsLiveData.observe(viewLifecycleOwner) { | ||||
|   | ||||
| @@ -3,14 +3,18 @@ package org.schabi.newpipe.local.subscription.item | ||||
| import android.view.View | ||||
| import com.xwray.groupie.viewbinding.BindableItem | ||||
| import org.schabi.newpipe.R | ||||
| import org.schabi.newpipe.databinding.ListEmptyViewBinding | ||||
| import org.schabi.newpipe.databinding.ListEmptyViewSubscriptionsBinding | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateSpec | ||||
| import org.schabi.newpipe.ui.emptystate.setEmptyStateComposable | ||||
|  | ||||
| /** | ||||
|  * When there are no subscriptions, show a hint to the user about how to import subscriptions | ||||
|  */ | ||||
| class ImportSubscriptionsHintPlaceholderItem : BindableItem<ListEmptyViewBinding>() { | ||||
| class ImportSubscriptionsHintPlaceholderItem : BindableItem<ListEmptyViewSubscriptionsBinding>() { | ||||
|     override fun getLayout(): Int = R.layout.list_empty_view_subscriptions | ||||
|     override fun bind(viewBinding: ListEmptyViewBinding, position: Int) {} | ||||
|     override fun bind(viewBinding: ListEmptyViewSubscriptionsBinding, position: Int) { | ||||
|         viewBinding.root.setEmptyStateComposable(EmptyStateSpec.NoSubscriptionsHint) | ||||
|     } | ||||
|     override fun getSpanSize(spanCount: Int, position: Int): Int = spanCount | ||||
|     override fun initializeViewBinding(view: View) = ListEmptyViewBinding.bind(view) | ||||
|     override fun initializeViewBinding(view: View) = ListEmptyViewSubscriptionsBinding.bind(view) | ||||
| } | ||||
|   | ||||
| @@ -11,6 +11,7 @@ import android.widget.TextView; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.compose.ui.platform.ComposeView; | ||||
| import androidx.fragment.app.DialogFragment; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| @@ -19,6 +20,8 @@ import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.database.subscription.SubscriptionEntity; | ||||
| import org.schabi.newpipe.error.ErrorUtil; | ||||
| import org.schabi.newpipe.local.subscription.SubscriptionManager; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateSpec; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateUtil; | ||||
| import org.schabi.newpipe.util.ThemeHelper; | ||||
| import org.schabi.newpipe.util.image.CoilHelper; | ||||
|  | ||||
| @@ -57,7 +60,7 @@ public class SelectChannelFragment extends DialogFragment { | ||||
|     private OnCancelListener onCancelListener = null; | ||||
|  | ||||
|     private ProgressBar progressBar; | ||||
|     private TextView emptyView; | ||||
|     private ComposeView emptyView; | ||||
|     private RecyclerView recyclerView; | ||||
|  | ||||
|     private List<SubscriptionEntity> subscriptions = new Vector<>(); | ||||
| @@ -91,6 +94,9 @@ public class SelectChannelFragment extends DialogFragment { | ||||
|  | ||||
|         progressBar = v.findViewById(R.id.progressBar); | ||||
|         emptyView = v.findViewById(R.id.empty_state_view); | ||||
|  | ||||
|         EmptyStateUtil.setEmptyStateComposable(emptyView, | ||||
|                 EmptyStateSpec.Companion.getNoSubscriptions()); | ||||
|         progressBar.setVisibility(View.VISIBLE); | ||||
|         recyclerView.setVisibility(View.GONE); | ||||
|         emptyView.setVisibility(View.GONE); | ||||
|   | ||||
| @@ -11,6 +11,7 @@ import android.widget.ProgressBar; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.compose.ui.platform.ComposeView; | ||||
| import androidx.fragment.app.DialogFragment; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| @@ -27,6 +28,8 @@ import org.schabi.newpipe.error.ErrorUtil; | ||||
| import org.schabi.newpipe.error.UserAction; | ||||
| import org.schabi.newpipe.local.playlist.LocalPlaylistManager; | ||||
| import org.schabi.newpipe.local.playlist.RemotePlaylistManager; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateSpec; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateUtil; | ||||
| import org.schabi.newpipe.util.image.CoilHelper; | ||||
|  | ||||
| import java.util.List; | ||||
| @@ -40,7 +43,7 @@ public class SelectPlaylistFragment extends DialogFragment { | ||||
|     private OnSelectedListener onSelectedListener = null; | ||||
|  | ||||
|     private ProgressBar progressBar; | ||||
|     private TextView emptyView; | ||||
|     private ComposeView emptyView; | ||||
|     private RecyclerView recyclerView; | ||||
|     private Disposable disposable = null; | ||||
|  | ||||
| @@ -62,6 +65,8 @@ public class SelectPlaylistFragment extends DialogFragment { | ||||
|         recyclerView = v.findViewById(R.id.items_list); | ||||
|         emptyView = v.findViewById(R.id.empty_state_view); | ||||
|  | ||||
|         EmptyStateUtil.setEmptyStateComposable(emptyView, | ||||
|                 EmptyStateSpec.Companion.getNoBookmarkedPlaylist()); | ||||
|         recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); | ||||
|         final SelectPlaylistAdapter playlistAdapter = new SelectPlaylistAdapter(); | ||||
|         recyclerView.setAdapter(playlistAdapter); | ||||
|   | ||||
| @@ -11,6 +11,8 @@ import androidx.fragment.app.Fragment; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
|  | ||||
| import org.schabi.newpipe.databinding.SettingsPreferencesearchFragmentBinding; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateSpec; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateUtil; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| @@ -39,6 +41,9 @@ public class PreferenceSearchFragment extends Fragment { | ||||
|         binding = SettingsPreferencesearchFragmentBinding.inflate(inflater, container, false); | ||||
|  | ||||
|         binding.searchResults.setLayoutManager(new LinearLayoutManager(getContext())); | ||||
|         EmptyStateUtil.setEmptyStateComposable( | ||||
|                 binding.emptyStateView, | ||||
|                 EmptyStateSpec.Companion.getNoSearchMaxSizeResult()); | ||||
|  | ||||
|         adapter = new PreferenceSearchAdapter(); | ||||
|         adapter.setOnItemClickListener(this::onItemClicked); | ||||
|   | ||||
| @@ -1,41 +0,0 @@ | ||||
| package org.schabi.newpipe.ui.components.common | ||||
|  | ||||
| import android.content.res.Configuration | ||||
| import androidx.annotation.StringRes | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.fillMaxWidth | ||||
| import androidx.compose.foundation.layout.wrapContentSize | ||||
| import androidx.compose.material3.Surface | ||||
| import androidx.compose.material3.Text | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.ui.Alignment | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.tooling.preview.Preview | ||||
| import androidx.compose.ui.unit.sp | ||||
| import org.schabi.newpipe.R | ||||
| import org.schabi.newpipe.ui.theme.AppTheme | ||||
|  | ||||
| @Composable | ||||
| fun NoItemsMessage(@StringRes message: Int) { | ||||
|     Column( | ||||
|         modifier = Modifier | ||||
|             .fillMaxWidth() | ||||
|             .wrapContentSize(Alignment.Center), | ||||
|         horizontalAlignment = Alignment.CenterHorizontally | ||||
|     ) { | ||||
|         Text(text = "(╯°-°)╯", fontSize = 35.sp) | ||||
|         Text(text = stringResource(id = message), fontSize = 24.sp) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Preview(name = "Light mode", uiMode = Configuration.UI_MODE_NIGHT_NO) | ||||
| @Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES) | ||||
| @Composable | ||||
| private fun NoItemsMessagePreview() { | ||||
|     AppTheme { | ||||
|         Surface { | ||||
|             NoItemsMessage(message = R.string.no_videos) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -25,9 +25,10 @@ import org.schabi.newpipe.R | ||||
| import org.schabi.newpipe.extractor.stream.StreamInfo | ||||
| import org.schabi.newpipe.extractor.stream.StreamType | ||||
| import org.schabi.newpipe.info_list.ItemViewMode | ||||
| import org.schabi.newpipe.ui.components.common.NoItemsMessage | ||||
| import org.schabi.newpipe.ui.components.items.ItemList | ||||
| import org.schabi.newpipe.ui.components.items.stream.StreamInfoItem | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateComposable | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateSpec | ||||
| import org.schabi.newpipe.ui.theme.AppTheme | ||||
| import org.schabi.newpipe.util.NO_SERVICE_ID | ||||
|  | ||||
| @@ -40,43 +41,44 @@ fun RelatedItems(info: StreamInfo) { | ||||
|         mutableStateOf(sharedPreferences.getBoolean(key, false)) | ||||
|     } | ||||
|  | ||||
|     if (info.relatedItems.isEmpty()) { | ||||
|         NoItemsMessage(message = R.string.no_videos) | ||||
|     } else { | ||||
|         ItemList( | ||||
|             items = info.relatedItems, | ||||
|             mode = ItemViewMode.LIST, | ||||
|             listHeader = { | ||||
|                 item { | ||||
|                     Row( | ||||
|                         modifier = Modifier | ||||
|                             .fillMaxWidth() | ||||
|                             .padding(start = 12.dp, end = 12.dp), | ||||
|                         horizontalArrangement = Arrangement.SpaceBetween, | ||||
|                         verticalAlignment = Alignment.CenterVertically, | ||||
|                     ) { | ||||
|                         Text(text = stringResource(R.string.auto_queue_description)) | ||||
|     ItemList( | ||||
|         items = info.relatedItems, | ||||
|         mode = ItemViewMode.LIST, | ||||
|         listHeader = { | ||||
|             item { | ||||
|                 Row( | ||||
|                     modifier = Modifier | ||||
|                         .fillMaxWidth() | ||||
|                         .padding(start = 12.dp, end = 12.dp), | ||||
|                     horizontalArrangement = Arrangement.SpaceBetween, | ||||
|                     verticalAlignment = Alignment.CenterVertically, | ||||
|                 ) { | ||||
|                     Text(text = stringResource(R.string.auto_queue_description)) | ||||
|  | ||||
|                         Row( | ||||
|                             horizontalArrangement = Arrangement.spacedBy(4.dp), | ||||
|                             verticalAlignment = Alignment.CenterVertically | ||||
|                         ) { | ||||
|                             Text(text = stringResource(R.string.auto_queue_toggle)) | ||||
|                             Switch( | ||||
|                                 checked = isAutoQueueEnabled, | ||||
|                                 onCheckedChange = { | ||||
|                                     isAutoQueueEnabled = it | ||||
|                                     sharedPreferences.edit { | ||||
|                                         putBoolean(key, it) | ||||
|                                     } | ||||
|                     Row( | ||||
|                         horizontalArrangement = Arrangement.spacedBy(4.dp), | ||||
|                         verticalAlignment = Alignment.CenterVertically | ||||
|                     ) { | ||||
|                         Text(text = stringResource(R.string.auto_queue_toggle)) | ||||
|                         Switch( | ||||
|                             checked = isAutoQueueEnabled, | ||||
|                             onCheckedChange = { | ||||
|                                 isAutoQueueEnabled = it | ||||
|                                 sharedPreferences.edit { | ||||
|                                     putBoolean(key, it) | ||||
|                                 } | ||||
|                             ) | ||||
|                         } | ||||
|                             } | ||||
|                         ) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         ) | ||||
|     } | ||||
|             if (info.relatedItems.isEmpty()) { | ||||
|                 item { | ||||
|                     EmptyStateComposable(EmptyStateSpec.NoVideos) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     ) | ||||
| } | ||||
|  | ||||
| @Preview(name = "Light mode", uiMode = Configuration.UI_MODE_NIGHT_NO) | ||||
|   | ||||
| @@ -17,6 +17,7 @@ import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.input.nestedscroll.nestedScroll | ||||
| import androidx.compose.ui.platform.rememberNestedScrollInteropConnection | ||||
| import androidx.compose.ui.res.pluralStringResource | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.tooling.preview.Preview | ||||
| import androidx.compose.ui.tooling.preview.datasource.LoremIpsum | ||||
| import androidx.compose.ui.unit.dp | ||||
| @@ -35,7 +36,8 @@ import org.schabi.newpipe.extractor.stream.Description | ||||
| import org.schabi.newpipe.paging.CommentRepliesSource | ||||
| import org.schabi.newpipe.ui.components.common.LazyColumnThemedScrollbar | ||||
| import org.schabi.newpipe.ui.components.common.LoadingIndicator | ||||
| import org.schabi.newpipe.ui.components.common.NoItemsMessage | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateComposable | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateSpec | ||||
| import org.schabi.newpipe.ui.theme.AppTheme | ||||
|  | ||||
| @Composable | ||||
| @@ -121,13 +123,17 @@ private fun CommentRepliesDialog( | ||||
|                         val refresh = comments.loadState.refresh | ||||
|                         if (refresh is LoadState.Loading) { | ||||
|                             LoadingIndicator(modifier = Modifier.padding(top = 8.dp)) | ||||
|                         } else if (refresh is LoadState.Error) { | ||||
|                             // TODO use error panel instead | ||||
|                             EmptyStateComposable( | ||||
|                                 EmptyStateSpec.DisabledComments.copy( | ||||
|                                     descriptionText = { | ||||
|                                         stringResource(R.string.error_unable_to_load_comments) | ||||
|                                     }, | ||||
|                                 ), | ||||
|                             ) | ||||
|                         } else { | ||||
|                             val message = if (refresh is LoadState.Error) { | ||||
|                                 R.string.error_unable_to_load_comments | ||||
|                             } else { | ||||
|                                 R.string.no_comments | ||||
|                             } | ||||
|                             NoItemsMessage(message) | ||||
|                             EmptyStateComposable(EmptyStateSpec.NoComments) | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|   | ||||
| @@ -13,6 +13,7 @@ import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.input.nestedscroll.nestedScroll | ||||
| import androidx.compose.ui.platform.rememberNestedScrollInteropConnection | ||||
| import androidx.compose.ui.res.pluralStringResource | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.tooling.preview.Preview | ||||
| import androidx.compose.ui.unit.dp | ||||
| import androidx.lifecycle.compose.collectAsStateWithLifecycle | ||||
| @@ -28,7 +29,8 @@ import org.schabi.newpipe.extractor.comments.CommentsInfoItem | ||||
| import org.schabi.newpipe.extractor.stream.Description | ||||
| import org.schabi.newpipe.ui.components.common.LazyColumnThemedScrollbar | ||||
| import org.schabi.newpipe.ui.components.common.LoadingIndicator | ||||
| import org.schabi.newpipe.ui.components.common.NoItemsMessage | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateComposable | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateSpec | ||||
| import org.schabi.newpipe.ui.theme.AppTheme | ||||
| import org.schabi.newpipe.viewmodels.CommentsViewModel | ||||
| import org.schabi.newpipe.viewmodels.util.Resource | ||||
| @@ -66,11 +68,11 @@ private fun CommentSection( | ||||
|  | ||||
|                     if (commentInfo.isCommentsDisabled) { | ||||
|                         item { | ||||
|                             NoItemsMessage(R.string.comments_are_disabled) | ||||
|                             EmptyStateComposable(EmptyStateSpec.DisabledComments) | ||||
|                         } | ||||
|                     } else if (count == 0) { | ||||
|                         item { | ||||
|                             NoItemsMessage(R.string.no_comments) | ||||
|                             EmptyStateComposable(EmptyStateSpec.NoComments) | ||||
|                         } | ||||
|                     } else { | ||||
|                         // do not show anything if the comment count is unknown | ||||
| @@ -95,7 +97,14 @@ private fun CommentSection( | ||||
|  | ||||
|                             is LoadState.Error -> { | ||||
|                                 item { | ||||
|                                     NoItemsMessage(R.string.error_unable_to_load_comments) | ||||
|                                     // TODO use error panel instead | ||||
|                                     EmptyStateComposable( | ||||
|                                         EmptyStateSpec.DisabledComments.copy( | ||||
|                                             descriptionText = { | ||||
|                                                 stringResource(R.string.error_unable_to_load_comments) | ||||
|                                             } | ||||
|                                         ) | ||||
|                                     ) | ||||
|                                 } | ||||
|                             } | ||||
|  | ||||
| @@ -110,7 +119,14 @@ private fun CommentSection( | ||||
|  | ||||
|                 is Resource.Error -> { | ||||
|                     item { | ||||
|                         NoItemsMessage(R.string.error_unable_to_load_comments) | ||||
|                         // TODO use error panel instead | ||||
|                         EmptyStateComposable( | ||||
|                             EmptyStateSpec.DisabledComments.copy( | ||||
|                                 descriptionText = { | ||||
|                                     stringResource(R.string.error_unable_to_load_comments) | ||||
|                                 } | ||||
|                             ) | ||||
|                         ) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|   | ||||
| @@ -0,0 +1,159 @@ | ||||
| package org.schabi.newpipe.ui.emptystate | ||||
|  | ||||
| import android.graphics.Color | ||||
| import androidx.compose.foundation.layout.Arrangement | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.fillMaxSize | ||||
| import androidx.compose.foundation.layout.fillMaxWidth | ||||
| import androidx.compose.foundation.layout.heightIn | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.material3.MaterialTheme | ||||
| import androidx.compose.material3.Text | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.ui.Alignment | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.text.style.TextAlign | ||||
| import androidx.compose.ui.tooling.preview.Preview | ||||
| import androidx.compose.ui.unit.dp | ||||
| import org.schabi.newpipe.R | ||||
| import org.schabi.newpipe.ui.theme.AppTheme | ||||
|  | ||||
| @Composable | ||||
| fun EmptyStateComposable( | ||||
|     spec: EmptyStateSpec, | ||||
|     modifier: Modifier = Modifier, | ||||
| ) = EmptyStateComposable( | ||||
|     modifier = spec.modifier(modifier), | ||||
|     emojiText = spec.emojiText(), | ||||
|     descriptionText = spec.descriptionText(), | ||||
| ) | ||||
|  | ||||
| @Composable | ||||
| private fun EmptyStateComposable( | ||||
|     emojiText: String, | ||||
|     descriptionText: String, | ||||
|     modifier: Modifier = Modifier, | ||||
| ) { | ||||
|     Column( | ||||
|         modifier = modifier, | ||||
|         horizontalAlignment = Alignment.CenterHorizontally, | ||||
|         verticalArrangement = Arrangement.Center | ||||
|     ) { | ||||
|         Text( | ||||
|             text = emojiText, | ||||
|             style = MaterialTheme.typography.titleLarge, | ||||
|             textAlign = TextAlign.Center, | ||||
|         ) | ||||
|  | ||||
|         Text( | ||||
|             modifier = Modifier | ||||
|                 .padding(top = 6.dp) | ||||
|                 .padding(horizontal = 16.dp), | ||||
|             text = descriptionText, | ||||
|             style = MaterialTheme.typography.bodyMedium, | ||||
|             textAlign = TextAlign.Center, | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Preview(showBackground = true, backgroundColor = Color.WHITE.toLong()) | ||||
| @Composable | ||||
| fun EmptyStateComposableGenericErrorPreview() { | ||||
|     AppTheme { | ||||
|         EmptyStateComposable(EmptyStateSpec.GenericError) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Preview(showBackground = true, backgroundColor = Color.WHITE.toLong()) | ||||
| @Composable | ||||
| fun EmptyStateComposableNoCommentPreview() { | ||||
|     AppTheme { | ||||
|         EmptyStateComposable(EmptyStateSpec.NoComments) | ||||
|     } | ||||
| } | ||||
|  | ||||
| data class EmptyStateSpec( | ||||
|     val modifier: (Modifier) -> Modifier, | ||||
|     val emojiText: @Composable () -> String, | ||||
|     val descriptionText: @Composable () -> String, | ||||
| ) { | ||||
|     companion object { | ||||
|  | ||||
|         val GenericError = | ||||
|             EmptyStateSpec( | ||||
|                 modifier = { | ||||
|                     it | ||||
|                         .fillMaxWidth() | ||||
|                         .heightIn(min = 128.dp) | ||||
|                 }, | ||||
|                 emojiText = { "¯\\_(ツ)_/¯" }, | ||||
|                 descriptionText = { stringResource(id = R.string.empty_list_subtitle) }, | ||||
|             ) | ||||
|  | ||||
|         val NoVideos = | ||||
|             EmptyStateSpec( | ||||
|                 modifier = { | ||||
|                     it | ||||
|                         .fillMaxWidth() | ||||
|                         .heightIn(min = 128.dp) | ||||
|                 }, | ||||
|                 emojiText = { "(╯°-°)╯" }, | ||||
|                 descriptionText = { stringResource(id = R.string.no_videos) }, | ||||
|             ) | ||||
|  | ||||
|         val NoComments = | ||||
|             EmptyStateSpec( | ||||
|                 modifier = { | ||||
|                     it | ||||
|                         .fillMaxWidth() | ||||
|                         .heightIn(min = 128.dp) | ||||
|                 }, | ||||
|                 emojiText = { "¯\\_(╹x╹)_/¯" }, | ||||
|                 descriptionText = { stringResource(id = R.string.no_comments) }, | ||||
|             ) | ||||
|  | ||||
|         val DisabledComments = | ||||
|             NoComments.copy( | ||||
|                 descriptionText = { stringResource(id = R.string.comments_are_disabled) }, | ||||
|             ) | ||||
|  | ||||
|         val NoSearchResult = | ||||
|             NoComments.copy( | ||||
|                 modifier = { it }, | ||||
|                 emojiText = { "╰(°●°╰)" }, | ||||
|                 descriptionText = { stringResource(id = R.string.search_no_results) } | ||||
|             ) | ||||
|  | ||||
|         val NoSearchMaxSizeResult = | ||||
|             NoSearchResult.copy( | ||||
|                 modifier = { it.fillMaxSize() }, | ||||
|             ) | ||||
|  | ||||
|         val ContentNotSupported = | ||||
|             NoComments.copy( | ||||
|                 modifier = { it.padding(top = 90.dp) }, | ||||
|                 emojiText = { "(︶︹︺)" }, | ||||
|                 descriptionText = { stringResource(id = R.string.content_not_supported) }, | ||||
|             ) | ||||
|  | ||||
|         val NoBookmarkedPlaylist = | ||||
|             EmptyStateSpec( | ||||
|                 modifier = { it }, | ||||
|                 emojiText = { "(╥﹏╥)" }, | ||||
|                 descriptionText = { stringResource(id = R.string.no_playlist_bookmarked_yet) }, | ||||
|             ) | ||||
|  | ||||
|         val NoSubscriptionsHint = | ||||
|             EmptyStateSpec( | ||||
|                 modifier = { it }, | ||||
|                 emojiText = { "(꩜ᯅ꩜)" }, | ||||
|                 descriptionText = { stringResource(id = R.string.import_subscriptions_hint) }, | ||||
|             ) | ||||
|  | ||||
|         val NoSubscriptions = | ||||
|             NoSubscriptionsHint.copy( | ||||
|                 descriptionText = { stringResource(id = R.string.no_channel_subscribed_yet) }, | ||||
|             ) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,30 @@ | ||||
| @file:JvmName("EmptyStateUtil") | ||||
|  | ||||
| package org.schabi.newpipe.ui.emptystate | ||||
|  | ||||
| import androidx.compose.material3.LocalContentColor | ||||
| import androidx.compose.material3.MaterialTheme | ||||
| import androidx.compose.material3.contentColorFor | ||||
| import androidx.compose.runtime.CompositionLocalProvider | ||||
| import androidx.compose.ui.platform.ComposeView | ||||
| import androidx.compose.ui.platform.ViewCompositionStrategy | ||||
| import org.schabi.newpipe.ui.theme.AppTheme | ||||
|  | ||||
| @JvmOverloads | ||||
| fun ComposeView.setEmptyStateComposable( | ||||
|     spec: EmptyStateSpec = EmptyStateSpec.GenericError, | ||||
|     strategy: ViewCompositionStrategy = ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed, | ||||
| ) = apply { | ||||
|     setViewCompositionStrategy(strategy) | ||||
|     setContent { | ||||
|         AppTheme { | ||||
|             CompositionLocalProvider( | ||||
|                 LocalContentColor provides contentColorFor(MaterialTheme.colorScheme.background) | ||||
|             ) { | ||||
|                 EmptyStateComposable( | ||||
|                     spec = spec | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -22,6 +22,7 @@ import androidx.activity.result.ActivityResultLauncher; | ||||
| import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.appcompat.app.AlertDialog; | ||||
| import androidx.compose.ui.platform.ComposeView; | ||||
| import androidx.fragment.app.Fragment; | ||||
| import androidx.preference.PreferenceManager; | ||||
| import androidx.recyclerview.widget.GridLayoutManager; | ||||
| @@ -34,6 +35,7 @@ import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.settings.NewPipeSettings; | ||||
| import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard; | ||||
| import org.schabi.newpipe.streams.io.StoredFileHelper; | ||||
| import org.schabi.newpipe.ui.emptystate.EmptyStateUtil; | ||||
| import org.schabi.newpipe.util.FilePickerActivityHelper; | ||||
|  | ||||
| import java.io.File; | ||||
| @@ -108,7 +110,8 @@ public class MissionsFragment extends Fragment { | ||||
|         mContext.bindService(new Intent(mContext, DownloadManagerService.class), mConnection, Context.BIND_AUTO_CREATE); | ||||
|  | ||||
|         // Views | ||||
|         mEmpty = v.findViewById(R.id.list_empty_view); | ||||
|         mEmpty = v.findViewById(R.id.empty_state_view); | ||||
|         EmptyStateUtil.setEmptyStateComposable((ComposeView) mEmpty); | ||||
|         mList = v.findViewById(R.id.mission_recycler); | ||||
|  | ||||
|         // Init layouts managers | ||||
|   | ||||
| @@ -24,15 +24,15 @@ | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
|     <include | ||||
|     <androidx.compose.ui.platform.ComposeView | ||||
|         android:id="@+id/empty_state_view" | ||||
|         layout="@layout/list_empty_view" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_centerInParent="true" | ||||
|         android:layout_marginTop="50dp" | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible" /> | ||||
|         tools:visibility="visible" | ||||
|         /> | ||||
|  | ||||
|     <View | ||||
|         android:layout_width="match_parent" | ||||
|   | ||||
| @@ -168,37 +168,14 @@ | ||||
|             android:visibility="gone" | ||||
|             tools:visibility="visible" /> | ||||
|  | ||||
|         <LinearLayout | ||||
|         <androidx.compose.ui.platform.ComposeView | ||||
|             android:id="@+id/empty_state_view" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_centerInParent="true" | ||||
|             android:orientation="vertical" | ||||
|             android:paddingTop="90dp" | ||||
|             android:visibility="gone" | ||||
|             tools:visibility="visible"> | ||||
|  | ||||
|             <org.schabi.newpipe.views.NewPipeTextView | ||||
|                 android:id="@+id/channel_kaomoji" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_gravity="center" | ||||
|                 android:layout_marginBottom="10dp" | ||||
|                 android:fontFamily="monospace" | ||||
|                 android:text="(︶︹︺)" | ||||
|                 android:textSize="35sp" | ||||
|                 tools:ignore="HardcodedText" /> | ||||
|  | ||||
|             <org.schabi.newpipe.views.NewPipeTextView | ||||
|                 android:id="@+id/error_content_not_supported" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_marginTop="20dp" | ||||
|                 android:text="@string/content_not_supported" | ||||
|                 android:textSize="15sp" | ||||
|                 android:visibility="gone" /> | ||||
|  | ||||
|         </LinearLayout> | ||||
|             tools:visibility="visible" | ||||
|             /> | ||||
|  | ||||
|         <!--ERROR PANEL--> | ||||
|         <include | ||||
|   | ||||
| @@ -20,15 +20,15 @@ | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
|     <include | ||||
|     <androidx.compose.ui.platform.ComposeView | ||||
|         android:id="@+id/empty_state_view" | ||||
|         layout="@layout/list_empty_view" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_centerInParent="true" | ||||
|         android:gravity="center" | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible" /> | ||||
|         tools:visibility="visible" | ||||
|         /> | ||||
|  | ||||
|     <!--ERROR PANEL--> | ||||
|     <include | ||||
|   | ||||
| @@ -20,36 +20,14 @@ | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
|     <LinearLayout | ||||
|     <androidx.compose.ui.platform.ComposeView | ||||
|         android:id="@+id/empty_state_view" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_centerInParent="true" | ||||
|         android:orientation="vertical" | ||||
|         android:paddingTop="90dp" | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible"> | ||||
|  | ||||
|         <org.schabi.newpipe.views.NewPipeTextView | ||||
|             android:id="@+id/channel_kaomoji" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_gravity="center" | ||||
|             android:layout_marginBottom="10dp" | ||||
|             android:fontFamily="monospace" | ||||
|             android:text="(╯°-°)╯" | ||||
|             android:textSize="35sp" | ||||
|             tools:ignore="HardcodedText,UnusedAttribute" /> | ||||
|  | ||||
|         <org.schabi.newpipe.views.NewPipeTextView | ||||
|             android:id="@+id/channel_no_videos" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_gravity="center" | ||||
|             android:text="@string/empty_view_no_videos" | ||||
|             android:textSize="24sp" /> | ||||
|  | ||||
|     </LinearLayout> | ||||
|         tools:visibility="visible" | ||||
|         /> | ||||
|  | ||||
|     <!--ERROR PANEL--> | ||||
|     <include | ||||
|   | ||||
| @@ -7,12 +7,13 @@ | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent"> | ||||
|  | ||||
|         <include | ||||
|         <androidx.compose.ui.platform.ComposeView | ||||
|             android:id="@+id/empty_state_view" | ||||
|             layout="@layout/list_empty_view" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_gravity="center_horizontal" | ||||
|             android:layout_marginTop="90dp" /> | ||||
|             android:layout_marginTop="90dp" | ||||
|             /> | ||||
|  | ||||
|     </androidx.core.widget.NestedScrollView> | ||||
| </RelativeLayout> | ||||
|   | ||||
| @@ -140,15 +140,15 @@ | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
|     <include | ||||
|     <androidx.compose.ui.platform.ComposeView | ||||
|         android:id="@+id/empty_state_view" | ||||
|         layout="@layout/list_empty_view" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_centerInParent="true" | ||||
|         android:layout_marginTop="50dp" | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible" /> | ||||
|         tools:visibility="visible" | ||||
|         /> | ||||
|  | ||||
|     <View | ||||
|         android:layout_width="match_parent" | ||||
|   | ||||
| @@ -52,33 +52,14 @@ | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
|     <LinearLayout | ||||
|     <androidx.compose.ui.platform.ComposeView | ||||
|         android:id="@+id/empty_state_view" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_centerInParent="true" | ||||
|         android:orientation="vertical" | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible"> | ||||
|  | ||||
|         <org.schabi.newpipe.views.NewPipeTextView | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_gravity="center" | ||||
|             android:layout_marginBottom="10dp" | ||||
|             android:fontFamily="monospace" | ||||
|             android:text="╰(°●°╰)" | ||||
|             android:textSize="35sp" | ||||
|             tools:ignore="HardcodedText,UnusedAttribute" /> | ||||
|  | ||||
|         <org.schabi.newpipe.views.NewPipeTextView | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_gravity="center" | ||||
|             android:text="@string/search_no_results" | ||||
|             android:textSize="24sp" /> | ||||
|  | ||||
|     </LinearLayout> | ||||
|         tools:visibility="visible" | ||||
|         /> | ||||
|  | ||||
|     <LinearLayout | ||||
|         android:id="@+id/suggestions_panel" | ||||
|   | ||||
| @@ -24,16 +24,16 @@ | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
|     <include | ||||
|     <androidx.compose.ui.platform.ComposeView | ||||
|         android:id="@+id/empty_state_view" | ||||
|         layout="@layout/list_empty_view" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_below="@id/items_list" | ||||
|         android:layout_centerInParent="true" | ||||
|         android:layout_marginTop="50dp" | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="visible" /> | ||||
|         tools:visibility="visible" | ||||
|         /> | ||||
|  | ||||
|     <View | ||||
|         android:layout_width="match_parent" | ||||
|   | ||||
| @@ -1,25 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:gravity="center" | ||||
|     android:minHeight="128dp" | ||||
|     android:orientation="vertical"> | ||||
|  | ||||
|     <org.schabi.newpipe.views.NewPipeTextView | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="¯\\_(ツ)_/¯" | ||||
|         android:textAppearance="?android:attr/textAppearanceLarge" | ||||
|         tools:ignore="HardcodedText" /> | ||||
|  | ||||
|     <org.schabi.newpipe.views.NewPipeTextView | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_gravity="center" | ||||
|         android:layout_marginTop="6dp" | ||||
|         android:gravity="center" | ||||
|         android:paddingHorizontal="16dp" | ||||
|         android:text="@string/empty_list_subtitle" /> | ||||
| </LinearLayout> | ||||
| @@ -1,25 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
| <androidx.compose.ui.platform.ComposeView | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:gravity="center" | ||||
|     android:minHeight="128dp" | ||||
|     android:orientation="vertical"> | ||||
|  | ||||
|     <org.schabi.newpipe.views.NewPipeTextView | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="¯\\_(ツ)_/¯" | ||||
|         android:textAppearance="?android:attr/textAppearanceLarge" | ||||
|         tools:ignore="HardcodedText" /> | ||||
|  | ||||
|     <org.schabi.newpipe.views.NewPipeTextView | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_gravity="center" | ||||
|         android:layout_marginTop="6dp" | ||||
|         android:gravity="center" | ||||
|         android:paddingHorizontal="16dp" | ||||
|         android:text="@string/import_subscriptions_hint" /> | ||||
| </LinearLayout> | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" /> | ||||
|   | ||||
| @@ -3,10 +3,11 @@ | ||||
|     android:layout_height="match_parent" | ||||
|     android:orientation="vertical"> | ||||
|  | ||||
|     <include | ||||
|         android:id="@+id/list_empty_view" | ||||
|         layout="@layout/list_empty_view" | ||||
|         android:visibility="gone" /> | ||||
|     <androidx.compose.ui.platform.ComposeView | ||||
|         android:id="@+id/empty_state_view" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:minHeight="128dp" /> | ||||
|  | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|         android:id="@+id/mission_recycler" | ||||
|   | ||||
| @@ -24,14 +24,11 @@ | ||||
|         android:layout_height="wrap_content" | ||||
|         tools:listitem="@layout/select_channel_item" /> | ||||
|  | ||||
|  | ||||
|     <org.schabi.newpipe.views.NewPipeTextView | ||||
|     <androidx.compose.ui.platform.ComposeView | ||||
|         android:id="@+id/empty_state_view" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_margin="10dp" | ||||
|         android:text="@string/no_channel_subscribed_yet" | ||||
|         android:textAppearance="?android:attr/textAppearanceListItem" /> | ||||
|         android:layout_margin="10dp" /> | ||||
|  | ||||
|     <ProgressBar | ||||
|         android:id="@+id/progressBar" | ||||
|   | ||||
| @@ -26,14 +26,11 @@ | ||||
|  | ||||
|     </androidx.recyclerview.widget.RecyclerView> | ||||
|  | ||||
|  | ||||
|     <org.schabi.newpipe.views.NewPipeTextView | ||||
|     <androidx.compose.ui.platform.ComposeView | ||||
|         android:id="@+id/empty_state_view" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_margin="10dp" | ||||
|         android:text="@string/no_playlist_bookmarked_yet" | ||||
|         android:textAppearance="?android:attr/textAppearanceListItem" /> | ||||
|         android:layout_margin="10dp" /> | ||||
|  | ||||
|     <ProgressBar | ||||
|         android:id="@+id/progressBar" | ||||
|   | ||||
| @@ -12,33 +12,14 @@ | ||||
|         android:layout_height="4dp" | ||||
|         android:background="?attr/toolbar_shadow" /> | ||||
|  | ||||
|     <LinearLayout | ||||
|     <androidx.compose.ui.platform.ComposeView | ||||
|         android:id="@+id/empty_state_view" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:gravity="center" | ||||
|         android:orientation="vertical" | ||||
|         android:visibility="gone" | ||||
|         tools:visibility="gone"> | ||||
|  | ||||
|         <org.schabi.newpipe.views.NewPipeTextView | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_gravity="center" | ||||
|             android:layout_marginBottom="10dp" | ||||
|             android:fontFamily="monospace" | ||||
|             android:text="╰(°●°╰)" | ||||
|             android:textSize="35sp" | ||||
|             tools:ignore="HardcodedText,UnusedAttribute" /> | ||||
|  | ||||
|         <org.schabi.newpipe.views.NewPipeTextView | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:layout_gravity="center" | ||||
|             android:text="@string/search_no_results" | ||||
|             android:textSize="24sp" /> | ||||
|  | ||||
|     </LinearLayout> | ||||
|         tools:visibility="gone" | ||||
|         /> | ||||
|  | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|         android:id="@+id/searchResults" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Isira Seneviratne
					Isira Seneviratne