Skip to content

Commit 40dcbd9

Browse files
committed
ANDROID: file manager webui (wip)
1 parent 04b0988 commit 40dcbd9

File tree

4 files changed

+111
-54
lines changed

4 files changed

+111
-54
lines changed

src/platform/android/app/src/main/java/net/sourceforge/smallbasic/WebServer.java

Lines changed: 72 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@
55
import java.io.ByteArrayInputStream;
66
import java.io.ByteArrayOutputStream;
77
import java.io.DataInputStream;
8+
import java.io.File;
89
import java.io.IOException;
910
import java.io.InputStream;
1011
import java.io.OutputStream;
12+
import java.io.UnsupportedEncodingException;
1113
import java.net.ServerSocket;
1214
import java.net.Socket;
1315
import java.net.URLDecoder;
16+
import java.nio.file.Files;
17+
import java.nio.file.attribute.BasicFileAttributes;
18+
import java.nio.file.attribute.FileTime;
19+
import java.text.DateFormat;
1420
import java.util.ArrayList;
1521
import java.util.Collection;
1622
import java.util.Collections;
@@ -55,32 +61,6 @@ public void run() {
5561
protected abstract void log(String message, Exception exception);
5662
protected abstract void log(String message);
5763

58-
/**
59-
* Appends a string field to the given JSON string
60-
*/
61-
private void appendJson(StringBuilder json, String field, String value, boolean nextField) {
62-
json.append(field)
63-
.append(":'")
64-
.append(value)
65-
.append("'");
66-
if (nextField) {
67-
json.append(",");
68-
}
69-
}
70-
71-
/**
72-
* Appends an int field to the given JSON string
73-
*/
74-
private void appendJson(StringBuilder json, String field, long value, boolean nextField) {
75-
json.append(field)
76-
.append(":'")
77-
.append(value)
78-
.append("'");
79-
if (nextField) {
80-
json.append(",");
81-
}
82-
}
83-
8464
/**
8565
* Parses HTTP GET parameters with the given name
8666
*/
@@ -168,21 +148,23 @@ private Response handleDownload(Map<String, Collection<String>> parameters) thro
168148
* Handler for files API
169149
*/
170150
private Response handleFileList() throws IOException {
171-
StringBuilder json = new StringBuilder("[");
151+
JsonBuilder builder = new JsonBuilder();
152+
builder.append('[');
172153
long id = 0;
173-
String comma = "";
154+
char comma = 0;
174155
for (FileData nextFile : getFileData()) {
175-
json.append(comma);
176-
json.append("{");
177-
appendJson(json, "id", id++, true);
178-
appendJson(json, "fileName", nextFile.fileName, true);
179-
appendJson(json, "size", nextFile.size, true);
180-
appendJson(json, "date", nextFile.date, false);
181-
json.append("}");
182-
comma = ",";
156+
builder.append(comma);
157+
builder.append('{');
158+
builder.append("id", id++, true);
159+
builder.append("fileName", nextFile.fileName, true);
160+
builder.append("size", nextFile.size, true);
161+
builder.append("date", nextFile.date, false);
162+
builder.append('}');
163+
comma = ',';
183164
}
184-
json.append("]");
185-
return new Response(new ByteArrayInputStream(json.toString().getBytes("utf-8")), json.length());
165+
builder.append(']');
166+
byte[] json = builder.getBytes();
167+
return new Response(new ByteArrayInputStream(json), json.length);
186168
}
187169

188170
/**
@@ -298,6 +280,56 @@ public static class FileData {
298280
String fileName;
299281
String date;
300282
long size;
283+
284+
FileData(File file) throws IOException {
285+
BasicFileAttributes attr = Files.readAttributes(file.toPath(), BasicFileAttributes.class);
286+
FileTime lastModifiedTime = attr.lastModifiedTime();
287+
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.DEFAULT);
288+
this.fileName = file.getName();
289+
this.date = dateFormat.format(lastModifiedTime.toMillis());
290+
this.size = file.length();
291+
}
292+
}
293+
294+
/**
295+
* Build JSON string
296+
*/
297+
public static class JsonBuilder {
298+
private final StringBuilder json;
299+
300+
JsonBuilder() {
301+
json = new StringBuilder();
302+
}
303+
304+
void append(char chr) {
305+
if (chr > 0) {
306+
json.append(chr);
307+
}
308+
}
309+
310+
void append(String field, String value, boolean nextField, boolean quote) {
311+
json.append("\"")
312+
.append(field)
313+
.append("\":")
314+
.append(quote ? "\"" : "")
315+
.append(value)
316+
.append(quote ? "\"" : "");
317+
if (nextField) {
318+
json.append(",");
319+
}
320+
}
321+
322+
void append(String field, String value, boolean nextField) {
323+
this.append(field, value, nextField, true);
324+
}
325+
326+
void append(String field, long value, boolean nextField) {
327+
this.append(field, String.valueOf(value), nextField, false);
328+
}
329+
330+
byte[] getBytes() throws UnsupportedEncodingException {
331+
return json.toString().getBytes("utf-8");
332+
}
301333
}
302334

303335
/**
@@ -312,11 +344,11 @@ public Response(InputStream inputStream, long length) {
312344
this.length = length;
313345
}
314346

315-
public InputStream getInputStream() {
347+
InputStream getInputStream() {
316348
return inputStream;
317349
}
318350

319-
public long getLength() {
351+
long getLength() {
320352
return length;
321353
}
322354

src/platform/android/webui/public/index.html

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,6 @@
99
</head>
1010
<body>
1111
<noscript>You need to enable JavaScript to run this app.</noscript>
12-
<script>
13-
window.rows = [
14-
{id: 1, fileName: '2048.bas', size: 1322, date: '12/12/2021' },
15-
{id: 2, fileName: '3dtorus.bas', size: 1222, date: '12/11/2021' },
16-
{id: 3, fileName: 'amiga.bas', size: 12, date: '12/10/2021' },
17-
{id: 4, fileName: 'very big long file name that goes forever.bas', size: 722, date: '12/09/2021' },
18-
];
19-
</script>
2012
<div id="root"></div>
2113
</body>
2214
</html>

src/platform/android/webui/server/src/main/java/net/sourceforge/smallbasic/Server.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.io.IOException;
55
import java.io.InputStream;
66
import java.nio.file.Files;
7+
import java.util.ArrayList;
78
import java.util.Collection;
89

910
public class Server {
@@ -16,7 +17,14 @@ protected void execStream(String line, InputStream inputStream) {
1617

1718
@Override
1819
protected Collection<FileData> getFileData() throws IOException {
19-
return null;
20+
final File folder = new File("../basic");
21+
Collection<FileData> result = new ArrayList<>();
22+
for (final File fileEntry : folder.listFiles()) {
23+
if (!fileEntry.isDirectory()) {
24+
result.add(new FileData(fileEntry));
25+
}
26+
}
27+
return result;
2028
}
2129

2230
@Override

src/platform/android/webui/src/App.js

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
useEffect,
23
useState
34
} from 'react';
45

@@ -7,6 +8,7 @@ import {
78
Box,
89
Button,
910
Link,
11+
TextField,
1012
Toolbar,
1113
Typography,
1214
} from '@mui/material';
@@ -60,8 +62,9 @@ function GridToolbarDownload(props) {
6062
let color = useTheme().palette.primary.main;
6163
let args = "";
6264
let join = "";
65+
console.log(props.rows);
6366
props.selections.forEach(i => {
64-
args += join + "f=" + encodeURIComponent(props.rows[i - 1].fileName);
67+
args += join + "f=" + encodeURIComponent(props.rows[i].fileName);
6568
join = "&";
6669
});
6770

@@ -87,9 +90,8 @@ function AppToolbar(props) {
8790
);
8891
}
8992

90-
export default function App() {
93+
function FileList(props) {
9194
const [selectionModel, setSelectionModel] = useState([]);
92-
const rows = window.rows;
9395
return (
9496
<Box sx={{flexGrow: 1}}>
9597
<AppBar position="static">
@@ -107,11 +109,11 @@ export default function App() {
107109
</Toolbar>
108110
</AppBar>
109111
<Box sx={{height: 'calc(100vh - 5.5em)', width: '100%'}}>
110-
<DataGrid rows={rows}
112+
<DataGrid rows={props.rows}
111113
columns={columns}
112114
pageSize={5}
113115
components={{Toolbar: AppToolbar}}
114-
componentsProps={{toolbar: {selections: selectionModel, rows: rows}}}
116+
componentsProps={{toolbar: {selections: selectionModel, rows: props.rows}}}
115117
onSelectionModelChange={(model) => setSelectionModel(model)}
116118
selectionModel={selectionModel}
117119
rowsPerPageOptions={[5]}
@@ -122,3 +124,26 @@ export default function App() {
122124

123125
);
124126
}
127+
128+
export default function App() {
129+
const [token, setToken] = useState("token=ABC123");
130+
const [rows, setRows] = useState([]);
131+
132+
useEffect(() => {
133+
const getFiles = async () => {
134+
let response = await fetch('/api/files', {
135+
method: 'POST',
136+
headers: {
137+
'Content-Type': 'application/text;charset=utf-8'
138+
},
139+
body: token
140+
});
141+
setRows(await response.json());
142+
};
143+
getFiles().catch(console.error);
144+
}, [token, setRows]);
145+
146+
return (
147+
<FileList rows={rows}/>
148+
);
149+
}

0 commit comments

Comments
 (0)