mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 01:40:07 +01:00
Re-organize gradle modules.
This commit is contained in:
committed by
jeffrey-signal
parent
f4863efb2e
commit
e162eb27c7
59
demo/debuglogs-viewer/src/main/assets/WebView.html
Normal file
59
demo/debuglogs-viewer/src/main/assets/WebView.html
Normal file
@@ -0,0 +1,59 @@
|
||||
<!--
|
||||
~ Copyright 2025 Signal Messenger, LLC
|
||||
~ SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<style>
|
||||
#container { position: absolute; top: 50px; bottom: 0; left: 0; right: 0; }
|
||||
#searchBar { position: fixed; top: 0; left: 0; width: 350px; display: none; padding: 10px; gap: 5px; z-index: 1; }
|
||||
#searchBar input { flex-grow: 1; padding: 5px ;}
|
||||
.searchMatches { position: absolute; background-color: rgba(182, 190, 250, 0.2); }
|
||||
#caseSensitiveButton.active { background-color: rgba(182, 190, 250, 0.2); }
|
||||
#matchCount { font-size: 10px; }
|
||||
#filterLevel { display: none; }
|
||||
|
||||
.ace_editor { background-color: #FBFCFF; }
|
||||
.ace_none { color: #000000; }
|
||||
.ace_verbose { color: #515151; }
|
||||
.ace_debug { color: #089314; }
|
||||
.ace_info { color: #0a7087; }
|
||||
.ace_warning { color: #b58c12; }
|
||||
.ace_error { color: #af0d0a; }
|
||||
|
||||
body.dark .ace_editor { background-color: #1B1C1F; }
|
||||
body.dark .ace_none { color: #ffffff; }
|
||||
body.dark .ace_verbose { color: #8a8a8a; }
|
||||
body.dark .ace_debug { color: #5ca72b; }
|
||||
body.dark .ace_info { color: #46bbb9; }
|
||||
body.dark .ace_warning { color: #cdd637; }
|
||||
body.dark .ace_error { color: #ff6b68; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="searchBar">
|
||||
<button id="cancelButton"> x </button>
|
||||
<input type="text" id="searchInput" placeholder="Search" />
|
||||
<button id="prevButton"> < </button>
|
||||
<button id="nextButton"> > </button>
|
||||
<button id="caseSensitiveButton"> Cc </button>
|
||||
<div id="matchCount"> No match </div>
|
||||
</div>
|
||||
<div id="filterLevel">
|
||||
<div class="filterLevelMenu">
|
||||
<label><input type="checkbox" value=" V ">Verbose</label>
|
||||
<label><input type="checkbox" value=" D ">Debug</label>
|
||||
<label><input type="checkbox" value=" I ">Info</label>
|
||||
<label><input type="checkbox" value=" W ">Warning</label>
|
||||
<label><input type="checkbox" value=" E ">Error</label>
|
||||
<label><input type="checkbox" value="SignalUncaughtException">SignalUncaughtException</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container">Loading...</div>
|
||||
<script src="https://www.unpkg.com/ace-builds@latest/src-noconflict/ace.js"></script>
|
||||
<script src="WebView.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
171
demo/debuglogs-viewer/src/main/assets/WebView.js
Normal file
171
demo/debuglogs-viewer/src/main/assets/WebView.js
Normal file
@@ -0,0 +1,171 @@
|
||||
// Create custom text mode to color different levels of debug log lines
|
||||
const TextMode = ace.require("ace/mode/text").Mode;
|
||||
const TextHighlightRules = ace.require("ace/mode/text_highlight_rules").TextHighlightRules;
|
||||
|
||||
function CustomHighlightRules() {
|
||||
this.$rules = {
|
||||
start: [
|
||||
{ token: "verbose", regex: "^.*\\sV\\s.*$" },
|
||||
{ token: "debug", regex: "^.*\\sD\\s.*$" },
|
||||
{ token: "info", regex: "^.*\\sI\\s.*$" },
|
||||
{ token: "warning", regex: "^.*\\sW\\s.*$" },
|
||||
{ token: "error", regex: "^.*\\sE\\s.*$" },
|
||||
{ token: "none", regex: ".*" },
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
CustomHighlightRules.prototype = new TextHighlightRules();
|
||||
|
||||
function CustomMode() {
|
||||
TextMode.call(this);
|
||||
this.HighlightRules = CustomHighlightRules;
|
||||
}
|
||||
|
||||
CustomMode.prototype = Object.create(TextMode.prototype);
|
||||
CustomMode.prototype.constructor = CustomMode;
|
||||
|
||||
// Create Ace Editor using the custom mode
|
||||
let editor = ace.edit("container", {
|
||||
mode: new CustomMode(),
|
||||
theme: "ace/theme/textmate",
|
||||
wrap: false, // Allow for horizontal scrolling
|
||||
readOnly: true,
|
||||
showGutter: false,
|
||||
highlightActiveLine: false,
|
||||
highlightSelectedWord: false, // Prevent Ace Editor from automatically highlighting all instances of a selected word (really laggy!)
|
||||
showPrintMargin: false,
|
||||
});
|
||||
|
||||
// Get search bar functionalities
|
||||
const input = document.getElementById("searchInput");
|
||||
const prevButton = document.getElementById("prevButton");
|
||||
const nextButton = document.getElementById("nextButton");
|
||||
const cancelButton = document.getElementById("cancelButton");
|
||||
const caseSensitiveButton = document.getElementById("caseSensitiveButton");
|
||||
|
||||
// Generate highlight markers for all search matches
|
||||
const Range = ace.require("ace/range").Range;
|
||||
const session = editor.getSession();
|
||||
|
||||
let markers = []; // IDs of highlighted search markers
|
||||
let matchRanges = []; // Ranges of all search matches
|
||||
let matchCount = 0; // Total number of matches
|
||||
let caseSensitive = false;
|
||||
|
||||
// Clear all search markers and match info
|
||||
function clearMarkers() {
|
||||
markers.forEach((id) => session.removeMarker(id));
|
||||
markers = [];
|
||||
matchRanges = [];
|
||||
matchCount = 0;
|
||||
}
|
||||
|
||||
// Highlight all instances of the search term
|
||||
function highlightAllMatches(term) {
|
||||
clearMarkers();
|
||||
if (!term) {
|
||||
updateMatchPosition();
|
||||
return;
|
||||
}
|
||||
|
||||
const searchTerm = caseSensitive ? term : term.toLowerCase();
|
||||
session
|
||||
.getDocument()
|
||||
.getAllLines()
|
||||
.forEach((line, row) => {
|
||||
let start = 0;
|
||||
const caseLine = caseSensitive ? line : line.toLowerCase();
|
||||
while (true) {
|
||||
const index = caseLine.indexOf(searchTerm, start);
|
||||
if (index === -1) {
|
||||
break;
|
||||
}
|
||||
const range = new Range(row, index, row, index + term.length);
|
||||
markers.push(session.addMarker(range, "searchMatches", "text", false));
|
||||
matchRanges.push(range);
|
||||
start = index + term.length;
|
||||
}
|
||||
});
|
||||
matchCount = markers.length;
|
||||
updateMatchPosition();
|
||||
}
|
||||
|
||||
input.addEventListener("input", () => highlightAllMatches(input.value));
|
||||
|
||||
// Return index of current match
|
||||
function getCurrentMatchIndex() {
|
||||
const current = editor.getSelection().getRange();
|
||||
return matchRanges.findIndex(
|
||||
(r) =>
|
||||
r.start.row === current.start.row &&
|
||||
r.start.column === current.start.column &&
|
||||
r.end.row === current.end.row &&
|
||||
r.end.column === current.end.column,
|
||||
);
|
||||
}
|
||||
|
||||
// Update the display for current match
|
||||
function updateMatchPosition() {
|
||||
document.getElementById("matchCount").textContent = matchCount == 0 ? "No match" : `${getCurrentMatchIndex() + 1} / ${matchCount}`;
|
||||
}
|
||||
|
||||
// Event listeners
|
||||
prevButton.onclick = () => {
|
||||
editor.find(input.value, {
|
||||
backwards: true,
|
||||
wrap: true,
|
||||
skipCurrent: true,
|
||||
caseSensitive: caseSensitive,
|
||||
});
|
||||
updateMatchPosition();
|
||||
};
|
||||
|
||||
nextButton.onclick = () => {
|
||||
editor.find(input.value, {
|
||||
backwards: false,
|
||||
wrap: true,
|
||||
skipCurrent: true,
|
||||
caseSensitive: caseSensitive,
|
||||
});
|
||||
updateMatchPosition();
|
||||
};
|
||||
|
||||
cancelButton.onclick = () => {
|
||||
editor.getSelection().clearSelection();
|
||||
input.value = "";
|
||||
clearMarkers();
|
||||
updateMatchPosition();
|
||||
document.getElementById("searchBar").style.display = "none";
|
||||
};
|
||||
|
||||
caseSensitiveButton.onclick = () => {
|
||||
caseSensitive = !caseSensitive;
|
||||
highlightAllMatches(input.value);
|
||||
caseSensitiveButton.classList.toggle("active", caseSensitive);
|
||||
};
|
||||
|
||||
// Filter by log levels
|
||||
let logLines = "";
|
||||
function filterLogs() {
|
||||
const selectedLevels = Array.from(document.querySelectorAll('input[type="checkbox"]:checked')).map((cb) => cb.value);
|
||||
|
||||
if (selectedLevels.length === 0) {
|
||||
// If no level is selected, show all
|
||||
editor.setValue(logLines, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
const filtered = logLines
|
||||
.split("\n")
|
||||
.filter((line) => {
|
||||
return selectedLevels.some((level) => line.includes(level));
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
editor.setValue(filtered, -1);
|
||||
}
|
||||
|
||||
document.querySelectorAll('input[type="checkbox"]').forEach((cb) => {
|
||||
cb.addEventListener("change", filterLogs);
|
||||
});
|
||||
21
demo/debuglogs-viewer/src/main/assets/log.txt
Normal file
21
demo/debuglogs-viewer/src/main/assets/log.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
refrigerator euro-pop digital math- sign saturation point weathered tanto nano- disposable tanto pistol neon tube engine boy.
|
||||
computer rebar singularity boat San Francisco city spook shanty town cartel shoes car franchise tank-traps city nodality boy.
|
||||
tiger-team boy corrupted engine franchise tiger-team realism uplink realism sub-orbital motion systema voodoo god hacker urban Kowloon.
|
||||
rain knife cartel digital augmented reality office pre- beef noodles savant woman nano- garage numinous sunglasses augmented reality monofilament.
|
||||
|
||||
semiotics semiotics gang long-chain hydrocarbons post- tanto pen modem BASE jump sprawl marketing motion -ware convenience store
|
||||
crypto- chrome. denim fluidity woman sensory refrigerator drone realism long-chain hydrocarbons cyber- convenience store knife
|
||||
decay drone cartel katana carbon. pre- girl spook soul-delay chrome towards pistol singularity plastic decay market bicycle
|
||||
advert tank-traps geodesic grenade. RAF artisanal pre- savant neural order-flow pre- weathered Tokyo digital neural advert artisanal
|
||||
denim fluidity marketing.
|
||||
|
||||
Legba RAF assault RAF into rebar vinyl cardboard paranoid rifle euro-pop boy katana neon meta- neon. Legba papier-mache kanji faded
|
||||
bicycle A.I. sign nodal point semiotics modem urban DIY 8-bit cardboard sentient meta-. kanji assault rifle warehouse post- franchise
|
||||
skyscraper footage cardboard bomb drone drugs silent corrupted boat fetishism. towards rebar sentient face forwards meta- neon BASE
|
||||
jump papier-mache faded vinyl engine sunglasses claymore mine gang pen uplink.
|
||||
|
||||
Shibuya media BASE jump geodesic car sub-orbital j-pop semiotics boat rebar weathered claymore mine systemic skyscraper fluidity uplink.
|
||||
network pre- skyscraper market assassin footage tiger-team cyber- carbon claymore mine camera kanji shanty town A.I. katana long-chain
|
||||
hydrocarbons. savant stimulate physical katana 8-bit -ware paranoid systema neon market tiger-team San Francisco systemic engine numinous
|
||||
hacker. disposable weathered plastic warehouse papier-mache San Francisco range-rover woman katana San Francisco shanty town semiotics
|
||||
towards tower -ware denim.
|
||||
Reference in New Issue
Block a user