Skip to content

Commit 226b6de

Browse files
Merge branch 'refs/heads/refactor' into About-Compose
# Conflicts: # app/src/main/java/org/schabi/newpipe/about/AboutActivity.kt # build.gradle
2 parents 4f4136c + 13585ca commit 226b6de

69 files changed

Lines changed: 1442 additions & 1216 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ jobs:
4747
BRANCH: ${{ github.head_ref }}
4848
run: git checkout -B "$BRANCH"
4949

50-
- name: set up JDK 17
50+
- name: set up JDK
5151
uses: actions/setup-java@v4
5252
with:
53-
java-version: 17
53+
java-version: 21
5454
distribution: "temurin"
5555
cache: 'gradle'
5656

@@ -88,10 +88,10 @@ jobs:
8888
sudo udevadm control --reload-rules
8989
sudo udevadm trigger --name-match=kvm
9090
91-
- name: set up JDK 17
91+
- name: set up JDK
9292
uses: actions/setup-java@v4
9393
with:
94-
java-version: 17
94+
java-version: 21
9595
distribution: "temurin"
9696
cache: 'gradle'
9797

@@ -121,10 +121,10 @@ jobs:
121121
with:
122122
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
123123

124-
- name: Set up JDK 17
124+
- name: Set up JDK
125125
uses: actions/setup-java@v4
126126
with:
127-
java-version: 17
127+
java-version: 21
128128
distribution: "temurin"
129129
cache: 'gradle'
130130

.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: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ android {
9696
buildFeatures {
9797
viewBinding true
9898
compose true
99+
buildConfig true
99100
}
100101

101102
packagingOptions {
@@ -116,7 +117,7 @@ ext {
116117
androidxRoomVersion = '2.6.1'
117118
androidxWorkVersion = '2.8.1'
118119

119-
icepickVersion = '3.2.0'
120+
stateSaverVersion = '1.4.1'
120121
exoPlayerVersion = '2.18.7'
121122
googleAutoServiceVersion = '1.1.1'
122123
groupieVersion = '2.10.1'
@@ -206,7 +207,8 @@ dependencies {
206207
// name and the commit hash with the commit hash of the (pushed) commit you want to test
207208
// This works thanks to JitPack: https://jitpack.io/
208209
implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751'
209-
implementation 'com.github.teamnewpipe:newpipeextractor:v0.24.2'
210+
// WORKAROUND: v0.24.2 can't be resolved by jitpack -> use git commit hash instead
211+
implementation 'com.github.TeamNewPipe:NewPipeExtractor:176da72cb4c3ec4679211339b0e59f6b01bf2f52'
210212
implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0'
211213

212214
/** Checkstyle **/
@@ -222,7 +224,7 @@ dependencies {
222224
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
223225
implementation 'androidx.core:core-ktx:1.12.0'
224226
implementation 'androidx.documentfile:documentfile:1.0.1'
225-
implementation 'androidx.fragment:fragment-ktx:1.6.2'
227+
implementation 'androidx.fragment:fragment-compose:1.8.2'
226228
implementation "androidx.lifecycle:lifecycle-livedata-ktx:${androidxLifecycleVersion}"
227229
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${androidxLifecycleVersion}"
228230
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
@@ -239,8 +241,9 @@ dependencies {
239241

240242
/** Third-party libraries **/
241243
// Instance state boilerplate elimination
242-
implementation "frankiesardo:icepick:${icepickVersion}"
243-
kapt "frankiesardo:icepick-processor:${icepickVersion}"
244+
implementation 'com.github.livefront:bridge:v2.0.2'
245+
implementation "com.evernote:android-state:$stateSaverVersion"
246+
kapt "com.evernote:android-state-processor:$stateSaverVersion"
244247

245248
// HTML parser
246249
implementation "org.jsoup:jsoup:1.17.2"
@@ -288,18 +291,19 @@ dependencies {
288291
// Date and time formatting
289292
implementation "org.ocpsoft.prettytime:prettytime:5.0.8.Final"
290293

291-
// Jetpack Compose BOM group
292-
implementation(platform('androidx.compose:compose-bom:2024.09.03'))
294+
// Jetpack Compose
295+
implementation(platform('androidx.compose:compose-bom:2024.10.01'))
293296
implementation 'androidx.compose.material3:material3'
297+
implementation 'androidx.compose.material3.adaptive:adaptive'
298+
implementation 'androidx.activity:activity-compose'
294299
implementation 'androidx.compose.ui:ui-tooling-preview'
300+
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose'
295301
implementation 'androidx.compose.ui:ui-text' // Needed for parsing HTML to AnnotatedString
302+
implementation 'androidx.compose.material:material-icons-extended'
296303

297304
// Jetpack Compose related dependencies
298-
implementation 'androidx.compose.material3.adaptive:adaptive:1.0.0'
299-
implementation 'androidx.activity:activity-compose:1.9.2'
300-
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6'
301305
implementation 'androidx.paging:paging-compose:3.3.2'
302-
implementation "androidx.navigation:navigation-compose:2.8.2"
306+
implementation "androidx.navigation:navigation-compose:2.8.3"
303307

304308
// Coroutines interop
305309
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-rx3:1.8.1'

app/proguard-rules.pro

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,6 @@
1313
## Rules for ExoPlayer
1414
-keep class com.google.android.exoplayer2.** { *; }
1515

16-
## Rules for Icepick. Copy pasted from https://github.com/frankiesardo/icepick
17-
-dontwarn icepick.**
18-
-keep class icepick.** { *; }
19-
-keep class **$$Icepick { *; }
20-
-keepclasseswithmembernames class * {
21-
@icepick.* <fields>;
22-
}
23-
-keepnames class * { @icepick.State *;}
24-
2516
## Rules for OkHttp. Copy pasted from https://github.com/square/okhttp
2617
-dontwarn okhttp3.**
2718
-dontwarn okio.**

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.schabi.newpipe.extractor.downloader.Downloader;
2222
import org.schabi.newpipe.ktx.ExceptionUtils;
2323
import org.schabi.newpipe.settings.NewPipeSettings;
24+
import org.schabi.newpipe.util.BridgeStateSaverInitializer;
2425
import org.schabi.newpipe.util.Localization;
2526
import org.schabi.newpipe.util.ServiceHelper;
2627
import org.schabi.newpipe.util.StateSaver;
@@ -107,6 +108,7 @@ public void onCreate() {
107108
Localization.getPreferredContentCountry(this));
108109
Localization.initPrettyTime(Localization.resolvePrettyTime(getApplicationContext()));
109110

111+
BridgeStateSaverInitializer.init(this);
110112
StateSaver.init(this);
111113
initNotificationChannels();
112114

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
import androidx.fragment.app.Fragment;
1111
import androidx.fragment.app.FragmentManager;
1212

13-
import icepick.Icepick;
14-
import icepick.State;
13+
import com.evernote.android.state.State;
14+
import com.livefront.bridge.Bridge;
15+
1516

1617
public abstract class BaseFragment extends Fragment {
1718
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
@@ -48,7 +49,7 @@ public void onCreate(final Bundle savedInstanceState) {
4849
+ "savedInstanceState = [" + savedInstanceState + "]");
4950
}
5051
super.onCreate(savedInstanceState);
51-
Icepick.restoreInstanceState(this, savedInstanceState);
52+
Bridge.restoreInstanceState(this, savedInstanceState);
5253
if (savedInstanceState != null) {
5354
onRestoreInstanceState(savedInstanceState);
5455
}
@@ -70,7 +71,7 @@ public void onViewCreated(@NonNull final View rootView, final Bundle savedInstan
7071
@Override
7172
public void onSaveInstanceState(@NonNull final Bundle outState) {
7273
super.onSaveInstanceState(outState);
73-
Icepick.saveInstanceState(this, outState);
74+
Bridge.saveInstanceState(this, outState);
7475
}
7576

7677
protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) {

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/RouterActivity.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
import androidx.lifecycle.LifecycleOwner;
4242
import androidx.preference.PreferenceManager;
4343

44+
import com.evernote.android.state.State;
45+
import com.livefront.bridge.Bridge;
46+
4447
import org.schabi.newpipe.database.stream.model.StreamEntity;
4548
import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
4649
import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding;
@@ -98,8 +101,6 @@
98101
import java.util.Optional;
99102
import java.util.function.Consumer;
100103

101-
import icepick.Icepick;
102-
import icepick.State;
103104
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
104105
import io.reactivex.rxjava3.core.Observable;
105106
import io.reactivex.rxjava3.core.Single;
@@ -152,7 +153,7 @@ protected void onCreate(final Bundle savedInstanceState) {
152153
getWindow().setAttributes(params);
153154

154155
super.onCreate(savedInstanceState);
155-
Icepick.restoreInstanceState(this, savedInstanceState);
156+
Bridge.restoreInstanceState(this, savedInstanceState);
156157

157158
// FragmentManager will take care to recreate (Playlist|Download)Dialog when screen rotates
158159
// We used to .setOnDismissListener(dialog -> finish()); when creating these DialogFragments
@@ -197,7 +198,7 @@ protected void onStop() {
197198
@Override
198199
protected void onSaveInstanceState(@NonNull final Bundle outState) {
199200
super.onSaveInstanceState(outState);
200-
Icepick.saveInstanceState(this, outState);
201+
Bridge.saveInstanceState(this, outState);
201202
}
202203

203204
@Override

0 commit comments

Comments
 (0)