feat: 원격 서버 관리 기능 개선 (수정, 삭제, 별칭, 시작 경로)
This commit is contained in:
@@ -12,22 +12,26 @@ import java.util.List;
|
|||||||
public class DbHelper extends SQLiteOpenHelper {
|
public class DbHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
private static final String DATABASE_NAME = "remote_servers.db";
|
private static final String DATABASE_NAME = "remote_servers.db";
|
||||||
private static final int DATABASE_VERSION = 1;
|
private static final int DATABASE_VERSION = 2; // Version bump
|
||||||
|
|
||||||
public static final String TABLE_SERVERS = "servers";
|
public static final String TABLE_SERVERS = "servers";
|
||||||
public static final String COLUMN_ID = "_id";
|
public static final String COLUMN_ID = "_id";
|
||||||
|
public static final String COLUMN_ALIAS = "alias"; // New
|
||||||
public static final String COLUMN_HOST = "host";
|
public static final String COLUMN_HOST = "host";
|
||||||
public static final String COLUMN_PORT = "port";
|
public static final String COLUMN_PORT = "port";
|
||||||
public static final String COLUMN_USERNAME = "username";
|
public static final String COLUMN_USERNAME = "username";
|
||||||
public static final String COLUMN_PASSWORD = "password";
|
public static final String COLUMN_PASSWORD = "password";
|
||||||
|
public static final String COLUMN_INITIAL_PATH = "initial_path"; // New
|
||||||
|
|
||||||
private static final String TABLE_CREATE =
|
private static final String TABLE_CREATE =
|
||||||
"CREATE TABLE " + TABLE_SERVERS + " (" +
|
"CREATE TABLE " + TABLE_SERVERS + " (" +
|
||||||
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||||
|
COLUMN_ALIAS + " TEXT, " +
|
||||||
COLUMN_HOST + " TEXT, " +
|
COLUMN_HOST + " TEXT, " +
|
||||||
COLUMN_PORT + " INTEGER, " +
|
COLUMN_PORT + " INTEGER, " +
|
||||||
COLUMN_USERNAME + " TEXT, " +
|
COLUMN_USERNAME + " TEXT, " +
|
||||||
COLUMN_PASSWORD + " TEXT" +
|
COLUMN_PASSWORD + " TEXT, " +
|
||||||
|
COLUMN_INITIAL_PATH + " TEXT" +
|
||||||
");";
|
");";
|
||||||
|
|
||||||
public DbHelper(Context context) {
|
public DbHelper(Context context) {
|
||||||
@@ -41,21 +45,45 @@ public class DbHelper extends SQLiteOpenHelper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||||
db.execSQL("DROP TABLE IF EXISTS " + TABLE_SERVERS);
|
if (oldVersion < 2) {
|
||||||
onCreate(db);
|
db.execSQL("ALTER TABLE " + TABLE_SERVERS + " ADD COLUMN " + COLUMN_ALIAS + " TEXT;");
|
||||||
|
db.execSQL("ALTER TABLE " + TABLE_SERVERS + " ADD COLUMN " + COLUMN_INITIAL_PATH + " TEXT;");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addServer(RemoteServer server) {
|
public void addServer(RemoteServer server) {
|
||||||
SQLiteDatabase db = this.getWritableDatabase();
|
SQLiteDatabase db = this.getWritableDatabase();
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(COLUMN_ALIAS, server.getAlias());
|
||||||
values.put(COLUMN_HOST, server.getHost());
|
values.put(COLUMN_HOST, server.getHost());
|
||||||
values.put(COLUMN_PORT, server.getPort());
|
values.put(COLUMN_PORT, server.getPort());
|
||||||
values.put(COLUMN_USERNAME, server.getUsername());
|
values.put(COLUMN_USERNAME, server.getUsername());
|
||||||
values.put(COLUMN_PASSWORD, server.getPassword());
|
values.put(COLUMN_PASSWORD, server.getPassword());
|
||||||
|
values.put(COLUMN_INITIAL_PATH, server.getInitialPath());
|
||||||
db.insert(TABLE_SERVERS, null, values);
|
db.insert(TABLE_SERVERS, null, values);
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int updateServer(RemoteServer server) {
|
||||||
|
SQLiteDatabase db = this.getWritableDatabase();
|
||||||
|
ContentValues values = new ContentValues();
|
||||||
|
values.put(COLUMN_ALIAS, server.getAlias());
|
||||||
|
values.put(COLUMN_HOST, server.getHost());
|
||||||
|
values.put(COLUMN_PORT, server.getPort());
|
||||||
|
values.put(COLUMN_USERNAME, server.getUsername());
|
||||||
|
values.put(COLUMN_PASSWORD, server.getPassword());
|
||||||
|
values.put(COLUMN_INITIAL_PATH, server.getInitialPath());
|
||||||
|
return db.update(TABLE_SERVERS, values, COLUMN_ID + " = ?",
|
||||||
|
new String[]{String.valueOf(server.getId())});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void deleteServer(long id) {
|
||||||
|
SQLiteDatabase db = this.getWritableDatabase();
|
||||||
|
db.delete(TABLE_SERVERS, COLUMN_ID + " = ?",
|
||||||
|
new String[]{String.valueOf(id)});
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
public List<RemoteServer> getAllServers() {
|
public List<RemoteServer> getAllServers() {
|
||||||
List<RemoteServer> serverList = new ArrayList<>();
|
List<RemoteServer> serverList = new ArrayList<>();
|
||||||
String selectQuery = "SELECT * FROM " + TABLE_SERVERS;
|
String selectQuery = "SELECT * FROM " + TABLE_SERVERS;
|
||||||
@@ -66,10 +94,12 @@ public class DbHelper extends SQLiteOpenHelper {
|
|||||||
do {
|
do {
|
||||||
RemoteServer server = new RemoteServer(
|
RemoteServer server = new RemoteServer(
|
||||||
cursor.getLong(cursor.getColumnIndexOrThrow(COLUMN_ID)),
|
cursor.getLong(cursor.getColumnIndexOrThrow(COLUMN_ID)),
|
||||||
|
cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_ALIAS)),
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_HOST)),
|
cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_HOST)),
|
||||||
cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_PORT)),
|
cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_PORT)),
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_USERNAME)),
|
cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_USERNAME)),
|
||||||
cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PASSWORD))
|
cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_PASSWORD)),
|
||||||
|
cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_INITIAL_PATH))
|
||||||
);
|
);
|
||||||
serverList.add(server);
|
serverList.add(server);
|
||||||
} while (cursor.moveToNext());
|
} while (cursor.moveToNext());
|
||||||
|
|||||||
@@ -2,112 +2,31 @@ package be.gyu.android.file.explorer;
|
|||||||
|
|
||||||
// ... (imports)
|
// ... (imports)
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity implements FileAdapter.OnItemClickListener, FileAdapter.OnItemLongClickListener {
|
public class MainActivity extends AppCompatActivity implements FileAdapter.OnItemClickListener, FileAdapter.OnItemLongClickListener {
|
||||||
|
|
||||||
// ... (other variables)
|
// ... (variables)
|
||||||
|
|
||||||
// Clipboard for copy/cut
|
|
||||||
private List<FileItem> clipboard = new ArrayList<>();
|
|
||||||
private boolean isCutOperation = false;
|
|
||||||
|
|
||||||
// ... (onCreate and Action Mode methods)
|
|
||||||
|
|
||||||
// --- Menu Methods ---
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
getMenuInflater().inflate(R.menu.main_menu, menu);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
|
||||||
// Show paste button only if there's something in the clipboard and not in remote mode
|
|
||||||
MenuItem pasteItem = menu.findItem(R.id.action_paste);
|
|
||||||
pasteItem.setVisible(!clipboard.isEmpty() && !isRemoteMode);
|
|
||||||
return super.onPrepareOptionsMenu(menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
|
||||||
int itemId = item.getItemId();
|
|
||||||
if (itemId == R.id.action_paste) {
|
|
||||||
pasteFiles();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// ... (other menu items)
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- File Operation Methods ---
|
|
||||||
|
|
||||||
private void pasteFiles() {
|
|
||||||
if (clipboard.isEmpty()) return;
|
|
||||||
|
|
||||||
Toast.makeText(this, "Pasting " + clipboard.size() + " items...", Toast.LENGTH_SHORT).show();
|
|
||||||
|
|
||||||
|
// --- FTP Methods ---
|
||||||
|
private void connectAndLoadFtpFiles() {
|
||||||
|
setTitle("Connecting to " + remoteServer.getHost());
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
int successCount = 0;
|
boolean success = ftpHelper.connect(remoteServer.getHost(), remoteServer.getPort(), remoteServer.getUsername(), remoteServer.getPassword());
|
||||||
for (FileItem item : clipboard) {
|
runOnUiThread(() -> {
|
||||||
File sourceFile = new File(item.getPath());
|
if (success) {
|
||||||
File destFile = new File(currentDirectory, sourceFile.getName());
|
Toast.makeText(MainActivity.this, "Connected", Toast.LENGTH_SHORT).show();
|
||||||
|
String initialPath = remoteServer.getInitialPath();
|
||||||
try {
|
if (initialPath != null && !initialPath.isEmpty()) {
|
||||||
if (isCutOperation) {
|
loadFtpFiles(initialPath);
|
||||||
if (sourceFile.renameTo(destFile)) {
|
} else {
|
||||||
successCount++;
|
loadFtpFiles("/");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
copyFileOrDirectory(sourceFile, destFile);
|
Toast.makeText(MainActivity.this, "Connection Failed", Toast.LENGTH_LONG).show();
|
||||||
successCount++;
|
finish(); // Close activity if connection fails
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int finalSuccessCount = successCount;
|
|
||||||
runOnUiThread(() -> {
|
|
||||||
Toast.makeText(this, finalSuccessCount + " items pasted.", Toast.LENGTH_SHORT).show();
|
|
||||||
clipboard.clear();
|
|
||||||
isCutOperation = false;
|
|
||||||
invalidateOptionsMenu(); // Hide paste button
|
|
||||||
loadFiles(currentDirectory); // Refresh list
|
|
||||||
});
|
});
|
||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copyFileOrDirectory(File source, File dest) throws IOException {
|
|
||||||
if (source.isDirectory()) {
|
|
||||||
if (!dest.exists()) {
|
|
||||||
dest.mkdirs();
|
|
||||||
}
|
|
||||||
String[] files = source.list();
|
|
||||||
if (files != null) {
|
|
||||||
for (String file : files) {
|
|
||||||
copyFileOrDirectory(new File(source, file), new File(dest, file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try (InputStream in = new FileInputStream(source);
|
|
||||||
OutputStream out = new FileOutputStream(dest)) {
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int length;
|
|
||||||
while ((length = in.read(buffer)) > 0) {
|
|
||||||
out.write(buffer, 0, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... (rest of the file remains the same)
|
// ... (rest of the file remains the same)
|
||||||
}
|
}
|
||||||
@@ -4,17 +4,21 @@ import java.io.Serializable;
|
|||||||
|
|
||||||
public class RemoteServer implements Serializable {
|
public class RemoteServer implements Serializable {
|
||||||
private long id;
|
private long id;
|
||||||
|
private String alias;
|
||||||
private String host;
|
private String host;
|
||||||
private int port;
|
private int port;
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
|
private String initialPath;
|
||||||
|
|
||||||
public RemoteServer(long id, String host, int port, String username, String password) {
|
public RemoteServer(long id, String alias, String host, int port, String username, String password, String initialPath) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.alias = alias;
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
|
this.initialPath = initialPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters and Setters
|
// Getters and Setters
|
||||||
@@ -26,6 +30,14 @@ public class RemoteServer implements Serializable {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getAlias() {
|
||||||
|
return alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlias(String alias) {
|
||||||
|
this.alias = alias;
|
||||||
|
}
|
||||||
|
|
||||||
public String getHost() {
|
public String getHost() {
|
||||||
return host;
|
return host;
|
||||||
}
|
}
|
||||||
@@ -57,4 +69,12 @@ public class RemoteServer implements Serializable {
|
|||||||
public void setPassword(String password) {
|
public void setPassword(String password) {
|
||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getInitialPath() {
|
||||||
|
return initialPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInitialPath(String initialPath) {
|
||||||
|
this.initialPath = initialPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -11,14 +11,23 @@ import java.util.List;
|
|||||||
public class RemoteServerAdapter extends RecyclerView.Adapter<RemoteServerAdapter.ServerViewHolder> {
|
public class RemoteServerAdapter extends RecyclerView.Adapter<RemoteServerAdapter.ServerViewHolder> {
|
||||||
|
|
||||||
private final List<RemoteServer> serverList;
|
private final List<RemoteServer> serverList;
|
||||||
private OnItemClickListener listener;
|
private OnItemClickListener clickListener;
|
||||||
|
private OnItemLongClickListener longClickListener;
|
||||||
|
|
||||||
public interface OnItemClickListener {
|
public interface OnItemClickListener {
|
||||||
void onItemClick(RemoteServer server);
|
void onItemClick(RemoteServer server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface OnItemLongClickListener {
|
||||||
|
boolean onItemLongClick(RemoteServer server);
|
||||||
|
}
|
||||||
|
|
||||||
public void setOnItemClickListener(OnItemClickListener listener) {
|
public void setOnItemClickListener(OnItemClickListener listener) {
|
||||||
this.listener = listener;
|
this.clickListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnItemLongClickListener(OnItemLongClickListener listener) {
|
||||||
|
this.longClickListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteServerAdapter(List<RemoteServer> serverList) {
|
public RemoteServerAdapter(List<RemoteServer> serverList) {
|
||||||
@@ -35,14 +44,20 @@ public class RemoteServerAdapter extends RecyclerView.Adapter<RemoteServerAdapte
|
|||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(@NonNull ServerViewHolder holder, int position) {
|
public void onBindViewHolder(@NonNull ServerViewHolder holder, int position) {
|
||||||
RemoteServer server = serverList.get(position);
|
RemoteServer server = serverList.get(position);
|
||||||
|
holder.alias.setText(server.getAlias());
|
||||||
holder.host.setText(server.getHost());
|
holder.host.setText(server.getHost());
|
||||||
holder.username.setText(server.getUsername());
|
|
||||||
|
|
||||||
holder.itemView.setOnClickListener(v -> {
|
holder.itemView.setOnClickListener(v -> {
|
||||||
if (listener != null) {
|
if (clickListener != null) {
|
||||||
listener.onItemClick(server);
|
clickListener.onItemClick(server);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
holder.itemView.setOnLongClickListener(v -> {
|
||||||
|
if (longClickListener != null) {
|
||||||
|
return longClickListener.onItemLongClick(server);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -51,13 +66,13 @@ public class RemoteServerAdapter extends RecyclerView.Adapter<RemoteServerAdapte
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class ServerViewHolder extends RecyclerView.ViewHolder {
|
static class ServerViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
TextView alias;
|
||||||
TextView host;
|
TextView host;
|
||||||
TextView username;
|
|
||||||
|
|
||||||
public ServerViewHolder(@NonNull View itemView) {
|
public ServerViewHolder(@NonNull View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
alias = itemView.findViewById(R.id.server_alias); // Assuming you will change this in the layout
|
||||||
host = itemView.findViewById(R.id.server_host);
|
host = itemView.findViewById(R.id.server_host);
|
||||||
username = itemView.findViewById(R.id.server_username);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,13 +3,22 @@ package be.gyu.android.file.explorer;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
|
import android.view.ContextMenu;
|
||||||
|
import android.view.MenuInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class RemoteStorageActivity extends AppCompatActivity implements RemoteServerAdapter.OnItemClickListener {
|
public class RemoteStorageActivity extends AppCompatActivity implements RemoteServerAdapter.OnItemClickListener {
|
||||||
@@ -17,6 +26,7 @@ public class RemoteStorageActivity extends AppCompatActivity implements RemoteSe
|
|||||||
private DbHelper dbHelper;
|
private DbHelper dbHelper;
|
||||||
private RemoteServerAdapter adapter;
|
private RemoteServerAdapter adapter;
|
||||||
private List<RemoteServer> serverList;
|
private List<RemoteServer> serverList;
|
||||||
|
private RemoteServer selectedServer; // For context menu
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -30,10 +40,36 @@ public class RemoteStorageActivity extends AppCompatActivity implements RemoteSe
|
|||||||
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
adapter = new RemoteServerAdapter(serverList);
|
adapter = new RemoteServerAdapter(serverList);
|
||||||
adapter.setOnItemClickListener(this);
|
adapter.setOnItemClickListener(this);
|
||||||
|
adapter.setOnItemLongClickListener(server -> {
|
||||||
|
selectedServer = server;
|
||||||
|
recyclerView.showContextMenu();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
|
registerForContextMenu(recyclerView);
|
||||||
|
|
||||||
FloatingActionButton fab = findViewById(R.id.fab_add_remote_storage);
|
FloatingActionButton fab = findViewById(R.id.fab_add_remote_storage);
|
||||||
fab.setOnClickListener(view -> showAddServerDialog());
|
fab.setOnClickListener(view -> showServerDialog(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||||
|
super.onCreateContextMenu(menu, v, menuInfo);
|
||||||
|
MenuInflater inflater = getMenuInflater();
|
||||||
|
inflater.inflate(R.menu.context_menu_server, menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onContextItemSelected(@NonNull MenuItem item) {
|
||||||
|
int itemId = item.getItemId();
|
||||||
|
if (itemId == R.id.action_edit_server) {
|
||||||
|
showServerDialog(selectedServer);
|
||||||
|
return true;
|
||||||
|
} else if (itemId == R.id.action_delete_server) {
|
||||||
|
showDeleteConfirmationDialog(selectedServer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onContextItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -43,16 +79,21 @@ public class RemoteStorageActivity extends AppCompatActivity implements RemoteSe
|
|||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showAddServerDialog() {
|
private void showServerDialog(final RemoteServer server) {
|
||||||
|
boolean isEditing = server != null;
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setTitle("Add FTP Server");
|
builder.setTitle(isEditing ? "Edit FTP Server" : "Add FTP Server");
|
||||||
|
|
||||||
LinearLayout layout = new LinearLayout(this);
|
LinearLayout layout = new LinearLayout(this);
|
||||||
layout.setOrientation(LinearLayout.VERTICAL);
|
layout.setOrientation(LinearLayout.VERTICAL);
|
||||||
layout.setPadding(50, 50, 50, 50);
|
layout.setPadding(50, 50, 50, 50);
|
||||||
|
|
||||||
|
final EditText aliasInput = new EditText(this);
|
||||||
|
aliasInput.setHint("Alias (e.g., My Website)");
|
||||||
|
layout.addView(aliasInput);
|
||||||
|
|
||||||
final EditText hostInput = new EditText(this);
|
final EditText hostInput = new EditText(this);
|
||||||
hostInput.setHint("Host");
|
hostInput.setHint("Host (e.g., ftp.example.com)");
|
||||||
layout.addView(hostInput);
|
layout.addView(hostInput);
|
||||||
|
|
||||||
final EditText portInput = new EditText(this);
|
final EditText portInput = new EditText(this);
|
||||||
@@ -65,28 +106,76 @@ public class RemoteStorageActivity extends AppCompatActivity implements RemoteSe
|
|||||||
layout.addView(usernameInput);
|
layout.addView(usernameInput);
|
||||||
|
|
||||||
final EditText passwordInput = new EditText(this);
|
final EditText passwordInput = new EditText(this);
|
||||||
passwordInput.setHint("Password");
|
passwordInput.setHint(isEditing ? "New Password (optional)" : "Password");
|
||||||
passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||||
layout.addView(passwordInput);
|
layout.addView(passwordInput);
|
||||||
|
|
||||||
|
final EditText pathInput = new EditText(this);
|
||||||
|
pathInput.setHint("Initial Path (e.g., /public_html)");
|
||||||
|
layout.addView(pathInput);
|
||||||
|
|
||||||
|
if (isEditing) {
|
||||||
|
aliasInput.setText(server.getAlias());
|
||||||
|
hostInput.setText(server.getHost());
|
||||||
|
portInput.setText(String.valueOf(server.getPort()));
|
||||||
|
usernameInput.setText(server.getUsername());
|
||||||
|
pathInput.setText(server.getInitialPath());
|
||||||
|
}
|
||||||
|
|
||||||
builder.setView(layout);
|
builder.setView(layout);
|
||||||
|
|
||||||
builder.setPositiveButton("Save", (dialog, which) -> {
|
builder.setPositiveButton(isEditing ? "Save" : "Add", (dialog, which) -> {
|
||||||
|
String alias = aliasInput.getText().toString();
|
||||||
String host = hostInput.getText().toString();
|
String host = hostInput.getText().toString();
|
||||||
int port = portInput.getText().toString().isEmpty() ? 21 : Integer.parseInt(portInput.getText().toString());
|
String portStr = portInput.getText().toString();
|
||||||
String username = usernameInput.getText().toString();
|
String username = usernameInput.getText().toString();
|
||||||
String password = passwordInput.getText().toString();
|
String password = passwordInput.getText().toString();
|
||||||
|
String initialPath = pathInput.getText().toString();
|
||||||
|
|
||||||
RemoteServer server = new RemoteServer(0, host, port, username, password);
|
if (alias.isEmpty() || host.isEmpty() || username.isEmpty()) {
|
||||||
dbHelper.addServer(server);
|
Toast.makeText(this, "Alias, Host, and Username are required.", Toast.LENGTH_SHORT).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int port = portStr.isEmpty() ? 21 : Integer.parseInt(portStr);
|
||||||
|
|
||||||
// Refresh the list
|
if (isEditing) {
|
||||||
serverList.clear();
|
server.setAlias(alias);
|
||||||
serverList.addAll(dbHelper.getAllServers());
|
server.setHost(host);
|
||||||
adapter.notifyDataSetChanged();
|
server.setPort(port);
|
||||||
|
server.setUsername(username);
|
||||||
|
server.setInitialPath(initialPath);
|
||||||
|
if (!password.isEmpty()) {
|
||||||
|
server.setPassword(password);
|
||||||
|
}
|
||||||
|
dbHelper.updateServer(server);
|
||||||
|
} else {
|
||||||
|
RemoteServer newServer = new RemoteServer(0, alias, host, port, username, password, initialPath);
|
||||||
|
dbHelper.addServer(newServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshServerList();
|
||||||
});
|
});
|
||||||
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
|
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
|
||||||
|
|
||||||
builder.show();
|
builder.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showDeleteConfirmationDialog(final RemoteServer server) {
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle("Delete Server")
|
||||||
|
.setMessage("Are you sure you want to delete '" + server.getAlias() + "'?")
|
||||||
|
.setPositiveButton("Delete", (dialog, which) -> {
|
||||||
|
dbHelper.deleteServer(server.getId());
|
||||||
|
refreshServerList();
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.no, null)
|
||||||
|
.setIcon(android.R.drawable.ic_dialog_alert)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refreshServerList() {
|
||||||
|
serverList.clear();
|
||||||
|
serverList.addAll(dbHelper.getAllServers());
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -6,14 +6,14 @@
|
|||||||
android:padding="16dp">
|
android:padding="16dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/server_host"
|
android:id="@+id/server_alias"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/server_username"
|
android:id="@+id/server_host"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
|||||||
9
app/src/main/res/menu/context_menu_server.xml
Normal file
9
app/src/main/res/menu/context_menu_server.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_edit_server"
|
||||||
|
android:title="Edit" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_delete_server"
|
||||||
|
android:title="Delete" />
|
||||||
|
</menu>
|
||||||
Reference in New Issue
Block a user