Skip to content

Commit 62ab9bd

Browse files
authored
Merge pull request #11060 from Isira-Seneviratne/Comments-Compose
Migrate comment fragments to Jetpack Compose
2 parents 8ada566 + fdf36cb commit 62ab9bd

38 files changed

Lines changed: 1178 additions & 1107 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ captures/
1010
*.class
1111
app/debug/
1212
app/release/
13+
.kotlin/
1314

1415
# vscode / eclipse files
1516
*.classpath

app/build.gradle

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ dependencies {
223223
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
224224
implementation 'androidx.core:core-ktx:1.12.0'
225225
implementation 'androidx.documentfile:documentfile:1.0.1'
226-
implementation 'androidx.fragment:fragment-ktx:1.6.2'
226+
implementation 'androidx.fragment:fragment-compose:1.8.2'
227227
implementation "androidx.lifecycle:lifecycle-livedata-ktx:${androidxLifecycleVersion}"
228228
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${androidxLifecycleVersion}"
229229
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
@@ -293,18 +293,19 @@ dependencies {
293293
// Date and time formatting
294294
implementation "org.ocpsoft.prettytime:prettytime:5.0.8.Final"
295295

296-
// Jetpack Compose BOM group
297-
implementation(platform('androidx.compose:compose-bom:2024.09.03'))
296+
// Jetpack Compose
297+
implementation(platform('androidx.compose:compose-bom:2024.10.01'))
298298
implementation 'androidx.compose.material3:material3'
299+
implementation 'androidx.compose.material3.adaptive:adaptive'
300+
implementation 'androidx.activity:activity-compose'
299301
implementation 'androidx.compose.ui:ui-tooling-preview'
302+
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose'
300303
implementation 'androidx.compose.ui:ui-text' // Needed for parsing HTML to AnnotatedString
304+
implementation 'androidx.compose.material:material-icons-extended'
301305

302306
// Jetpack Compose related dependencies
303-
implementation 'androidx.compose.material3.adaptive:adaptive:1.0.0'
304-
implementation 'androidx.activity:activity-compose:1.9.2'
305-
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6'
306307
implementation 'androidx.paging:paging-compose:3.3.2'
307-
implementation "androidx.navigation:navigation-compose:2.8.2"
308+
implementation "androidx.navigation:navigation-compose:2.8.3"
308309

309310
// Coroutines interop
310311
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-rx3:1.8.1'

app/src/main/java/org/schabi/newpipe/MainActivity.java

Lines changed: 13 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,13 @@
4444
import android.widget.Spinner;
4545

4646
import androidx.annotation.NonNull;
47-
import androidx.annotation.Nullable;
4847
import androidx.appcompat.app.ActionBar;
4948
import androidx.appcompat.app.ActionBarDrawerToggle;
5049
import androidx.appcompat.app.AppCompatActivity;
5150
import androidx.core.app.ActivityCompat;
5251
import androidx.core.view.GravityCompat;
5352
import androidx.drawerlayout.widget.DrawerLayout;
5453
import androidx.fragment.app.Fragment;
55-
import androidx.fragment.app.FragmentContainerView;
5654
import androidx.fragment.app.FragmentManager;
5755
import androidx.preference.PreferenceManager;
5856

@@ -66,13 +64,11 @@
6664
import org.schabi.newpipe.error.ErrorUtil;
6765
import org.schabi.newpipe.extractor.NewPipe;
6866
import org.schabi.newpipe.extractor.StreamingService;
69-
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
7067
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
7168
import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance;
7269
import org.schabi.newpipe.fragments.BackPressable;
7370
import org.schabi.newpipe.fragments.MainFragment;
7471
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
75-
import org.schabi.newpipe.fragments.list.comments.CommentRepliesFragment;
7672
import org.schabi.newpipe.fragments.list.search.SearchFragment;
7773
import org.schabi.newpipe.local.feed.notifications.NotificationWorker;
7874
import org.schabi.newpipe.player.Player;
@@ -557,39 +553,27 @@ public void onBackPressed() {
557553
// In case bottomSheet is not visible on the screen or collapsed we can assume that the user
558554
// interacts with a fragment inside fragment_holder so all back presses should be
559555
// handled by it
556+
final var fragmentManager = getSupportFragmentManager();
557+
560558
if (bottomSheetHiddenOrCollapsed()) {
561-
final FragmentManager fm = getSupportFragmentManager();
562-
final Fragment fragment = fm.findFragmentById(R.id.fragment_holder);
559+
final var fragment = fragmentManager.findFragmentById(R.id.fragment_holder);
563560
// If current fragment implements BackPressable (i.e. can/wanna handle back press)
564561
// delegate the back press to it
565-
if (fragment instanceof BackPressable) {
566-
if (((BackPressable) fragment).onBackPressed()) {
567-
return;
568-
}
569-
} else if (fragment instanceof CommentRepliesFragment) {
570-
// expand DetailsFragment if CommentRepliesFragment was opened
571-
// to show the top level comments again
572-
// Expand DetailsFragment if CommentRepliesFragment was opened
573-
// and no other CommentRepliesFragments are on top of the back stack
574-
// to show the top level comments again.
575-
openDetailFragmentFromCommentReplies(fm, false);
562+
if (fragment instanceof BackPressable backPressable && backPressable.onBackPressed()) {
563+
return;
576564
}
577-
578565
} else {
579-
final Fragment fragmentPlayer = getSupportFragmentManager()
580-
.findFragmentById(R.id.fragment_player_holder);
566+
final var player = fragmentManager.findFragmentById(R.id.fragment_player_holder);
581567
// If current fragment implements BackPressable (i.e. can/wanna handle back press)
582568
// delegate the back press to it
583-
if (fragmentPlayer instanceof BackPressable) {
584-
if (!((BackPressable) fragmentPlayer).onBackPressed()) {
585-
BottomSheetBehavior.from(mainBinding.fragmentPlayerHolder)
586-
.setState(BottomSheetBehavior.STATE_COLLAPSED);
587-
}
569+
if (player instanceof BackPressable backPressable && !backPressable.onBackPressed()) {
570+
BottomSheetBehavior.from(mainBinding.fragmentPlayerHolder)
571+
.setState(BottomSheetBehavior.STATE_COLLAPSED);
588572
return;
589573
}
590574
}
591575

592-
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
576+
if (fragmentManager.getBackStackEntryCount() == 1) {
593577
finish();
594578
} else {
595579
super.onBackPressed();
@@ -648,15 +632,9 @@ public void onRequestPermissionsResult(final int requestCode,
648632
* </pre>
649633
*/
650634
private void onHomeButtonPressed() {
651-
final FragmentManager fm = getSupportFragmentManager();
652-
final Fragment fragment = fm.findFragmentById(R.id.fragment_holder);
653-
654-
if (fragment instanceof CommentRepliesFragment) {
655-
// Expand DetailsFragment if CommentRepliesFragment was opened
656-
// and no other CommentRepliesFragments are on top of the back stack
657-
// to show the top level comments again.
658-
openDetailFragmentFromCommentReplies(fm, true);
659-
} else if (!NavigationHelper.tryGotoSearchFragment(fm)) {
635+
final var fm = getSupportFragmentManager();
636+
637+
if (!NavigationHelper.tryGotoSearchFragment(fm)) {
660638
// If search fragment wasn't found in the backstack go to the main fragment
661639
NavigationHelper.gotoMainFragment(fm);
662640
}
@@ -854,68 +832,6 @@ public void onReceive(final Context context, final Intent intent) {
854832
}
855833
}
856834

857-
private void openDetailFragmentFromCommentReplies(
858-
@NonNull final FragmentManager fm,
859-
final boolean popBackStack
860-
) {
861-
// obtain the name of the fragment under the replies fragment that's going to be popped
862-
@Nullable final String fragmentUnderEntryName;
863-
if (fm.getBackStackEntryCount() < 2) {
864-
fragmentUnderEntryName = null;
865-
} else {
866-
fragmentUnderEntryName = fm.getBackStackEntryAt(fm.getBackStackEntryCount() - 2)
867-
.getName();
868-
}
869-
870-
// the root comment is the comment for which the user opened the replies page
871-
@Nullable final CommentRepliesFragment repliesFragment =
872-
(CommentRepliesFragment) fm.findFragmentByTag(CommentRepliesFragment.TAG);
873-
@Nullable final CommentsInfoItem rootComment =
874-
repliesFragment == null ? null : repliesFragment.getCommentsInfoItem();
875-
876-
// sometimes this function pops the backstack, other times it's handled by the system
877-
if (popBackStack) {
878-
fm.popBackStackImmediate();
879-
}
880-
881-
// only expand the bottom sheet back if there are no more nested comment replies fragments
882-
// stacked under the one that is currently being popped
883-
if (CommentRepliesFragment.TAG.equals(fragmentUnderEntryName)) {
884-
return;
885-
}
886-
887-
final BottomSheetBehavior<FragmentContainerView> behavior = BottomSheetBehavior
888-
.from(mainBinding.fragmentPlayerHolder);
889-
// do not return to the comment if the details fragment was closed
890-
if (behavior.getState() == BottomSheetBehavior.STATE_HIDDEN) {
891-
return;
892-
}
893-
894-
// scroll to the root comment once the bottom sheet expansion animation is finished
895-
behavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
896-
@Override
897-
public void onStateChanged(@NonNull final View bottomSheet,
898-
final int newState) {
899-
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
900-
final Fragment detailFragment = fm.findFragmentById(
901-
R.id.fragment_player_holder);
902-
if (detailFragment instanceof VideoDetailFragment && rootComment != null) {
903-
// should always be the case
904-
((VideoDetailFragment) detailFragment).scrollToComment(rootComment);
905-
}
906-
behavior.removeBottomSheetCallback(this);
907-
}
908-
}
909-
910-
@Override
911-
public void onSlide(@NonNull final View bottomSheet, final float slideOffset) {
912-
// not needed, listener is removed once the sheet is expanded
913-
}
914-
});
915-
916-
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
917-
}
918-
919835
private boolean bottomSheetHiddenOrCollapsed() {
920836
final BottomSheetBehavior<FrameLayout> bottomSheetBehavior =
921837
BottomSheetBehavior.from(mainBinding.fragmentPlayerHolder);

app/src/main/java/org/schabi/newpipe/error/ReCaptchaActivity.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,8 @@ private void handleCookiesFromUrl(@Nullable final String url) {
185185
final int abuseEnd = url.indexOf("+path");
186186

187187
try {
188-
String abuseCookie = url.substring(abuseStart + 13, abuseEnd);
189-
abuseCookie = Utils.decodeUrlUtf8(abuseCookie);
190-
handleCookies(abuseCookie);
191-
} catch (IllegalArgumentException | StringIndexOutOfBoundsException e) {
188+
handleCookies(Utils.decodeUrlUtf8(url.substring(abuseStart + 13, abuseEnd)));
189+
} catch (final StringIndexOutOfBoundsException e) {
192190
if (MainActivity.DEBUG) {
193191
Log.e(TAG, "handleCookiesFromUrl: invalid google abuse starting at "
194192
+ abuseStart + " and ending at " + abuseEnd + " for url " + url, e);

app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@
7474
import org.schabi.newpipe.error.UserAction;
7575
import org.schabi.newpipe.extractor.Image;
7676
import org.schabi.newpipe.extractor.NewPipe;
77-
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
7877
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
7978
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
8079
import org.schabi.newpipe.extractor.stream.AudioStream;
@@ -881,8 +880,7 @@ private void initTabs() {
881880
tabContentDescriptions.clear();
882881

883882
if (shouldShowComments()) {
884-
pageAdapter.addFragment(
885-
CommentsFragment.getInstance(serviceId, url, title), COMMENTS_TAB_TAG);
883+
pageAdapter.addFragment(CommentsFragment.getInstance(serviceId, url), COMMENTS_TAB_TAG);
886884
tabIcons.add(R.drawable.ic_comment);
887885
tabContentDescriptions.add(R.string.comments_tab_description);
888886
}
@@ -1012,20 +1010,6 @@ public void scrollToTop() {
10121010
updateTabLayoutVisibility();
10131011
}
10141012

1015-
public void scrollToComment(final CommentsInfoItem comment) {
1016-
final int commentsTabPos = pageAdapter.getItemPositionByTitle(COMMENTS_TAB_TAG);
1017-
final Fragment fragment = pageAdapter.getItem(commentsTabPos);
1018-
if (!(fragment instanceof CommentsFragment)) {
1019-
return;
1020-
}
1021-
1022-
// unexpand the app bar only if scrolling to the comment succeeded
1023-
if (((CommentsFragment) fragment).scrollToComment(comment)) {
1024-
binding.appBarLayout.setExpanded(false, false);
1025-
binding.viewPager.setCurrentItem(commentsTabPos, false);
1026-
}
1027-
}
1028-
10291013
/*//////////////////////////////////////////////////////////////////////////
10301014
// Play Utils
10311015
//////////////////////////////////////////////////////////////////////////*/

0 commit comments

Comments
 (0)