Remove legacy XML UI code after Compose migration
This commit is contained in:
@@ -49,52 +49,6 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- OLD: Legacy MainActivity (DEPRECATED - kept for reference only) -->
|
||||
<activity
|
||||
android:name=".view.MainActivity"
|
||||
android:exported="false">
|
||||
<!-- Removed LAUNCHER intent - now using ComposeMainActivity -->
|
||||
</activity>
|
||||
|
||||
<!-- Upload History Activity -->
|
||||
<activity
|
||||
android:name=".view.UploadHistoryActivity"
|
||||
android:label="Upload History"
|
||||
android:parentActivityName=".view.MainActivity"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".view.MainActivity" />
|
||||
</activity>
|
||||
|
||||
<!-- Settings Activity -->
|
||||
<activity
|
||||
android:name=".view.SettingsActivity"
|
||||
android:label="Settings"
|
||||
android:parentActivityName=".view.MainActivity"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".view.MainActivity" />
|
||||
</activity>
|
||||
|
||||
<!-- Welcome Activity -->
|
||||
<activity
|
||||
android:name=".view.WelcomeActivity"
|
||||
android:label="Welcome"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
|
||||
|
||||
<!-- Server Setup Activity -->
|
||||
<activity
|
||||
android:name=".view.ServerSetupActivity"
|
||||
android:label="Server Setup"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".view.WelcomeActivity" />
|
||||
</activity>
|
||||
|
||||
<!-- File Upload Foreground Service -->
|
||||
<service
|
||||
android:name=".service.FileUploadForegroundService"
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
package com.mattintech.simplelogupload.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.format.Formatter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.mattintech.simplelogupload.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Adapter for displaying dumpstate files in a RecyclerView with multi-selection capability
|
||||
*/
|
||||
public class DumpstateAdapter extends RecyclerView.Adapter<DumpstateAdapter.ViewHolder> {
|
||||
|
||||
private final List<File> files;
|
||||
private final Context context;
|
||||
private final Set<Integer> selectedPositions = new HashSet<>();
|
||||
private OnSelectionChangedListener selectionChangedListener;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The context
|
||||
* @param files List of dumpstate files
|
||||
*/
|
||||
public DumpstateAdapter(Context context, List<File> files) {
|
||||
this.context = context;
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a listener for selection changes
|
||||
*
|
||||
* @param listener The listener
|
||||
*/
|
||||
public void setOnSelectionChangedListener(OnSelectionChangedListener listener) {
|
||||
this.selectionChangedListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of selected files
|
||||
*
|
||||
* @return List of selected files
|
||||
*/
|
||||
public List<File> getSelectedFiles() {
|
||||
List<File> selectedFiles = new ArrayList<>();
|
||||
for (int position : selectedPositions) {
|
||||
if (position >= 0 && position < files.size()) {
|
||||
selectedFiles.add(files.get(position));
|
||||
}
|
||||
}
|
||||
return selectedFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an item is selected
|
||||
*
|
||||
* @param position The position to check
|
||||
* @return true if selected, false otherwise
|
||||
*/
|
||||
public boolean isSelected(int position) {
|
||||
return selectedPositions.contains(position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select or deselect an item
|
||||
*
|
||||
* @param position The position to select/deselect
|
||||
* @param selected Whether to select (true) or deselect (false)
|
||||
*/
|
||||
public void setSelected(int position, boolean selected) {
|
||||
if (selected) {
|
||||
selectedPositions.add(position);
|
||||
} else {
|
||||
selectedPositions.remove(position);
|
||||
}
|
||||
notifyItemChanged(position);
|
||||
|
||||
if (selectionChangedListener != null) {
|
||||
selectionChangedListener.onSelectionChanged(selectedPositions.size());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle selection state of an item
|
||||
*
|
||||
* @param position The position to toggle
|
||||
*/
|
||||
public void toggleSelection(int position) {
|
||||
setSelected(position, !isSelected(position));
|
||||
}
|
||||
|
||||
/**
|
||||
* Select all items
|
||||
*/
|
||||
public void selectAll() {
|
||||
selectedPositions.clear();
|
||||
for (int i = 0; i < files.size(); i++) {
|
||||
selectedPositions.add(i);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
|
||||
if (selectionChangedListener != null) {
|
||||
selectionChangedListener.onSelectionChanged(selectedPositions.size());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all selections
|
||||
*/
|
||||
public void clearSelections() {
|
||||
selectedPositions.clear();
|
||||
notifyDataSetChanged();
|
||||
|
||||
if (selectionChangedListener != null) {
|
||||
selectionChangedListener.onSelectionChanged(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of selected items
|
||||
*
|
||||
* @return The count of selected items
|
||||
*/
|
||||
public int getSelectedCount() {
|
||||
return selectedPositions.size();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_dumpstate_file, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
File file = files.get(position);
|
||||
|
||||
// Set file name
|
||||
holder.fileNameText.setText(file.getName());
|
||||
|
||||
// Add tooltip for long filenames
|
||||
holder.fileNameText.setOnLongClickListener(v -> {
|
||||
Toast.makeText(context, file.getName(), Toast.LENGTH_LONG).show();
|
||||
return true;
|
||||
});
|
||||
|
||||
// Format and set file date
|
||||
Date lastModified = new Date(file.lastModified());
|
||||
String formattedDate = DateFormat.format("MMM dd, yyyy hh:mm a", lastModified).toString();
|
||||
holder.fileDateText.setText(context.getString(R.string.dumpstate_date_format, formattedDate));
|
||||
|
||||
// Format and set file size
|
||||
String fileSize = Formatter.formatFileSize(context, file.length());
|
||||
holder.fileSizeText.setText(context.getString(R.string.dumpstate_size_format, fileSize));
|
||||
|
||||
// Set checkbox state
|
||||
holder.checkBox.setChecked(isSelected(position));
|
||||
|
||||
// Set click listeners
|
||||
holder.checkBox.setOnClickListener(v -> toggleSelection(holder.getAbsoluteAdapterPosition()));
|
||||
|
||||
holder.itemView.setOnClickListener(v -> toggleSelection(holder.getAbsoluteAdapterPosition()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return files.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* ViewHolder for dumpstate file items
|
||||
*/
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
final CheckBox checkBox;
|
||||
final TextView fileNameText;
|
||||
final TextView fileDateText;
|
||||
final TextView fileSizeText;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
checkBox = itemView.findViewById(R.id.checkBox);
|
||||
fileNameText = itemView.findViewById(R.id.fileNameText);
|
||||
fileDateText = itemView.findViewById(R.id.fileDateText);
|
||||
fileSizeText = itemView.findViewById(R.id.fileSizeText);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for handling selection changes
|
||||
*/
|
||||
public interface OnSelectionChangedListener {
|
||||
void onSelectionChanged(int selectedCount);
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
package com.mattintech.simplelogupload.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.format.Formatter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.mattintech.simplelogupload.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Adapter for displaying dumpstate files in a RecyclerView
|
||||
*/
|
||||
public class DumpstateFileAdapter extends RecyclerView.Adapter<DumpstateFileAdapter.ViewHolder> {
|
||||
|
||||
private final List<File> files;
|
||||
private final Context context;
|
||||
private int selectedPosition = -1;
|
||||
private OnItemSelectedListener listener;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The context
|
||||
* @param files List of dumpstate files
|
||||
*/
|
||||
public DumpstateFileAdapter(Context context, List<File> files) {
|
||||
this.context = context;
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a listener for item selection
|
||||
*
|
||||
* @param listener The listener
|
||||
*/
|
||||
public void setOnItemSelectedListener(OnItemSelectedListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently selected file
|
||||
*
|
||||
* @return The selected file or null if none selected
|
||||
*/
|
||||
public File getSelectedFile() {
|
||||
if (selectedPosition >= 0 && selectedPosition < files.size()) {
|
||||
return files.get(selectedPosition);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_dumpstate_file, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
File file = files.get(position);
|
||||
|
||||
// Set file name
|
||||
holder.fileNameText.setText(file.getName());
|
||||
|
||||
// Add tooltip for long filenames
|
||||
holder.fileNameText.setOnLongClickListener(v -> {
|
||||
Toast.makeText(context, file.getName(), Toast.LENGTH_LONG).show();
|
||||
return true;
|
||||
});
|
||||
|
||||
// Format and set file date
|
||||
Date lastModified = new Date(file.lastModified());
|
||||
String formattedDate = DateFormat.format("MMM dd, yyyy hh:mm a", lastModified).toString();
|
||||
holder.fileDateText.setText(context.getString(R.string.dumpstate_date_format, formattedDate));
|
||||
|
||||
// Format and set file size
|
||||
String fileSize = Formatter.formatFileSize(context, file.length());
|
||||
holder.fileSizeText.setText(context.getString(R.string.dumpstate_size_format, fileSize));
|
||||
|
||||
// Set checkbox state
|
||||
holder.checkBox.setChecked(position == selectedPosition);
|
||||
|
||||
// Set click listener for the whole item
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
int previousSelected = selectedPosition;
|
||||
selectedPosition = holder.getAdapterPosition();
|
||||
|
||||
// Update previous selected item
|
||||
if (previousSelected >= 0) {
|
||||
notifyItemChanged(previousSelected);
|
||||
}
|
||||
|
||||
// Update newly selected item
|
||||
notifyItemChanged(selectedPosition);
|
||||
|
||||
// Notify listener
|
||||
if (listener != null) {
|
||||
listener.onItemSelected(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return files.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* ViewHolder for dumpstate file items
|
||||
*/
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
final CheckBox checkBox;
|
||||
final TextView fileNameText;
|
||||
final TextView fileDateText;
|
||||
final TextView fileSizeText;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
checkBox = itemView.findViewById(R.id.checkBox);
|
||||
fileNameText = itemView.findViewById(R.id.fileNameText);
|
||||
fileDateText = itemView.findViewById(R.id.fileDateText);
|
||||
fileSizeText = itemView.findViewById(R.id.fileSizeText);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for handling item selection
|
||||
*/
|
||||
public interface OnItemSelectedListener {
|
||||
void onItemSelected(File file);
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import com.mattintech.simplelogupload.controller.FileController;
|
||||
import com.mattintech.simplelogupload.controller.UploadController;
|
||||
import com.mattintech.simplelogupload.model.UploadResult;
|
||||
import com.mattintech.simplelogupload.upload.UploadStrategySelector;
|
||||
import com.mattintech.simplelogupload.view.MainActivity;
|
||||
import com.mattintech.simplelogupload.ComposeMainActivity;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
@@ -198,7 +198,7 @@ public class FileUploadForegroundService extends Service {
|
||||
* @return The notification
|
||||
*/
|
||||
private Notification createInitialNotification() {
|
||||
Intent notificationIntent = new Intent(this, MainActivity.class);
|
||||
Intent notificationIntent = new Intent(this, ComposeMainActivity.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
|
||||
notificationIntent, PendingIntent.FLAG_IMMUTABLE);
|
||||
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
package com.mattintech.simplelogupload.view;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.mattintech.simplelogupload.R;
|
||||
import com.mattintech.simplelogupload.adapter.DumpstateFileAdapter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Dialog for selecting a dumpstate file from multiple options
|
||||
*/
|
||||
public class DumpstateSelectionDialog extends Dialog {
|
||||
|
||||
private final List<File> dumpstateFiles;
|
||||
private final OnDumpstateSelectedListener listener;
|
||||
|
||||
private TextView titleText;
|
||||
private RecyclerView recyclerView;
|
||||
private TextView emptyView;
|
||||
private Button selectButton;
|
||||
private Button cancelButton;
|
||||
|
||||
private DumpstateFileAdapter adapter;
|
||||
|
||||
/**
|
||||
* Interface for handling dumpstate selection
|
||||
*/
|
||||
public interface OnDumpstateSelectedListener {
|
||||
void onDumpstateSelected(File dumpstateFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The context
|
||||
* @param dumpstateFiles List of dumpstate files
|
||||
* @param listener Listener for selection events
|
||||
*/
|
||||
public DumpstateSelectionDialog(@NonNull Context context,
|
||||
File[] dumpstateFiles,
|
||||
OnDumpstateSelectedListener listener) {
|
||||
super(context);
|
||||
this.dumpstateFiles = Arrays.asList(dumpstateFiles);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.dialog_dumpstate_selection);
|
||||
|
||||
// Initialize views
|
||||
titleText = findViewById(R.id.titleText);
|
||||
recyclerView = findViewById(R.id.dumpstateRecyclerView);
|
||||
emptyView = findViewById(R.id.emptyView);
|
||||
selectButton = findViewById(R.id.selectButton);
|
||||
cancelButton = findViewById(R.id.cancelButton);
|
||||
|
||||
// Update title with file count
|
||||
titleText.setText(getContext().getString(R.string.dumpstate_selection_subtitle, dumpstateFiles.size()));
|
||||
|
||||
// Set up RecyclerView
|
||||
setupRecyclerView();
|
||||
|
||||
// Set up buttons
|
||||
cancelButton.setOnClickListener(v -> dismiss());
|
||||
selectButton.setOnClickListener(v -> {
|
||||
File selectedFile = adapter.getSelectedFile();
|
||||
if (selectedFile != null && listener != null) {
|
||||
listener.onDumpstateSelected(selectedFile);
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
// Show empty view if no files
|
||||
if (dumpstateFiles.isEmpty()) {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
emptyView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
emptyView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the RecyclerView with the adapter
|
||||
*/
|
||||
private void setupRecyclerView() {
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
adapter = new DumpstateFileAdapter(getContext(), dumpstateFiles);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
// Listen for item selection to enable/disable select button
|
||||
adapter.setOnItemSelectedListener(file -> {
|
||||
selectButton.setEnabled(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,732 +0,0 @@
|
||||
package com.mattintech.simplelogupload.view;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.mattintech.simplelogupload.R;
|
||||
import com.mattintech.simplelogupload.adapter.DumpstateAdapter;
|
||||
import com.mattintech.simplelogupload.constant.AppConstants;
|
||||
import com.mattintech.simplelogupload.controller.FileController;
|
||||
import com.mattintech.simplelogupload.controller.ShareIntentHandler;
|
||||
import com.mattintech.simplelogupload.controller.UploadController;
|
||||
import com.mattintech.simplelogupload.service.FileUploadForegroundService;
|
||||
import com.mattintech.simplelogupload.util.PermissionUtil;
|
||||
import com.mattintech.simplelogupload.util.PreferencesUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Main activity for the application
|
||||
*/
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
private static final String TAG = AppConstants.APP_TAG + "MainActivity";
|
||||
|
||||
private TextView dumpstateStatusText;
|
||||
private TextView selectedFileText;
|
||||
private Button selectFileButton;
|
||||
private Button uploadDumpstateButton;
|
||||
private Button uploadSelectedFileButton;
|
||||
private ProgressBar progressBar;
|
||||
private CardView selectedFileCard;
|
||||
|
||||
// Dumpstate multi-select components
|
||||
private RecyclerView dumpstateRecyclerView;
|
||||
private Button toggleDumpstateListButton;
|
||||
private Button selectAllButton;
|
||||
private Button clearSelectionsButton;
|
||||
private LinearLayout multiSelectButtonsLayout;
|
||||
private DumpstateAdapter dumpstateAdapter;
|
||||
|
||||
private File selectedFile;
|
||||
private File dumpstateFile;
|
||||
|
||||
private UploadController uploadController;
|
||||
|
||||
// BroadcastReceiver to listen for upload results
|
||||
private BroadcastReceiver uploadReceiver;
|
||||
|
||||
// Activity result launcher for file picking
|
||||
private ActivityResultLauncher<String> filePickerLauncher;
|
||||
|
||||
// Flag to track if dumpstate list is expanded
|
||||
private boolean isDumpstateListExpanded = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Check if setup is required
|
||||
if (!PreferencesUtil.isSetupCompleted(this) || !PreferencesUtil.areServerSettingsConfigured(this)) {
|
||||
// Navigate to welcome activity
|
||||
Intent intent = new Intent(this, WelcomeActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// Set content view
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
uploadController = new UploadController(this);
|
||||
|
||||
// Initialize UI elements
|
||||
dumpstateStatusText = findViewById(R.id.dumpstateStatusText);
|
||||
selectedFileText = findViewById(R.id.selectedFileText);
|
||||
selectFileButton = findViewById(R.id.selectFileButton);
|
||||
uploadDumpstateButton = findViewById(R.id.uploadDumpstateButton);
|
||||
uploadSelectedFileButton = findViewById(R.id.uploadSelectedFileButton);
|
||||
progressBar = findViewById(R.id.progressBar);
|
||||
selectedFileCard = findViewById(R.id.selectedFileCard);
|
||||
|
||||
// Initialize multi-select UI elements
|
||||
dumpstateRecyclerView = findViewById(R.id.dumpstateRecyclerView);
|
||||
toggleDumpstateListButton = findViewById(R.id.toggleDumpstateListButton);
|
||||
selectAllButton = findViewById(R.id.selectAllButton);
|
||||
clearSelectionsButton = findViewById(R.id.clearSelectionsButton);
|
||||
multiSelectButtonsLayout = findViewById(R.id.multiSelectButtonsLayout);
|
||||
|
||||
// Set up RecyclerView
|
||||
dumpstateRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
|
||||
// Set up button click listeners
|
||||
selectFileButton.setOnClickListener(v -> openFilePicker());
|
||||
uploadDumpstateButton.setOnClickListener(v -> uploadDumpstate());
|
||||
uploadSelectedFileButton.setOnClickListener(v -> uploadSelectedFile());
|
||||
toggleDumpstateListButton.setOnClickListener(v -> toggleDumpstateList());
|
||||
selectAllButton.setOnClickListener(v -> selectAllDumpstates());
|
||||
clearSelectionsButton.setOnClickListener(v -> clearDumpstateSelections());
|
||||
|
||||
// Initialize file picker launcher
|
||||
filePickerLauncher = registerForActivityResult(
|
||||
new ActivityResultContracts.GetContent(),
|
||||
uri -> {
|
||||
if (uri != null) {
|
||||
handleFileSelection(uri);
|
||||
}
|
||||
});
|
||||
|
||||
// Check for necessary permissions
|
||||
checkAndRequestPermissions();
|
||||
|
||||
// Initialize broadcast receiver
|
||||
setupBroadcastReceiver();
|
||||
|
||||
// Handle intent (e.g., from share)
|
||||
handleIntent(getIntent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the visibility of the dumpstate list
|
||||
*/
|
||||
private void toggleDumpstateList() {
|
||||
isDumpstateListExpanded = !isDumpstateListExpanded;
|
||||
|
||||
if (isDumpstateListExpanded) {
|
||||
// Show the list
|
||||
loadDumpstateFiles();
|
||||
dumpstateRecyclerView.setVisibility(View.VISIBLE);
|
||||
multiSelectButtonsLayout.setVisibility(View.VISIBLE);
|
||||
toggleDumpstateListButton.setText(R.string.hide_dumpstates);
|
||||
|
||||
// Change the upload button to handle multiple files
|
||||
updateUploadButtonForMultiSelect();
|
||||
} else {
|
||||
// Hide the list
|
||||
dumpstateRecyclerView.setVisibility(View.GONE);
|
||||
multiSelectButtonsLayout.setVisibility(View.GONE);
|
||||
toggleDumpstateListButton.setText(R.string.show_dumpstates);
|
||||
|
||||
// Restore normal upload button
|
||||
uploadDumpstateButton.setText(R.string.upload_dumpstate_button);
|
||||
uploadDumpstateButton.setOnClickListener(v -> uploadDumpstate());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load dumpstate files into the RecyclerView
|
||||
*/
|
||||
private void loadDumpstateFiles() {
|
||||
File[] dumpstateFiles = FileController.getAllDumpStateFiles();
|
||||
|
||||
if (dumpstateFiles.length > 0) {
|
||||
List<File> fileList = new ArrayList<>(Arrays.asList(dumpstateFiles));
|
||||
|
||||
if (dumpstateAdapter == null) {
|
||||
dumpstateAdapter = new DumpstateAdapter(this, fileList);
|
||||
dumpstateAdapter.setOnSelectionChangedListener(this::onDumpstateSelectionChanged);
|
||||
dumpstateRecyclerView.setAdapter(dumpstateAdapter);
|
||||
} else {
|
||||
// Just update the adapter with new files
|
||||
dumpstateAdapter = new DumpstateAdapter(this, fileList);
|
||||
dumpstateAdapter.setOnSelectionChangedListener(this::onDumpstateSelectionChanged);
|
||||
dumpstateRecyclerView.setAdapter(dumpstateAdapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle selection changes in the dumpstate list
|
||||
*
|
||||
* @param selectedCount The number of selected items
|
||||
*/
|
||||
private void onDumpstateSelectionChanged(int selectedCount) {
|
||||
// Update the upload button text
|
||||
if (selectedCount > 0) {
|
||||
uploadDumpstateButton.setText(getString(R.string.upload_multiple_dumpstates, selectedCount));
|
||||
uploadDumpstateButton.setEnabled(true);
|
||||
} else {
|
||||
uploadDumpstateButton.setText(R.string.upload_dumpstate_button);
|
||||
uploadDumpstateButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the upload button to handle multiple files
|
||||
*/
|
||||
private void updateUploadButtonForMultiSelect() {
|
||||
uploadDumpstateButton.setOnClickListener(v -> uploadSelectedDumpstates());
|
||||
|
||||
// Initially disable until files are selected
|
||||
uploadDumpstateButton.setEnabled(dumpstateAdapter != null && dumpstateAdapter.getSelectedCount() > 0);
|
||||
|
||||
// Update button text if there are already selections
|
||||
if (dumpstateAdapter != null && dumpstateAdapter.getSelectedCount() > 0) {
|
||||
uploadDumpstateButton.setText(getString(R.string.upload_multiple_dumpstates,
|
||||
dumpstateAdapter.getSelectedCount()));
|
||||
} else {
|
||||
uploadDumpstateButton.setText(R.string.upload_dumpstate_button);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select all dumpstate files
|
||||
*/
|
||||
private void selectAllDumpstates() {
|
||||
if (dumpstateAdapter != null) {
|
||||
dumpstateAdapter.selectAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all dumpstate selections
|
||||
*/
|
||||
private void clearDumpstateSelections() {
|
||||
if (dumpstateAdapter != null) {
|
||||
dumpstateAdapter.clearSelections();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload selected dumpstate files
|
||||
*/
|
||||
private void uploadSelectedDumpstates() {
|
||||
if (dumpstateAdapter == null || dumpstateAdapter.getSelectedCount() == 0) {
|
||||
Toast.makeText(this, R.string.no_dumpstates_selected, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
List<File> selectedFiles = dumpstateAdapter.getSelectedFiles();
|
||||
int fileCount = selectedFiles.size();
|
||||
|
||||
// Show upload parameters dialog first
|
||||
new UploadParamsDialog(this, new UploadParamsDialog.UploadParamsListener() {
|
||||
@Override
|
||||
public void onUploadParamsSet(int maxDownloads, int expiryHours) {
|
||||
// Update UI
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
uploadDumpstateButton.setEnabled(false);
|
||||
dumpstateStatusText.setText(getString(R.string.preparing_multiple_files, fileCount));
|
||||
|
||||
// Prepare and upload multiple files
|
||||
FileController.prepareMultipleFilesForUploadAsync(selectedFiles, MainActivity.this)
|
||||
.thenAccept(zipFile -> {
|
||||
Log.d(TAG, "Multiple files zipped successfully: " + zipFile.getAbsolutePath());
|
||||
|
||||
runOnUiThread(() -> {
|
||||
dumpstateStatusText.setText(getString(R.string.uploading_multiple_files, fileCount));
|
||||
});
|
||||
|
||||
// Upload the zip file with parameters
|
||||
startUploadService(zipFile, maxDownloads, expiryHours);
|
||||
})
|
||||
.exceptionally(ex -> {
|
||||
Log.e(TAG, "Error preparing multiple files", ex);
|
||||
runOnUiThread(() -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
uploadDumpstateButton.setEnabled(true);
|
||||
Toast.makeText(MainActivity.this,
|
||||
getString(R.string.file_error, ex.getMessage()),
|
||||
Toast.LENGTH_LONG).show();
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUploadParamsCancelled() {
|
||||
// User cancelled, do nothing
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
setIntent(intent);
|
||||
handleIntent(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the intent, particularly for share intents
|
||||
*
|
||||
* @param intent The intent to handle
|
||||
*/
|
||||
private void handleIntent(Intent intent) {
|
||||
if (intent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is a share intent
|
||||
if (ShareIntentHandler.isShareIntent(intent)) {
|
||||
handleShareIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a share intent
|
||||
*
|
||||
* @param intent The share intent
|
||||
*/
|
||||
private void handleShareIntent(Intent intent) {
|
||||
List<Uri> sharedUris = ShareIntentHandler.extractSharedUris(intent);
|
||||
|
||||
if (sharedUris.isEmpty()) {
|
||||
Toast.makeText(this, "No files shared", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// For now, just handle the first URI
|
||||
Uri sharedUri = sharedUris.get(0);
|
||||
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
|
||||
// Process the shared URI
|
||||
ShareIntentHandler.processSharedUri(this, sharedUri)
|
||||
.thenAccept(file -> {
|
||||
// Save the file for upload
|
||||
updateSelectedFile(file);
|
||||
runOnUiThread(() -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
});
|
||||
})
|
||||
.exceptionally(ex -> {
|
||||
Log.e(TAG, "Error processing shared file", ex);
|
||||
runOnUiThread(() -> {
|
||||
Toast.makeText(MainActivity.this,
|
||||
getString(R.string.file_error, ex.getMessage()),
|
||||
Toast.LENGTH_LONG).show();
|
||||
progressBar.setVisibility(View.GONE);
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the file picker
|
||||
*/
|
||||
private void openFilePicker() {
|
||||
filePickerLauncher.launch("*/*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle file selection from file picker
|
||||
*
|
||||
* @param uri The URI of the selected file
|
||||
*/
|
||||
private void handleFileSelection(Uri uri) {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
|
||||
// Process the URI
|
||||
ShareIntentHandler.processSharedUri(this, uri)
|
||||
.thenAccept(file -> {
|
||||
// Save the file for upload
|
||||
updateSelectedFile(file);
|
||||
runOnUiThread(() -> {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
});
|
||||
})
|
||||
.exceptionally(ex -> {
|
||||
Log.e(TAG, "Error processing selected file", ex);
|
||||
runOnUiThread(() -> {
|
||||
Toast.makeText(MainActivity.this,
|
||||
getString(R.string.file_error, ex.getMessage()),
|
||||
Toast.LENGTH_LONG).show();
|
||||
progressBar.setVisibility(View.GONE);
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the selected file
|
||||
*/
|
||||
private void uploadSelectedFile() {
|
||||
if (selectedFile == null || !selectedFile.exists()) {
|
||||
Toast.makeText(this, R.string.no_file_selected, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// Show upload parameters dialog
|
||||
showUploadParamsDialog(selectedFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the dumpstate file
|
||||
*/
|
||||
private void uploadDumpstate() {
|
||||
// Get all dumpstate files
|
||||
File[] dumpstateFiles = FileController.getAllDumpStateFiles();
|
||||
|
||||
if (dumpstateFiles.length == 0) {
|
||||
Toast.makeText(this, R.string.no_dumpstate_found, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (dumpstateFiles.length == 1) {
|
||||
// Only one dumpstate file, use it directly
|
||||
dumpstateFile = dumpstateFiles[0];
|
||||
showUploadParamsDialog(dumpstateFile);
|
||||
} else {
|
||||
// Multiple dumpstate files are available, suggest expanding the list
|
||||
if (!isDumpstateListExpanded) {
|
||||
toggleDumpstateList();
|
||||
} else {
|
||||
// If list is already expanded, use the first file
|
||||
dumpstateFile = dumpstateFiles[0];
|
||||
showUploadParamsDialog(dumpstateFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start uploading the selected dumpstate file
|
||||
*
|
||||
* @param file The dumpstate file to upload
|
||||
* @param maxDownloads The maximum number of downloads
|
||||
* @param expiryHours The expiry time in hours
|
||||
*/
|
||||
private void startDumpstateUpload(File file, int maxDownloads, int expiryHours) {
|
||||
if (file == null || !file.exists()) {
|
||||
Toast.makeText(this, R.string.no_dumpstate_found, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
// Update UI
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
uploadDumpstateButton.setEnabled(false);
|
||||
dumpstateStatusText.setText(getString(R.string.uploading_file, file.getName()));
|
||||
|
||||
// Start the upload service with parameters
|
||||
startUploadService(file, maxDownloads, expiryHours);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the upload service with the given file and parameters
|
||||
*
|
||||
* @param file The file to upload
|
||||
* @param maxDownloads The maximum number of downloads
|
||||
* @param expiryHours The expiry time in hours
|
||||
*/
|
||||
private void startUploadService(File file, int maxDownloads, int expiryHours) {
|
||||
// Start the upload service
|
||||
Intent serviceIntent = new Intent(this, FileUploadForegroundService.class);
|
||||
serviceIntent.putExtra(FileUploadForegroundService.EXTRA_FILE_PATH, file.getAbsolutePath());
|
||||
serviceIntent.putExtra(FileUploadForegroundService.EXTRA_MAX_DOWNLOADS, maxDownloads);
|
||||
serviceIntent.putExtra(FileUploadForegroundService.EXTRA_EXPIRY_HOURS, expiryHours);
|
||||
startService(serviceIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the upload parameters dialog
|
||||
*
|
||||
* @param file The file to upload
|
||||
*/
|
||||
private void showUploadParamsDialog(File file) {
|
||||
new UploadParamsDialog(this, new UploadParamsDialog.UploadParamsListener() {
|
||||
@Override
|
||||
public void onUploadParamsSet(int maxDownloads, int expiryHours) {
|
||||
// Update UI
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
uploadSelectedFileButton.setEnabled(false);
|
||||
|
||||
if (file == selectedFile) {
|
||||
selectedFileText.setText(getString(R.string.uploading_file, file.getName()));
|
||||
} else if (file == dumpstateFile) {
|
||||
dumpstateStatusText.setText(getString(R.string.uploading_file, file.getName()));
|
||||
uploadDumpstateButton.setEnabled(false);
|
||||
}
|
||||
|
||||
// Start the upload service with parameters
|
||||
startUploadService(file, maxDownloads, expiryHours);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUploadParamsCancelled() {
|
||||
// User cancelled, do nothing
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the selected file UI
|
||||
*
|
||||
* @param file The selected file
|
||||
*/
|
||||
private void updateSelectedFile(File file) {
|
||||
selectedFile = file;
|
||||
runOnUiThread(() -> {
|
||||
selectedFileCard.setVisibility(View.VISIBLE);
|
||||
selectedFileText.setText(getString(R.string.selected_file, file.getName()));
|
||||
uploadSelectedFileButton.setVisibility(View.VISIBLE);
|
||||
uploadSelectedFileButton.setEnabled(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the broadcast receiver for upload results
|
||||
*/
|
||||
private void setupBroadcastReceiver() {
|
||||
uploadReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d(TAG, "Received broadcast: " + intent.getAction());
|
||||
progressBar.setVisibility(View.GONE);
|
||||
uploadSelectedFileButton.setEnabled(true);
|
||||
uploadDumpstateButton.setEnabled(true);
|
||||
|
||||
if (intent.getAction().equals(AppConstants.ACTION_UPLOAD_COMPLETE)) {
|
||||
String uploadCode = intent.getStringExtra(AppConstants.EXTRA_UPLOAD_CODE);
|
||||
Log.d(TAG, "Upload complete with code: " + uploadCode);
|
||||
showUploadSuccessDialog(uploadCode);
|
||||
} else if (intent.getAction().equals(AppConstants.ACTION_UPLOAD_ERROR)) {
|
||||
String errorMessage = intent.getStringExtra(AppConstants.EXTRA_UPLOAD_ERROR);
|
||||
Log.e(TAG, "Upload error: " + errorMessage);
|
||||
Toast.makeText(MainActivity.this,
|
||||
getString(R.string.upload_error, errorMessage),
|
||||
Toast.LENGTH_LONG).show();
|
||||
resetUI();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the UI after upload completion or error
|
||||
*/
|
||||
private void resetUI() {
|
||||
// Get all dumpstate files
|
||||
File[] dumpstateFiles = FileController.getAllDumpStateFiles();
|
||||
|
||||
if (dumpstateFiles.length > 0) {
|
||||
if (dumpstateFiles.length == 1) {
|
||||
// Only one dumpstate file
|
||||
dumpstateFile = dumpstateFiles[0];
|
||||
dumpstateStatusText.setText(getString(R.string.dumpstate_found, dumpstateFile.getName()));
|
||||
} else {
|
||||
// Multiple dumpstate files
|
||||
dumpstateStatusText.setText(getString(R.string.multiple_dumpstates_found) +
|
||||
" (" + dumpstateFiles.length + ")");
|
||||
|
||||
// If we have a specific file selected, show it
|
||||
if (dumpstateFile != null && dumpstateFile.exists()) {
|
||||
dumpstateStatusText.append("\n" + dumpstateFile.getName());
|
||||
} else {
|
||||
// Otherwise show the most recent one
|
||||
dumpstateFile = dumpstateFiles[0];
|
||||
dumpstateStatusText.append("\n" + dumpstateFile.getName());
|
||||
}
|
||||
}
|
||||
uploadDumpstateButton.setEnabled(true);
|
||||
|
||||
// Update multiselect if active
|
||||
if (isDumpstateListExpanded && dumpstateAdapter != null) {
|
||||
loadDumpstateFiles();
|
||||
updateUploadButtonForMultiSelect();
|
||||
}
|
||||
} else {
|
||||
dumpstateFile = null;
|
||||
dumpstateStatusText.setText(R.string.no_dumpstate_found);
|
||||
uploadDumpstateButton.setEnabled(false);
|
||||
}
|
||||
|
||||
if (selectedFile != null) {
|
||||
selectedFileText.setText(getString(R.string.selected_file, selectedFile.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// Check for file if we have permissions
|
||||
if (PermissionUtil.hasAllFilesAccessPermission()) {
|
||||
checkForDumpStateAndUpdateUI();
|
||||
}
|
||||
|
||||
// Register the broadcast receiver
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(AppConstants.ACTION_UPLOAD_COMPLETE);
|
||||
filter.addAction(AppConstants.ACTION_UPLOAD_ERROR);
|
||||
|
||||
// Register with both regular and local broadcast managers to ensure delivery
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
||||
registerReceiver(uploadReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
|
||||
} else {
|
||||
registerReceiver(uploadReceiver, filter);
|
||||
}
|
||||
|
||||
// Also register with LocalBroadcastManager for reliability
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(uploadReceiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
// Unregister the broadcast receiver
|
||||
try {
|
||||
unregisterReceiver(uploadReceiver);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Receiver not registered, ignore
|
||||
}
|
||||
|
||||
// Also unregister from LocalBroadcastManager
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(uploadReceiver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for and request necessary permissions
|
||||
*/
|
||||
private void checkAndRequestPermissions() {
|
||||
// Request notification permission
|
||||
PermissionUtil.requestNotificationPermission(this);
|
||||
|
||||
// Check and request all files access permission
|
||||
if (!PermissionUtil.hasAllFilesAccessPermission()) {
|
||||
PermissionUtil.requestAllFilesAccessPermission(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for dumpstate files and update the UI
|
||||
*/
|
||||
private void checkForDumpStateAndUpdateUI() {
|
||||
// Look for dumpstate files
|
||||
File[] dumpstateFiles = FileController.getAllDumpStateFiles();
|
||||
|
||||
if (dumpstateFiles.length > 0) {
|
||||
if (dumpstateFiles.length == 1) {
|
||||
// Only one dumpstate file found, use it directly
|
||||
dumpstateFile = dumpstateFiles[0];
|
||||
dumpstateStatusText.setText(getString(R.string.dumpstate_found, dumpstateFile.getName()));
|
||||
uploadDumpstateButton.setEnabled(true);
|
||||
} else {
|
||||
// Multiple dumpstate files found
|
||||
dumpstateStatusText.setText(getString(R.string.multiple_dumpstates_found) +
|
||||
" (" + dumpstateFiles.length + ")");
|
||||
|
||||
// Set the most recent one as default
|
||||
dumpstateFile = dumpstateFiles[0];
|
||||
// Show the dumpstate name in a new line
|
||||
dumpstateStatusText.append("\n" + dumpstateFile.getName());
|
||||
uploadDumpstateButton.setEnabled(true);
|
||||
|
||||
// Update toggle button visibility
|
||||
toggleDumpstateListButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
dumpstateFile = null;
|
||||
dumpstateStatusText.setText(R.string.no_dumpstate_found);
|
||||
uploadDumpstateButton.setEnabled(false);
|
||||
toggleDumpstateListButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (requestCode == PermissionUtil.REQUEST_MANAGE_EXTERNAL_STORAGE) {
|
||||
if (PermissionUtil.hasAllFilesAccessPermission()) {
|
||||
checkForDumpStateAndUpdateUI();
|
||||
} else {
|
||||
Toast.makeText(this, R.string.permission_not_granted, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a dialog with the upload success result
|
||||
*
|
||||
* @param uploadCode The upload code
|
||||
*/
|
||||
private void showUploadSuccessDialog(String uploadCode) {
|
||||
Log.d(TAG, "Opening upload success dialog with code: " + uploadCode);
|
||||
runOnUiThread(() -> {
|
||||
try {
|
||||
UploadResultDialog dialog = new UploadResultDialog(this, uploadCode);
|
||||
dialog.show();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error showing upload result dialog", e);
|
||||
Toast.makeText(this, getString(R.string.upload_success, uploadCode), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.main_menu, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
|
||||
if (id == R.id.action_history) {
|
||||
// Open upload history activity
|
||||
startActivity(new Intent(this, UploadHistoryActivity.class));
|
||||
return true;
|
||||
} else if (id == R.id.action_settings) {
|
||||
// Open settings activity
|
||||
startActivity(new Intent(this, SettingsActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
package com.mattintech.simplelogupload.view;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.journeyapps.barcodescanner.ScanContract;
|
||||
import com.journeyapps.barcodescanner.ScanOptions;
|
||||
import com.journeyapps.barcodescanner.ScanIntentResult;
|
||||
import com.mattintech.simplelogupload.R;
|
||||
import com.mattintech.simplelogupload.constant.AppConstants;
|
||||
import com.mattintech.simplelogupload.model.QrServerConfig;
|
||||
import com.mattintech.simplelogupload.util.PermissionUtil;
|
||||
import com.mattintech.simplelogupload.util.PreferencesUtil;
|
||||
import com.mattintech.simplelogupload.util.QrScannerUtil;
|
||||
|
||||
/**
|
||||
* Activity for server setup
|
||||
*/
|
||||
public class ServerSetupActivity extends AppCompatActivity {
|
||||
private static final String TAG = AppConstants.APP_TAG + "ServerSetupActivity";
|
||||
|
||||
private TextInputEditText serverAddressInput;
|
||||
private TextInputEditText serverPortInput;
|
||||
private TextInputEditText clientKeyInput;
|
||||
private ActivityResultLauncher<ScanOptions> qrScannerLauncher;
|
||||
private Button scanQrButton;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_server_setup);
|
||||
|
||||
// Initialize UI components
|
||||
serverAddressInput = findViewById(R.id.serverAddressInput);
|
||||
serverPortInput = findViewById(R.id.serverPortInput);
|
||||
clientKeyInput = findViewById(R.id.clientKeyInput);
|
||||
Button finishSetupButton = findViewById(R.id.finishSetupButton);
|
||||
scanQrButton = findViewById(R.id.scanQrButton);
|
||||
|
||||
// Initialize QR scanner launcher
|
||||
qrScannerLauncher = registerForActivityResult(
|
||||
new ScanContract(),
|
||||
result -> handleQrScanResult(result)
|
||||
);
|
||||
|
||||
// Set up QR scan button click listener
|
||||
scanQrButton.setOnClickListener(v -> initiateQrScan());
|
||||
|
||||
// Set up action bar
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().setTitle("Server Setup");
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
// Set up button click listener
|
||||
finishSetupButton.setOnClickListener(v -> saveSettings());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save settings to SharedPreferences
|
||||
*/
|
||||
private void saveSettings() {
|
||||
try {
|
||||
// Get values from input fields
|
||||
String serverAddress = serverAddressInput.getText().toString().trim();
|
||||
String serverPortStr = serverPortInput.getText().toString().trim();
|
||||
String clientKey = clientKeyInput.getText().toString().trim();
|
||||
|
||||
// Validate input
|
||||
if (TextUtils.isEmpty(serverAddress)) {
|
||||
serverAddressInput.setError("Server address is required");
|
||||
return;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(serverPortStr)) {
|
||||
serverPortInput.setError("Server port is required");
|
||||
return;
|
||||
}
|
||||
|
||||
int serverPort;
|
||||
try {
|
||||
serverPort = Integer.parseInt(serverPortStr);
|
||||
if (serverPort <= 0 || serverPort > 65535) {
|
||||
serverPortInput.setError("Port must be between 1 and 65535");
|
||||
return;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
serverPortInput.setError("Invalid port number");
|
||||
return;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(clientKey)) {
|
||||
clientKeyInput.setError("Client key is required");
|
||||
return;
|
||||
}
|
||||
|
||||
// Save settings
|
||||
PreferencesUtil.setServerAddress(this, serverAddress);
|
||||
PreferencesUtil.setServerPort(this, serverPort);
|
||||
PreferencesUtil.setClientKey(this, clientKey);
|
||||
PreferencesUtil.setSetupCompleted(this, true);
|
||||
|
||||
Log.d(TAG, "Server setup completed successfully");
|
||||
Toast.makeText(this, "Setup completed successfully!", Toast.LENGTH_SHORT).show();
|
||||
|
||||
// Navigate to main activity
|
||||
Intent intent = new Intent(ServerSetupActivity.this, MainActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error saving settings", e);
|
||||
Toast.makeText(this, "Error saving settings: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate QR code scan
|
||||
*/
|
||||
private void initiateQrScan() {
|
||||
// Check camera permission
|
||||
if (!PermissionUtil.hasCameraPermission(this)) {
|
||||
PermissionUtil.requestCameraPermission(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Launch scanner
|
||||
ScanOptions options = QrScannerUtil.createScanOptions();
|
||||
qrScannerLauncher.launch(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle QR scan result
|
||||
*
|
||||
* @param result The scan result
|
||||
*/
|
||||
private void handleQrScanResult(ScanIntentResult result) {
|
||||
QrScannerUtil.processScanResult(
|
||||
result.getContents(),
|
||||
new QrScannerUtil.QrScanCallback() {
|
||||
@Override
|
||||
public void onQrScanned(QrServerConfig config) {
|
||||
// Auto-fill the input fields
|
||||
serverAddressInput.setText(config.getServer());
|
||||
serverPortInput.setText(String.valueOf(config.getPort()));
|
||||
clientKeyInput.setText(config.getKey());
|
||||
|
||||
Toast.makeText(ServerSetupActivity.this,
|
||||
R.string.qr_scan_success,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
|
||||
Log.d(TAG, "QR code scanned successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQrScanCancelled() {
|
||||
Toast.makeText(ServerSetupActivity.this,
|
||||
R.string.qr_scan_cancelled,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQrScanError(String errorMessage) {
|
||||
Toast.makeText(ServerSetupActivity.this,
|
||||
getString(R.string.qr_scan_error, errorMessage),
|
||||
Toast.LENGTH_LONG).show();
|
||||
Log.e(TAG, "QR scan error: " + errorMessage);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle permission request results
|
||||
*/
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
if (requestCode == PermissionUtil.REQUEST_CAMERA_PERMISSION) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
// Permission granted, initiate scan
|
||||
initiateQrScan();
|
||||
} else {
|
||||
// Permission denied
|
||||
Toast.makeText(this, R.string.camera_permission_denied, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
package com.mattintech.simplelogupload.view;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.journeyapps.barcodescanner.ScanContract;
|
||||
import com.journeyapps.barcodescanner.ScanOptions;
|
||||
import com.journeyapps.barcodescanner.ScanIntentResult;
|
||||
import com.mattintech.simplelogupload.R;
|
||||
import com.mattintech.simplelogupload.constant.AppConstants;
|
||||
import com.mattintech.simplelogupload.model.QrServerConfig;
|
||||
import com.mattintech.simplelogupload.util.PermissionUtil;
|
||||
import com.mattintech.simplelogupload.util.PreferencesUtil;
|
||||
import com.mattintech.simplelogupload.util.QrScannerUtil;
|
||||
|
||||
/**
|
||||
* Activity for application settings
|
||||
*/
|
||||
public class SettingsActivity extends AppCompatActivity {
|
||||
private static final String TAG = AppConstants.APP_TAG + "SettingsActivity";
|
||||
|
||||
private TextInputEditText serverAddressInput;
|
||||
private TextInputEditText serverPortInput;
|
||||
private TextInputEditText clientKeyInput;
|
||||
private ActivityResultLauncher<ScanOptions> qrScannerLauncher;
|
||||
private Button scanQrButton;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_settings);
|
||||
|
||||
// Initialize UI components
|
||||
serverAddressInput = findViewById(R.id.serverAddressInput);
|
||||
serverPortInput = findViewById(R.id.serverPortInput);
|
||||
clientKeyInput = findViewById(R.id.clientKeyInput);
|
||||
Button saveButton = findViewById(R.id.saveSettingsButton);
|
||||
Button resetButton = findViewById(R.id.resetSettingsButton);
|
||||
scanQrButton = findViewById(R.id.scanQrButton);
|
||||
|
||||
// Initialize QR scanner launcher
|
||||
qrScannerLauncher = registerForActivityResult(
|
||||
new ScanContract(),
|
||||
result -> handleQrScanResult(result)
|
||||
);
|
||||
|
||||
// Set up QR scan button click listener
|
||||
scanQrButton.setOnClickListener(v -> initiateQrScan());
|
||||
|
||||
// Set up action bar
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setTitle("Settings");
|
||||
}
|
||||
|
||||
// Load current settings
|
||||
loadSettings();
|
||||
|
||||
// Set up button click listeners
|
||||
saveButton.setOnClickListener(v -> saveSettings());
|
||||
resetButton.setOnClickListener(v -> resetSettings());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load current settings from SharedPreferences
|
||||
*/
|
||||
private void loadSettings() {
|
||||
String serverAddress = PreferencesUtil.getServerAddress(this);
|
||||
int serverPort = PreferencesUtil.getServerPort(this);
|
||||
String clientKey = PreferencesUtil.getClientKey(this);
|
||||
|
||||
serverAddressInput.setText(serverAddress);
|
||||
if (serverPort > 0) {
|
||||
serverPortInput.setText(String.valueOf(serverPort));
|
||||
} else {
|
||||
serverPortInput.setText("");
|
||||
}
|
||||
clientKeyInput.setText(clientKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save settings to SharedPreferences
|
||||
*/
|
||||
private void saveSettings() {
|
||||
try {
|
||||
// Get values from input fields
|
||||
String serverAddress = serverAddressInput.getText().toString().trim();
|
||||
String serverPortStr = serverPortInput.getText().toString().trim();
|
||||
String clientKey = clientKeyInput.getText().toString().trim();
|
||||
|
||||
// Validate input
|
||||
if (TextUtils.isEmpty(serverAddress)) {
|
||||
serverAddressInput.setError("Server address is required");
|
||||
return;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(serverPortStr)) {
|
||||
serverPortInput.setError("Server port is required");
|
||||
return;
|
||||
}
|
||||
|
||||
int serverPort;
|
||||
try {
|
||||
serverPort = Integer.parseInt(serverPortStr);
|
||||
if (serverPort <= 0 || serverPort > 65535) {
|
||||
serverPortInput.setError("Port must be between 1 and 65535");
|
||||
return;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
serverPortInput.setError("Invalid port number");
|
||||
return;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(clientKey)) {
|
||||
clientKeyInput.setError("Client key is required");
|
||||
return;
|
||||
}
|
||||
|
||||
// Save settings
|
||||
PreferencesUtil.setServerAddress(this, serverAddress);
|
||||
PreferencesUtil.setServerPort(this, serverPort);
|
||||
PreferencesUtil.setClientKey(this, clientKey);
|
||||
|
||||
Log.d(TAG, "Settings saved successfully");
|
||||
Toast.makeText(this, "Settings saved successfully", Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error saving settings", e);
|
||||
Toast.makeText(this, "Error saving settings: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset settings to default values
|
||||
*/
|
||||
private void resetSettings() {
|
||||
PreferencesUtil.resetToDefaults(this);
|
||||
loadSettings();
|
||||
Toast.makeText(this, "Settings reset to defaults", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate QR code scan
|
||||
*/
|
||||
private void initiateQrScan() {
|
||||
// Check camera permission
|
||||
if (!PermissionUtil.hasCameraPermission(this)) {
|
||||
PermissionUtil.requestCameraPermission(this);
|
||||
return;
|
||||
}
|
||||
|
||||
// Launch scanner
|
||||
ScanOptions options = QrScannerUtil.createScanOptions();
|
||||
qrScannerLauncher.launch(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle QR scan result
|
||||
*
|
||||
* @param result The scan result
|
||||
*/
|
||||
private void handleQrScanResult(ScanIntentResult result) {
|
||||
QrScannerUtil.processScanResult(
|
||||
result.getContents(),
|
||||
new QrScannerUtil.QrScanCallback() {
|
||||
@Override
|
||||
public void onQrScanned(QrServerConfig config) {
|
||||
// Auto-fill the input fields
|
||||
serverAddressInput.setText(config.getServer());
|
||||
serverPortInput.setText(String.valueOf(config.getPort()));
|
||||
clientKeyInput.setText(config.getKey());
|
||||
|
||||
Toast.makeText(SettingsActivity.this,
|
||||
R.string.qr_scan_success,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
|
||||
Log.d(TAG, "QR code scanned successfully");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQrScanCancelled() {
|
||||
Toast.makeText(SettingsActivity.this,
|
||||
R.string.qr_scan_cancelled,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onQrScanError(String errorMessage) {
|
||||
Toast.makeText(SettingsActivity.this,
|
||||
getString(R.string.qr_scan_error, errorMessage),
|
||||
Toast.LENGTH_LONG).show();
|
||||
Log.e(TAG, "QR scan error: " + errorMessage);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle permission request results
|
||||
*/
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
|
||||
if (requestCode == PermissionUtil.REQUEST_CAMERA_PERMISSION) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
// Permission granted, initiate scan
|
||||
initiateQrScan();
|
||||
} else {
|
||||
// Permission denied
|
||||
Toast.makeText(this, R.string.camera_permission_denied, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
package com.mattintech.simplelogupload.view;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.mattintech.simplelogupload.R;
|
||||
import com.mattintech.simplelogupload.constant.AppConstants;
|
||||
import com.mattintech.simplelogupload.model.UploadHistory;
|
||||
import com.mattintech.simplelogupload.view.adapter.UploadHistoryAdapter;
|
||||
import com.mattintech.simplelogupload.viewmodel.UploadHistoryViewModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Activity for displaying upload history
|
||||
*/
|
||||
public class UploadHistoryActivity extends AppCompatActivity implements UploadHistoryAdapter.OnHistoryItemClickListener {
|
||||
private static final String TAG = AppConstants.APP_TAG + "HistoryActivity";
|
||||
|
||||
private UploadHistoryViewModel viewModel;
|
||||
private UploadHistoryAdapter adapter;
|
||||
private RecyclerView recyclerView;
|
||||
private TextView emptyView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_upload_history);
|
||||
|
||||
// Enable "up" navigation
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
// Initialize views
|
||||
recyclerView = findViewById(R.id.historyRecyclerView);
|
||||
emptyView = findViewById(R.id.emptyView);
|
||||
|
||||
// Set up the RecyclerView
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||
adapter = new UploadHistoryAdapter(this);
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
// Initialize the ViewModel
|
||||
viewModel = new ViewModelProvider.AndroidViewModelFactory(getApplication())
|
||||
.create(UploadHistoryViewModel.class);
|
||||
|
||||
// Observe the history data
|
||||
viewModel.getAllHistory().observe(this, new Observer<List<UploadHistory>>() {
|
||||
@Override
|
||||
public void onChanged(List<UploadHistory> history) {
|
||||
// Update the cached copy of the history in the adapter
|
||||
adapter.setHistory(history);
|
||||
|
||||
// Show/hide empty view
|
||||
if (history == null || history.isEmpty()) {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
emptyView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
emptyView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Observe the delete status to provide feedback
|
||||
viewModel.getDeleteStatus().observe(this, deleteSuccess -> {
|
||||
if (deleteSuccess != null) {
|
||||
if (deleteSuccess) {
|
||||
Toast.makeText(this, "File deleted from server successfully", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(this, "Failed to delete file from server, but removed from local history",
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
|
||||
if (id == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
} else if (id == R.id.action_clear_history) {
|
||||
// Show confirmation dialog
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Clear All History")
|
||||
.setMessage("Do you want to delete all uploads from both local history and the server?")
|
||||
.setPositiveButton("Yes", (dialog, which) -> {
|
||||
// Show progress dialog
|
||||
AlertDialog progressDialog = new AlertDialog.Builder(this)
|
||||
.setTitle("Deleting...")
|
||||
.setMessage("Attempting to delete all files from server and clear history.")
|
||||
.setCancelable(false)
|
||||
.create();
|
||||
progressDialog.show();
|
||||
|
||||
// Attempt to delete all
|
||||
viewModel.deleteAll()
|
||||
.thenAccept(unused -> {
|
||||
runOnUiThread(() -> {
|
||||
progressDialog.dismiss();
|
||||
// Toast message will be shown through the observer
|
||||
});
|
||||
});
|
||||
})
|
||||
.setNegativeButton("No", null)
|
||||
.show();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCopyCodeClick(UploadHistory history) {
|
||||
copyToClipboard(history.getUploadCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteClick(UploadHistory history) {
|
||||
// Show confirmation dialog
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle("Delete Upload")
|
||||
.setMessage("Do you want to delete this upload from both local history and the server?")
|
||||
.setPositiveButton("Yes", (dialog, which) -> {
|
||||
// Show progress dialog
|
||||
AlertDialog progressDialog = new AlertDialog.Builder(this)
|
||||
.setTitle("Deleting...")
|
||||
.setMessage("Attempting to delete from server and local history.")
|
||||
.setCancelable(false)
|
||||
.create();
|
||||
progressDialog.show();
|
||||
|
||||
// Attempt to delete
|
||||
viewModel.delete(history)
|
||||
.thenAccept(unused -> {
|
||||
runOnUiThread(() -> {
|
||||
progressDialog.dismiss();
|
||||
});
|
||||
});
|
||||
})
|
||||
.setNegativeButton("No", null)
|
||||
.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy text to clipboard
|
||||
*
|
||||
* @param text The text to copy
|
||||
*/
|
||||
private void copyToClipboard(String text) {
|
||||
try {
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText("Upload Code", text);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Toast.makeText(this, "Code copied to clipboard", Toast.LENGTH_SHORT).show();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error copying to clipboard", e);
|
||||
Toast.makeText(this, "Failed to copy code", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
package com.mattintech.simplelogupload.view;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.mattintech.simplelogupload.R;
|
||||
import com.mattintech.simplelogupload.constant.NetworkConstants;
|
||||
|
||||
/**
|
||||
* Dialog for setting upload parameters
|
||||
*/
|
||||
public class UploadParamsDialog extends Dialog {
|
||||
|
||||
private EditText maxDownloadsInput;
|
||||
private EditText expiryTimeInput;
|
||||
private final UploadParamsListener listener;
|
||||
|
||||
/**
|
||||
* Interface for upload parameter callbacks
|
||||
*/
|
||||
public interface UploadParamsListener {
|
||||
void onUploadParamsSet(int maxDownloads, int expiryHours);
|
||||
void onUploadParamsCancelled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The context
|
||||
* @param listener Callback listener
|
||||
*/
|
||||
public UploadParamsDialog(@NonNull Context context, UploadParamsListener listener) {
|
||||
super(context);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.dialog_upload_params);
|
||||
|
||||
// Initialize views
|
||||
maxDownloadsInput = findViewById(R.id.maxDownloadsInput);
|
||||
expiryTimeInput = findViewById(R.id.expiryTimeInput);
|
||||
|
||||
// Set default values as hints
|
||||
maxDownloadsInput.setHint("Default: " + NetworkConstants.DEFAULT_MAX_DOWNLOADS);
|
||||
expiryTimeInput.setHint("Default: " + NetworkConstants.DEFAULT_EXPIRY_HOURS);
|
||||
|
||||
// Set up buttons
|
||||
Button confirmButton = findViewById(R.id.confirmButton);
|
||||
Button cancelButton = findViewById(R.id.cancelButton);
|
||||
|
||||
confirmButton.setOnClickListener(v -> {
|
||||
int maxDownloads = getMaxDownloadsValue();
|
||||
int expiryHours = getExpiryHoursValue();
|
||||
|
||||
// Validate expiry time
|
||||
if (expiryHours > NetworkConstants.MAX_EXPIRY_HOURS) {
|
||||
expiryTimeInput.setError("Maximum expiry time is " +
|
||||
NetworkConstants.MAX_EXPIRY_HOURS + " hours");
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate max downloads (must be non-negative)
|
||||
if (maxDownloads < 0) {
|
||||
maxDownloadsInput.setError("Downloads must be 0 or greater");
|
||||
return;
|
||||
}
|
||||
|
||||
if (listener != null) {
|
||||
listener.onUploadParamsSet(maxDownloads, expiryHours);
|
||||
}
|
||||
dismiss();
|
||||
});
|
||||
|
||||
cancelButton.setOnClickListener(v -> {
|
||||
if (listener != null) {
|
||||
listener.onUploadParamsCancelled();
|
||||
}
|
||||
dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the max downloads value from the input
|
||||
*
|
||||
* @return The max downloads value (default if not set)
|
||||
*/
|
||||
private int getMaxDownloadsValue() {
|
||||
if (TextUtils.isEmpty(maxDownloadsInput.getText())) {
|
||||
return NetworkConstants.DEFAULT_MAX_DOWNLOADS;
|
||||
}
|
||||
|
||||
try {
|
||||
return Integer.parseInt(maxDownloadsInput.getText().toString());
|
||||
} catch (NumberFormatException e) {
|
||||
return NetworkConstants.DEFAULT_MAX_DOWNLOADS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expiry hours value from the input
|
||||
*
|
||||
* @return The expiry hours value (default if not set)
|
||||
*/
|
||||
private int getExpiryHoursValue() {
|
||||
if (TextUtils.isEmpty(expiryTimeInput.getText())) {
|
||||
return NetworkConstants.DEFAULT_EXPIRY_HOURS;
|
||||
}
|
||||
|
||||
try {
|
||||
return Integer.parseInt(expiryTimeInput.getText().toString());
|
||||
} catch (NumberFormatException e) {
|
||||
return NetworkConstants.DEFAULT_EXPIRY_HOURS;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.mattintech.simplelogupload.view;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.mattintech.simplelogupload.R;
|
||||
import com.mattintech.simplelogupload.constant.AppConstants;
|
||||
|
||||
/**
|
||||
* Dialog to display upload result
|
||||
*/
|
||||
public class UploadResultDialog extends Dialog {
|
||||
private static final String TAG = AppConstants.APP_TAG + "ResultDialog";
|
||||
|
||||
private final String uploadCode;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The context
|
||||
* @param uploadCode The upload code
|
||||
*/
|
||||
public UploadResultDialog(Context context, String uploadCode) {
|
||||
super(context);
|
||||
this.uploadCode = uploadCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
setContentView(R.layout.upload_result_dialog);
|
||||
|
||||
TextView codeTextView = findViewById(R.id.uploadCode);
|
||||
codeTextView.setText(uploadCode);
|
||||
|
||||
Button copyButton = findViewById(R.id.copyButton);
|
||||
copyButton.setOnClickListener(v -> copyCodeToClipboard());
|
||||
|
||||
Button closeButton = findViewById(R.id.closeButton);
|
||||
closeButton.setOnClickListener(v -> dismiss());
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the upload code to the clipboard
|
||||
*/
|
||||
private void copyCodeToClipboard() {
|
||||
try {
|
||||
ClipboardManager clipboard = (ClipboardManager)
|
||||
getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
|
||||
ClipData clip = ClipData.newPlainText("Upload Code", uploadCode);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
|
||||
Toast.makeText(getContext(), "Code copied to clipboard", Toast.LENGTH_SHORT).show();
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error copying to clipboard", e);
|
||||
Toast.makeText(getContext(), "Failed to copy code", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package com.mattintech.simplelogupload.view;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.mattintech.simplelogupload.R;
|
||||
|
||||
/**
|
||||
* Welcome activity for first-time setup
|
||||
*/
|
||||
public class WelcomeActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_welcome);
|
||||
|
||||
// Hide action bar for cleaner look
|
||||
if (getSupportActionBar() != null) {
|
||||
getSupportActionBar().hide();
|
||||
}
|
||||
|
||||
// Set up next button
|
||||
Button nextButton = findViewById(R.id.nextButton);
|
||||
nextButton.setOnClickListener(v -> {
|
||||
// Proceed to server setup activity
|
||||
Intent intent = new Intent(WelcomeActivity.this, ServerSetupActivity.class);
|
||||
startActivity(intent);
|
||||
// No finish() here to allow back navigation
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
package com.mattintech.simplelogupload.view.adapter;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.mattintech.simplelogupload.R;
|
||||
import com.mattintech.simplelogupload.model.UploadHistory;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Adapter for displaying upload history items
|
||||
*/
|
||||
public class UploadHistoryAdapter extends RecyclerView.Adapter<UploadHistoryAdapter.HistoryViewHolder> {
|
||||
|
||||
private List<UploadHistory> history = new ArrayList<>();
|
||||
private final OnHistoryItemClickListener listener;
|
||||
private final SimpleDateFormat dateFormat = new SimpleDateFormat("MMM dd, yyyy HH:mm", Locale.getDefault());
|
||||
|
||||
/**
|
||||
* Interface for history item click events
|
||||
*/
|
||||
public interface OnHistoryItemClickListener {
|
||||
void onCopyCodeClick(UploadHistory history);
|
||||
void onDeleteClick(UploadHistory history);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param listener The click listener
|
||||
*/
|
||||
public UploadHistoryAdapter(OnHistoryItemClickListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the history data
|
||||
*
|
||||
* @param history The new history data
|
||||
*/
|
||||
public void setHistory(List<UploadHistory> history) {
|
||||
this.history = history;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public HistoryViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View itemView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_upload_history, parent, false);
|
||||
return new HistoryViewHolder(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull HistoryViewHolder holder, int position) {
|
||||
UploadHistory current = history.get(position);
|
||||
|
||||
holder.fileNameTextView.setText(current.getFileName());
|
||||
holder.uploadCodeTextView.setText(current.getUploadCode());
|
||||
|
||||
// Format date
|
||||
String formattedDate = dateFormat.format(new Date(current.getUploadTime()));
|
||||
holder.uploadTimeTextView.setText(formattedDate);
|
||||
|
||||
// Set details text
|
||||
String details = String.format(Locale.getDefault(),
|
||||
"Max downloads: %d • Expires in %d hours",
|
||||
current.getMaxDownloads(),
|
||||
current.getExpiryHours());
|
||||
holder.detailsTextView.setText(details);
|
||||
|
||||
// Set click listeners
|
||||
holder.copyButton.setOnClickListener(v -> {
|
||||
if (listener != null) {
|
||||
listener.onCopyCodeClick(current);
|
||||
}
|
||||
});
|
||||
|
||||
holder.deleteButton.setOnClickListener(v -> {
|
||||
if (listener != null) {
|
||||
listener.onDeleteClick(current);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return history.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* ViewHolder for history items
|
||||
*/
|
||||
static class HistoryViewHolder extends RecyclerView.ViewHolder {
|
||||
private final TextView fileNameTextView;
|
||||
private final TextView uploadCodeTextView;
|
||||
private final TextView uploadTimeTextView;
|
||||
private final TextView detailsTextView;
|
||||
private final Button copyButton;
|
||||
private final Button deleteButton;
|
||||
|
||||
HistoryViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
fileNameTextView = itemView.findViewById(R.id.fileNameText);
|
||||
uploadCodeTextView = itemView.findViewById(R.id.uploadCodeText);
|
||||
uploadTimeTextView = itemView.findViewById(R.id.uploadTimeText);
|
||||
detailsTextView = itemView.findViewById(R.id.detailsText);
|
||||
copyButton = itemView.findViewById(R.id.copyButton);
|
||||
deleteButton = itemView.findViewById(R.id.deleteButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/headerText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/app_header"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="16dp"/>
|
||||
|
||||
<!-- Main Upload Options Section -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/uploadOptionsCard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/headerText">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/upload_options_title"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/selectFileButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/select_file_button"
|
||||
android:drawableStart="@android:drawable/ic_menu_search"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/uploadDumpstateButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/upload_dumpstate_button"
|
||||
android:drawableStart="@android:drawable/ic_menu_save"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"/>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<!-- Dumpstate Section -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/dumpstateCard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="4dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/uploadOptionsCard">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dumpstate_section_title"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="4dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dumpstateStatusText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/looking_for_dumpstate"
|
||||
android:textSize="16sp"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="start"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/toggleDumpstateListButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/show_dumpstates"
|
||||
android:textSize="12sp"
|
||||
style="@style/Widget.AppCompat.Button.Small" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/dumpstateRecyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/multiSelectButtonsLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="8dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<Button
|
||||
android:id="@+id/selectAllButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/select_all"
|
||||
android:textSize="12sp"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/clearSelectionsButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/clear_selections"
|
||||
android:textSize="12sp"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<!-- Selected File Section -->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/selectedFileCard"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="4dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/dumpstateCard">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/selected_file_section_title"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/selectedFileText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/no_file_selected"
|
||||
android:textSize="16sp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/uploadSelectedFileButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/upload_selected_file"
|
||||
android:visibility="gone"/>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintTop_toBottomOf="@id/selectedFileCard"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginTop="16dp"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,134 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/setupTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:text="Server Configuration"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/setupDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Please enter your server details below. These are required to connect to your SimpleLogUpload server."
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/setupTitle" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/finishSetupButton"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/setupDescription">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/serverAddressLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="Server Address (IP or hostname)">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/serverAddressInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/serverPortLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="Server Port">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/serverPortInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/clientKeyLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:hint="Client Key">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/clientKeyInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- QR Code Scan Button -->
|
||||
<Button
|
||||
android:id="@+id/scanQrButton"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/scan_qr_code_button"
|
||||
android:drawableLeft="@drawable/ic_qr_scan"
|
||||
android:drawablePadding="8dp"
|
||||
android:paddingVertical="12dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/scan_qr_code_hint"
|
||||
android:textAlignment="center"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="italic" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/testConnectionInfo"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="You can test your connection after saving these settings."
|
||||
android:textAlignment="center"
|
||||
android:textStyle="italic" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/finishSetupButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Save and Continue"
|
||||
android:padding="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,98 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Server Configuration"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:hint="Server Address">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/serverAddressInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="text" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:hint="Server Port">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/serverPortInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Authentication"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:hint="Client Key"
|
||||
app:endIconMode="password_toggle">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/clientKeyInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textPassword" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- QR Code Scan Button -->
|
||||
<Button
|
||||
android:id="@+id/scanQrButton"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/scan_qr_code_button"
|
||||
android:drawableLeft="@drawable/ic_qr_scan"
|
||||
android:drawablePadding="8dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/saveSettingsButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Save Settings"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/resetSettingsButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Reset to Defaults"
|
||||
android:layout_marginTop="8dp"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".view.UploadHistoryActivity">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/historyRecyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
android:padding="8dp"
|
||||
android:clipToPadding="false" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/emptyView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:text="No upload history"
|
||||
android:textSize="18sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -1,65 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="24dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/logoImage"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="120dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:src="@drawable/ic_app_icon"
|
||||
android:contentDescription="SimpleLogUpload logo"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/welcomeTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="Welcome to SimpleLogUpload"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/logoImage" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/welcomeDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="Before you can use this app, you need to configure it to connect to your SimpleLogUpload server instance."
|
||||
android:textAlignment="center"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/welcomeTitle" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/welcomeDetails"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="The app requires:\n\n• Server Address - IP or hostname of your server\n• Server Port - Port your server is running on\n• Client Key - Authentication key for secure uploads\n\nYour administrator should have provided these details."
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/welcomeDescription" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/nextButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:text="Continue to Setup"
|
||||
android:padding="12dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,53 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/titleText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dumpstate_selection_title"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/dumpstateRecyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxHeight="300dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/emptyView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/no_dumpstate_found"
|
||||
android:gravity="center"
|
||||
android:visibility="gone"
|
||||
android:padding="16dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end"
|
||||
android:layout_marginTop="16dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/cancelButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@android:string/cancel"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/selectButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/select_button"
|
||||
android:enabled="false"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -1,97 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/upload_params_title"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/max_downloads_label"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/maxDownloadsInput"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:inputType="number"
|
||||
android:hint="@string/max_downloads_hint"
|
||||
android:importantForAutofill="no" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/max_downloads_note"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="italic"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/expiry_time_label"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/expiryTimeInput"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:inputType="number"
|
||||
android:hint="@string/expiry_time_hint"
|
||||
android:importantForAutofill="no" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/expiry_time_note"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="italic"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end">
|
||||
|
||||
<Button
|
||||
android:id="@+id/cancelButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/cancel_button"
|
||||
style="@style/Widget.AppCompat.Button.Borderless" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/confirmButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/upload_button" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -1,51 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkBox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fileNameText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold"
|
||||
android:ellipsize="start"
|
||||
android:singleLine="true"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintStart_toEndOf="@id/checkBox"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fileDateText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintStart_toEndOf="@id/checkBox"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/fileNameText"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fileSizeText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintStart_toEndOf="@id/checkBox"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/fileDateText"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -1,90 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
app:cardElevation="4dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/fileNameText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="16sp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/uploadTimeText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14sp"
|
||||
android:textColor="#757575"
|
||||
android:layout_marginTop="4dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Code: "
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/uploadCodeText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textIsSelectable="true"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#0066CC" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detailsText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/copyButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="Copy Code"
|
||||
style="@style/Widget.AppCompat.Button.Colored" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/deleteButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="Delete"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
@@ -1,70 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/dialogTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Upload Successful"
|
||||
android:textAlignment="center"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/codeLabel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Your upload code:"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintTop_toBottomOf="@id/dialogTitle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/uploadCode"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAlignment="center"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textColor="#007BFF"
|
||||
app:layout_constraintTop_toBottomOf="@id/codeLabel"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/copyButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:text="Copy Code"
|
||||
app:layout_constraintTop_toBottomOf="@id/uploadCode"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/closeButton"
|
||||
app:layout_constraintHorizontal_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/closeButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:text="Close"
|
||||
style="@style/Widget.AppCompat.Button.Borderless.Colored"
|
||||
app:layout_constraintTop_toBottomOf="@id/uploadCode"
|
||||
app:layout_constraintStart_toEndOf="@id/copyButton"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_weight="1" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Reference in New Issue
Block a user