Files
PinPoint/app/src/main/res/layout-land/activity_bowling_camera.xml
T

198 lines
8.4 KiB
XML
Raw Normal View History

2026-08-11 19:46:54 +08:00
<?xml version="1.0" encoding="utf-8"?>
<!--
Landscape button arrangement: with the screen wide and short, a bottom bar
(see the portrait default in res/layout/) would leave little room for the
preview and put the record button awkwardly close to the edge, so it moves
to a vertically-centered side column instead. Same view IDs as the
portrait layout so BowlingCameraActivity's view-binding code needs no
orientation-specific logic - Android just swaps which XML gets inflated.
-->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
tools:context=".bowling.BowlingCameraActivity">
<androidx.camera.view.PreviewView
android:id="@+id/camera_preview"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<com.example.jnicpp.bowling.PoseOverlayView
android:id="@+id/pose_overlay"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="@id/camera_preview"
app:layout_constraintBottom_toBottomOf="@id/camera_preview"
app:layout_constraintStart_toStartOf="@id/camera_preview"
app:layout_constraintEnd_toEndOf="@id/camera_preview" />
<!--
Recording indicator: red dot + elapsed timer, only visible while
recording. Anchored below btn_back (rather than parent's top) so the
two never overlap - btn_back is declared later in this file so it
draws on top, but ConstraintLayout resolves constraint references
regardless of declaration order, so this forward reference is fine.
-->
<LinearLayout
android:id="@+id/layout_recording_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:background="@color/overlay_scrim"
android:paddingHorizontal="12dp"
android:paddingVertical="6dp"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toBottomOf="@id/btn_back"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginTop="8dp"
android:layout_marginStart="16dp">
<View
android:id="@+id/view_recording_dot"
android:layout_width="12dp"
android:layout_height="12dp"
android:background="@drawable/shape_recording_dot" />
<TextView
android:id="@+id/text_timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="@string/recording_timer_placeholder"
android:textColor="@color/white"
android:textSize="16sp"
android:fontFamily="monospace" />
2026-08-14 18:16:55 +08:00
<!-- Live step counter, resets to 0 when the bowler returns to a
stationary starting stance mid-recording (see LiveStepDetector). -->
<TextView
android:id="@+id/text_step_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="@string/step_count_placeholder"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold" />
2026-08-11 19:46:54 +08:00
</LinearLayout>
<!-- Live "you're in your final position" banner, shown once the 5th
(final) foot-plant of the current attempt is detected (see
BowlingCameraActivity's stepEvents collector), cleared automatically
whenever the step count resets for the next attempt. Centered
horizontally regardless of orientation, anchored below the top
corner buttons so it never overlaps them. -->
<TextView
android:id="@+id/text_final_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/overlay_scrim"
android:paddingHorizontal="20dp"
android:paddingVertical="10dp"
android:text="@string/final_position_reached"
android:textColor="@color/final_position_highlight"
android:textSize="22sp"
android:textStyle="bold"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toBottomOf="@id/btn_switch_camera"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp" />
2026-08-11 19:46:54 +08:00
<!--
2026-08-12 12:46:33 +08:00
Mirrored onto the start edge at the same vertical center as btn_record
on the end edge. Live pose overlay + baked-in-recording toggle; only
togglable while not recording (see
BowlingCameraActivity#renderRecordingState) since the recording
pipeline picks its pose mode once at start.
2026-08-11 19:46:54 +08:00
-->
2026-08-12 12:46:33 +08:00
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switch_pose"
2026-08-11 19:46:54 +08:00
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
2026-08-12 12:46:33 +08:00
android:text="@string/toggle_pose"
android:textColor="@color/white"
app:layout_constraintTop_toTopOf="@id/btn_record"
app:layout_constraintBottom_toBottomOf="@id/btn_record"
2026-08-11 19:46:54 +08:00
app:layout_constraintStart_toStartOf="parent" />
2026-08-12 12:46:33 +08:00
<!-- Side column instead of a bottom bar: vertically centered, hugging the end edge. -->
2026-08-11 19:46:54 +08:00
<Button
2026-08-12 12:46:33 +08:00
android:id="@+id/btn_record"
2026-08-11 19:46:54 +08:00
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
2026-08-12 12:46:33 +08:00
android:text="@string/record"
2026-08-11 19:46:54 +08:00
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
2026-08-12 12:46:33 +08:00
<!-- Above the record button in the same side column, rather than the top corner. -->
2026-08-11 19:46:54 +08:00
<Button
android:id="@+id/btn_switch_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/switch_camera"
2026-08-12 12:46:33 +08:00
app:layout_constraintBottom_toTopOf="@id/btn_record"
app:layout_constraintEnd_toEndOf="@id/btn_record" />
2026-08-11 19:46:54 +08:00
<!-- Shown instead of the camera UI when CAMERA/RECORD_AUDIO aren't granted -->
<LinearLayout
android:id="@+id/layout_permission_rationale"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="24dp"
android:background="@color/black"
android:visibility="gone"
tools:visibility="visible"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<TextView
android:id="@+id/text_permission_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/permission_rationale_message"
android:textColor="@color/white"
android:textSize="16sp"
android:gravity="center"
android:layout_marginBottom="16dp" />
<Button
android:id="@+id/btn_grant_permissions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/grant_permissions" />
</LinearLayout>
<!-- Declared last so it draws above the permission rationale screen too,
keeping a way back out of this Activity available in every state. -->
<Button
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:text="@string/back"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>