App v0.2.26 and gateway 0.1.20
Client: seek controls, Bazarr subtitle download and cast panel in the player; MDBList ratings strip; episode and schedule detail pages; series pace estimate; what's new panel; install-permission onboarding step; synced per-profile preferences; Emby outage banner. Gateway: rebuilt admin console (one fragment per page), preference history and restore, merged Continue Watching, Emby health probe, subtitle selection and Bazarr download, structured request logging with per-request identity, and embedded build version. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2675e6d82b
commit
4a4df7a73c
@@ -22,6 +22,11 @@
|
||||
controller, so it can appear briefly without opening the transport controls. -->
|
||||
<include layout="@layout/player_playback_identity" />
|
||||
|
||||
<!-- Skipping. Declared before the timing cues so those sit above it: a lower third on
|
||||
the left and this centred chip do not overlap, and if they ever do, the cue that
|
||||
appears once matters more than one that appears on every press. -->
|
||||
<include layout="@layout/player_seek_indicator" />
|
||||
|
||||
<!-- The ten-minute cue. Declared before the next-up banner so that banner covers it
|
||||
if the two ever coincide: what comes next matters more than how long is left. -->
|
||||
<include layout="@layout/player_time_remaining" />
|
||||
|
||||
@@ -242,6 +242,15 @@
|
||||
android:src="@drawable/exo_ic_subtitle_on"
|
||||
tools:ignore="PrivateResource" />
|
||||
|
||||
<!-- Beside the subtitle picker rather than buried in the settings list:
|
||||
"who is this?" is asked mid-scene, and a question that has to survive a
|
||||
dialog and four menu rows is one nobody asks twice. -->
|
||||
<ImageButton
|
||||
android:id="@+id/player_cast"
|
||||
style="@style/MembyPlayerControlButton"
|
||||
android:contentDescription="@string/player_cast_open"
|
||||
android:src="@drawable/ic_player_cast" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_settings"
|
||||
style="@style/MembyPlayerControlButton"
|
||||
|
||||
@@ -1,64 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- The cast panel. It covers the bottom of somebody's film, so it is a fade rather than a
|
||||
card: the scrim carries the names and the scene stays legible above them. The paddings
|
||||
match the transport row's 48dp side inset, so opening this does not shift the column
|
||||
the title and controls are read in. -->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/player_cast_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#70000000"
|
||||
android:background="@drawable/player_cast_scrim"
|
||||
android:clickable="true"
|
||||
android:clipChildren="false"
|
||||
android:focusable="true"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="340dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@drawable/player_overlay_panel_background"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="48dp"
|
||||
android:paddingTop="25dp"
|
||||
android:paddingTop="20dp"
|
||||
android:paddingEnd="48dp"
|
||||
android:paddingBottom="22dp">
|
||||
android:paddingBottom="34dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:letterSpacing="0.14"
|
||||
android:text="@string/player_now_playing"
|
||||
android:text="@string/player_cast_eyebrow"
|
||||
android:textColor="#FF52B54B"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<!-- The title, not the word "Cast". The eyebrow above already says what the panel
|
||||
is, and a viewer who opened this mid-scene wants confirmation of what they are
|
||||
watching more than a heading repeating the button they just pressed. -->
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/player_cast_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="@string/player_cast"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="#FFFFFFFF"
|
||||
android:textSize="28sp"
|
||||
android:textSize="26sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_cast_status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="18dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:text="@string/player_cast_loading"
|
||||
android:textColor="#AFFFFFFF"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/player_cast_scroller"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="false"
|
||||
android:overScrollMode="never">
|
||||
android:overScrollMode="never"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/player_cast_people"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:gravity="top"
|
||||
android:orientation="horizontal" />
|
||||
</HorizontalScrollView>
|
||||
@@ -66,8 +81,10 @@
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:letterSpacing="0.08"
|
||||
android:text="@string/player_back_to_close"
|
||||
android:textColor="#78FFFFFF"
|
||||
android:textSize="12sp" />
|
||||
android:textColor="#6EFFFFFF"
|
||||
android:textSize="11sp" />
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- What a press of Left or Right just did, and where it lands. It sits over somebody's
|
||||
film, so it is near-black, non-focusable and centred low on the screen where the
|
||||
transport controls would be — the viewer is already looking there. It never opens the
|
||||
transport OSD: skipping is meant to cost one press, not one press plus a menu. -->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/player_seek_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:layout_marginBottom="104dp"
|
||||
android:focusable="false"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/time_remaining_cue_background"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="18dp"
|
||||
android:paddingTop="12dp"
|
||||
android:paddingEnd="22dp"
|
||||
android:paddingBottom="12dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/player_seek_glyph"
|
||||
android:layout_width="26dp"
|
||||
android:layout_height="26dp"
|
||||
android:contentDescription="@null"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_player_forward" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="14dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_seek_amount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#FFFFFFFF"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
tools:text="Forward 30 seconds" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_seek_position"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:textColor="#99FFFFFF"
|
||||
android:textSize="13sp"
|
||||
tools:text="12:34 / 1:45:00" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
@@ -1,107 +1,157 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- A drop-up over the subtitle button rather than a full-height panel: the film keeps
|
||||
playing behind it, so there is no scrim and nothing bigger than the question being
|
||||
asked. The margins line the panel up with the transport row's end inset (48dp) and
|
||||
clear its 72dp button strip plus the controls' 28dp bottom padding; the top margin is
|
||||
what caps how tall the track list can grow before it scrolls.
|
||||
|
||||
The panel holds two screens, not three sections. Choosing a track and fetching one the
|
||||
title does not have are separate questions, and at 344dp by a third of a 720p screen
|
||||
there is not room to ask both — stacking them squeezed the track list to a single row.
|
||||
So `player_subtitle_main_section` and the results half of the download section swap:
|
||||
the search row is the way in, Back is the way out, one press per level. -->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/player_subtitle_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#70000000"
|
||||
android:background="@android:color/transparent"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:visibility="gone">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="520dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginStart="30dp"
|
||||
android:background="@drawable/player_overlay_panel_background"
|
||||
android:id="@+id/player_subtitle_menu"
|
||||
android:layout_width="344dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginTop="96dp"
|
||||
android:layout_marginEnd="44dp"
|
||||
android:layout_marginBottom="112dp"
|
||||
android:background="@drawable/player_menu_background"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="34dp"
|
||||
android:paddingTop="32dp"
|
||||
android:paddingEnd="34dp"
|
||||
android:paddingBottom="26dp">
|
||||
android:paddingStart="10dp"
|
||||
android:paddingTop="14dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:paddingBottom="12dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:letterSpacing="0.14"
|
||||
android:text="@string/player_playback_options"
|
||||
android:textColor="#FF52B54B"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="7dp"
|
||||
android:text="@string/player_subtitles"
|
||||
android:textColor="#FFFFFFFF"
|
||||
android:textSize="30sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
<LinearLayout
|
||||
android:id="@+id/player_subtitle_main_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="7dp"
|
||||
android:lineSpacingExtra="2dp"
|
||||
android:text="@string/player_subtitle_overlay_hint"
|
||||
android:textColor="#AFFFFFFF"
|
||||
android:textSize="14sp" />
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_weight="1"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
android:overScrollMode="never">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="14dp"
|
||||
android:letterSpacing="0.12"
|
||||
android:text="@string/player_subtitle_track"
|
||||
android:textColor="#7AFFFFFF"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:letterSpacing="0.12"
|
||||
android:text="@string/player_subtitle_track"
|
||||
android:textColor="#8FFFFFFF"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold" />
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_weight="1"
|
||||
android:fillViewport="false"
|
||||
android:overScrollMode="never"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/player_subtitle_tracks"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="9dp"
|
||||
android:orientation="vertical" />
|
||||
</ScrollView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="25dp"
|
||||
android:letterSpacing="0.12"
|
||||
android:text="@string/player_text_size"
|
||||
android:textColor="#8FFFFFFF"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold" />
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:background="#14FFFFFF" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:letterSpacing="0.12"
|
||||
android:text="@string/player_text_size"
|
||||
android:textColor="#7AFFFFFF"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/player_subtitle_sizes"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Fetching a subtitle the title does not have. The whole group is GONE on a
|
||||
backend that cannot do it, rather than showing a row that leads nowhere. -->
|
||||
<LinearLayout
|
||||
android:id="@+id/player_subtitle_download_section"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<!-- Hidden with the section above it: with the menu swapped out this heading is
|
||||
the first thing on the panel, and a rule above the first thing is a line
|
||||
under the panel's own top edge. -->
|
||||
<View
|
||||
android:id="@+id/player_subtitle_download_rule"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:background="#14FFFFFF" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:letterSpacing="0.12"
|
||||
android:text="@string/player_subtitle_download"
|
||||
android:textColor="#7AFFFFFF"
|
||||
android:textSize="11sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_subtitle_download_status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:textColor="#96FFFFFF"
|
||||
android:textSize="12sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_weight="1"
|
||||
android:fillViewport="false"
|
||||
android:overScrollMode="never"
|
||||
android:scrollbars="none">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/player_subtitle_sizes"
|
||||
android:id="@+id/player_subtitle_downloads"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="9dp"
|
||||
android:orientation="vertical" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="14dp"
|
||||
android:text="@string/player_back_to_close"
|
||||
android:textColor="#78FFFFFF"
|
||||
android:textSize="12sp" />
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
||||
Reference in New Issue
Block a user