diff --git a/VERSION b/VERSION index 8f8b3f7..e6a68e9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.7.11 +1.7.12 diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index ab9c1ee..6cb10cd 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -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 { diff --git a/android/app/src/main/java/com/remotedisplay/player/MainActivity.kt b/android/app/src/main/java/com/remotedisplay/player/MainActivity.kt index 4916ac4..8da5f5e 100644 --- a/android/app/src/main/java/com/remotedisplay/player/MainActivity.kt +++ b/android/app/src/main/java/com/remotedisplay/player/MainActivity.kt @@ -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") diff --git a/tizen/js/app.js b/tizen/js/app.js index efd5bf8..a1c62ac 100644 --- a/tizen/js/app.js +++ b/tizen/js/app.js @@ -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 = '