Migrate empty_state_view to Jetpack Compose
This commit is contained in:
parent
295f719b77
commit
8b79d0ee29
|
@ -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;
|
||||
|
@ -20,6 +19,7 @@ import android.view.ViewGroup;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.compose.runtime.MutableState;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.core.view.MenuProvider;
|
||||
|
@ -45,6 +45,9 @@ 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.EmptyStateSpecBuilder;
|
||||
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;
|
||||
|
@ -102,6 +105,8 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
|
|||
private SubscriptionEntity channelSubscription;
|
||||
private MenuProvider menuProvider;
|
||||
|
||||
private MutableState<EmptyStateSpec> emptyStateSpec;
|
||||
|
||||
public static ChannelFragment getInstance(final int serviceId, final String url,
|
||||
final String name) {
|
||||
final ChannelFragment instance = new ChannelFragment();
|
||||
|
@ -199,6 +204,10 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
|
|||
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
||||
super.initViews(rootView, savedInstanceState);
|
||||
|
||||
emptyStateSpec = EmptyStateUtil.mutableStateOf(
|
||||
EmptyStateSpec.Companion.getContentNotSupported());
|
||||
EmptyStateUtil.setEmptyStateComposable(binding.emptyStateView, emptyStateSpec);
|
||||
|
||||
tabAdapter = new TabAdapter(getChildFragmentManager());
|
||||
binding.viewPager.setAdapter(tabAdapter);
|
||||
binding.tabLayout.setupWithViewPager(binding.viewPager);
|
||||
|
@ -645,8 +654,10 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
|
|||
return;
|
||||
}
|
||||
|
||||
binding.errorContentNotSupported.setVisibility(View.VISIBLE);
|
||||
binding.channelKaomoji.setText("(︶︹︺)");
|
||||
binding.channelKaomoji.setTextSize(TypedValue.COMPLEX_UNIT_SP, 45f);
|
||||
emptyStateSpec.setValue(
|
||||
new EmptyStateSpecBuilder(emptyStateSpec.getValue())
|
||||
.descriptionVisibility(true)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,7 @@ 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.EmptyStateUtil;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.OnClickGesture;
|
||||
import org.schabi.newpipe.util.debounce.DebounceSavable;
|
||||
|
@ -123,6 +124,7 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
|||
super.initViews(rootView, savedInstanceState);
|
||||
|
||||
itemListAdapter.setUseItemHandle(true);
|
||||
EmptyStateUtil.setEmptyStateComposable(rootView.findViewById(R.id.empty_state_view));
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
|
|
@ -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,7 @@ 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.EmptyStateUtil;
|
||||
import org.schabi.newpipe.util.image.CoilHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -40,7 +42,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 +64,7 @@ public class SelectPlaylistFragment extends DialogFragment {
|
|||
recyclerView = v.findViewById(R.id.items_list);
|
||||
emptyView = v.findViewById(R.id.empty_state_view);
|
||||
|
||||
EmptyStateUtil.setEmptyStateText(emptyView, R.string.no_playlist_bookmarked_yet);
|
||||
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);
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
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.LocalContentColor
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import org.schabi.newpipe.R
|
||||
import org.schabi.newpipe.ui.theme.AppTheme
|
||||
import org.schabi.newpipe.ui.theme.errorHint
|
||||
|
||||
@Composable
|
||||
fun EmptyStateComposable(
|
||||
spec: EmptyStateSpec,
|
||||
modifier: Modifier = Modifier,
|
||||
) = EmptyStateComposable(
|
||||
modifier = spec.modifier(modifier),
|
||||
emojiModifier = spec.emojiModifier(),
|
||||
emojiText = spec.emojiText(),
|
||||
emojiTextStyle = spec.emojiTextStyle(),
|
||||
descriptionModifier = spec.descriptionModifier(),
|
||||
descriptionText = spec.descriptionText(),
|
||||
descriptionTextStyle = spec.descriptionTextStyle(),
|
||||
descriptionTextVisibility = spec.descriptionVisibility(),
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun EmptyStateComposable(
|
||||
modifier: Modifier,
|
||||
emojiModifier: Modifier,
|
||||
emojiText: String,
|
||||
emojiTextStyle: TextStyle,
|
||||
descriptionModifier: Modifier,
|
||||
descriptionText: String,
|
||||
descriptionTextStyle: TextStyle,
|
||||
descriptionTextVisibility: Boolean,
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides MaterialTheme.colorScheme.errorHint
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
modifier = emojiModifier,
|
||||
text = emojiText,
|
||||
style = emojiTextStyle,
|
||||
)
|
||||
|
||||
if (descriptionTextVisibility) {
|
||||
Text(
|
||||
modifier = descriptionModifier,
|
||||
text = descriptionText,
|
||||
style = descriptionTextStyle,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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.NoComment)
|
||||
}
|
||||
}
|
||||
|
||||
data class EmptyStateSpec(
|
||||
val modifier: (Modifier) -> Modifier,
|
||||
val emojiModifier: () -> Modifier,
|
||||
val emojiText: @Composable () -> String,
|
||||
val emojiTextStyle: @Composable () -> TextStyle,
|
||||
val descriptionText: @Composable () -> String,
|
||||
val descriptionModifier: () -> Modifier,
|
||||
val descriptionTextStyle: @Composable () -> TextStyle,
|
||||
val descriptionVisibility: () -> Boolean = { true },
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
val GenericError =
|
||||
EmptyStateSpec(
|
||||
modifier = {
|
||||
it
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = 128.dp)
|
||||
},
|
||||
emojiModifier = { Modifier },
|
||||
emojiText = { "¯\\_(ツ)_/¯" },
|
||||
emojiTextStyle = { MaterialTheme.typography.titleLarge },
|
||||
descriptionModifier = {
|
||||
Modifier
|
||||
.padding(top = 6.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
},
|
||||
descriptionText = { stringResource(id = R.string.empty_list_subtitle) },
|
||||
descriptionTextStyle = { MaterialTheme.typography.bodyMedium }
|
||||
)
|
||||
|
||||
val NoComment =
|
||||
EmptyStateSpec(
|
||||
modifier = { it.padding(top = 85.dp) },
|
||||
emojiModifier = { Modifier.padding(bottom = 10.dp) },
|
||||
emojiText = { "(╯°-°)╯" },
|
||||
emojiTextStyle = {
|
||||
LocalTextStyle.current.merge(
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 35.sp,
|
||||
)
|
||||
},
|
||||
descriptionModifier = { Modifier },
|
||||
descriptionText = { stringResource(id = R.string.no_comments) },
|
||||
descriptionTextStyle = {
|
||||
LocalTextStyle.current.merge(fontSize = 24.sp)
|
||||
}
|
||||
)
|
||||
|
||||
val NoSearchResult =
|
||||
NoComment.copy(
|
||||
modifier = { it },
|
||||
emojiText = { "╰(°●°╰)" },
|
||||
descriptionText = { stringResource(id = R.string.search_no_results) }
|
||||
)
|
||||
|
||||
val NoSearchMaxSizeResult =
|
||||
NoSearchResult.copy(
|
||||
modifier = { it.fillMaxSize() },
|
||||
)
|
||||
|
||||
val ContentNotSupported =
|
||||
NoComment.copy(
|
||||
modifier = { it.padding(top = 90.dp) },
|
||||
emojiText = { "(︶︹︺)" },
|
||||
emojiTextStyle = { LocalTextStyle.current.merge(fontSize = 45.sp) },
|
||||
descriptionModifier = { Modifier.padding(top = 20.dp) },
|
||||
descriptionText = { stringResource(id = R.string.content_not_supported) },
|
||||
descriptionTextStyle = { LocalTextStyle.current.merge(fontSize = 15.sp) },
|
||||
descriptionVisibility = { false },
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
@file:JvmName("EmptyStateUtil")
|
||||
|
||||
package org.schabi.newpipe.ui.emptystate
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import org.schabi.newpipe.ui.theme.AppTheme
|
||||
import org.schabi.newpipe.ui.theme.errorHint
|
||||
import androidx.compose.runtime.mutableStateOf as composeRuntimeMutableStateOf
|
||||
|
||||
@JvmOverloads
|
||||
fun ComposeView.setEmptyStateText(
|
||||
@StringRes stringRes: Int,
|
||||
strategy: ViewCompositionStrategy = ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed,
|
||||
) = apply {
|
||||
setViewCompositionStrategy(strategy)
|
||||
setContent {
|
||||
AppTheme {
|
||||
Text(
|
||||
text = stringResource(id = stringRes),
|
||||
color = MaterialTheme.colorScheme.errorHint,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun ComposeView.setEmptyStateComposable(
|
||||
spec: EmptyStateSpec = EmptyStateSpec.GenericError,
|
||||
strategy: ViewCompositionStrategy = ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed,
|
||||
) = apply {
|
||||
setViewCompositionStrategy(strategy)
|
||||
setContent {
|
||||
AppTheme {
|
||||
EmptyStateComposable(
|
||||
spec = spec
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun ComposeView.setEmptyStateComposable(
|
||||
spec: State<EmptyStateSpec>,
|
||||
strategy: ViewCompositionStrategy = ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed,
|
||||
) = apply {
|
||||
setViewCompositionStrategy(strategy)
|
||||
setContent {
|
||||
AppTheme {
|
||||
EmptyStateComposable(
|
||||
spec = spec.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in Java land to bridge the [MutableState] API.
|
||||
*/
|
||||
fun <T> mutableStateOf(param: T): MutableState<T> {
|
||||
return composeRuntimeMutableStateOf(param)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used in Java land to modify [EmptyStateSpec] properties.
|
||||
* TODO: remove after Kotlin migration
|
||||
*/
|
||||
class EmptyStateSpecBuilder(var spec: EmptyStateSpec) {
|
||||
|
||||
fun descriptionText(@StringRes stringRes: Int) = apply {
|
||||
spec = spec.copy(
|
||||
descriptionText = { stringResource(id = stringRes) }
|
||||
)
|
||||
}
|
||||
|
||||
fun descriptionVisibility(descriptionTextVisibility: Boolean) = apply {
|
||||
spec = spec.copy(descriptionVisibility = { descriptionTextVisibility })
|
||||
}
|
||||
|
||||
fun build() = spec
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.schabi.newpipe.ui.theme
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
/**
|
||||
* Extended color for error hint.
|
||||
* See [specification](https://m1.material.io/patterns/errors.html#errors-user-input-errors)
|
||||
*/
|
||||
val md_theme_light_error_hint = Color(0x61000000)
|
||||
|
||||
val md_theme_dark_error_hint = Color(0x80FFFFFF)
|
||||
|
||||
val ColorScheme.errorHint: Color
|
||||
@Composable get() = if (isSystemInDarkTheme()) {
|
||||
Color(0x80FFFFFF)
|
||||
} else {
|
||||
Color(0x61000000)
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -26,14 +26,12 @@
|
|||
|
||||
</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" />
|
||||
/>
|
||||
|
||||
<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"
|
||||
|
|
Loading…
Reference in New Issue