1
0
Fork 0
mirror of https://github.com/TeamNewPipe/NewPipe.git synced 2025-10-03 09:49:21 +02:00

Merge pull request #12604 from Isira-Seneviratne/Refactor-EmptyState

This commit is contained in:
Stypox 2025-09-06 15:33:49 +02:00 committed by GitHub
commit b2d89a41fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 77 additions and 132 deletions

View file

@ -3,6 +3,7 @@ package org.schabi.newpipe.fragments.list.channel;
import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
import static org.schabi.newpipe.ui.emptystate.EmptyStateUtil.setEmptyStateComposable;
import android.content.Context;
import android.content.SharedPreferences;
@ -45,7 +46,6 @@ 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;
@ -200,10 +200,7 @@ 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()
);
setEmptyStateComposable(binding.emptyStateView, EmptyStateSpec.ContentNotSupported);
tabAdapter = new TabAdapter(getChildFragmentManager());
binding.viewPager.setAdapter(tabAdapter);

View file

@ -3,6 +3,7 @@ package org.schabi.newpipe.fragments.list.search;
import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags;
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.ui.emptystate.EmptyStateUtil.setEmptyStateComposable;
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
import static java.util.Arrays.asList;
@ -66,7 +67,6 @@ 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;
@ -357,9 +357,7 @@ 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());
setEmptyStateComposable(searchBinding.emptyStateView, EmptyStateSpec.NoSearchResult);
searchBinding.suggestionsList.setAdapter(suggestionListAdapter);
// animations are just strange and useless, since the suggestions keep changing too much

View file

@ -15,6 +15,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.compose.ui.platform.ComposeView;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
@ -125,10 +126,8 @@ 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()
);
final ComposeView emptyView = rootView.findViewById(R.id.empty_state_view);
EmptyStateUtil.setEmptyStateComposable(emptyView, EmptyStateSpec.NoBookmarkedPlaylist);
}
@Override

View file

@ -95,8 +95,7 @@ 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());
EmptyStateUtil.setEmptyStateComposable(emptyView, EmptyStateSpec.NoSubscriptions);
progressBar.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
emptyView.setVisibility(View.GONE);

View file

@ -65,8 +65,7 @@ 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());
EmptyStateUtil.setEmptyStateComposable(emptyView, EmptyStateSpec.NoBookmarkedPlaylist);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
final SelectPlaylistAdapter playlistAdapter = new SelectPlaylistAdapter();
recyclerView.setAdapter(playlistAdapter);

View file

@ -1,5 +1,7 @@
package org.schabi.newpipe.settings.preferencesearch;
import static org.schabi.newpipe.ui.emptystate.EmptyStateUtil.setEmptyStateComposable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@ -12,7 +14,6 @@ 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;
@ -41,9 +42,7 @@ public class PreferenceSearchFragment extends Fragment {
binding = SettingsPreferencesearchFragmentBinding.inflate(inflater, container, false);
binding.searchResults.setLayoutManager(new LinearLayoutManager(getContext()));
EmptyStateUtil.setEmptyStateComposable(
binding.emptyStateView,
EmptyStateSpec.Companion.getNoSearchMaxSizeResult());
setEmptyStateComposable(binding.emptyStateView, EmptyStateSpec.NoSearchResult);
adapter = new PreferenceSearchAdapter();
adapter.setOnItemClickListener(this::onItemClicked);

View file

@ -19,7 +19,6 @@ 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
@ -122,28 +121,23 @@ private fun CommentRepliesDialog(
if (comments.itemCount == 0) {
item {
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(
spec = EmptyStateSpec.DisabledComments.copy(
descriptionText = {
stringResource(R.string.error_unable_to_load_comments)
when (val refresh = comments.loadState.refresh) {
is LoadState.Loading -> {
LoadingIndicator(modifier = Modifier.padding(top = 8.dp))
}
else -> {
// TODO use error panel instead
EmptyStateComposable(
spec = if (refresh is LoadState.Error) {
EmptyStateSpec.ErrorLoadingComments
} else {
EmptyStateSpec.NoComments
},
),
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 128.dp)
)
} else {
EmptyStateComposable(
spec = EmptyStateSpec.NoComments,
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 128.dp)
)
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 128.dp)
)
}
}
}
} else {

View file

@ -15,7 +15,6 @@ 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
@ -75,7 +74,6 @@ private fun CommentSection(
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 128.dp)
)
}
} else if (count == 0) {
@ -111,13 +109,7 @@ private fun CommentSection(
is LoadState.Error -> {
item {
// TODO use error panel instead
EmptyStateComposable(
EmptyStateSpec.DisabledComments.copy(
descriptionText = {
stringResource(R.string.error_unable_to_load_comments)
}
)
)
EmptyStateComposable(EmptyStateSpec.ErrorLoadingComments)
}
}
@ -134,11 +126,7 @@ private fun CommentSection(
item {
// TODO use error panel instead
EmptyStateComposable(
spec = EmptyStateSpec.DisabledComments.copy(
descriptionText = {
stringResource(R.string.error_unable_to_load_comments)
}
),
spec = EmptyStateSpec.ErrorLoadingComments,
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 128.dp)

View file

@ -1,6 +1,7 @@
package org.schabi.newpipe.ui.emptystate
import android.graphics.Color
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
@ -22,25 +23,14 @@ import org.schabi.newpipe.ui.theme.AppTheme
fun EmptyStateComposable(
spec: EmptyStateSpec,
modifier: Modifier = Modifier,
) = EmptyStateComposable(
emojiText = spec.emojiText(),
descriptionText = spec.descriptionText(),
modifier = modifier
)
@Composable
private fun EmptyStateComposable(
emojiText: String,
descriptionText: String,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
verticalArrangement = Arrangement.Center,
) {
Text(
text = emojiText,
text = spec.emojiText,
style = MaterialTheme.typography.titleLarge,
textAlign = TextAlign.Center,
)
@ -49,7 +39,7 @@ private fun EmptyStateComposable(
modifier = Modifier
.padding(top = 6.dp)
.padding(horizontal = 16.dp),
text = descriptionText,
text = stringResource(spec.descriptionText),
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
)
@ -82,66 +72,48 @@ fun EmptyStateComposableNoCommentPreview() {
}
}
data class EmptyStateSpec(
val emojiText: @Composable () -> String,
val descriptionText: @Composable () -> String,
enum class EmptyStateSpec(
val emojiText: String,
@field:StringRes val descriptionText: Int,
) {
companion object {
val GenericError =
EmptyStateSpec(
emojiText = { "¯\\_(ツ)_/¯" },
descriptionText = { stringResource(id = R.string.empty_list_subtitle) },
)
val NoVideos =
EmptyStateSpec(
emojiText = { "(╯°-°)╯" },
descriptionText = { stringResource(id = R.string.no_videos) },
)
val NoComments =
EmptyStateSpec(
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(
emojiText = { "╰(°●°╰)" },
descriptionText = { stringResource(id = R.string.search_no_results) }
)
val NoSearchMaxSizeResult =
NoSearchResult
val ContentNotSupported =
NoComments.copy(
emojiText = { "(︶︹︺)" },
descriptionText = { stringResource(id = R.string.content_not_supported) },
)
val NoBookmarkedPlaylist =
EmptyStateSpec(
emojiText = { "(╥﹏╥)" },
descriptionText = { stringResource(id = R.string.no_playlist_bookmarked_yet) },
)
val NoSubscriptionsHint =
EmptyStateSpec(
emojiText = { "(꩜ᯅ꩜)" },
descriptionText = { stringResource(id = R.string.import_subscriptions_hint) },
)
val NoSubscriptions =
NoSubscriptionsHint.copy(
descriptionText = { stringResource(id = R.string.no_channel_subscribed_yet) },
)
}
GenericError(
emojiText = "¯\\_(ツ)_/¯",
descriptionText = R.string.empty_list_subtitle,
),
NoVideos(
emojiText = "(╯°-°)╯",
descriptionText = R.string.no_videos,
),
NoComments(
emojiText = "¯\\_(╹x╹)_/¯",
descriptionText = R.string.no_comments,
),
DisabledComments(
emojiText = "¯\\_(╹x╹)_/¯",
descriptionText = R.string.comments_are_disabled,
),
ErrorLoadingComments(
emojiText = "¯\\_(╹x╹)_/¯",
descriptionText = R.string.error_unable_to_load_comments,
),
NoSearchResult(
emojiText = "╰(°●°╰)",
descriptionText = R.string.search_no_results,
),
ContentNotSupported(
emojiText = "(︶︹︺)",
descriptionText = R.string.content_not_supported,
),
NoBookmarkedPlaylist(
emojiText = "(╥﹏╥)",
descriptionText = R.string.no_playlist_bookmarked_yet,
),
NoSubscriptionsHint(
emojiText = "(꩜ᯅ꩜)",
descriptionText = R.string.import_subscriptions_hint,
),
NoSubscriptions(
emojiText = "(꩜ᯅ꩜)",
descriptionText = R.string.no_channel_subscribed_yet,
),
}