Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ public final class VideoDetailFragment
} else if (getString(R.string.show_description_key).equals(key)) {
showDescription = sharedPreferences.getBoolean(key, true);
tabSettingsChanged = true;
} else if (getString(R.string.pinned_video_player_key).equals(key)) {
setupPinnedPlayerMode();
}
};

Expand All @@ -207,6 +209,9 @@ public final class VideoDetailFragment
@State
protected boolean autoPlayEnabled = true;

// Pinned player fields
private boolean isPinnedPlayerEnabled = false;

@Nullable
private StreamInfo currentInfo = null;
private Disposable currentWorker;
Expand Down Expand Up @@ -627,6 +632,9 @@ protected void initViews(final View rootView, final Bundle savedInstanceState) {

binding.detailThumbnailRootLayout.requestFocus();

// Setup pinned player mode
setupPinnedPlayerMode();

binding.detailControlsPlayWithKodi.setVisibility(
KoreUtils.shouldShowPlayWithKodi(requireContext(), serviceId)
? View.VISIBLE
Expand Down Expand Up @@ -1271,7 +1279,14 @@ private void tryAddVideoPlayerView() {
if (binding != null) {
// prevent from re-adding a view multiple times
playerUi.removeViewFromParent();
binding.playerPlaceholder.addView(playerUi.getBinding().getRoot());

// Add to appropriate placeholder based on pinned mode
if (isPinnedPlayerEnabled) {
binding.pinnedPlayerPlaceholder.addView(playerUi.getBinding().getRoot());
} else {
binding.playerPlaceholder.addView(playerUi.getBinding().getRoot());
}

playerUi.setupVideoSurfaceIfNeeded();
}
});
Expand All @@ -1295,6 +1310,85 @@ private void makeDefaultHeightForVideoPlaceholder() {
binding.playerPlaceholder.requestLayout();
}

/*//////////////////////////////////////////////////////////////////////////
// Pinned Player Methods
//////////////////////////////////////////////////////////////////////////*/

/**
* Check if pinned player mode is enabled in settings.
*
* @return true if pinned player mode is enabled, false otherwise
*/
private boolean isPinnedPlayerEnabled() {
return PreferenceManager.getDefaultSharedPreferences(requireContext())
.getBoolean(getString(R.string.pinned_video_player_key), false);
}

/**
* Setup pinned player mode based on user preference.
*/
private void setupPinnedPlayerMode() {
isPinnedPlayerEnabled = isPinnedPlayerEnabled();

if (binding == null) {
return;
}

if (isPinnedPlayerEnabled) {
// Show pinned overlay, hide original content
binding.pinnedPlayerOverlay.setVisibility(View.VISIBLE);
binding.detailMainContent.setVisibility(View.GONE);

// Copy data to pinned layout
copyDataToPinnedLayout();

// Setup tabs for pinned mode
setupPinnedTabs();
} else {
// Show original layout, hide pinned overlay
binding.pinnedPlayerOverlay.setVisibility(View.GONE);
binding.detailMainContent.setVisibility(View.VISIBLE);
}
}

/**
* Copy video data to pinned layout elements.
*/
private void copyDataToPinnedLayout() {
if (currentInfo == null || binding == null) {
return;
}

// Copy title
binding.pinnedDetailTitleView.setText(currentInfo.getName());

// Copy uploader info
binding.pinnedDetailUploaderNameView.setText(currentInfo.getUploaderName());
// Note: Subscriber count and description methods may not be available
// binding.pinnedDetailUploaderSubscriberCountView.setText(
// currentInfo.getSubscriberCount());
// binding.pinnedDetailDescriptionView.setText(currentInfo.getDescription());

// Load uploader thumbnail - check if method exists
// if (currentInfo.getUploaderAvatarUrl() != null) {
// PicassoHelper.loadAvatarImage(currentInfo.getUploaderAvatarUrl())
// .into(binding.pinnedDetailUploaderThumbnailView);
// }
}

/**
* Setup tabs for pinned mode (similar to original tabs).
*/
private void setupPinnedTabs() {
if (binding == null || pageAdapter == null) {
return;
}

// Setup ViewPager and TabLayout for pinned mode
binding.pinnedViewPager.setAdapter(pageAdapter);
binding.pinnedTabLayout.setupWithViewPager(binding.pinnedViewPager);
}

private final ViewTreeObserver.OnPreDrawListener preDrawListener =
new ViewTreeObserver.OnPreDrawListener() {
@Override
Expand Down Expand Up @@ -1499,6 +1593,9 @@ public void handleResult(@NonNull final StreamInfo info) {

updateTabs(info);

// Update pinned player data when video info is loaded
copyDataToPinnedLayout();

animate(binding.detailThumbnailPlayButton, true, 200);
binding.detailVideoTitleView.setText(title);

Expand Down
129 changes: 129 additions & 0 deletions app/src/main/res/layout/fragment_video_detail.xml
Original file line number Diff line number Diff line change
Expand Up @@ -704,4 +704,133 @@

</RelativeLayout>

<!-- PINNED PLAYER OVERLAY (shown when pinned mode is enabled) -->
<LinearLayout
android:id="@+id/pinned_player_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone"
android:background="?attr/windowBackground">

<!-- PINNED PLAYER AREA -->
<FrameLayout
android:id="@+id/pinned_player_placeholder"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@android:color/black" />

<!-- SCROLLABLE CONTENT BELOW PINNED PLAYER -->
<androidx.core.widget.NestedScrollView
android:id="@+id/pinned_content_scroll"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">

<!-- TITLE -->
<org.schabi.newpipe.views.NewPipeTextView
android:id="@+id/pinned_detail_title_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
android:layout_marginBottom="16dp"
tools:text="Video Title" />

<!-- UPLOADER INFO -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="16dp">

<ImageView
android:id="@+id/pinned_detail_uploader_thumbnail_view"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginEnd="12dp"
android:background="@drawable/ic_person"
android:contentDescription="@string/detail_uploader_thumbnail_view_description"
android:scaleType="centerCrop"
tools:src="@drawable/placeholder_thumbnail_channel" />

<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">

<org.schabi.newpipe.views.NewPipeTextView
android:id="@+id/pinned_detail_uploader_name_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp"
tools:text="Channel Name" />

<org.schabi.newpipe.views.NewPipeTextView
android:id="@+id/pinned_detail_uploader_subscriber_count_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp"
tools:text="1.2M subscribers" />

</LinearLayout>

<androidx.appcompat.widget.AppCompatButton
android:id="@+id/pinned_detail_subscribe_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/subscribe_button_title"
android:textSize="12sp" />

</LinearLayout>

<!-- DESCRIPTION -->
<org.schabi.newpipe.views.NewPipeTextView
android:id="@+id/pinned_detail_description_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"
android:textSize="12sp"
android:layout_marginBottom="16dp"
tools:text="Stream meta info with link" />

<!-- TAB CONTENT (Comments, Related, etc.) -->
<androidx.viewpager.widget.ViewPager
android:id="@+id/pinned_view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>

</LinearLayout>

</androidx.core.widget.NestedScrollView>

<!-- TAB LAYOUT FOR PINNED MODE -->
<com.google.android.material.tabs.TabLayout
android:id="@+id/pinned_tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="16dp"
app:tabBackground="?attr/windowBackground"
app:tabGravity="fill"
app:tabIconTint="?attr/colorAccent"
app:tabIndicatorGravity="top" />

</LinearLayout>

</FrameLayout>
27 changes: 0 additions & 27 deletions app/src/main/res/values-v35/styles.xml

This file was deleted.

3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@
<string name="clear_queue_confirmation_description">The active player queue will be replaced</string>
<string name="ignore_hardware_media_buttons_title">Ignore hardware media button events</string>
<string name="ignore_hardware_media_buttons_summary">Useful, for instance, if you are using a headset with broken physical buttons</string>
<string name="pinned_video_player_key">pinned_video_player_key</string>
<string name="pinned_video_player_title">Pin video player at top</string>
<string name="pinned_video_player_summary">Keep the video player visible at the top while scrolling through comments and recommendations</string>
<string name="show_comments_title">Show comments</string>
<string name="show_comments_summary">Turn off to hide comments</string>
<string name="show_next_and_similar_title">Show \'Next\' and \'Similar\' videos</string>
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/res/xml/video_audio_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,13 @@
android:title="@string/ignore_hardware_media_buttons_title"
app:singleLineTitle="false"
app:iconSpaceReserved="false" />

<SwitchPreferenceCompat
android:defaultValue="false"
android:key="@string/pinned_video_player_key"
android:summary="@string/pinned_video_player_summary"
android:title="@string/pinned_video_player_title"
app:singleLineTitle="false"
app:iconSpaceReserved="false" />
</PreferenceCategory>
</PreferenceScreen>