diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3b60b54..84cc633 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -11,8 +11,8 @@ android { applicationId = "me.lecaro.breakout" minSdk = 21 targetSdk = 34 - versionCode = 29038230 - versionName = "29038230" + versionCode = 29038466 + versionName = "29038466" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary = true diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0864465..644eaef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,10 +1,6 @@ - - + \ No newline at end of file diff --git a/app/src/main/assets/index.html b/app/src/main/assets/index.html index 8df477a..0b3aaeb 100644 --- a/app/src/main/assets/index.html +++ b/app/src/main/assets/index.html @@ -1 +1,3764 @@ -Breakout 71 \ No newline at end of file + + + + + + + Breakout 71 + + + + + + + + + + + + + diff --git a/app/src/main/java/me/lecaro/breakout/MainActivity.kt b/app/src/main/java/me/lecaro/breakout/MainActivity.kt index 04456e2..130c978 100644 --- a/app/src/main/java/me/lecaro/breakout/MainActivity.kt +++ b/app/src/main/java/me/lecaro/breakout/MainActivity.kt @@ -2,12 +2,15 @@ package me.lecaro.breakout import android.app.Activity import android.app.DownloadManager +import android.content.ContentValues import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.net.Uri +import android.os.Build import android.os.Bundle import android.os.Environment +import android.provider.MediaStore import android.util.Log import android.view.Window import android.view.WindowManager @@ -35,8 +38,7 @@ class MainActivity : android.app.Activity() { if (resultCode == RESULT_OK) { filePathCallback?.onReceiveValue( WebChromeClient.FileChooserParams.parseResult( - resultCode, - data + resultCode, data ) ) filePathCallback = null @@ -44,68 +46,81 @@ class MainActivity : android.app.Activity() { } } } - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - when (requestCode) { - PERM_REQUEST_CODE -> { - if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) { - downloadFile() - } else { - Toast.makeText(this, "We cant make a save file without that permission", Toast.LENGTH_SHORT).show() - } - return - } - } - } - var filePathCallback: ValueCallback>? = null - var fileToDownload:String? = null - fun downloadFile(){ - val url = fileToDownload ?: return - try{ + var filePathCallback: ValueCallback>? = null + + private fun downloadFile(url: String) { + try { if (!url.startsWith("data:")) { Log.w("DL", "url ignored because it does not start with data:") return } val sdf = SimpleDateFormat("yyyy-M-dd-hh-mm") val currentDate = sdf.format(Date()) - // Extract filename from contentDisposition if available - + val base64Data = url.substringAfterLast(',') + val decodedBytes = android.util.Base64.decode(base64Data, android.util.Base64.DEFAULT) if (url.startsWith("data:application/json;base64,")) { - Log.d("DL", "saving application/json ") - val base64Data = url.substringAfterLast(',') - val decodedBytes = - android.util.Base64.decode(base64Data, android.util.Base64.DEFAULT) - val jsonData = String(decodedBytes); - val dir = - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) - val fileName = "breakout-71-save-$currentDate.b71" - val file = File(dir, fileName) - file.writeText(jsonData) - Toast.makeText(this, "Saved in $dir", Toast.LENGTH_LONG).show() - Log.d("DL", "finished saving application/json ") + writeFile(decodedBytes, "breakout-71-save-$currentDate.b71", "application/b71") } else if (url.startsWith("data:video/webm;base64,")) { - Log.d("DL", "saving video/webm ") - // TODO - Log.d("DL", "finished savign video/webm ") + writeFile(decodedBytes, "breakout-71-gameplay-capture-$currentDate.webm", "application/b71") } else { Log.w("DL", "unexpected type " + url) } - }catch (e:Exception){ - Log.e("DL", "Error ${e.message}") - Toast.makeText(this, "Error ${e.message}", Toast.LENGTH_LONG).show() - - } - - + } catch (e: Exception) { + Log.e("DL", "Error ${e.message}") + Toast.makeText(this, "Error ${e.message}", Toast.LENGTH_LONG).show() + } } + + fun writeFile(decodedBytes:ByteArray,fileName:String, mime:String){ + + + + val jsonData = String(decodedBytes); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + + + val contentValues = ContentValues().apply { + put(MediaStore.Downloads.DISPLAY_NAME, fileName) + put(MediaStore.Downloads.MIME_TYPE,mime ) + put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS) + } + + val uri: Uri? = contentResolver.insert( + MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues + ) + uri?.let { + contentResolver.openOutputStream(it)?.use { outputStream -> + outputStream.write(decodedBytes) + } + } + + val shareIntent: Intent = Intent().apply { + action = Intent.ACTION_SEND + // Example: content://com.google.android.apps.photos.contentprovider/... + putExtra(Intent.EXTRA_STREAM, uri) + type = mime + } + startActivity(Intent.createChooser(shareIntent, null)) + + } else { + + + val dir = getExternalFilesDir(null) + val file = File(dir, fileName) + file.writeText(jsonData) + Toast.makeText(this, "Saved in $dir", Toast.LENGTH_LONG).show() + + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestWindowFeature(Window.FEATURE_NO_TITLE); window.setFlags( - WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN + WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN ); val webView = WebView(this) webView.settings.javaScriptEnabled = true @@ -113,13 +128,13 @@ class MainActivity : android.app.Activity() { webView.settings.setSupportZoom(false) webView.loadUrl("file:///android_asset/index.html?isInWebView=true") - val activity=this; + val activity = this; webView.webChromeClient = object : WebChromeClient() { override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean { Log.d( - "WebView", "${consoleMessage.message()} -- From line " + - "${consoleMessage.lineNumber()} of ${consoleMessage.sourceId()}" + "WebView", + "${consoleMessage.message()} -- From line " + "${consoleMessage.lineNumber()} of ${consoleMessage.sourceId()}" ) return true } @@ -129,13 +144,15 @@ class MainActivity : android.app.Activity() { filePathCallback: ValueCallback>?, fileChooserParams: FileChooserParams? ): Boolean { - try{ + try { - startActivityForResult(fileChooserParams?.createIntent(), CHOOSE_FILE_REQUEST_CODE) + startActivityForResult( + fileChooserParams?.createIntent(), CHOOSE_FILE_REQUEST_CODE + ) this@MainActivity.filePathCallback = filePathCallback return true - }catch (e:Exception){ - Log.e("DL", "Error ${e.message}") + } catch (e: Exception) { + Log.e("DL", "Error ${e.message}") Toast.makeText(activity, "Error ${e.message}", Toast.LENGTH_LONG).show() return false @@ -144,18 +161,11 @@ class MainActivity : android.app.Activity() { } webView.setDownloadListener(DownloadListener { url, userAgent, contentDisposition, mimetype, contentLength -> - - fileToDownload = url - if (activity.checkSelfPermission( android.Manifest.permission.WRITE_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { - activity.requestPermissions(arrayOf( android.Manifest.permission.WRITE_EXTERNAL_STORAGE), PERM_REQUEST_CODE) - }else{ - downloadFile() - } + downloadFile(url) }) setContentView(webView) } -} +} \ No newline at end of file diff --git a/dist/PWA/sw-b71.js b/dist/PWA/sw-b71.js index f4f4e03..7f48046 100644 --- a/dist/PWA/sw-b71.js +++ b/dist/PWA/sw-b71.js @@ -1,2 +1,33 @@ -function e(e,t,n,r,a,i,c){try{var o=e[i](c),u=o.value}catch(e){n(e);return}o.done?t(u):Promise.resolve(u).then(r,a)}function t(t){return function(){var n=this,r=arguments;return new Promise(function(a,i){var c=t.apply(n,r);function o(t){e(c,a,i,o,u,"next",t)}function u(t){e(c,a,i,o,u,"throw",t)}o(void 0)})}}function n(e,t){var n,r,a,i,c={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]};return i={next:o(0),throw:o(1),return:o(2)},"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function o(i){return function(o){return function(i){if(n)throw TypeError("Generator is already executing.");for(;c;)try{if(n=1,r&&(a=2&i[0]?r.return:i[0]?r.throw||((a=r.return)&&a.call(r),0):r.next)&&!(a=a.call(r,i[1])).done)return a;switch(r=0,a&&(i=[2&i[0],a.value]),i[0]){case 0:case 1:a=i;break;case 4:return c.label++,{value:i[1],done:!1};case 5:c.label++,r=i[1],i=[0];continue;case 7:i=c.ops.pop(),c.trys.pop();continue;default:if(!(a=(a=c.trys).length>0&&a[a.length-1])&&(6===i[0]||2===i[0])){c=0;continue}if(3===i[0]&&(!a||i[1]>a[0]&&i[1]{ + event.waitUntil((async ()=>{ + const cache = await caches.open(CACHE_NAME); + cache.addAll(APP_STATIC_RESOURCES); + })()); +}); +// delete old caches on activate +self.addEventListener("activate", (event)=>{ + event.waitUntil((async ()=>{ + const names = await caches.keys(); + await Promise.all(names.map((name)=>{ + if (name !== CACHE_NAME) return caches.delete(name); + })); + await clients.claim(); + })()); +}); +self.addEventListener("fetch", (event)=>{ + if (event.request.mode === "navigate" && event.request.url.endsWith("/index.html?isPWA=true")) { + event.respondWith(caches.match("/")); + return; + } +}); + //# sourceMappingURL=sw-b71.js.map diff --git a/dist/PWA/sw-b71.js.map b/dist/PWA/sw-b71.js.map index ea084fe..2de9db7 100644 --- a/dist/PWA/sw-b71.js.map +++ b/dist/PWA/sw-b71.js.map @@ -1 +1 @@ -{"mappings":"A,S,E,C,C,C,C,C,C,C,C,C,C,C,C,C,E,G,C,I,E,C,C,E,C,G,E,E,K,A,C,M,E,C,E,G,M,C,E,I,C,E,G,Q,O,C,G,I,C,E,E,C,S,E,C,E,O,W,I,E,I,C,E,U,O,I,Q,S,C,C,C,E,I,E,E,K,C,E,G,S,E,C,E,E,E,E,E,E,E,O,E,C,S,E,C,E,E,E,E,E,E,E,Q,E,C,E,K,E,E,C,C,S,E,C,C,C,E,I,E,E,E,E,E,C,M,E,K,W,G,A,E,C,C,E,C,M,C,C,E,C,O,C,C,E,A,E,K,E,C,I,E,A,E,O,E,C,K,E,G,M,E,G,O,E,E,E,A,Y,O,Q,C,C,C,O,Q,C,C,W,O,I,A,C,E,E,S,E,C,E,O,S,C,E,O,A,S,C,E,G,E,M,A,U,mC,K,G,G,C,G,E,E,G,C,E,A,E,C,C,E,C,E,M,C,C,C,E,C,E,K,E,C,A,C,E,E,M,A,G,E,I,C,G,C,E,E,I,A,G,C,A,C,E,E,I,C,E,C,C,E,C,E,I,C,O,E,O,E,E,A,G,C,E,C,A,E,C,C,E,C,E,K,C,A,E,C,C,E,E,K,E,K,E,E,E,K,M,E,O,E,K,G,C,M,C,C,E,C,K,C,C,C,M,E,E,K,G,E,C,C,E,C,E,C,E,C,Q,M,E,E,E,G,C,G,G,E,I,C,G,G,Q,S,G,C,C,E,A,C,E,E,I,A,E,M,C,G,C,C,E,M,C,E,A,G,C,A,I,C,C,E,E,A,I,C,C,E,A,E,C,E,E,Q,C,G,A,I,C,C,E,E,C,C,G,C,C,E,C,C,C,E,E,C,C,E,C,C,C,E,A,E,C,E,K,C,C,C,E,C,K,C,G,A,I,C,C,E,E,E,K,C,C,C,E,C,C,E,K,C,C,C,E,C,E,E,K,C,G,G,E,K,C,C,C,E,C,C,E,K,C,C,C,E,C,E,G,C,I,C,G,K,C,C,C,E,E,E,G,C,G,G,E,I,C,G,G,Q,C,E,E,I,C,E,E,C,M,E,C,E,C,E,E,C,E,C,Q,C,E,E,C,C,G,A,E,C,C,E,C,M,C,C,E,C,M,C,M,C,C,E,C,C,C,E,C,K,E,K,C,C,C,E,C,E,E,C,C,C,CCIA,IAAM,EAAc,eAAsB,MAAA,CAH1B,YAMV,EAAuB,CAAC,IAAI,CAGlC,KAAK,gBAAgB,CAAC,UAAW,SAAC,CAAlC,EACE,EAAM,SAAS,CACb,EAAC,W,O,E,I,C,S,C,E,O,E,K,E,K,EACe,MAAA,C,EAAM,OAAO,IAAI,CAAC,G,A,M,E,OAChC,AADc,EAAR,IAAA,GACA,MAAM,CAAC,G,C,E,A,C,EACf,KAEJ,GAGA,KAAK,gBAAgB,CAAC,WAAY,SAAC,CAAnC,EACE,EAAM,SAAS,CACb,EAAC,W,O,E,I,C,S,C,E,O,E,K,E,K,EACe,MAAA,C,EAAM,OAAO,IAAI,G,A,M,EAC/B,MAAA,C,EAAM,QAAQ,GAAG,CACf,AAFY,EAAR,IAAA,GAEE,GAAG,CAAC,SAAC,CADP,EAEF,GAAI,IAAS,EACX,OAAO,OAAO,MAAM,CAAC,EAEzB,I,A,M,EAEF,OAPA,EAAA,IAAA,GAOA,C,EAAM,QAAQ,KAAK,G,A,M,E,OAAnB,EAAA,IAAA,G,C,E,A,C,EACF,KAEJ,GAEA,KAAK,gBAAgB,CAAC,QAAS,SAAC,CAAhC,EACE,GACE,AAAuB,aAAvB,EAAM,OAAO,CAAC,IAAI,EAClB,EAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,0BAC3B,CACA,EAAM,WAAW,CAAC,OAAO,KAAK,CAAC,MAC/B,MACF,CACF","sources":["","src/PWA/sw-b71.js"],"sourcesContent":["// The version of the cache.\nfunction asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {\n try {\n var info = gen[key](arg);\n var value = info.value;\n } catch (error) {\n reject(error);\n return;\n }\n if (info.done) {\n resolve(value);\n } else {\n Promise.resolve(value).then(_next, _throw);\n }\n}\nfunction _async_to_generator(fn) {\n return function() {\n var self1 = this, args = arguments;\n return new Promise(function(resolve, reject) {\n var gen = fn.apply(self1, args);\n function _next(value) {\n asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"next\", value);\n }\n function _throw(err) {\n asyncGeneratorStep(gen, resolve, reject, _next, _throw, \"throw\", err);\n }\n _next(undefined);\n });\n };\n}\nfunction _ts_generator(thisArg, body) {\n var f, y, t, g, _ = {\n label: 0,\n sent: function() {\n if (t[0] & 1) throw t[1];\n return t[1];\n },\n trys: [],\n ops: []\n };\n return g = {\n next: verb(0),\n \"throw\": verb(1),\n \"return\": verb(2)\n }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() {\n return this;\n }), g;\n function verb(n) {\n return function(v) {\n return step([\n n,\n v\n ]);\n };\n }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while(_)try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [\n op[0] & 2,\n t.value\n ];\n switch(op[0]){\n case 0:\n case 1:\n t = op;\n break;\n case 4:\n _.label++;\n return {\n value: op[1],\n done: false\n };\n case 5:\n _.label++;\n y = op[1];\n op = [\n 0\n ];\n continue;\n case 7:\n op = _.ops.pop();\n _.trys.pop();\n continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {\n _ = 0;\n continue;\n }\n if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {\n _.label = op[1];\n break;\n }\n if (op[0] === 6 && _.label < t[1]) {\n _.label = t[1];\n t = op;\n break;\n }\n if (t && _.label < t[2]) {\n _.label = t[2];\n _.ops.push(op);\n break;\n }\n if (t[2]) _.ops.pop();\n _.trys.pop();\n continue;\n }\n op = body.call(thisArg, _);\n } catch (e) {\n op = [\n 6,\n e\n ];\n y = 0;\n } finally{\n f = t = 0;\n }\n if (op[0] & 5) throw op[1];\n return {\n value: op[0] ? op[1] : void 0,\n done: true\n };\n }\n}\nvar VERSION = \"29038230\";\n// The name of the cache\nvar CACHE_NAME = \"breakout-71-\".concat(VERSION);\n// The static resources that the app needs to function.\nvar APP_STATIC_RESOURCES = [\n \"/\"\n];\n// On install, cache the static resources\nself.addEventListener(\"install\", function(event) {\n event.waitUntil(_async_to_generator(function() {\n var cache;\n return _ts_generator(this, function(_state) {\n switch(_state.label){\n case 0:\n return [\n 4,\n caches.open(CACHE_NAME)\n ];\n case 1:\n cache = _state.sent();\n cache.addAll(APP_STATIC_RESOURCES);\n return [\n 2\n ];\n }\n });\n })());\n});\n// delete old caches on activate\nself.addEventListener(\"activate\", function(event) {\n event.waitUntil(_async_to_generator(function() {\n var names;\n return _ts_generator(this, function(_state) {\n switch(_state.label){\n case 0:\n return [\n 4,\n caches.keys()\n ];\n case 1:\n names = _state.sent();\n return [\n 4,\n Promise.all(names.map(function(name) {\n if (name !== CACHE_NAME) return caches[\"delete\"](name);\n }))\n ];\n case 2:\n _state.sent();\n return [\n 4,\n clients.claim()\n ];\n case 3:\n _state.sent();\n return [\n 2\n ];\n }\n });\n })());\n});\nself.addEventListener(\"fetch\", function(event) {\n if (event.request.mode === \"navigate\" && event.request.url.endsWith(\"/index.html?isPWA=true\")) {\n event.respondWith(caches.match(\"/\"));\n return;\n }\n});\n\n//# sourceMappingURL=sw-b71.js.map\n","// The version of the cache.\nconst VERSION = \"29038230\";\n\n// The name of the cache\nconst CACHE_NAME = `breakout-71-${VERSION}`;\n\n// The static resources that the app needs to function.\nconst APP_STATIC_RESOURCES = [\"/\"];\n\n// On install, cache the static resources\nself.addEventListener(\"install\", (event) => {\n event.waitUntil(\n (async () => {\n const cache = await caches.open(CACHE_NAME);\n cache.addAll(APP_STATIC_RESOURCES);\n })(),\n );\n});\n\n// delete old caches on activate\nself.addEventListener(\"activate\", (event) => {\n event.waitUntil(\n (async () => {\n const names = await caches.keys();\n await Promise.all(\n names.map((name) => {\n if (name !== CACHE_NAME) {\n return caches.delete(name);\n }\n }),\n );\n await clients.claim();\n })(),\n );\n});\n\nself.addEventListener(\"fetch\", (event) => {\n if (\n event.request.mode === \"navigate\" &&\n event.request.url.endsWith(\"/index.html?isPWA=true\")\n ) {\n event.respondWith(caches.match(\"/\"));\n return;\n }\n});\n"],"names":["asyncGeneratorStep","gen","resolve","reject","_next","_throw","key","arg","info","value","error","done","Promise","then","_async_to_generator","fn","self1","args","arguments","apply","err","undefined","_ts_generator","thisArg","body","f","y","t","g","_","label","sent","trys","ops","next","verb","Symbol","iterator","n","v","step","op","TypeError","call","pop","length","push","e","CACHE_NAME","concat","APP_STATIC_RESOURCES","self","addEventListener","event","waitUntil","_state","caches","open","cache","addAll","keys","all","names","map","name","clients","claim","request","mode","url","endsWith","respondWith","match"],"version":3,"file":"sw-b71.js.map"} \ No newline at end of file +{"mappings":"AAAA,4BAA4B;AAC5B,MAAM,UAAU;AAEhB,wBAAwB;AACxB,MAAM,aAAa,CAAC,YAAY,EAAE,SAAS;AAE3C,uDAAuD;AACvD,MAAM,uBAAuB;IAAC;CAAI;AAElC,yCAAyC;AACzC,KAAK,gBAAgB,CAAC,WAAW,CAAC;IAChC,MAAM,SAAS,CACb,AAAC,CAAA;QACC,MAAM,QAAQ,MAAM,OAAO,IAAI,CAAC;QAChC,MAAM,MAAM,CAAC;IACf,CAAA;AAEJ;AAEA,gCAAgC;AAChC,KAAK,gBAAgB,CAAC,YAAY,CAAC;IACjC,MAAM,SAAS,CACb,AAAC,CAAA;QACC,MAAM,QAAQ,MAAM,OAAO,IAAI;QAC/B,MAAM,QAAQ,GAAG,CACf,MAAM,GAAG,CAAC,CAAC;YACT,IAAI,SAAS,YACX,OAAO,OAAO,MAAM,CAAC;QAEzB;QAEF,MAAM,QAAQ,KAAK;IACrB,CAAA;AAEJ;AAEA,KAAK,gBAAgB,CAAC,SAAS,CAAC;IAC9B,IACE,MAAM,OAAO,CAAC,IAAI,KAAK,cACvB,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,2BAC3B;QACA,MAAM,WAAW,CAAC,OAAO,KAAK,CAAC;QAC/B;IACF;AACF","sources":["src/PWA/sw-b71.js"],"sourcesContent":["// The version of the cache.\nconst VERSION = \"29038466\";\n\n// The name of the cache\nconst CACHE_NAME = `breakout-71-${VERSION}`;\n\n// The static resources that the app needs to function.\nconst APP_STATIC_RESOURCES = [\"/\"];\n\n// On install, cache the static resources\nself.addEventListener(\"install\", (event) => {\n event.waitUntil(\n (async () => {\n const cache = await caches.open(CACHE_NAME);\n cache.addAll(APP_STATIC_RESOURCES);\n })(),\n );\n});\n\n// delete old caches on activate\nself.addEventListener(\"activate\", (event) => {\n event.waitUntil(\n (async () => {\n const names = await caches.keys();\n await Promise.all(\n names.map((name) => {\n if (name !== CACHE_NAME) {\n return caches.delete(name);\n }\n }),\n );\n await clients.claim();\n })(),\n );\n});\n\nself.addEventListener(\"fetch\", (event) => {\n if (\n event.request.mode === \"navigate\" &&\n event.request.url.endsWith(\"/index.html?isPWA=true\")\n ) {\n event.respondWith(caches.match(\"/\"));\n return;\n }\n});\n"],"names":[],"version":3,"file":"sw-b71.js.map","sourceRoot":"/__parcel_source_root/"} \ No newline at end of file diff --git a/dist/index.html b/dist/index.html index 8df477a..0b3aaeb 100644 --- a/dist/index.html +++ b/dist/index.html @@ -1 +1,3764 @@ -Breakout 71 \ No newline at end of file + + + + + + + Breakout 71 + + + + + + + + + + + + + diff --git a/src/PWA/sw-b71.js b/src/PWA/sw-b71.js index e4620df..5596180 100644 --- a/src/PWA/sw-b71.js +++ b/src/PWA/sw-b71.js @@ -1,5 +1,5 @@ // The version of the cache. -const VERSION = "29038230"; +const VERSION = "29038466"; // The name of the cache const CACHE_NAME = `breakout-71-${VERSION}`; diff --git a/src/data/version.json b/src/data/version.json index 7acf91a..629f6ff 100644 --- a/src/data/version.json +++ b/src/data/version.json @@ -1 +1 @@ -"29038230" +"29038466" diff --git a/src/gameStateMutators.ts b/src/gameStateMutators.ts index ae4124e..3325c4e 100644 --- a/src/gameStateMutators.ts +++ b/src/gameStateMutators.ts @@ -1284,9 +1284,7 @@ export function append( where.list[where.indexMin].destroyed = false; makeItem(where.list[where.indexMin]); where.indexMin++; - console.log("Reused item " + where.indexMin); } else { - console.log("Created item " + where.indexMin); const p = { destroyed: false }; makeItem(p); where.list.push(p); @@ -1321,5 +1319,3 @@ export function forEachLiveOne( } }); } - -//TODO check destroyed usage in code diff --git a/src/recording.ts b/src/recording.ts index 33d2db7..3ef8a76 100644 --- a/src/recording.ts +++ b/src/recording.ts @@ -117,20 +117,42 @@ export function startRecordingGame(gameState: GameState) { video.loop = true; video.muted = true; video.playsInline = true; + video.src = URL.createObjectURL(blob); + targetDiv.appendChild(video); const a = document.createElement("a"); a.download = captureFileName("webm"); a.target = "_blank"; - a.href = video.src; + if (window.location.href.endsWith("index.html?isInWebView=true")) { + a.href = await blobToBase64(blob); + } else { + a.href = video.src; + } + a.textContent = t("main_menu.record_download", { size: (blob.size / 1000000).toFixed(2), }); - targetDiv.appendChild(video); targetDiv.appendChild(a); }; } +function blobToBase64(blob: Blob): Promise { + return new Promise((resolve, reject) => { + let reader = new FileReader(); + + reader.onload = function () { + resolve(reader.result); + }; + reader.onerror = function (e) { + console.error(e); + reject(new Error("Failed to readAsDataURL of the video ")); + }; + + reader.readAsDataURL(blob); + }); +} + export function pauseRecording() { if (!isOptionOn("record")) { return; diff --git a/src/types.d.ts b/src/types.d.ts index 99159dd..5bdb231 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -150,7 +150,6 @@ export type PerksMap = { [k in PerkId]: number; }; -// TODO ensure T has a destroyed;boolean field export type ReusableArray = { // All items below that index should not be destroyed indexMin: number;