Skip to content

Migrate playlist fragment to Jetpack Compose #11259

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 72 commits into
base: refactor
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 69 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
08f0338
Convert comment replies views to Jetpack Compose
Isira-Seneviratne May 12, 2024
c429deb
Rename .java to .kt
Isira-Seneviratne May 12, 2024
e193265
Use reply header composable in fragment
Isira-Seneviratne May 12, 2024
fc8a748
Added like count
Isira-Seneviratne May 12, 2024
b302c1b
Added missing comment features, fixed theming
Isira-Seneviratne May 17, 2024
b14da3a
Add comment ellipsis
Isira-Seneviratne Jun 16, 2024
65fce6e
Update replies fragment to use the comment composable as well
Isira-Seneviratne Jun 18, 2024
f056edd
Improve previews, display date of comment
Isira-Seneviratne Jun 18, 2024
e75eb2d
Fixed some comment issues
Isira-Seneviratne Jun 18, 2024
c29fa70
Use AnnotatedString to handle HTML parsing
Isira-Seneviratne Jun 19, 2024
e71fc38
Add replies button
Isira-Seneviratne Jun 19, 2024
b6a0f5d
Set view strategy
Isira-Seneviratne Jun 20, 2024
552ea50
Fixed like count display
Isira-Seneviratne Jun 20, 2024
cf3fb0b
Fixed fragment title
Isira-Seneviratne Jun 21, 2024
f27273e
Rename .java to .kt
Isira-Seneviratne Jun 21, 2024
03bc4e2
Migrate comments fragment to Jetpack Compose
Isira-Seneviratne Jun 21, 2024
ff88184
Added scrollbar to comment section
Isira-Seneviratne Jun 21, 2024
754bf45
Replace CommentRepliesFragment with bottom sheet composable, improve …
Isira-Seneviratne Jun 23, 2024
cc6f1ff
Replace Spacers with the horizontalArrangement parameter
Isira-Seneviratne Jun 23, 2024
8d4c608
Handle no comments and comments disabled scenarios
Isira-Seneviratne Jun 23, 2024
e87a2e0
Rm redundant Surface
Isira-Seneviratne Jun 26, 2024
219da28
Improve code organization
Isira-Seneviratne Jun 28, 2024
975a341
Cache paging data using the cachedIn() extension
Isira-Seneviratne Jun 30, 2024
94ef79c
Add comment view model
Isira-Seneviratne Jul 2, 2024
21b22d3
Rm extra padding in header
Isira-Seneviratne Jul 5, 2024
4b13e30
Replace padding modifier with verticalArrangement in comment header
Isira-Seneviratne Jul 5, 2024
1c503ce
Added loading indicator
Isira-Seneviratne Jul 6, 2024
ddbfcf8
Rm unused method
Isira-Seneviratne Jul 8, 2024
3c55d95
Improve comment loading smoothness
Isira-Seneviratne Jul 8, 2024
f438ba4
Animate comment expand/collapse
Isira-Seneviratne Jul 9, 2024
b83f643
Make parsed links clickable, visible
Isira-Seneviratne Jul 10, 2024
0d9c4aa
Fix alignment of comment message
Isira-Seneviratne Jul 12, 2024
f285bc0
Fix some modifiers
Isira-Seneviratne Jul 16, 2024
f1591ab
Added DescriptionText composable
Isira-Seneviratne Jul 25, 2024
b2748cc
Improved component organisation
Isira-Seneviratne Jul 28, 2024
10dd571
Update Kotlin to 2.0, update dependencies and fix issues
Isira-Seneviratne Jul 28, 2024
68b3dd5
Create playlist header composable
Isira-Seneviratne Jun 28, 2024
8603b0d
Start implementing full playlist view, add view model
Isira-Seneviratne Jun 28, 2024
bf1c9ba
Start implementing stream composable, grid layout
Isira-Seneviratne Jul 1, 2024
72bbe0e
Implement card and list layouts, check for preferred layout from sett…
Isira-Seneviratne Jul 2, 2024
37e4064
Cache total duration calculation
Isira-Seneviratne Jul 2, 2024
462ed5c
Added loading indicator to playlist view
Isira-Seneviratne Jul 6, 2024
5e33b69
Moved stream display to separate composable for reusability
Isira-Seneviratne Jul 8, 2024
bbdff4b
Show dropdown menu on long click, make some adjustments
Isira-Seneviratne Jul 9, 2024
7501f2f
Animate playlist description expand/collapse
Isira-Seneviratne Jul 9, 2024
c978fb7
Fix stream thumbnail text color
Isira-Seneviratne Jul 12, 2024
3da4aee
Rename .java to .kt
Isira-Seneviratne Jul 13, 2024
9dfd064
Remove old playlist fragment
Isira-Seneviratne Jul 13, 2024
b9556a1
Improved PlaylistHeader
Isira-Seneviratne Jul 16, 2024
82e5b6b
Remove playlist preview dependency on external HTTP calls
Isira-Seneviratne Jul 22, 2024
d7de38c
Remove TextEllipsizer
Isira-Seneviratne Jul 25, 2024
b443abb
Improved component organisation
Isira-Seneviratne Jul 28, 2024
06a5828
Improved stream components
Isira-Seneviratne Jul 28, 2024
8e8f627
Dismiss popup menu on clicking an option
Isira-Seneviratne Jul 28, 2024
4453061
Added stream grid mini preview
Isira-Seneviratne Jul 28, 2024
2f9364a
Fix crash when opening YouTube mixes
Isira-Seneviratne Jul 29, 2024
75475da
Improve StreamThumbnail composable
Isira-Seneviratne Jul 29, 2024
a885a88
Add duration comment
Isira-Seneviratne Jul 29, 2024
aec18c7
Move item view mode composable
Isira-Seneviratne Aug 1, 2024
52a2acc
Merge branch 'refactor' into Playlist-Compose
Isira-Seneviratne Dec 26, 2024
b644160
Use UI state classes in playlist
Isira-Seneviratne Dec 29, 2024
902b41f
Merge remote-tracking branch 'newpipe/refactor' into Playlist-Compose
Isira-Seneviratne Jan 27, 2025
07cd1d4
Merge branch 'refactor' into Playlist-Compose
Isira-Seneviratne Feb 6, 2025
076f63d
Extract string, refactor ItemList
Isira-Seneviratne Feb 11, 2025
cf37de8
Use extracted playlist page key
Isira-Seneviratne Feb 12, 2025
14a0e5d
Rename .java to .kt
Isira-Seneviratne Apr 4, 2025
86381f2
Implement remaining playlist functionality
Isira-Seneviratne Apr 6, 2025
cdacc04
Merge branch 'refactor' into Playlist-Compose
Isira-Seneviratne Apr 6, 2025
3711e37
Avoid displaying channel and playlist menu options at the same time
Isira-Seneviratne Apr 6, 2025
a2e023b
Reduce button padding
Isira-Seneviratne Apr 6, 2025
799d492
Merge branch 'refactor' into Playlist-Compose
Isira-Seneviratne Apr 10, 2025
69ae8e1
Remove duplicate composables
Isira-Seneviratne Apr 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ dependencies {
implementation libs.androidx.media
implementation libs.androidx.preference
implementation libs.androidx.recyclerview
implementation libs.androidx.room.runtime
implementation libs.androidx.room.ktx
implementation libs.androidx.room.rxjava3
kapt libs.androidx.room.compiler
implementation libs.androidx.swiperefreshlayout
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import androidx.room.testing.MigrationTestHelper
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import kotlinx.coroutines.reactive.awaitFirst
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNull
Expand Down Expand Up @@ -226,7 +228,7 @@ class DatabaseMigrationTest {
}

@Test
fun migrateDatabaseFrom8to9() {
fun migrateDatabaseFrom8to9() = runBlocking {
val databaseInV8 = testHelper.createDatabase(AppDatabase.DATABASE_NAME, Migrations.DB_VER_8)

val localUid1: Long
Expand Down Expand Up @@ -283,8 +285,8 @@ class DatabaseMigrationTest {
)

val migratedDatabaseV9 = getMigratedDatabase()
var localListFromDB = migratedDatabaseV9.playlistDAO().all.blockingFirst()
var remoteListFromDB = migratedDatabaseV9.playlistRemoteDAO().all.blockingFirst()
var localListFromDB = migratedDatabaseV9.playlistDAO().getAll().awaitFirst()
var remoteListFromDB = migratedDatabaseV9.playlistRemoteDAO().getAll().awaitFirst()

assertEquals(1, localListFromDB.size)
assertEquals(localUid2, localListFromDB[0].uid)
Expand All @@ -303,8 +305,8 @@ class DatabaseMigrationTest {
)
)

localListFromDB = migratedDatabaseV9.playlistDAO().all.blockingFirst()
remoteListFromDB = migratedDatabaseV9.playlistRemoteDAO().all.blockingFirst()
localListFromDB = migratedDatabaseV9.playlistDAO().getAll().awaitFirst()
remoteListFromDB = migratedDatabaseV9.playlistRemoteDAO().getAll().awaitFirst()
assertEquals(2, localListFromDB.size)
assertEquals(localUid3, localListFromDB[1].uid)
assertEquals(-1, localListFromDB[1].displayIndex)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.schabi.newpipe.database.playlist.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import io.reactivex.rxjava3.core.Flowable
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.firstOrNull
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity

@Dao
interface PlaylistRemoteDAO {
@Query("SELECT * FROM remote_playlists")
fun getAll(): Flowable<List<PlaylistRemoteEntity>>

@Query("SELECT * FROM remote_playlists WHERE url = :url AND service_id = :serviceId")
fun getPlaylist(serviceId: Int, url: String): Flow<PlaylistRemoteEntity?>

@Query("SELECT * FROM remote_playlists ORDER BY display_index")
fun getPlaylists(): Flowable<List<PlaylistRemoteEntity>>

@Insert
suspend fun insert(playlist: PlaylistRemoteEntity): Long

@Update
suspend fun update(playlist: PlaylistRemoteEntity)

@Transaction
suspend fun upsert(playlist: PlaylistRemoteEntity) {
val dbPlaylist = getPlaylist(playlist.serviceId, playlist.url).firstOrNull()

if (dbPlaylist == null) {
insert(playlist)
} else {
playlist.uid = dbPlaylist.uid
update(playlist)
}
}

@Query("DELETE FROM remote_playlists WHERE uid = :playlistId")
suspend fun deletePlaylist(playlistId: Long): Int
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
package org.schabi.newpipe.database.playlist.model;

import android.text.TextUtils;

import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.Index;
import androidx.room.PrimaryKey;

import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
import org.schabi.newpipe.ui.components.playlist.PlaylistScreenInfo;
import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.image.ImageStrategy;

import static org.schabi.newpipe.database.LocalItem.LocalItemType.PLAYLIST_REMOTE_ITEM;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_NAME;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_SERVICE_ID;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_TABLE;
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_URL;
Expand Down Expand Up @@ -84,31 +81,14 @@ public PlaylistRemoteEntity(final int serviceId, final String name, final String
}

@Ignore
public PlaylistRemoteEntity(final PlaylistInfo info) {
public PlaylistRemoteEntity(final PlaylistScreenInfo info) {
this(info.getServiceId(), info.getName(), info.getUrl(),
// use uploader avatar when no thumbnail is available
ImageStrategy.imageListToDbUrl(info.getThumbnails().isEmpty()
? info.getUploaderAvatars() : info.getThumbnails()),
info.getUploaderName(), info.getStreamCount());
}

@Ignore
public boolean isIdenticalTo(final PlaylistInfo info) {
/*
* Returns boolean comparing the online playlist and the local copy.
* (False if info changed such as playlist name or track count)
*/
return getServiceId() == info.getServiceId()
&& getStreamCount() == info.getStreamCount()
&& TextUtils.equals(getName(), info.getName())
&& TextUtils.equals(getUrl(), info.getUrl())
// we want to update the local playlist data even when either the remote thumbnail
// URL changes, or the preferred image quality setting is changed by the user
&& TextUtils.equals(getThumbnailUrl(),
ImageStrategy.imageListToDbUrl(info.getThumbnails()))
&& TextUtils.equals(getUploader(), info.getUploaderName());
}

@Override
public long getUid() {
return uid;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
private MenuItem menuRssButton;
private MenuItem menuNotifyButton;
private SubscriptionEntity channelSubscription;
private MenuProvider menuProvider;

public static ChannelFragment getInstance(final int serviceId, final String url,
final String name) {
Expand All @@ -122,9 +121,24 @@ private void setInitialData(final int sid, final String u, final String title) {
//////////////////////////////////////////////////////////////////////////*/

@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
menuProvider = new MenuProvider() {
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
subscriptionManager = new SubscriptionManager(activity);
}

@Override
public View onCreateView(@NonNull final LayoutInflater inflater,
@Nullable final ViewGroup container,
@Nullable final Bundle savedInstanceState) {
binding = FragmentChannelBinding.inflate(inflater, container, false);
return binding.getRoot();
}

@Override // called from onViewCreated in BaseFragment.onViewCreated
protected void initViews(final View rootView, final Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);

final var menuProvider = new MenuProvider() {
@Override
public void onCreateMenu(@NonNull final Menu menu,
@NonNull final MenuInflater inflater) {
Expand All @@ -134,7 +148,6 @@ public void onCreateMenu(@NonNull final Menu menu,
Log.d(TAG, "onCreateOptionsMenu() called with: "
+ "menu = [" + menu + "], inflater = [" + inflater + "]");
}

}

@Override
Expand Down Expand Up @@ -179,26 +192,7 @@ public boolean onMenuItemSelected(@NonNull final MenuItem item) {
return true;
}
};
activity.addMenuProvider(menuProvider);
}

@Override
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
subscriptionManager = new SubscriptionManager(activity);
}

@Override
public View onCreateView(@NonNull final LayoutInflater inflater,
@Nullable final ViewGroup container,
@Nullable final Bundle savedInstanceState) {
binding = FragmentChannelBinding.inflate(inflater, container, false);
return binding.getRoot();
}

@Override // called from onViewCreated in BaseFragment.onViewCreated
protected void initViews(final View rootView, final Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState);
activity.addMenuProvider(menuProvider, getViewLifecycleOwner());

EmptyStateUtil.setEmptyStateComposable(
binding.emptyStateView,
Expand Down Expand Up @@ -246,8 +240,6 @@ public void onDestroy() {
}
disposables.clear();
binding = null;
activity.removeMenuProvider(menuProvider);
menuProvider = null;
}

/*//////////////////////////////////////////////////////////////////////////
Expand Down
Loading
Loading