### Enter Nix Development Environment Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Start the Nix development shell which includes Rust and Android SDK. Ensure Nix with Flakes is installed. ```bash nix develop ``` -------------------------------- ### Start Existing Container Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Start a previously created and stopped container. Use 'ia' flags for interactive and attach modes. ```bash docker start -ia deltachat ``` ```bash podman start -ia deltachat ``` -------------------------------- ### Install Toolchains and Build Native Library Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Inside the Docker container, run these scripts to install the necessary toolchains and build the native library for Delta Chat. ```bash deltachat@6012dcb974fe:/home/app$ scripts/install-toolchains.sh ``` ```bash deltachat@6012dcb974fe:/home/app$ scripts/ndk-make.sh ``` -------------------------------- ### Install 32-bit Libraries for Android Studio on Ubuntu/Fedora Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Installs essential 32-bit libraries required by Android Studio on 64-bit Linux systems. Use the appropriate command for your distribution. ```bash sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386 ``` ```bash sudo yum install zlib.i686 ncurses-libs.i686 bzip2-libs.i686 ``` -------------------------------- ### Initialize Media Stream and Call Manager Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Sets up the media stream for video and audio, initializes the call manager, and handles user media permissions. It attempts to get both video and audio, falling back to audio-only if video fails. Tracks are enabled/disabled based on component state. ```javascript const d = H(s); d.current = s; const [f, w] = D(null), [m, g] = D(null), v = ae(async () => { let b; try { b = await navigator.mediaDevices.getUserMedia({ video: !i, audio: !0, }); } catch { console.warn('Failed to getUserMedia with video, will try just audio'), (b = await navigator.mediaDevices.getUserMedia({ audio: !0 })); } return ( b.getAudioTracks().forEach(C => (C.enabled = u.current)), b.getVideoTracks().forEach(C => (C.enabled = d.current)), b ); }, [i]); const [k, I] = D(null); N(() => { let b = !1; return ( I(null), v.then(C => { b || I(C); }), () => { b = !0; } ); }, [v]); k && n.current && n.current.srcObject !== k && (n.current.srcObject = k); ``` -------------------------------- ### Start Outgoing Call Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Initiates an outgoing call by creating an offer, setting the local description, and sending the offer to the remote peer. It also sets up ICE candidate handling. ```javascript async startCall(){ await this.setIceServersPromise; const t=Xe(this.peerConnection), n=await this.outStreamPromise; console.log("getUserMedia() completed"), n.getTracks().forEach(i=>this.peerConnection.addTrack(i,n)), this.peerConnection.setLocalDescription(await this.peerConnection.createOffer()), await t; const o=this.peerConnection.localDescription.sdp; this.peerConnection.onicecandidate=this.trickleIceOverDataChannel.bind(this), z("Start outgoing call with offer:",o), window.calls.startCall(o), this.state="ringing", this.onStateChanged(this.state) } ``` -------------------------------- ### Generate JSON-RPC Bindings Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Run this script to generate or update JSON-RPC bindings after installing Rust tooling and the dcrpcgen tool. ```bash ./scripts/update-rpc-bindings.sh ``` -------------------------------- ### Configure Android NDK Environment Variables Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Set the ANDROID_NDK_ROOT environment variable and add the NDK toolchain to the PATH. Ensure '[version]' is replaced with your NDK version and the path correctly points to your NDK installation. ```bash export ANDROID_NDK_ROOT=${HOME}/Android/Sdk/ndk/[version] # (or wherever your NDK is) Note that there is no `/` at the end! export PATH=${PATH}:${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/:${ANDROID_NDK_ROOT} ``` -------------------------------- ### Handle Incoming Call Offer Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Processes an incoming call offer received via URL hash. It prompts the user to accept the call and then initiates the call setup if accepted. ```javascript s=async()=>{ var d; const u=decodeURIComponent(window.location.hash.substring(1)); if(!u||u.length===0){ console.log("empty URL hash: ",window.location.href); return } if((d=this.resolveCallAcceptedPromise)==null||d.call(this,!1), u==="startCall")console.log("URL hash CMD: ",u), await this.startCall(); else if(u.startsWith("offerIncomingCall=")){ const f=window.atob(u.split("offerIncomingCall=",2)[1]); z("Incoming call (with user prompt) with offer:",f), this.state="promptingUserToAcceptCall", this.onStateChanged(this.state); const w=await new Promise(m=>{ const g=v=>{ m(v), this.resolveCallAcceptedPromise===g&& (this.resolveCallAcceptedPromise=void 0) }; this.resolveCallAcceptedPromise=g }); if(console.log("Accept call prompt resolved: "+(w?"accepted":"not accepted")), !w) return; await _(f) } else if(u.startsWith("acceptCall=")){ const f=window.atob(u.substring(11)); z("Incoming call with offer:",f), await _(f) } else if(u.startsWith("onAnswer=")){ const f=window.atob(u.substring(9)); z("Outgoing call was accepted with answer:",f), p(f) } else console.log("unexpected URL hash: ",u) }; s() ``` -------------------------------- ### Build Docker Image Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Build the Docker image for Delta Chat Android. Ensure you have Docker or Podman installed. The --build-arg UID and GID ensure correct file permissions. ```bash podman build --build-arg UID=$(id -u) --build-arg GID=$(id -g) . -t deltachat-android ``` ```bash docker build --build-arg UID=$(id -u) --build-arg GID=$(id -g) . -t deltachat-android ``` -------------------------------- ### Run Docker Container Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Run the built Docker image to create a container for building. The -v flag mounts the current directory, and -w sets the working directory inside the container. ```bash podman run --userns=keep-id -it --name deltachat -v $(pwd):/home/app:z -w /home/app localhost/deltachat-android ``` ```bash docker run -it --name deltachat -v $(pwd):/home/app:z -w /home/app localhost/deltachat-android ``` -------------------------------- ### Tag and Push Git Release Source: https://github.com/deltachat/deltachat-android/blob/main/RELEASE.md Tag a specific commit for release and push the tag to the repository. F-Droid uses tags starting with 'v' for builds. ```shell git tag v1.2.1 COMMIT; git push --tags ``` -------------------------------- ### Build APK Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Execute the Gradle wrapper to assemble the debug APK. This command is run from within the Docker container. ```bash deltachat@6012dcb974fe:/home/app$ ./gradlew assembleDebug ``` -------------------------------- ### Configure Rootless Podman Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Commands to set up Podman for rootless operation. Replace 'yourusername' with your actual username. This is necessary for running Podman without root privileges. ```bash sudo touch /etc/subgid sudo touch /etc/subuid sudo usermod --add-subuids 165536-231072 --add-subgids 165536-231072 yourusername ``` -------------------------------- ### Export ANDROID_NDK_ROOT and add NDK to PATH Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Sets the ANDROID_NDK_ROOT environment variable and adds the NDK's toolchain binaries to the system's PATH. This is necessary for the build process to locate NDK tools. ```bash export ANDROID_NDK_ROOT=${HOME}/android-ndk export PATH=${PATH}:${ANDROID_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/bin/:${ANDROID_NDK_ROOT} ``` -------------------------------- ### Upload Beta Release Source: https://github.com/deltachat/deltachat-android/blob/main/RELEASE.md Uploads both debug and release APKs to testrun.org and drafts a message for testing channels. ```shell ./scripts/upload-beta.sh VERSION ``` -------------------------------- ### Create and Manage Call Session Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Creates a new call session using the `se` constructor, passing the media stream and other configuration. It also reports muted states to the remote participant. ```javascript const [E, U] = D(null), R = ae(() => { const b = C => { i && (C.getVideoTracks().forEach(Y => C.removeTrack(Y)), C.addEventListener('addtrack', Y => { Y.track.kind === 'video' && C.removeTrack(Y.track); })), U(C); }; return new se(v, b, t, w, g); }, [v, i]); N(() => { window.__callsManager = R; }, [R]); ``` -------------------------------- ### Initialize WebRTC Peer Connection Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Initializes a WebRTC RTCPeerConnection with specified ICE servers and policies. Sets up data channels for ICE trickling and muted state synchronization. ```javascript const Ke={iceServers:[],iceTransportPolicy:"all",bundlePolicy:"max-bundle",iceCandidatePoolSize:1},le=class le{ constructor(t,n,o,i,r){ $(this,"peerConnection"); $(this,"setIceServersPromise"); $(this,"state"); $(this,"resolveCallAcceptedPromise"); $(this,"mutedStateDataChannel"); $(this,"iceTricklingDataChannel"); $(this,"iceTricklingBuffer"); $(this,"mutedStateDataChannelOpen"); this.outStreamPromise=t, this.onStateChanged=o, this.peerConnection=new RTCPeerConnection(Ke); const a=u=>{ this.peerConnection.setConfiguration({...Ke,iceServers:u}) }, l=window.calls.getIceServers(); typeof l=="string"?(a(JSON.parse(l)),this.setIceServersPromise=Promise.resolve()):this.setIceServersPromise=l.then(u=>{ a(JSON.parse(u)) }), this.state=le.initialState, this.iceTricklingBuffer=[], this.iceTricklingDataChannel=this.peerConnection.createDataChannel("iceTrickling",{negotiated:!0,id:1}), this.iceTricklingDataChannel.onmessage=async u=>{ console.log("received ICE candidate from remote peer",u.data); const d=JSON.parse(u.data); try{ await this.peerConnection.addIceCandidate(d) }catch(f){ if(!(d==null&&f instanceof Error&&f.message.includes("missing values for both sdpMid and sdpMLineIndex")))throw f } }, this.iceTricklingDataChannel.onopen=()=>{ console.log("iceTricklingDataChannel open: sending buffered ICE candidates",this.iceTricklingBuffer); for(const u of this.iceTricklingBuffer)Ye(this.iceTricklingDataChannel,u); this.iceTricklingBuffer=[] }, this.mutedStateDataChannel=this.peerConnection.createDataChannel("mutedState",{negotiated:!0,id:3}), this.mutedStateDataChannel.onmessage=u=>{ console.log("received mutedState from remote peer",u.data); const d=JSON.parse(u.data); let f,w; if(!(typeof d=="object"&&d&&"videoEnabled"in d&&typeof(f=d.videoEnabled)=="boolean"&&"audioEnabled"in d&&typeof(w=d.audioEnabled)=="boolean")){ console.error("remote sent an invalid mutedState message",d); return } i({audioEnabled:w,videoEnabled:f}) }, this.mutedStateDataChannelOpen=new Promise((u,d)=>{ this.mutedStateDataChannel.onopen=()=>{ console.log("mutedStateDataChannel open"), u() }, this.mutedStateDataChannel.onclose=()=>{ console.log("mutedStateDataChannel closed"), d("data channel closed") } }); const c=()=>{ this.peerConnection.connectionState==="connected"&&( this.peerConnection.removeEventListener("connectionstatechange",c), setTimeout(()=>{ const u=this.peerConnection.getSenders().map(m=>{ var g; return(g=m.transport)==null?void 0:g.iceTransport }).filter(m=>m!=null), d=()=>u.map(m=>m.getSelectedCandidatePair()).filter(m=>m!=null), f=()=>{ const m=d(); if(m.length>0){ const g=m.some(v=>v.local.type==="relay"||v.remote.type==="relay"); r(g) }else r(null) }; f(); for(const m of u)m.addEventListener("selectedcandidatepairchange",f); d().forEach(m=>{ const g=v=>v==="relay"?`${v} (TURN)`:v==="srflx"?`${v} (STUN)`:v; console.log(`Selected candidate pair: local: ${g(m.local.type)} ${m.local.address} => remote: ${g(m.remote.type)} ${m.remote.address}`,m) }) },500)) }; this.peerConnection.addEventListener("connectionstatechange",c); const _=async u=>{ this.state="connecting", this.onStateChanged(this.state), await this.setIceServersPromise; const d=Xe(this.peerConnection), f={type:"offer",sdp:u}, w=new RTCSessionDescription(f); this.peerConnection.setRemoteDesc } } } ``` -------------------------------- ### Component Initialization and Execution Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Initializes and executes a component's internal logic. This might be used for setting up component state or methods. ```javascript function ve(e){var t=T;e.__c=e.__();T=t} ``` -------------------------------- ### Configure Email Credentials for Tests Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Provide email account credentials for online tests by adding them to the ~/.gradle/gradle.properties file. Ensure the file is created if it doesn't exist. ```properties TEST_ADDR=youraccount@yourdomain.org TEST_MAIL_PW=youpassword ``` -------------------------------- ### Build Android APK using Gradle Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Build the debug APK for the Android application. This is a two-step process that first prepares native code and then uses Gradle for the main build. ```bash $ scripts/ndk-make.sh ``` ```bash ./gradlew assembleDebug ``` -------------------------------- ### Clone F-Droid Data and Server Repositories Source: https://github.com/deltachat/deltachat-android/blob/main/docs/f-droid.md Clone the necessary F-Droid repositories to manage metadata and build the application locally. Adapt the configuration file as needed for your environment. ```bash git clone https://gitlab.com/fdroid/fdroiddata git clone https://gitlab.com/fdroid/fdroidserver cd fdroiddata ``` ```bash cp ../fdroidserver/examples/config.py . ``` -------------------------------- ### JavaScript for WebXDC Loading and Sandbox Test Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/res/raw/webxdc_wrapper.html Handles the loading of the WebXDC application, including a test for sandbox isolation and a mechanism to limit RTCPeerConnection creation. This script manages the loading progress and displays errors if the sandbox is not properly isolated or if too many connections are created. ```javascript const loadingDiv = document.getElementById("loading"); const iframe = document.getElementById("frame"); let fill500 = async (href) => { const connections = []; const loadingProgress = document.getElementById("progress"); const isolatedContextTest = document.getElementById( "test-isolated-sandbox-context" ); const cert = { certificates: [ await RTCPeerConnection.generateCertificate({ name: "ECDSA", namedCurve: "P-256", }), ], }; console.log("WEBRTC-WG: allocating"); loadingProgress.value = 0; while (connections.length < 500) { try { connections.push(new RTCPeerConnection(cert)); if (connections.length%50 == 0) { loadingProgress.value = connections.length; await new Promise((res) => setTimeout(res)); } } catch (error) { loadingProgress.value++; new Array(1024*1024).fill(0); await new Promise((res) => setTimeout(res, 500)); console.log("WEBRTC-WG: waiting for gc"); } } console.log("WEBRTC-WG: done"); try { connections.push(new RTCPeerConnection()); console.log("Error: was able to create more than 500 connections"); loadingDiv.innerText = "Error: was not able to block webrtc ERROR_A"; } catch (error) { /** @type {Promise} */ const sandboxedIframeCheckIsGoodPromise = new Promise(resolve => { /** @type {HTMLIFrameElement} */ const sandboxedIframe = document.getElementById("test-isolated-sandbox-context"); const askIframeToPerformCheck = () => { // Why `"*"`? See the comment below. sandboxedIframe.contentWindow.postMessage("performCheck", "*"); }; /** @type {(e: MessageEvent) => void} */ const messageListener = (e) => { // Checking `event.origin !== location.origin` just in case would be safer, // but `sandbox`ed iframes seem to send messages with `origin` set to `null`, // so we skip the check, relying on the fact that we don't actually load any // untrusted scripts that could `postMessage` before this check is completed. // And we can't just add `sandbox="allow-same-origin"` because it could turn off // process-isolation: // https://chromium-review.googlesource.com/c/chromium/src/+/3416475 if (event.source !== sandboxedIframe.contentWindow) { return; } switch (event.data.msgType) { case "ready": { askIframeToPerformCheck(); break; } case "result": { resolve(event.data.rtcpcCreationFailed); sandboxedIframe.remove(); window.removeEventListener("message", messageListener); break; } } } window.addEventListener("message", messageListener); askIframeToPerformCheck(); }); if (await sandboxedIframeCheckIsGoodPromise !== true) { console.log( "Error: was able to create more than 500 connections, iframe is probably isolated" ); loadingDiv.innerText = "Error: was not able to block webrtc ERROR_C"; } else { loadingDiv.innerHTML = ""; iframe.style.display = 'block'; iframe.src = href; } } return Object.freeze({ len: () => { return connections.length; }, }); }; const params = new URLSearchParams(document.location.search); const internetAccess = (params.get("i") || "0") === "1"; const href = params.get("href"); if (internetAccess) { // fill500 not needed, just load the frame fill500 = (href) => { loadingDiv.innerHTML = ""; iframe.style.display = 'block'; iframe.src = href; } } const thisUnchangable = fill500(href) ``` -------------------------------- ### Build Application using F-Droid Tools Source: https://github.com/deltachat/deltachat-android/blob/main/docs/f-droid.md Build a specific application package using the 'fdroid build' command. This command requires the package name and the versionCode. ```bash ../froidserver/fdroid build -v com.b44t.messenger: ``` -------------------------------- ### Upload Release Version Source: https://github.com/deltachat/deltachat-android/blob/main/RELEASE.md Uploads the release version of the APK. This is typically done before pushing to stores. ```shell ./scripts/upload-release.sh VERSION ``` -------------------------------- ### Module Preload Polyfill Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html This polyfill ensures module preloading works in browsers that do not natively support it. It uses MutationObserver to detect dynamically added module preload links. ```javascript console.log("version: v0.12.0"); var wt=Object.defineProperty;var Ct=(e,t,n)=>t in e?wt(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var $=(e,t,n)=>Ct(e,typeof t!="symbol"?t+"":t,n);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))o(i);new MutationObserver(i=>{for(const r of i)if(r.type==="childList")for(const a of r.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&o(a)}).observe(document,{childList:!0,subtree:!0});function n(i){const r={};return i.integrity&&(r.integrity=i.integrity),i.referrerPolicy&&(r.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?r.credentials="include":i.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function o(i){if(i.ep)return;i.ep=!0;const r=n(i);fetch(i.href,r)}})(); ``` -------------------------------- ### CSS for WebXDC Wrapper Styling Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/res/raw/webxdc_wrapper.html Basic CSS to style the iframe container and hide the iframe until it's ready. Used for layout and initial display control. ```css html, body { margin: 0; padding: 0; } .iframe-container { overflow: hidden; height: 100vh; width: 100vw; position: relative; } .iframe-container iframe { display: none; border: 0; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } #progress { width: 100%; } ``` -------------------------------- ### Analyze Network Candidates and Media Streams Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Analyzes network candidates and media stream details from a given WebRTC session description (SDP). Useful for debugging network connectivity and media capabilities. ```javascript function X(e,t,n){const o=e.filter(i=>i.condition).map(i=>i.status);if(o.length>0)return o;const i=e.find(a=>a.condition);return n.push(i.status),i.details.forEach(a=>n.push(a)),n.push(""),n.push("🎥 Media Streams:"),t.media.forEach(a=>{var l;const r=_e[a.type]||_e.default;n.push(` ${r} ${a.type.toUpperCase()}:`),n.push(` Port: ${a.port===Qe?`Dynamic (${Qe} = placeholder)`:a.port}`),n.push(` Protocol: ${a.protocol}`),n.push(` Connection: ${((l=a.connection)==null?void 0:l.address)|| ``` -------------------------------- ### CSS for Call Interface Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Provides basic CSS styling for the call interface, including full-screen layout, absolute positioning for media elements, and styling for buttons. ```css ._btn_2u459_1 { border: none; display: inline-flex; flex-direction: row; flex-wrap: nowrap; gap: 0.2em; align-items: center; padding: 0.5em; } ._btn_2u459_1, ._btn_2u459_1 * { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-touch-callout: none; cursor: pointer; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } html, body { padding: 0; margin: 0; background: #000; color: #fff; height: 100%; font-family: system-ui; } ``` -------------------------------- ### Update Translations and Local Help Source: https://github.com/deltachat/deltachat-android/blob/main/RELEASE.md Pull the latest translations and generate local help files. Requires deltachat-pages to be checked out in the parent directory. ```shell ./scripts/tx-pull-translations.sh ./scripts/create-local-help.sh # requires deltachat-pages checked out at ../deltachat-pages ``` -------------------------------- ### Answer Incoming Call Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Answers an incoming call by creating an answer, setting the local description, and adding received media tracks. It also sets up ICE candidate handling. ```javascript async _(w){const m=await t;console.log("getUserMedia() completed"),m.getTracks().forEach(v=>this.peerConnection.addTrack(v,m)),this.peerConnection.setLocalDescription(await this.peerConnection.createAnswer()),await d;const g=this.peerConnection.localDescription.sdp;this.peerConnection.onicecandidate=this.trickleIceOverDataChannel.bind(this),z("Answering incoming call with answer:",g),window.calls.acceptCall(g)} ``` -------------------------------- ### Accept Incoming Call Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Sets the remote description for an incoming call using the provided SDP answer. This is typically called after the user accepts the call. ```javascript p=u=>{ const d={type:"answer",sdp:u}, f=new RTCSessionDescription(d); this.peerConnection.setRemoteDescription(f) } ``` -------------------------------- ### Clone Repository with Submodules Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Clone the deltachat-android repository and its submodules. Use `--recursive` for initial clone or `git submodule update --init --recursive` for existing clones. ```bash git clone --recursive https://github.com/deltachat/deltachat-android ``` ```bash git submodule update --init --recursive ``` -------------------------------- ### Forwarding Refs in Components Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Creates a component that forwards a ref to its underlying component. This is a common pattern for higher-order components or wrapper components. ```javascript var Lt=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.forward_ref")||3911;function M(e){function t(n){var o=ht({},n);return delete o.ref,e(o,n.ref||null)}return t.$$typeof=Lt,t.render=e,t.prototype.isReactComponent=t.__f=!0,t.displayName="ForwardRef("+(e.displayName||e.name)+")",t} ``` -------------------------------- ### React Element Creation and Type Checking Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Defines a standard for creating React elements and includes checks for element types, potentially for optimization or specific rendering logic. ```javascript var Nt=typeof Symbol<"u"&&Symbol.for&&Symbol.for("react.element")||60103,Ut=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image(!S)|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[\][A-Z]/,Vt=/^on(Ani|Tra|Tou|BeforeInp|Compo)/,qt=/[\][A-Z0-9]/g,Ht=typeof document<"u",Mt=function(e){return(typeof Symbol<"u"&&typeof Symbol()==="symbol"? /fil|che|rad/:/fil|che|ra/).test(e)};L.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(e){Object.defineProperty(L.prototype,e,{configurable:!0,get:function(){return this["UNSAFE_"+e]},set:function(t){Object.defineProperty(this,e,{configurable:!0,writable:!0,value:t})}})});var We=y.vnode;y.vnode=function(e){typeof e.type=="string"&&function(t){var n=t.props,o=t.type,i={},r=o.indexOf("-")} ``` -------------------------------- ### Deobfuscate Java Stack Traces with retrace Source: https://github.com/deltachat/deltachat-android/blob/main/BUILDING.md Deobfuscate obfuscated Java stack traces from crash reports using `retrace`. The `mapping.txt` file, included in the symbols zip, is required. Output is redirected to `decoded-crash.txt`. ```bash retrace mapping.txt crash.txt > decoded-crash.txt ``` -------------------------------- ### Component Rendering and Reconciliation Source: https://github.com/deltachat/deltachat-android/blob/main/src/main/assets/calls/index.html Core functions for creating and updating virtual DOM nodes, handling component props, keys, and refs. It includes logic for efficient DOM diffing and patching. ```javascript var ce,y,tt,q,Ae,nt,ot,it,me,de,fe,G={},rt=[],kt=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,K=Array.isArray;function x(e,t){for(var n in t)e[n]=t[n];return e}function ge(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function pe(e,t,n){var o,i,r,a={};for(r in t)r=="key"?o=t[r]:r=="ref"?i=t[r]:a[r]=t[r];if(arguments.length>2&&(a.children=arguments.length>3?ce.call(arguments,2):n),typeof e=="function"&&e.defaultProps!=null)for(r in e.defaultProps)a[r]===void 0&&(a[r]=e.defaultProps[r]);return te(e,a,o,i,null)}function te(e,t,n,o,i){var r={type:e,props:t,key:n,ref:o,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:i??++tt,__i:-1,__u:0};return i==null&&y.vnode!=null&&y.vnode(r),r}function B(e){return e.children}function L(e,t){this.props=e,this.context=t}function F(e){return e.__?F(e.__,e.__i+1):null}function at(e){var t,n;if((e=e.__)!=null&&e.__c!=null){for(e.__e=e.__c.base=null,t=0;tl&&q.sort(ot),e=q.shift(),l=q.length,e.__d&&(n=void 0,o=void 0,i=(o=(t=e).__v).__e,r=[],a=[],t.__P&&(n=x({},o)).__v=o.__v+1,y.vnode&&y.vnode(n),ye(t.__P,n,o,t.__n,t.__P.namespaceURI,32&o.__u?[i]:null,r,i??F(o),!!(32&o.__u),a),n.__v=o.__v,n.__. __k[n.__i]=n,ct(r,n,a),o.__e=o.__=null,n.__e!=i&&at(n)));ie.__r=0}function st(e,t,n,o,i,r,a,l,c,_,p){var s,u,d,f,w,m,g=o&&o.__k||rt,k=t.length;for(c=Tt(n,t,g,c,k),s=0;s0?a=e.__k[r]=te(a.type,a.props,a.key,a.ref?a.ref:null,a.__v):e.__k[r]=a,c=r+u,a.__=e,a.__b=e.__b+1,l=null,(_=a.__i=St(a,n,c,s))!=-1&&(s--,(l=n[_])&& (l.__u|=2)):e.__k[r]=null;if(s)for(r=0;r(p?1:0)){for(i=n-1,r=n+1;i>=0||r=0?i--:r++])!=null&&(2&_.__u)==0&&l==_.key&&c==_.type)return a}return-1}function Pe(e,t,n){e.setProperty(t,n??"")||(e[t]=n==null?"":typeof n!="number"||kt.test(t)?n:n+"px")}function Z(e,t,n,o,i){var r,a;e:if(t=="style")if(typeof n=="string")e.style.cssText=n;else{if(typeof o=="string"&&(e.style.cssText=o=""),o)for(t in o)n&&t in n||Pe(e.style,t,"");if(n)for(t in n)o&&n[t]==o[t] ```