Skip to content

Commit 24f2027

Browse files
committed
ANDROID: implemented file manager delete file operation.
1 parent cb470ce commit 24f2027

File tree

4 files changed

+142
-17
lines changed

4 files changed

+142
-17
lines changed

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,25 @@ private boolean isPublicStorage(String dir) {
938938
private class WebServerImpl extends WebServer {
939939
private final Map<String, Long> fileLengths = new HashMap<>();
940940

941+
@Override
942+
protected byte[] decodeBase64(String data) {
943+
return Base64.decode(data, Base64.DEFAULT);
944+
}
945+
946+
@Override
947+
protected void deleteFile(String fileName) throws IOException {
948+
if (fileName == null) {
949+
throw new IOException("Empty file name");
950+
}
951+
File file = getFile(fileName);
952+
if (file == null) {
953+
throw new IOException("File not found");
954+
}
955+
if (!file.delete()) {
956+
throw new IOException("Failed to delete file:" + fileName);
957+
}
958+
}
959+
941960
@Override
942961
protected void execStream(InputStream inputStream) throws IOException {
943962
MainActivity.this.execStream(inputStream);
@@ -983,8 +1002,8 @@ protected void log(String message) {
9831002

9841003
@Override
9851004
protected void renameFile(String from, String to) throws IOException {
986-
if (to == null || !to.endsWith(".bas")) {
987-
throw new IOException("Invalid file name: " + to);
1005+
if (to == null) {
1006+
throw new IOException("Empty file name");
9881007
}
9891008
File toFile = getFile(to);
9901009
if (toFile != null) {

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

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package net.sourceforge.smallbasic;
22

3-
import android.util.Base64;
4-
53
import java.io.BufferedOutputStream;
64
import java.io.ByteArrayInputStream;
75
import java.io.ByteArrayOutputStream;
@@ -64,9 +62,11 @@ public void run() {
6462
socketThread.start();
6563
}
6664

65+
protected abstract void deleteFile(String fileName) throws IOException;
6766
protected abstract void execStream(InputStream inputStream) throws IOException;
6867
protected abstract Response getFile(String path, boolean asset) throws IOException;
6968
protected abstract Collection<FileData> getFileData() throws IOException;
69+
protected abstract byte[] decodeBase64(String data);
7070
protected abstract void log(String message);
7171
protected abstract void log(String message, Exception exception);
7272
protected abstract void renameFile(String from, String to) throws IOException;
@@ -100,7 +100,7 @@ private void runServer(final int socketNum, final String token) throws IOExcepti
100100
/**
101101
* Server Request base class
102102
*/
103-
public abstract static class AbstractRequest {
103+
public abstract class AbstractRequest {
104104
final Socket socket;
105105
final String method;
106106
final String url;
@@ -267,7 +267,7 @@ public FileData(File file) {
267267
/**
268268
* Holder for POST form data
269269
*/
270-
public static class FormField {
270+
public class FormField {
271271
private static final String BASE_64_PREFIX = ";base64,";
272272
private final String string;
273273
private final byte[] bytes;
@@ -277,7 +277,7 @@ public FormField(String key, String value) throws IOException {
277277
if (index != -1 && "data".equals(key)) {
278278
ByteArrayOutputStream data = new ByteArrayOutputStream();
279279
String base64Value = value.substring(index + BASE_64_PREFIX.length());
280-
data.write(Base64.decode(base64Value, Base64.DEFAULT));
280+
data.write(decodeBase64(base64Value));
281281
this.string = null;
282282
this.bytes = data.toByteArray();
283283
} else {
@@ -286,7 +286,8 @@ public FormField(String key, String value) throws IOException {
286286
}
287287
}
288288

289-
public String getString() {
289+
@Override
290+
public String toString() {
290291
return string;
291292
}
292293

@@ -438,7 +439,7 @@ private Response handleDownload(Map<String, Collection<String>> data) throws IOE
438439
* Handler for files API
439440
*/
440441
private Response handleFileList() throws IOException {
441-
log("Sending file list");
442+
log("Creating file list");
442443
JsonBuilder builder = new JsonBuilder();
443444
builder.append('[');
444445
long id = 0;
@@ -492,6 +493,8 @@ private void handlePost(Map<String, FormField> data) throws IOException {
492493
handleUpload(data).send(socket, null);
493494
} else if (url.startsWith("/api/rename")) {
494495
handleRename(data).send(socket, null);
496+
} else if (url.startsWith("/api/delete")) {
497+
handleDelete(data).send(socket, null);
495498
} else {
496499
new Response(SC_NOT_FOUND).send(socket, null);
497500
}
@@ -506,6 +509,22 @@ private void handlePost(Map<String, FormField> data) throws IOException {
506509
}
507510
}
508511

512+
/**
513+
* Handler for File delete
514+
*/
515+
private Response handleDelete(Map<String, FormField> data) throws IOException {
516+
String fileName = getString(data, "fileName");
517+
Response result;
518+
try {
519+
deleteFile(fileName);
520+
log("Deleted " + fileName);
521+
result = handleFileList();
522+
} catch (IOException e) {
523+
result = handleStatus(false, e.getMessage());
524+
}
525+
return result;
526+
}
527+
509528
/**
510529
* Handler for File rename operations
511530
*/

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

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
import java.io.InputStream;
99
import java.io.OutputStream;
1010
import java.nio.file.Files;
11+
import java.nio.file.Paths;
1112
import java.nio.file.attribute.BasicFileAttributes;
1213
import java.nio.file.attribute.FileTime;
1314
import java.time.Instant;
1415
import java.time.ZoneId;
1516
import java.time.ZonedDateTime;
1617
import java.time.format.DateTimeFormatter;
1718
import java.util.ArrayList;
19+
import java.util.Base64;
1820
import java.util.Collection;
1921
import java.util.Objects;
2022

@@ -24,6 +26,16 @@ public class Server {
2426
public static void main(String[] args ) throws IOException {
2527
// ln -s ../../../../../../../../app/src/main/java/net/sourceforge/smallbasic/WebServer.java .
2628
WebServer webServer = new WebServer() {
29+
@Override
30+
protected byte[] decodeBase64(String data) {
31+
return Base64.getDecoder().decode(data);
32+
}
33+
34+
@Override
35+
protected void deleteFile(String fileName) throws IOException {
36+
Files.delete(Paths.get(BASIC_HOME, fileName));
37+
}
38+
2739
@Override
2840
protected void execStream(InputStream inputStream) {
2941
try {
@@ -35,6 +47,13 @@ protected void execStream(InputStream inputStream) {
3547
}
3648
}
3749

50+
@Override
51+
protected Response getFile(String path, boolean asset) throws IOException {
52+
String prefix = asset ? "../build/" : BASIC_HOME;
53+
File file = new File(prefix + path);
54+
return new Response(Files.newInputStream(file.toPath()), file.length());
55+
}
56+
3857
@Override
3958
protected Collection<FileData> getFileData() throws IOException {
4059
final File folder = new File(BASIC_HOME);
@@ -53,13 +72,6 @@ protected Collection<FileData> getFileData() throws IOException {
5372
return result;
5473
}
5574

56-
@Override
57-
protected Response getFile(String path, boolean asset) throws IOException {
58-
String prefix = asset ? "../build/" : BASIC_HOME;
59-
File file = new File(prefix + path);
60-
return new Response(Files.newInputStream(file.toPath()), file.length());
61-
}
62-
6375
@Override
6476
protected void log(String message) {
6577
System.err.println(message);
@@ -73,7 +85,7 @@ protected void log(String message, Exception exception) {
7385

7486
@Override
7587
protected void renameFile(String from, String to) throws IOException {
76-
if (to == null || !to.endsWith(".bas")) {
88+
if (to == null) {
7789
throw new IOException("Invalid File Name: " + to);
7890
}
7991
File toFile = new File(BASIC_HOME, to);

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

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ import {
99
Box,
1010
Button,
1111
CssBaseline,
12+
Dialog,
13+
DialogActions,
14+
DialogContent,
15+
DialogContentText,
16+
DialogTitle,
1217
Link,
1318
Snackbar,
1419
TextField,
@@ -26,6 +31,7 @@ import {
2631
} from '@mui/x-data-grid';
2732

2833
import {
34+
Delete as DeleteIcon,
2935
Download as DownloadIcon,
3036
Upload as UploadIcon
3137
} from '@mui/icons-material';
@@ -96,6 +102,11 @@ function renameFile(from, to, success, fail) {
96102
callApi('/api/rename', body, success, fail);
97103
}
98104

105+
function deleteFile(fileName, success, fail) {
106+
let body = "fileName=" + encodeURIComponent(fileName);
107+
callApi('/api/delete', body, success, fail);
108+
}
109+
99110
function copyFiles(event, success, progress, fail) {
100111
const fileReader = new FileReader();
101112
const input = event.target;
@@ -116,6 +127,68 @@ function copyFiles(event, success, progress, fail) {
116127
fileReader.readAsDataURL(files[index]);
117128
}
118129

130+
function ConfirmDeleteDialog(props) {
131+
return (
132+
<div>
133+
<Dialog
134+
open={props.open}
135+
onClose={props.handleClose}
136+
aria-labelledby="alert-dialog-title"
137+
aria-describedby="alert-dialog-description">
138+
<DialogTitle id="alert-dialog-title">
139+
{"Delete file"}
140+
</DialogTitle>
141+
<DialogContent>
142+
<DialogContentText id="alert-dialog-description">
143+
Are you sure you want to permanently delete {props.name}? You cannot undo this.
144+
</DialogContentText>
145+
</DialogContent>
146+
<DialogActions>
147+
<Button onClick={props.handleClose}>Cancel</Button>
148+
<Button onClick={props.handleDelete} autoFocus>
149+
Delete
150+
</Button>
151+
</DialogActions>
152+
</Dialog>
153+
</div>
154+
);
155+
}
156+
157+
function GridToolbarDelete(props) {
158+
const [error, setError] = useState(null);
159+
const [open, setOpen] = useState(false);
160+
161+
const showPrompt = () => {
162+
setOpen(true);
163+
};
164+
165+
const handleClose = () => {
166+
setOpen(false);
167+
};
168+
169+
const handleDelete = () => {
170+
setOpen(false);
171+
deleteFile(props.rows[props.selections[0]].fileName, (data) => {
172+
props.setRows(data);
173+
props.setSelections([]);
174+
}, (error) => {
175+
setError(error);
176+
setError(true);
177+
});
178+
};
179+
180+
return props.selections.length !== 1 ? null : (
181+
<Fragment>
182+
<ConfirmDeleteDialog open={open} name={props.rows[props.selections[0]].fileName} handleClose={handleClose} handleDelete={handleDelete}/>
183+
<ErrorMessage error={error} setError={setError} severity="error"/>
184+
<Button color="primary" size="small" component="label" sx={{marginLeft: '-4px'}} onClick={showPrompt}>
185+
<DeleteIcon />
186+
DELETE
187+
</Button>
188+
</Fragment>
189+
);
190+
}
191+
119192
function GridToolbarDownload(props) {
120193
let color = useTheme().palette.primary.main;
121194
let args = "";
@@ -203,6 +276,7 @@ function AppToolbar(props) {
203276
<GridToolbarDensitySelector />
204277
<GridToolbarUpload {...props}/>
205278
<GridToolbarDownload {...props}/>
279+
<GridToolbarDelete {...props}/>
206280
</GridToolbarContainer>
207281
);
208282
}
@@ -227,6 +301,7 @@ function FileList(props) {
227301

228302
const toolbarProps = {
229303
selections: selectionModel,
304+
setSelections: setSelectionModel,
230305
setRows: props.setRows,
231306
rows: props.rows
232307
};

0 commit comments

Comments
 (0)