mirror of
https://gitlab.com/vyla-entertainment/go.git
synced 2026-11-14 07:27:23 -05:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 23c2cd53c5 | |||
| 7b6fc838b8 | |||
| 60b24bf9e4 | |||
| 3958f751ee |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vyla-go",
|
"name": "vyla-go",
|
||||||
"version": "1.0.13",
|
"version": "1.0.15",
|
||||||
"description": "Vyla Go Mobile Launcher",
|
"description": "Vyla Go Mobile Launcher",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -1,36 +1,73 @@
|
|||||||
package com.vyla.go
|
package com.vyla.go
|
||||||
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Color
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.WindowManager
|
||||||
import android.view.ViewGroup
|
import android.webkit.JavascriptInterface
|
||||||
import android.webkit.WebChromeClient
|
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
|
|
||||||
class MainActivity : TauriActivity() {
|
class MainActivity : TauriActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
private var webView: WebView? = null
|
||||||
super.onCreate(savedInstanceState)
|
private var insetTop = 0f
|
||||||
|
private var insetRight = 0f
|
||||||
|
private var insetBottom = 0f
|
||||||
|
private var insetLeft = 0f
|
||||||
|
|
||||||
val root = findViewById<ViewGroup>(android.R.id.content)
|
private inner class InsetBridge {
|
||||||
root.viewTreeObserver.addOnGlobalLayoutListener {
|
@JavascriptInterface
|
||||||
findAndHookWebView(root)
|
fun get(): String =
|
||||||
}
|
"{\"top\":$insetTop,\"right\":$insetRight,\"bottom\":$insetBottom,\"left\":$insetLeft}"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findAndHookWebView(view: View) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
if (view is WebView) {
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
view.webChromeClient = object : WebChromeClient() {
|
window.statusBarColor = Color.TRANSPARENT
|
||||||
override fun getDefaultVideoPoster(): Bitmap {
|
window.navigationBarColor = Color.TRANSPARENT
|
||||||
return Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
}
|
window.isNavigationBarContrastEnforced = false
|
||||||
}
|
window.isStatusBarContrastEnforced = false
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
|
window.attributes.layoutInDisplayCutoutMode =
|
||||||
|
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||||
|
}
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
WindowInsetsControllerCompat(window, window.decorView).apply {
|
||||||
|
isAppearanceLightStatusBars = false
|
||||||
|
isAppearanceLightNavigationBars = false
|
||||||
|
}
|
||||||
|
ViewCompat.setOnApplyWindowInsetsListener(window.decorView) { _, insets ->
|
||||||
|
val bars = insets.getInsets(
|
||||||
|
WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout()
|
||||||
|
)
|
||||||
|
val d = resources.displayMetrics.density
|
||||||
|
insetTop = bars.top / d
|
||||||
|
insetRight = bars.right / d
|
||||||
|
insetBottom = bars.bottom / d
|
||||||
|
insetLeft = bars.left / d
|
||||||
|
pushInsets()
|
||||||
|
insets
|
||||||
|
}
|
||||||
|
ViewCompat.requestApplyInsets(window.decorView)
|
||||||
|
}
|
||||||
|
|
||||||
if (view is ViewGroup) {
|
override fun onWebViewCreate(webView: WebView) {
|
||||||
for (i in 0 until view.childCount) {
|
this.webView = webView
|
||||||
findAndHookWebView(view.getChildAt(i))
|
webView.addJavascriptInterface(InsetBridge(), "VylaInsets")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun pushInsets() {
|
||||||
|
val wv = webView ?: return
|
||||||
|
wv.post {
|
||||||
|
wv.evaluateJavascript(
|
||||||
|
"window.__vylaApplyInsets&&window.__vylaApplyInsets($insetTop,$insetRight,$insetBottom,$insetLeft)",
|
||||||
|
null
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,6 +132,28 @@ process.on('uncaughtException', (e) => console.error('uncaughtException', e && e
|
|||||||
process.on('unhandledRejection', (e) => console.error('unhandledRejection', e && e.stack || e));
|
process.on('unhandledRejection', (e) => console.error('unhandledRejection', e && e.stack || e));
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
const LAUNCHER_SCRIPT: &str = r#"
|
||||||
|
const path = require('path');
|
||||||
|
const { pathToFileURL } = require('url');
|
||||||
|
|
||||||
|
async function boot(file, port) {
|
||||||
|
process.env.PORT = String(port);
|
||||||
|
try {
|
||||||
|
await import(pathToFileURL(file).href);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('failed to start ' + file, e && e.stack || e);
|
||||||
|
} finally {
|
||||||
|
process.env.PORT = '3000';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const root = process.env.VYLA_ROOT;
|
||||||
|
await boot(path.join(root, 'player', 'server.js'), 3000);
|
||||||
|
await boot(path.join(root, 'frontend', 'server.js'), 3001);
|
||||||
|
})();
|
||||||
|
"#;
|
||||||
|
|
||||||
fn android_log(msg: &str) {
|
fn android_log(msg: &str) {
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
{
|
{
|
||||||
@@ -261,7 +283,10 @@ fn spawn_service_manager(base_dir: &std::path::Path) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let server_js = server_script.to_string_lossy().to_string();
|
let launcher_path = base_dir.join("launcher.js");
|
||||||
|
let _ = std::fs::write(&launcher_path, LAUNCHER_SCRIPT);
|
||||||
|
std::env::set_var("VYLA_ROOT", base_dir.to_string_lossy().to_string());
|
||||||
|
let server_js = launcher_path.to_string_lossy().to_string();
|
||||||
let player_dir_str = player_dir.to_string_lossy().to_string();
|
let player_dir_str = player_dir.to_string_lossy().to_string();
|
||||||
|
|
||||||
let _ = std::thread::Builder::new().stack_size(16 * 1024 * 1024).spawn(move || {
|
let _ = std::thread::Builder::new().stack_size(16 * 1024 * 1024).spawn(move || {
|
||||||
@@ -300,6 +325,7 @@ fn spawn_service_manager(base_dir: &std::path::Path) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let _ = wait_for_port(3000, Duration::from_secs(45));
|
let _ = wait_for_port(3000, Duration::from_secs(45));
|
||||||
|
let _ = wait_for_port(3001, Duration::from_secs(45));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_directory_replacements(dir: &std::path::Path, find_val: &str, replace_val: &str) {
|
fn apply_directory_replacements(dir: &std::path::Path, find_val: &str, replace_val: &str) {
|
||||||
@@ -355,7 +381,8 @@ async fn download_and_extract_payload(app: tauri::AppHandle, window: WebviewWind
|
|||||||
let marker = base_dir.join(".installed");
|
let marker = base_dir.join(".installed");
|
||||||
let frontend_index = base_dir.join("frontend").join("index.html");
|
let frontend_index = base_dir.join("frontend").join("index.html");
|
||||||
let server_script = base_dir.join("player").join("server.js");
|
let server_script = base_dir.join("player").join("server.js");
|
||||||
if marker.exists() && frontend_index.exists() && server_script.exists() {
|
let frontend_server = base_dir.join("frontend").join("server.js");
|
||||||
|
if marker.exists() && frontend_index.exists() && server_script.exists() && frontend_server.exists() {
|
||||||
android_log("App already installed, launching...");
|
android_log("App already installed, launching...");
|
||||||
apply_patches(&base_dir);
|
apply_patches(&base_dir);
|
||||||
spawn_service_manager(&base_dir);
|
spawn_service_manager(&base_dir);
|
||||||
@@ -363,7 +390,6 @@ async fn download_and_extract_payload(app: tauri::AppHandle, window: WebviewWind
|
|||||||
return Ok(base_dir);
|
return Ok(base_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Check if a valid local archive already exists on device
|
|
||||||
let local_payload_candidates = [
|
let local_payload_candidates = [
|
||||||
base_dir.join("update-payload.zip"),
|
base_dir.join("update-payload.zip"),
|
||||||
base_dir.join("temp-payload.zip"),
|
base_dir.join("temp-payload.zip"),
|
||||||
@@ -600,9 +626,37 @@ const ANDROID_VIDEO_FIX_SCRIPT: &str = r#"
|
|||||||
})();
|
})();
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
const EDGE_TO_EDGE_SCRIPT: &str = r#"
|
||||||
|
(function() {
|
||||||
|
var m = document.querySelector('meta[name=viewport]');
|
||||||
|
if (m && m.content.indexOf('viewport-fit') === -1) {
|
||||||
|
m.content += ', viewport-fit=cover';
|
||||||
|
}
|
||||||
|
function apply(t, r, b, l) {
|
||||||
|
var s = document.documentElement.style;
|
||||||
|
s.setProperty('--safe-top', t + 'px');
|
||||||
|
s.setProperty('--safe-right', r + 'px');
|
||||||
|
s.setProperty('--safe-bottom', b + 'px');
|
||||||
|
s.setProperty('--safe-left', l + 'px');
|
||||||
|
}
|
||||||
|
window.__vylaApplyInsets = apply;
|
||||||
|
try {
|
||||||
|
if (window.VylaInsets) {
|
||||||
|
var v = JSON.parse(window.VylaInsets.get());
|
||||||
|
apply(v.top, v.right, v.bottom, v.left);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
})();
|
||||||
|
"#;
|
||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
.on_page_load(|webview, payload| {
|
||||||
|
if payload.event() == tauri::webview::PageLoadEvent::Finished {
|
||||||
|
let _ = webview.eval(EDGE_TO_EDGE_SCRIPT);
|
||||||
|
}
|
||||||
|
})
|
||||||
.plugin(tauri_plugin_shell::init())
|
.plugin(tauri_plugin_shell::init())
|
||||||
.plugin(tauri_plugin_process::init())
|
.plugin(tauri_plugin_process::init())
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
@@ -681,7 +735,7 @@ pub fn run() {
|
|||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(400));
|
std::thread::sleep(std::time::Duration::from_millis(400));
|
||||||
let _ = window.eval(&format!(
|
let _ = window.eval(&format!(
|
||||||
"{}; window.location.replace('http://vyla.localhost/frontend/index.html');",
|
"{}; window.location.replace('http://localhost:3001/');",
|
||||||
ANDROID_VIDEO_FIX_SCRIPT
|
ANDROID_VIDEO_FIX_SCRIPT
|
||||||
));
|
));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "Vyla Go",
|
"productName": "Vyla Go",
|
||||||
"version": "1.0.13",
|
"version": "1.0.15",
|
||||||
"identifier": "com.vyla.go",
|
"identifier": "com.vyla.go",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "",
|
"beforeDevCommand": "",
|
||||||
|
|||||||
@@ -3,9 +3,17 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
<meta name="viewport"
|
||||||
|
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
||||||
<title>Vyla Go</title>
|
<title>Vyla Go</title>
|
||||||
<style>
|
<style>
|
||||||
|
:root {
|
||||||
|
--safe-top: env(safe-area-inset-top, 0px);
|
||||||
|
--safe-right: env(safe-area-inset-right, 0px);
|
||||||
|
--safe-bottom: env(safe-area-inset-bottom, 0px);
|
||||||
|
--safe-left: env(safe-area-inset-left, 0px);
|
||||||
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -62,7 +70,7 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
padding: 20px 16px 30px 16px;
|
padding: 20px calc(16px + var(--safe-right)) calc(30px + var(--safe-bottom)) calc(16px + var(--safe-left));
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -122,7 +130,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="center-brand">
|
<div class="center-brand">
|
||||||
<img src="https://gitlab.com/vyla-entertainment/go/-/raw/main/assets/logos/white_logo.png" alt="Logo" />
|
<img src="/white_logo.png" alt="Logo" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bottom-dock">
|
<div class="bottom-dock">
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Reference in New Issue
Block a user