fallbackwidth and fallbackheight are empty when you run the config in the browser
Note
The current version is messy.
| import { Page, Toolbar, CodeBlock } from "@mmrl/ui"; | |
| import { useActivity, useConfig } from "@mmrl/hooks"; | |
| import { withRequireNewVersion } from "@mmrl/hoc"; | |
| import { ConfigProvider } from "@mmrl/providers"; | |
| import { | |
| List, | |
| ListItem, | |
| ListItemButton, | |
| ListItemText, | |
| ListSubheader, | |
| DialogTitle, | |
| Dialog, | |
| ListItemIcon, | |
| Switch, | |
| Checkbox, | |
| Button, | |
| Divider, | |
| TextField, | |
| DialogActions | |
| } from "@mui/material"; | |
| import { Check } from "@mui/icons-material" | |
| const screen_dims = Shell.cmd("wm size").result() | |
| const width_height = Shell.cmd(`${screen_dims} | tr -s ' ' ':' | cut -d':' -f3`).result() | |
| const width = Shell.cmd(`${width_height} | cut -d'x' -f1`).result() | |
| const height = Shell.cmd(`${width_height} | cut -d'x' -f2`).result() | |
| const initialConfig = { | |
| background: "transparent", | |
| colors: true, | |
| wordwrap: true, // assuming true since it's present | |
| logcatlevels: { | |
| V: true, | |
| D: true, | |
| I: true, | |
| W: true, | |
| E: true, | |
| F: true, | |
| S: true, | |
| }, | |
| logcatbuffers: { | |
| M: true, | |
| S: true, | |
| R: true, | |
| E: true, | |
| C: true, | |
| }, | |
| logcatformat: 'threadtime', | |
| dmesg: true, | |
| lines: '80', | |
| save: true, | |
| fallbackwidth: width, | |
| fallbackheight: height, | |
| } | |
| const backgroundsList = [ | |
| { | |
| name: "Default", | |
| value: " " | |
| }, | |
| { | |
| name: "Transparent", | |
| value: "transparent" | |
| }, | |
| { | |
| name: "Dark", | |
| value: "dark" | |
| }, | |
| ] | |
| const logcatFormatsList = [ | |
| { | |
| name: "Brief", | |
| value: "brief" | |
| }, | |
| { | |
| name: "Process", | |
| value: "process" | |
| }, | |
| { | |
| name: "Tag", | |
| value: "tag" | |
| }, | |
| { | |
| name: "Thread", | |
| value: "thread" | |
| }, | |
| { | |
| name: "Time", | |
| value: "time" | |
| }, | |
| { | |
| name: "Thread time", | |
| value: "threadtime" | |
| } | |
| ] | |
| const logcatBuffersList = [ | |
| { | |
| name: "Main", | |
| value: "M" | |
| }, | |
| { | |
| name: "System", | |
| value: "S" | |
| }, | |
| { | |
| name: "Radio", | |
| value: "R" | |
| }, | |
| { | |
| name: "Events", | |
| value: "E" | |
| }, | |
| { | |
| name: "Crash", | |
| value: "C" | |
| }, | |
| ] | |
| const logcatLevelsList = [ | |
| { | |
| name: "Verbose", | |
| value: "V" | |
| }, | |
| { | |
| name: "Debug", | |
| value: "D" | |
| }, | |
| { | |
| name: "Info", | |
| value: "I" | |
| }, | |
| { | |
| name: "Warning", | |
| value: "W" | |
| }, | |
| { | |
| name: "Error", | |
| value: "E" | |
| }, | |
| { | |
| name: "Fatal", | |
| value: "F" | |
| }, | |
| { | |
| name: "Silent", | |
| value: "S" | |
| }, | |
| ] | |
| const RenderToolbar = () => { | |
| const { context } = useActivity() | |
| return ( | |
| <Toolbar modifier="noshadow"> | |
| <Toolbar.Left> | |
| <Toolbar.BackButton onClick={context.popPage} /> | |
| </Toolbar.Left> | |
| <Toolbar.Center> | |
| Liveboot Magisk | |
| </Toolbar.Center> | |
| </Toolbar> | |
| ) | |
| } | |
| function ListItemSelectDialog(props) { | |
| const [config, setConfig] = useConfig(); | |
| const [open, setOpen] = React.useState(false); | |
| const { conf, primary, secondary, items } = props; | |
| const handleClickOpen = () => { | |
| setOpen(true); | |
| }; | |
| const handleClose = () => { | |
| setOpen(false) | |
| setConfig(conf, items[0].value) | |
| }; | |
| const handleListItemClick = (value) => { | |
| setOpen(false) | |
| setConfig(conf, value); | |
| }; | |
| return ( | |
| <> | |
| <ListItemButton onClick={handleClickOpen}> | |
| <ListItemText primary={primary} secondary={secondary} /> | |
| </ListItemButton> | |
| <Dialog fullWidth onClose={handleClose} open={open}> | |
| <DialogTitle>{primary}</DialogTitle> | |
| <List sx={{ pt: 0 }}> | |
| {items.map((item) => ( | |
| <ListItem disablePadding key={item.value}> | |
| <ListItemButton onClick={() => handleListItemClick(item.value)}> | |
| <ListItemText primary={item.name} /> | |
| {item.value === config[conf] && ( | |
| <ListItemIcon> | |
| <Check /> | |
| </ListItemIcon> | |
| )} | |
| </ListItemButton> | |
| </ListItem> | |
| ))} | |
| </List> | |
| </Dialog> | |
| </> | |
| ); | |
| } | |
| const ListItemCheckboxDialog = (props) => { | |
| const [config, setConfig] = useConfig(); | |
| const [open, setOpen] = React.useState(false); | |
| const { conf, primary, secondary, items } = props; | |
| const handleClickOpen = () => { | |
| setOpen(true); | |
| }; | |
| const handleClose = () => { | |
| setOpen(false) | |
| }; | |
| const handleToggle = (e, item) => { | |
| setConfig(conf, (prev) => { | |
| return Object.assign(prev, { | |
| [item.value]: e.target.checked | |
| }) | |
| }); | |
| }; | |
| return ( | |
| <> | |
| <ListItemButton onClick={handleClickOpen}> | |
| <ListItemText primary={primary} secondary={secondary} /> | |
| </ListItemButton> | |
| <Dialog fullWidth open={open} onClose={handleClose}> | |
| <DialogTitle>{props.primary}</DialogTitle> | |
| <List> | |
| {items.map((item) => ( | |
| <ListItem key={item.value}> | |
| <ListItemIcon> | |
| <Checkbox | |
| edge="start" | |
| checked={config[conf][item.value]} | |
| onChange={(e) => handleToggle(e, item)} | |
| /> | |
| </ListItemIcon> | |
| <ListItemText primary={item.name} secondary={item.desc} /> | |
| </ListItem> | |
| ))} | |
| </List> | |
| <DialogActions> | |
| <Button onClick={handleClose} color="primary"> | |
| Close | |
| </Button> | |
| </DialogActions> | |
| </Dialog> | |
| </> | |
| ) | |
| } | |
| const ListItemSwitch = (props) => { | |
| const [config, setConfig] = useConfig(); | |
| return ( | |
| <ListItem> | |
| <ListItemText primary={props.primary} secondary={props.secondary} /> | |
| <Switch checked={config[props.conf]} onChange={(e) => setConfig(props.conf, e.target.checked)} /> | |
| </ListItem> | |
| ) | |
| } | |
| const App = () => { | |
| const [config, setConfig] = useConfig(); | |
| const logcatbuffers = React.useMemo(() => Object.entries(config.logcatbuffers).map((buf) => { | |
| const key = buf[0] | |
| const value = buf[1] | |
| if (value) return key | |
| }).join(""), [config]) | |
| const logcatlevels = React.useMemo(() => Object.entries(config.logcatlevels).map((lvl) => { | |
| const key = lvl[0] | |
| const value = lvl[1] | |
| if (value) return key | |
| }).join(""), [config]) | |
| const commandString = React.useMemo(() => { | |
| let command = ""; | |
| if (config.background) command += `${config.background} `; | |
| if (config.colors) { | |
| command += "colors "; | |
| } else { | |
| command += "logcatnocolors "; | |
| } | |
| if (config.wordwrap) command += "wordwrap "; | |
| if (config.save) command += "save "; | |
| if (logcatlevels.length !== 0) { | |
| command += `logcatlevels=${logcatlevels} `; | |
| } | |
| if (logcatbuffers.length !== 0) { | |
| command += `logcatbuffers=${logcatbuffers} `; | |
| } | |
| command += `logcatformat=${config.logcatformat} `; | |
| if (config.dmesg) { | |
| command += `dmesg=0-99 `; | |
| } else { | |
| command += `dmesg=0--1 `; | |
| } | |
| command += `lines=${config.lines} `; | |
| command += `fallbackwidth=${config.fallbackwidth} `; | |
| command += `fallbackheight=${config.fallbackheight}`; | |
| const parsedCommand = command.trim() | |
| SuFile.write("/data/adb/liveboot.args.txt", parsedCommand) | |
| return parsedCommand; | |
| }, [config]) | |
| const findBackground = React.useMemo(() => backgroundsList.find((t) => t.value === config.background), [config.background]) | |
| const findLogcatFormat = React.useMemo(() => logcatFormatsList.find((t) => t.value === config.logcatformat), [config.logcatformat]) | |
| const findLogcatBuffers = React.useMemo(() => logcatBuffersList.filter((buf) => logcatbuffers.includes(buf.value)).map((n) => n.name), [config.logcatbuffers]) | |
| const findLogcatLevels = React.useMemo(() => logcatLevelsList.filter((lvl) => logcatlevels.includes(lvl.value)).map((n) => n.name), [config.logcatlevels]) | |
| return ( | |
| <Page sx={{ p: 2 }} renderToolbar={RenderToolbar}> | |
| <CodeBlock lang="">{`liveboot ${commandString}`}</CodeBlock> | |
| <List subheader={<ListSubheader>Logcat appearence</ListSubheader>}> | |
| <ListItemSwitch conf="wordwrap" primary="Word wrap" /> | |
| <ListItemSwitch conf="colors" primary="Colorful logs" /> | |
| <ListItemSelectDialog conf="background" primary="Background" secondary={findBackground.name} items={backgroundsList} /> | |
| </List> | |
| <Divider /> | |
| <List subheader={<ListSubheader>Settings</ListSubheader>}> | |
| <ListItemSelectDialog conf="logcatformat" primary="Logcat format" secondary={findLogcatFormat.name} items={logcatFormatsList} /> | |
| <ListItemCheckboxDialog conf="logcatbuffers" primary="Logcat buffers" secondary={findLogcatBuffers.join(", ")} items={logcatBuffersList} /> | |
| <ListItemCheckboxDialog conf="logcatlevels" primary="Logcat levels" secondary={findLogcatLevels.join(", ")} items={logcatLevelsList} /> | |
| </List> | |
| <Divider /> | |
| <List subheader={<ListSubheader>Other</ListSubheader>}> | |
| <ListItemSwitch conf="save" primary="Save logs" /> | |
| <ListItemSwitch conf="dmesg" primary="DMESG" /> | |
| <TextField | |
| sx={{ m: 1, width: "calc(100% - 16px)" }} | |
| type="number" | |
| label="Lines" | |
| variant="outlined" | |
| value={config.lines} | |
| onInput={(e) => { | |
| e.target.value = Math.max(0, parseInt(e.target.value)).toString().slice(0, 5) | |
| }} | |
| onChange={(e) => setConfig("lines", e.target.value)} /> | |
| </List> | |
| </Page> | |
| ) | |
| } | |
| export default withRequireNewVersion({ | |
| versionCode: 32325, | |
| component: () => { | |
| return ( | |
| <ConfigProvider | |
| loadFromFile="/data/adb/liveboot.config.json" | |
| initialConfig={initialConfig} | |
| loader="json" | |
| > | |
| <App /> | |
| </ConfigProvider> | |
| ); | |
| }, | |
| }); |
@DerGoogler Isn't it possible to get the fallbackwidth and fallbackheight values of the device with this code? Or at least run the shell command and use its output?