Merge pull request #72 from screentinker/feat/player-orientation

feat(player): software orientation (portrait + flipped), Android + Tizen (1.7.12)
This commit is contained in:
screentinker 2026-06-09 21:43:12 -05:00 committed by GitHub
commit 26cd29c530
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 57 additions and 3 deletions

View file

@ -1 +1 @@
1.7.11
1.7.12

View file

@ -11,8 +11,8 @@ android {
applicationId = "com.remotedisplay.player"
minSdk = 26
targetSdk = 34
versionCode = 14
versionName = "1.7.11"
versionCode = 15
versionName = "1.7.12"
}
signingConfigs {

View file

@ -52,6 +52,7 @@ class MainActivity : AppCompatActivity() {
private lateinit var statusOverlay: View
private lateinit var statusText: TextView
private lateinit var rootView: View
private var currentOrientation: String? = null
private val handler = Handler(Looper.getMainLooper())
private var remoteStreaming = false
@ -198,9 +199,40 @@ class MainActivity : AppCompatActivity() {
}
// Rotate the whole stage in software so portrait / flipped signage works even on
// fixed-landscape hardware (Fire TV, Android TV and most signage sticks ignore
// setRequestedOrientation - they can't physically rotate the panel). Resizes
// rootView to the rotated dimensions, recenters, and rotates. Covers single-zone
// (playerView/imageView/youtubeWebView) and multi-zone (ZoneManager renders into
// the same rootView). Values mirror the dashboard: landscape / portrait /
// landscape-flipped / portrait-flipped.
private fun applyOrientation(orientation: String) {
if (orientation == currentOrientation) return
currentOrientation = orientation
val m = resources.displayMetrics
val w = m.widthPixels.toFloat()
val h = m.heightPixels.toFloat()
val (rot, swap) = when (orientation) {
"portrait" -> 90f to true
"portrait-flipped" -> 270f to true
"landscape-flipped" -> 180f to false
else -> 0f to false // landscape
}
val lp = rootView.layoutParams
lp.width = (if (swap) h else w).toInt()
lp.height = (if (swap) w else h).toInt()
rootView.layoutParams = lp
rootView.translationX = if (swap) (w - h) / 2f else 0f
rootView.translationY = if (swap) (h - w) / 2f else 0f
rootView.rotation = rot
rootView.requestLayout()
Log.i("MainActivity", "Applied orientation: $orientation (rotation=$rot, swap=$swap)")
}
private fun setupServiceCallbacks() {
wsService?.onPlaylistUpdate = { data ->
try {
applyOrientation(data.optString("orientation", "landscape"))
// Check if device is suspended (trial expired / over limit)
if (data.optBoolean("suspended", false)) {
val message = data.optString("message", "Account Suspended")

View file

@ -192,8 +192,30 @@
// ---- playback ----
var player = new PlaylistPlayer(elStage, function () { return serverUrl.replace(/\/+$/, ''); });
// Rotate the playback stage in software for portrait / flipped signage. Tizen TVs
// are fixed-landscape, so we rotate the CONTENT (not the panel). Values mirror the
// dashboard: landscape / portrait / landscape-flipped / portrait-flipped.
function applyOrientation(o) {
var s = elStage;
if (!o || o === 'landscape') {
s.style.position = ''; s.style.top = ''; s.style.left = '';
s.style.width = ''; s.style.height = ''; s.style.transform = ''; s.style.transformOrigin = '';
return;
}
var deg = o === 'portrait' ? 90 : o === 'portrait-flipped' ? 270 : o === 'landscape-flipped' ? 180 : 0;
var swap = (deg === 90 || deg === 270);
s.style.position = 'absolute';
s.style.top = '50%';
s.style.left = '50%';
s.style.width = swap ? '100vh' : '100vw';
s.style.height = swap ? '100vw' : '100vh';
s.style.transformOrigin = 'center center';
s.style.transform = 'translate(-50%, -50%) rotate(' + deg + 'deg)';
}
function onPlaylist(payload) {
if (!payload) return;
applyOrientation(payload.orientation || 'landscape');
if (payload.suspended) {
player.stop();
elStage.innerHTML = '<div class="card" style="position:relative"><h1>' +