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;