From 74230ebfc0fadb8a06485bda2db30fc6bc0bb7bb Mon Sep 17 00:00:00 2001 From: An Bui <91354810+AnBui2004@users.noreply.github.com> Date: Mon, 13 Jul 2026 18:09:40 +0700 Subject: [PATCH] 4.3.5 - Open source licenses have been added. - New virtual machine creator interface. - Network card options have been added. --- app/build.gradle | 7 +- .../java/com/vectras/vm/AboutActivity.java | 3 + .../com/vectras/vm/ExportRomActivity.java | 1 + app/src/main/java/com/vectras/vm/StartVM.java | 5 + .../vectras/vm/creator/VMCreatorActivity.java | 710 +++--------------- .../vectras/vm/creator/VMCreatorSelector.java | 23 +- .../vm/creator/{ => configs}/ListManager.java | 26 +- .../creator/editor/AdvancedConfigsDialog.java | 108 +++ .../vm/creator/editor/BoardConfigsDialog.java | 102 +++ .../creator/editor/FirmwareConfigsDialog.java | 124 +++ .../creator/editor/NetworkConfigsDialog.java | 86 +++ .../creator/editor/StorageConfigsDialog.java | 569 ++++++++++++++ .../vm/creator/utils/CreatorUtils.java | 107 +++ .../com/vectras/vm/main/vms/DataMainRoms.java | 52 +- .../com/vectras/vm/view/CheckBoxView.java | 2 +- .../java/com/vectras/vm/view/SwitchView.java | 2 +- .../main/res/layout/activity_vm_creator.xml | 534 ++++--------- app/src/main/res/layout/checkbox_view.xml | 3 +- app/src/main/res/layout/content_about.xml | 8 + .../res/layout/creator_advanced_dialog.xml | 58 ++ .../main/res/layout/creator_board_dialog.xml | 77 ++ .../res/layout/creator_firmware_dialog.xml | 86 +++ .../res/layout/creator_network_dialog.xml | 47 ++ .../res/layout/creator_storage_dialog.xml | 215 ++++++ .../main/res/layout/rom_options_dialog.xml | 3 +- app/src/main/res/layout/select_box_view.xml | 3 +- app/src/main/res/layout/switch_view.xml | 6 +- app/src/main/res/values-vi/strings.xml | 9 + app/src/main/res/values/strings.xml | 31 + build.gradle | 1 + gradle/libs.versions.toml | 24 +- web/data/UpdateConfig.json | 8 +- 32 files changed, 1988 insertions(+), 1052 deletions(-) rename app/src/main/java/com/vectras/vm/creator/{ => configs}/ListManager.java (82%) create mode 100644 app/src/main/java/com/vectras/vm/creator/editor/AdvancedConfigsDialog.java create mode 100644 app/src/main/java/com/vectras/vm/creator/editor/BoardConfigsDialog.java create mode 100644 app/src/main/java/com/vectras/vm/creator/editor/FirmwareConfigsDialog.java create mode 100644 app/src/main/java/com/vectras/vm/creator/editor/NetworkConfigsDialog.java create mode 100644 app/src/main/java/com/vectras/vm/creator/editor/StorageConfigsDialog.java create mode 100644 app/src/main/java/com/vectras/vm/creator/utils/CreatorUtils.java create mode 100644 app/src/main/res/layout/creator_advanced_dialog.xml create mode 100644 app/src/main/res/layout/creator_board_dialog.xml create mode 100644 app/src/main/res/layout/creator_firmware_dialog.xml create mode 100644 app/src/main/res/layout/creator_network_dialog.xml create mode 100644 app/src/main/res/layout/creator_storage_dialog.xml diff --git a/app/build.gradle b/app/build.gradle index f5d72cf..c39bff4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,6 +2,7 @@ plugins { id 'com.android.application' id 'com.google.gms.google-services' id 'com.google.firebase.crashlytics' + id 'com.google.android.gms.oss-licenses-plugin' } android { @@ -12,8 +13,8 @@ android { applicationId "com.vectras.vm" minSdk minApi targetSdk targetApi - versionCode 138 - versionName "4.3.4" + versionCode 139 + versionName "4.3.5" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" multiDexEnabled true @@ -123,4 +124,6 @@ dependencies { testImplementation libs.junit androidTestImplementation libs.androidx.junit androidTestImplementation libs.androidx.espresso.core + + implementation libs.play.services.oss.licenses } \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/AboutActivity.java b/app/src/main/java/com/vectras/vm/AboutActivity.java index 5b79239..da8ed84 100644 --- a/app/src/main/java/com/vectras/vm/AboutActivity.java +++ b/app/src/main/java/com/vectras/vm/AboutActivity.java @@ -8,6 +8,7 @@ import android.os.Bundle; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.LinearLayoutManager; +import com.google.android.gms.oss.licenses.OssLicensesMenuActivity; import com.vectras.vm.adapters.GithubUserAdapter; import com.vectras.vm.utils.CommandUtils; import com.vectras.vm.utils.UIUtils; @@ -100,6 +101,8 @@ public class AboutActivity extends AppCompatActivity implements View.OnClickList }); }); + findViewById(R.id.btn_open_source_licenses).setOnClickListener(v -> startActivity(new Intent(this, OssLicensesMenuActivity.class))); + } @Override diff --git a/app/src/main/java/com/vectras/vm/ExportRomActivity.java b/app/src/main/java/com/vectras/vm/ExportRomActivity.java index a28e4f4..58456c6 100644 --- a/app/src/main/java/com/vectras/vm/ExportRomActivity.java +++ b/app/src/main/java/com/vectras/vm/ExportRomActivity.java @@ -168,6 +168,7 @@ public class ExportRomActivity extends AppCompatActivity { vmConfigMap.put("fdb", ""); } + vmConfigMap.put("networkCard", current.networkCard); vmConfigMap.put("sharedFolder", current.sharedFolder); vmConfigMap.put("bootFrom", current.bootFrom); vmConfigMap.put("isShowBootMenu", current.isShowBootMenu); diff --git a/app/src/main/java/com/vectras/vm/StartVM.java b/app/src/main/java/com/vectras/vm/StartVM.java index 2d1f769..6a18f1d 100644 --- a/app/src/main/java/com/vectras/vm/StartVM.java +++ b/app/src/main/java/com/vectras/vm/StartVM.java @@ -73,6 +73,11 @@ public class StartVM { if (!cpuParams.isEmpty()) extraParams = cpuParams + " " + extraParams; + String network = Objects.requireNonNull(VMCreatorSelector.getNetworkCard(activity, vmData.networkCard).get("value")).toString(); + if (!network.isEmpty()) { + extraParams = "-device " + network + ",netdev=net0 -netdev user,id=net0 " + extraParams; + } + String bootFromParams = Objects.requireNonNull(VMCreatorSelector.getBootFrom(activity, vmData.bootFrom).get("value")).toString(); String showBootMenuParams = vmData.isShowBootMenu ? "menu=on" : ""; String bootParams = ""; diff --git a/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java b/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java index 22ce9da..485a772 100644 --- a/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java +++ b/app/src/main/java/com/vectras/vm/creator/VMCreatorActivity.java @@ -24,14 +24,17 @@ import androidx.appcompat.app.AppCompatActivity; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.google.android.material.textfield.TextInputEditText; -import com.google.android.material.textfield.TextInputLayout; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.vectras.qemu.MainSettingsManager; import com.vectras.vm.AppConfig; -import com.vectras.vm.Fragment.CreateImageDialogFragment; import com.vectras.vm.R; +import com.vectras.vm.creator.editor.AdvancedConfigsDialog; +import com.vectras.vm.creator.editor.BoardConfigsDialog; +import com.vectras.vm.creator.editor.NetworkConfigsDialog; +import com.vectras.vm.creator.utils.CreatorUtils; +import com.vectras.vm.creator.editor.FirmwareConfigsDialog; +import com.vectras.vm.creator.editor.StorageConfigsDialog; import com.vectras.vm.file.FilePickerDialog; import com.vectras.vm.store.RomInfo; import com.vectras.vm.SplashActivity; @@ -58,14 +61,11 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.File; -import java.io.IOException; -import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.vectras.vm.utils.ZipUtils; -import com.vectras.vterm.Terminal; import com.vectras.vm.utils.PermissionUtils; import com.vectras.vterm.Terminal2; @@ -76,7 +76,6 @@ public class VMCreatorActivity extends AppCompatActivity { private final ExecutorService executor = Executors.newSingleThreadExecutor(); private DialogProgressStyleBinding dialogProgressStyleBinding; private AlertDialog progressDialog; - boolean iseditparams = false; public String previousName = ""; public boolean addromnowdone = false; private boolean created = false; @@ -85,16 +84,8 @@ public class VMCreatorActivity extends AppCompatActivity { public static DataMainRoms current = new DataMainRoms(); private String thumbnailPath = ""; private String vmID = VMManager.idGenerator(); - private int cpu = 0; - private int cores = 0; - private int threads = 0; - private boolean isUseBattery = false; - private boolean isShowBootMenu = false; - private boolean isUseLocalTime = true; - private boolean isUseUefi = false; - private boolean isUseDefaultBios = true; - private boolean sharedFolder = false; - private int bootFrom = 0; + + private CreatorUtils utils; @Override public boolean onOptionsItemSelected(MenuItem item) { @@ -106,7 +97,7 @@ public class VMCreatorActivity extends AppCompatActivity { try { if (MainSettingsManager.getBuiltInFilePicker(this)) { FilePickerDialog filePickerDialog = new FilePickerDialog(); - filePickerDialog.pick(this, filePickerDialog.TYPE_FILE, (path -> handleAddFile(Uri.fromFile(new File (path))))); + filePickerDialog.pick(this, FilePickerDialog.TYPE_FILE, (path -> handleAddFile(Uri.fromFile(new File (path))))); } else { filePicker.launch("*/*"); } @@ -158,24 +149,6 @@ public class VMCreatorActivity extends AppCompatActivity { binding.btnCreate.setOnClickListener(v -> startCreateVM()); - setupStorageUi(); - - binding.qemu.setOnClickListener(v -> { - iseditparams = true; - Intent intent = new Intent(); - intent.setClass(getApplicationContext(), QemuParamsEditorActivity.class); - intent.putExtra("content", Objects.requireNonNull(binding.qemu.getText()).toString()); - startActivity(intent); - }); - - binding.qemuField.setOnClickListener(v -> { - iseditparams = true; - Intent intent = new Intent(); - intent.setClass(getApplicationContext(), QemuParamsEditorActivity.class); - intent.putExtra("content", Objects.requireNonNull(binding.qemu.getText()).toString()); - startActivity(intent); - }); - TextWatcher afterTextChangedListener = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -197,8 +170,6 @@ public class VMCreatorActivity extends AppCompatActivity { } }; binding.title.addTextChangedListener(afterTextChangedListener); - binding.drive.addTextChangedListener(afterTextChangedListener); - binding.qemu.addTextChangedListener(afterTextChangedListener); binding.ivIcon.setOnClickListener(v -> { if (thumbnailPath.isEmpty()) { @@ -217,56 +188,57 @@ public class VMCreatorActivity extends AppCompatActivity { binding.ivAddThubnail.setImageResource(R.drawable.add_24px); VMManager.setIconWithName(binding.ivIcon, Objects.requireNonNull(binding.title.getText()).toString()); - if (FileUtils.isFileExists(VmFileManager.getThumbnail(vmID))) markDelete(VmFileManager.getThumbnail(vmID)); + if (FileUtils.isFileExists(VmFileManager.getThumbnail(vmID))) utils.markDelete(VmFileManager.getThumbnail(vmID)); }, null); } }); binding.lineardisclaimer.setOnClickListener(v -> DialogUtils.oneDialog(this, getResources().getString(R.string.dont_miss_out), getResources().getString(R.string.disclaimer_when_using_rom), getResources().getString(R.string.i_agree), true, R.drawable.verified_user_24px, true, null, null)); + binding.lnBoard.setOnClickListener(v -> { + save(); - binding.sbvCpu.setOnClickListener(v -> VMCreatorSelector.cpu(this, MainSettingsManager.getArch(this), cpu, ((position, name, value) -> { - cpu = position; - binding.sbvCpu.setSubtitle(name); - }))); - - binding.sbvCore.setOnClickListener(v -> VMCreatorSelector.cpuCore(this, MainSettingsManager.getArch(this), cores, ((position, name, value) -> { - cores = position; - binding.sbvCore.setSubtitle(name); - }))); - - binding.sbvThread.setOnClickListener(v -> VMCreatorSelector.cpuThread(this, MainSettingsManager.getArch(this), threads, ((position, name, value) -> { - threads = position; - binding.sbvThread.setSubtitle(name); - }))); - - binding.cbvBattery.setOnCheckedChangeListener((v, isChecked) -> isUseBattery = isChecked); - - - - binding.sbvBootfrom.setOnClickListener(v -> VMCreatorSelector.bootFrom(this, bootFrom, ((position, name, value) -> { - bootFrom = position; - binding.sbvBootfrom.setSubtitle(name); - }))); - - binding.cbvShowbootmenu.setOnCheckedChangeListener((v, isChecked) -> isShowBootMenu = isChecked); - - binding.cbvUselocaltime.setOnCheckedChangeListener((v, isChecked) -> isUseLocalTime = isChecked); - - if (!MainSettingsManager.getArch(this).equals("X86_64")) { - binding.cbvUseuefi.setVisibility(View.GONE); - } else { - binding.cbvUseuefi.setOnCheckedChangeListener((v, isChecked) -> isUseUefi = isChecked); - } - - binding.cbvUseDefaultBios.setOnCheckedChangeListener((v, isChecked) -> { - isUseDefaultBios = isChecked; - binding.cbvUseuefi.setEnabled(isChecked); + BoardConfigsDialog dialog = new BoardConfigsDialog(); + dialog.setConfigs(current); + dialog.setOnDismiss(this::loadConfig); + dialog.show(getSupportFragmentManager(), "board_configs_dialog"); }); + binding.lnStorage.setOnClickListener(v -> { + save(); + StorageConfigsDialog dialog = new StorageConfigsDialog(); + dialog.setConfigs(current); + dialog.setOnDismiss(this::loadConfig); + dialog.show(getSupportFragmentManager(), "storage_configs_dialog"); + }); - VmFileManager.removeTemp(this, vmID, peddingTempFolder); + binding.lnFirmware.setOnClickListener(v -> { + save(); + + FirmwareConfigsDialog dialog = new FirmwareConfigsDialog(); + dialog.setConfigs(current); + dialog.setOnDismiss(this::loadConfig); + dialog.show(getSupportFragmentManager(), "firmware_configs_dialog"); + }); + + binding.lnNetwork.setOnClickListener(v -> { + save(); + + NetworkConfigsDialog dialog = new NetworkConfigsDialog(); + dialog.setConfigs(current); + dialog.setOnDismiss(this::loadConfig); + dialog.show(getSupportFragmentManager(), "network_configs_dialog"); + }); + + binding.lnAdvanced.setOnClickListener(v -> { + save(); + + AdvancedConfigsDialog dialog = new AdvancedConfigsDialog(); + dialog.setConfigs(current); + dialog.setOnDismiss(this::loadConfig); + dialog.show(getSupportFragmentManager(), "advanced_configs_dialog"); + }); modify = getIntent().getBooleanExtra("MODIFY", false); if (modify) { @@ -275,20 +247,23 @@ public class VMCreatorActivity extends AppCompatActivity { loadConfig(VMManager.getVMConfig(getIntent().getIntExtra("POS", 0))); - vmID = getIntent().getStringExtra("VMID"); - - if (vmID == null || vmID.isEmpty()) { - vmID = VMManager.idGenerator(); - } +// vmID = getIntent().getStringExtra("VMID"); +// +// if (vmID == null || vmID.isEmpty()) { +// vmID = VMManager.idGenerator(); +// } previousName = current.itemName; } else { checkVMID(); + + utils = new CreatorUtils(this, vmID); + if (getIntent().hasExtra("addromnow")) { if (Objects.requireNonNull(getIntent().getStringExtra("romextra")).isEmpty()) { setDefault(); } else { - binding.qemu.setText(VmFileManager.textMarkToPath(this, vmID, Objects.requireNonNull(getIntent().getStringExtra("romextra")))); + current.itemExtra = VmFileManager.textMarkToPath(this, vmID, Objects.requireNonNull(getIntent().getStringExtra("romextra"))); } binding.title.setText(getIntent().getStringExtra("romname")); @@ -309,9 +284,9 @@ public class VMCreatorActivity extends AppCompatActivity { handleDiskFile(Uri.fromFile(new File((Objects.requireNonNull(getIntent().getStringExtra("rompath"))))), false); } if (!Objects.requireNonNull(getIntent().getStringExtra("addtodrive")).isEmpty()) { - setDrive(SELECT_DISK_0_FILE_MODE, VmFileManager.getPath(vmID, getIntent().getStringExtra("romfilename"))); + current.itemPath = VmFileManager.getPath(vmID, getIntent().getStringExtra("romfilename")); } else { - setDrive(SELECT_DISK_0_FILE_MODE, null); + current.itemPath = ""; } } @@ -320,7 +295,7 @@ public class VMCreatorActivity extends AppCompatActivity { try { if (MainSettingsManager.getBuiltInFilePicker(this)) { FilePickerDialog filePickerDialog = new FilePickerDialog(); - filePickerDialog.pick(this, filePickerDialog.ROM_FILE, (path -> importRom(null, path, new File(path).getName()))); + filePickerDialog.pick(this, FilePickerDialog.ROM_FILE, (path -> importRom(null, path, new File(path).getName()))); } else { cvbiPicker.launch("*/*"); } @@ -343,7 +318,7 @@ public class VMCreatorActivity extends AppCompatActivity { public void onFinished(String command, String log, int status) { new Handler(Looper.getMainLooper()).post(() -> { if (status == terminal2.SUCCESS) - binding.drive.setText(VmFileManager.getPath(vmID, "disk.qcow2")); + current.itemPath = VmFileManager.getPath(vmID, "disk.qcow2"); }); } @@ -355,12 +330,14 @@ public class VMCreatorActivity extends AppCompatActivity { }); } } else { - setDrive(SELECT_DISK_0_FILE_MODE, null); + current.itemPath = ""; } } } + utils.removeTemp(); + checkCreateCommandConfig(); getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { @@ -375,10 +352,6 @@ public class VMCreatorActivity extends AppCompatActivity { public void onResume() { super.onResume(); PermissionUtils.storagepermission(this, true); - if (iseditparams) { - iseditparams = false; - binding.qemu.setText(QemuParamsEditorActivity.result); - } } private void onBack() { @@ -413,94 +386,6 @@ public class VMCreatorActivity extends AppCompatActivity { handleThumbnail(uri); }); - private final ActivityResultLauncher diskPicker = - registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> { - if (uri == null) return; - handleDiskFile(uri, true); - }); - - @SuppressLint("SetTextI18n") - private final ActivityResultLauncher isoPicker = - registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> { - if (uri == null) return; - - String fileName = FileUtils.getFileNameFromUri(this, uri); - if (fileName != null && !fileName.isEmpty() && !FormatManager.isOpticalFileFormat(fileName)) { - DialogUtils.twoDialog(this, getString(R.string.problem_has_been_detected), getString(R.string.file_format_is_not_supported_optical_drive), getResources().getString(R.string.continuetext), getResources().getString(R.string.cancel), true, R.drawable.album_24px, true, - () -> handleFile(uri), null, null); - } else { - handleFile(uri); - } - }); - - - @SuppressLint("SetTextI18n") - private final ActivityResultLauncher floppyPicker = - registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> { - if (uri == null) return; - - String fileName = FileUtils.getFileNameFromUri(this, uri); - if (fileName != null && !fileName.isEmpty() && !FormatManager.isFloppyFileFormat(fileName)) { - DialogUtils.twoDialog(this, getString(R.string.problem_has_been_detected), getString(R.string.file_format_is_not_supported_floppy_drive), getResources().getString(R.string.continuetext), getResources().getString(R.string.cancel), true, R.drawable.save_24px, true, - () -> handleFile(uri), null, null); - } else { - handleFile(uri); - } - }); - - - private void handleFile(Uri uri) { - if (MainSettingsManager.copyFile(this)) { - showProgressDialog(getString(R.string.copying_file)); - - executor.execute(() -> { - try { - isProcessingFile = true; - - String path = copyToTemp(uri); - - runOnUiThread(() -> setDrive(this.PENDING_SELECT_FILE_MODE, path)); - } catch (Exception e) { - runOnUiThread(() -> DialogUtils.oneDialog(this, - getString(R.string.oops), - getString(R.string.unable_to_copy_file_content), - getString(R.string.ok), - true, - R.drawable.warning_48px, - true, - null, - null)); - Log.e(TAG, "isoPicker: " + e.getMessage()); - } finally { - isProcessingFile = false; - runOnUiThread(() -> DialogUtils.safeDismiss(this, progressDialog)); - } - }); - } else { - executor.execute(() -> { - if (!FileUtils.isValidFilePath(this, FileUtils.getPath(this, uri), false)) { - runOnUiThread(() -> DialogUtils.oneDialog(this, - getString(R.string.problem_has_been_detected), - getString(R.string.invalid_file_path_content), - getString(R.string.ok), - true, - R.drawable.warning_48px, - true, - null, - null) - ); - } else { - runOnUiThread(() -> showProgressDialog(getString(R.string.just_a_moment))); - String path = getPath(uri); - runOnUiThread(() -> { - setDrive(this.PENDING_SELECT_FILE_MODE, new File(path).getAbsolutePath()); - DialogUtils.safeDismiss(this, progressDialog); - }); - } - }); - } - } - private final ActivityResultLauncher cvbiPicker = registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> { @@ -533,7 +418,7 @@ public class VMCreatorActivity extends AppCompatActivity { try { isProcessingFile = true; - String filePath = copyToTemp(uri); + String filePath = utils.copyToTemp(uri); runOnUiThread(() -> DialogUtils.twoDialog(this, getString(R.string.file_added), @@ -572,6 +457,8 @@ public class VMCreatorActivity extends AppCompatActivity { checkVMID(); } + utils = new CreatorUtils(this, vmID); + if (current.itemArch != null) { VMManager.setArch(current.itemArch, this); binding.collapsingToolbarLayout.setSubtitle(MainSettingsManager.getArch(this)); @@ -581,77 +468,10 @@ public class VMCreatorActivity extends AppCompatActivity { binding.title.setText(current.itemName); } - if (current.itemPath != null && !current.itemPath.isEmpty()) { - setDrive(SELECT_DISK_0_FILE_MODE, (current.itemPath.contains("/") ? "" : VmFileManager.getPath(vmID)).concat(current.itemPath)); - } - - if (current.hd1 != null && !current.hd1.isEmpty()) { - setDrive(SELECT_DISK_1_FILE_MODE, (current.hd1.contains("/") ? "" : VmFileManager.getPath(vmID)).concat(current.hd1)); - } - - if (MainSettingsManager.getArch(this).equals(MainSettingsManager.ARM64_ARCH)) { - binding.lnFloppyContainer.setVisibility(View.GONE); - } else { - if (current.fda!= null && !current.fda.isEmpty()) { - setDrive(SELECT_FLOPPY_A_FILE_MODE, (current.fda.contains("/") ? "" : VmFileManager.getPath(vmID)).concat(current.fda)); - } - - if (current.fdb!= null && !current.fdb.isEmpty()) { - setDrive(SELECT_FLOPPY_B_FILE_MODE, (current.fdb.contains("/") ? "" : VmFileManager.getPath(vmID)).concat(current.fdb)); - } - } - - if (current.imgCdrom != null && !current.imgCdrom.isEmpty()) { - setDrive(SELECT_CDROM_0_FILE_MODE, (current.imgCdrom.contains("/") ? "" : VmFileManager.getPath(vmID)).concat(current.imgCdrom)); - } - - if (current.cdrom1 != null && !current.cdrom1.isEmpty()) { - setDrive(SELECT_CDROM_1_FILE_MODE, (current.cdrom1.contains("/") ? "" : VmFileManager.getPath(vmID)).concat(current.cdrom1)); - } - if (current.itemIcon != null && !current.itemIcon.isEmpty()) { thumbnailPath = (current.itemIcon.contains("/") ? current.itemIcon : VmFileManager.getPath(vmID, current.itemIcon)); updateThumbnailViewer(""); } - - if (current.itemExtra != null) { - binding.qemu.setText(VmFileManager.textMarkToPath(this, vmID, current.itemExtra)); - } - - cpu = current.cpu; - binding.sbvCpu.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getCpu(this, MainSettingsManager.getArch(this), current.cpu).get("name")).toString()); - - cores = current.cores; - binding.sbvCore.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getCpuCore(MainSettingsManager.getArch(this), cores).get("value")).toString()); - - threads = current.threads; - binding.sbvThread.setSubtitle(String.valueOf(threads + 1)); - - isUseBattery = current.battery; - binding.cbvBattery.setChecked(isUseBattery); - - bootFrom = current.bootFrom; - binding.sbvBootfrom.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getBootFrom(this, current.bootFrom).get("name")).toString()); - isShowBootMenu = current.isShowBootMenu; - binding.cbvShowbootmenu.setChecked(isShowBootMenu); - - sharedFolder = current.sharedFolder; - binding.svSharedFolder.setChecked(sharedFolder); - - if (MainSettingsManager.getArch(this).equals(MainSettingsManager.X86_64_ARCH)) { - isUseUefi = current.isUseUefi; - binding.cbvUseuefi.setChecked(isUseUefi); - } else { - binding.cbvUseuefi.setVisibility(View.GONE); - } - - isUseDefaultBios = current.isUseDefaultBios; - binding.cbvUseDefaultBios.setChecked(isUseDefaultBios); - - binding.cbvUseuefi.setEnabled(isUseDefaultBios); - - isUseLocalTime = current.isUseLocalTime; - binding.cbvUselocaltime.setChecked(isUseLocalTime); } } @@ -660,36 +480,32 @@ public class VMCreatorActivity extends AppCompatActivity { if (DeviceUtils.is64bit()) { defQemuParams = switch (MainSettingsManager.getArch(this)) { case "ARM64" -> - "-M virt,virtualization=true -accel tcg,thread=multi -net nic,model=e1000 -net user -device nec-usb-xhci -device usb-kbd -device usb-mouse -device VGA"; + "-M virt,virtualization=true -accel tcg,thread=multi -device nec-usb-xhci -device usb-kbd -device usb-mouse -device VGA"; case "PPC" -> "-M mac99 -accel tcg,thread=multi"; default -> - "-M pc -accel tcg,thread=multi -vga std -netdev user,id=usernet -device e1000,netdev=usernet -usb -device usb-tablet"; + "-M pc -accel tcg,thread=multi -vga std -usb -device usb-tablet"; }; } else { defQemuParams = switch (MainSettingsManager.getArch(this)) { case "ARM64" -> - "-M virt -net nic,model=e1000 -net user -device nec-usb-xhci -device usb-kbd -device usb-mouse -device VGA"; - case "PPC" -> "-M mac99 1"; + "-M virt -device nec-usb-xhci -device usb-kbd -device usb-mouse -device VGA"; + case "PPC" -> "-M mac99"; default -> - "-M pc -vga std -netdev user,id=usernet -device e1000,netdev=usernet -usb -device usb-tablet"; + "-M pc -vga std -usb -device usb-tablet"; }; } binding.title.setText(getString(R.string.new_vm)); - binding.qemu.setText(defQemuParams); + current.itemExtra = defQemuParams; String currentArch = MainSettingsManager.getArch(this); if (currentArch.equals(MainSettingsManager.X86_64_ARCH)) { - cores = Math.min(1, VMCreatorSelector.getCpuCorePosition(new CpuHelper().getCpuCores() - 1)); - binding.sbvCore.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getCpuCore(currentArch, cores).get("value")).toString()); + current.cores = Math.min(1, VMCreatorSelector.getCpuCorePosition(new CpuHelper().getCpuCores() - 1)); } else if (currentArch.equals(MainSettingsManager.ARM64_ARCH)) { - cores = Math.min(2, VMCreatorSelector.getCpuCorePosition(new CpuHelper().getCpuCores() - 1)); - binding.sbvCore.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getCpuCore(currentArch, cores).get("value")).toString()); - } else { - binding.sbvCore.setSubtitle("1"); + current.cores = Math.min(2, VMCreatorSelector.getCpuCorePosition(new CpuHelper().getCpuCores() - 1)); } - binding.sbvThread.setSubtitle("1"); + current.networkCard = 3; // Intel E1000 (82540EM) } private void checkVMID() { @@ -720,16 +536,18 @@ public class VMCreatorActivity extends AppCompatActivity { } private void startCreateVM() { - if (Objects.requireNonNull(binding.title.getText()).toString().isEmpty()) { + save(); + + if (current.itemName.isEmpty()) { DialogUtils.oneDialog(this, getString(R.string.oops), getString(R.string.need_set_name), getString(R.string.ok), true, R.drawable.error_96px, true, null, null); } else { String _contentDialog = ""; - if (Objects.requireNonNull(binding.qemu.getText()).toString().isEmpty()) { + if (current.itemExtra.isEmpty()) { _contentDialog = getResources().getString(R.string.qemu_params_is_empty); } if (isAllDriveEmpty()) { - if (!VMManager.isHaveADisk(Objects.requireNonNull(binding.qemu.getText()).toString())) { + if (!current.itemExtra.isEmpty()) { if (!_contentDialog.isEmpty()) { _contentDialog += "\n\n"; } @@ -756,7 +574,7 @@ public class VMCreatorActivity extends AppCompatActivity { FileUtils.writeToFile(AppConfig.maindirpath, "roms-data.json", "[]"); } - if (!VMManager.addVM(finalVmConfig(), modify ? getIntent().getIntExtra("POS", 0) : -1)) { + if (!VMManager.addVM(current, modify ? getIntent().getIntExtra("POS", 0) : -1)) { DialogUtils.oneDialog( this, getString(R.string.oops), @@ -776,7 +594,7 @@ public class VMCreatorActivity extends AppCompatActivity { showProgressDialog(getString(R.string.just_a_sec)); new Thread(() -> { - moveAllFromTemp(); + utils.moveAllFromTemp(); VmFileManager.unMarkAllPendingAdd(vmID); VmFileManager.removeAllPendingDeleteMarkFiles(vmID); @@ -796,7 +614,7 @@ public class VMCreatorActivity extends AppCompatActivity { }).start(); } - private DataMainRoms finalVmConfig() { + private void save() { current.vmID = vmID; current.itemArch = MainSettingsManager.getArch(this); @@ -804,38 +622,7 @@ public class VMCreatorActivity extends AppCompatActivity { current.itemIcon = thumbnailPath; - current.cpu = cpu; - current.cores = cores; - current.threads = threads; - current.battery = isUseBattery; - - - current.itemPath = Objects.requireNonNull(binding.drive.getText()).toString(); - current.hd1 = Objects.requireNonNull(binding.tieHd1.getText()).toString(); - - current.fda = Objects.requireNonNull(binding.tieFda.getText()).toString(); - current.fdb = Objects.requireNonNull(binding.tieFdb.getText()).toString(); - - current.imgCdrom = Objects.requireNonNull(binding.cdrom.getText()).toString(); - current.cdrom1 = Objects.requireNonNull(binding.tieCdrom1.getText()).toString(); - - current.sharedFolder = sharedFolder; - - - current.bootFrom = bootFrom; - current.isShowBootMenu = isShowBootMenu; - current.isUseLocalTime = isUseLocalTime; - - current.isUseUefi = isUseUefi; - current.isUseDefaultBios = isUseDefaultBios; - - - current.itemExtra = Objects.requireNonNull(binding.qemu.getText()).toString(); - - current.qmpPort = 8080; - - return current; } private void handleThumbnail(Uri uri) { @@ -848,7 +635,7 @@ public class VMCreatorActivity extends AppCompatActivity { if (FileUtils.isFileExists(VmFileManager.getThumbnail(vmID))) VmFileManager.markPendingDelete(VmFileManager.getThumbnail(vmID)); - String tempPath = VmFileManager.getTempPath(this, vmID, peddingTempFolder + VmFileManager.THUMBNAIL_FILE_NAME); + String tempPath = utils.getTempPath(VmFileManager.THUMBNAIL_FILE_NAME); ImageUtils.convertToPng(this, uri, tempPath); @@ -931,7 +718,7 @@ public class VMCreatorActivity extends AppCompatActivity { _filename = String.valueOf(System.currentTimeMillis()); } - String path = copyToTemp(_content_describer); + String path = utils.copyToTemp(_content_describer); String final_filename = _filename; runOnUiThread(() -> { @@ -941,7 +728,7 @@ public class VMCreatorActivity extends AppCompatActivity { return; } if (_addtodrive) { - setDrive(PENDING_SELECT_FILE_MODE, path); + current.itemPath = path; } }); } catch (Exception e) { @@ -977,7 +764,7 @@ public class VMCreatorActivity extends AppCompatActivity { null, null); } else { - setDrive(PENDING_SELECT_FILE_MODE, path); + current.itemPath = path; } }); }).start(); @@ -1096,13 +883,13 @@ public class VMCreatorActivity extends AppCompatActivity { addromnowdone = true; if (Objects.requireNonNull(getIntent().getStringExtra("romextra")).isEmpty()) { setDefault(); - binding.drive.setText(_getDiskFile); + current.itemPath = _getDiskFile; } else { if (Objects.requireNonNull(getIntent().getStringExtra("romextra")).contains(Objects.requireNonNull(getIntent().getStringExtra("finalromfilename")))) { - binding.qemu.setText(Objects.requireNonNull(getIntent().getStringExtra("romextra")).replaceAll(Objects.requireNonNull(getIntent().getStringExtra("finalromfilename")), "\"" + _getDiskFile + "\"")); + current.itemExtra = Objects.requireNonNull(getIntent().getStringExtra("romextra")).replaceAll(Objects.requireNonNull(getIntent().getStringExtra("finalromfilename")), "\"" + _getDiskFile + "\""); } else { - binding.drive.setText(_getDiskFile); - binding.qemu.setText(VmFileManager.textMarkToPath(this, vmID, Objects.requireNonNull(getIntent().getStringExtra("romextra")))); + current.itemPath = _getDiskFile; + current.itemExtra = VmFileManager.textMarkToPath(this, vmID, Objects.requireNonNull(getIntent().getStringExtra("romextra"))); } } @@ -1112,13 +899,11 @@ public class VMCreatorActivity extends AppCompatActivity { handleThumbnail(Uri.parse(getIntent().getStringExtra("romicon"))); } } else { - if (Objects.requireNonNull(binding.qemu.getText()).toString().isEmpty()) { - setDefault(); - } + if (current.itemExtra.isEmpty()) setDefault(); if (Objects.requireNonNull(binding.title.getText()).toString().isEmpty() || binding.title.getText().toString().equals("New VM")) { binding.title.setText(_filename.replace(".cvbi", "")); } - binding.drive.setText(_getDiskFile); + current.itemPath = _getDiskFile; VMManager.setArch("", this); } @@ -1202,291 +987,17 @@ public class VMCreatorActivity extends AppCompatActivity { if (!isFinishing() && !isDestroyed()) progressDialog.show(); } - private String copyToTemp(Uri uri) throws IOException { - String fileName = FileUtils.getFileNameFromUri(this, uri); - - if (fileName == null || fileName.isEmpty()) { - fileName = String.valueOf(System.currentTimeMillis()); - } - - FileUtils.copyFileFromUri(this, uri, VmFileManager.getTempPath(this, vmID, peddingTempFolder + fileName)); - return VmFileManager.getPath(vmID, fileName); - } - public String getPath(Uri uri) { return FileUtils.getPath(this, uri); } - String peddingTempFolder = "pedding/"; - - private void onFileChange(String fileName) { - markDelete(VmFileManager.getPath(vmID, fileName)); - } - - private void markDelete(String path) { - VmFileManager.markPendingDelete(path); - deleteTemp(new File(path).getName()); - } - - private void deleteTemp(String fileName) { - VmFileManager.removeTemp(this, vmID, peddingTempFolder + fileName); - } - - public void moveAllFromTemp() { - ArrayList fileList = new ArrayList<>(); - FileUtils.getAListOfAllFilesAndFoldersInADirectory(VmFileManager.getTempPath(this, vmID, peddingTempFolder), fileList); - for (int position = 0; position < fileList.size(); position++) { - FileUtils.moveToFolder(fileList.get(position), VmFileManager.getPath(vmID)); - } - - ArrayList fileListInternal = new ArrayList<>(); - FileUtils.getAListOfAllFilesAndFoldersInADirectory(VmFileManager.getInternalTempPath(this, vmID, peddingTempFolder), fileListInternal); - for (int position = 0; position < fileListInternal.size(); position++) { - FileUtils.moveToFolder(fileListInternal.get(position), VmFileManager.getPath(vmID)); - } - } - - // STORAGE LOGIC CORE - - private void setupStorageUi() { - binding.drive.setOnClickListener(v -> pickStorageFile(SELECT_DISK_0_FILE_MODE)); - binding.driveField.setOnClickListener(v -> pickStorageFile(SELECT_DISK_0_FILE_MODE)); - binding.driveField.setEndIconOnClickListener(v -> { - if (Objects.requireNonNull(binding.drive.getText()).toString().isEmpty()) { - callQcow2CreatorDialog(SELECT_DISK_0_FILE_MODE); - } else { - storageFileOptionDialog(SELECT_DISK_0_FILE_MODE); - } - }); - - - - binding.tieHd1.setOnClickListener(v -> pickStorageFile(SELECT_DISK_1_FILE_MODE)); - binding.tilHd1.setOnClickListener(v -> pickStorageFile(SELECT_DISK_1_FILE_MODE)); - binding.tilHd1.setEndIconOnClickListener(v -> { - if (Objects.requireNonNull(binding.tieHd1.getText()).toString().isEmpty()) { - callQcow2CreatorDialog(SELECT_DISK_1_FILE_MODE); - } else { - storageFileOptionDialog(SELECT_DISK_1_FILE_MODE); - } - }); - - - - if (MainSettingsManager.getArch(this).equals(MainSettingsManager.ARM64_ARCH)) { - binding.lnFloppyContainer.setVisibility(View.GONE); - } - - binding.tieFda.setOnClickListener(v -> pickStorageFile(SELECT_FLOPPY_A_FILE_MODE)); - binding.tilFda.setOnClickListener(v -> pickStorageFile(SELECT_FLOPPY_A_FILE_MODE)); - binding.tilFda.setEndIconOnClickListener(v -> setDrive(SELECT_FLOPPY_A_FILE_MODE, null)); - - binding.tieFdb.setOnClickListener(v -> pickStorageFile(SELECT_FLOPPY_B_FILE_MODE)); - binding.tilFdb.setOnClickListener(v -> pickStorageFile(SELECT_FLOPPY_B_FILE_MODE)); - binding.tilFdb.setEndIconOnClickListener(v -> setDrive(SELECT_FLOPPY_B_FILE_MODE, null)); - - - binding.cdrom.setOnClickListener(v -> pickStorageFile(SELECT_CDROM_0_FILE_MODE)); - binding.cdromField.setOnClickListener(v -> pickStorageFile(SELECT_CDROM_0_FILE_MODE)); - binding.cdromField.setEndIconOnClickListener(v -> setDrive(SELECT_CDROM_0_FILE_MODE, null)); - - binding.tieCdrom1.setOnClickListener(v -> pickStorageFile(SELECT_CDROM_1_FILE_MODE)); - binding.tilCdrom1.setOnClickListener(v -> pickStorageFile(SELECT_CDROM_1_FILE_MODE)); - binding.tilCdrom1.setEndIconOnClickListener(v -> setDrive(SELECT_CDROM_1_FILE_MODE, null)); - - - - binding.svSharedFolder.setSubTitle(AppConfig.sharedFolder); - binding.svSharedFolder.setOnCheckedChangeListener((v, isChecked) -> sharedFolder = isChecked); - } - - private final int SELECT_DISK_0_FILE_MODE = 0; - private final int SELECT_DISK_1_FILE_MODE = 1; - public final int SELECT_CDROM_0_FILE_MODE = 2; - public final int SELECT_CDROM_1_FILE_MODE = 3; - public final int SELECT_FLOPPY_A_FILE_MODE = 4; - public final int SELECT_FLOPPY_B_FILE_MODE = 5; - private int PENDING_SELECT_FILE_MODE = 0; - private String PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE = ""; - - private void pickStorageFile(int mode) { - PENDING_SELECT_FILE_MODE = mode; - PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE = Objects.requireNonNull(getPeddingStorageEditText().getText()).toString(); - - try { - if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_0_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_CDROM_1_FILE_MODE) { - if (MainSettingsManager.getBuiltInFilePicker(this)) { - builtInFilePicker(PICK_OPTICAL_FILE_MODE); - } else { - isoPicker.launch("*/*"); - } - } else if (PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_A_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_B_FILE_MODE) { - if (MainSettingsManager.getBuiltInFilePicker(this)) { - builtInFilePicker(PICK_FLOPPY_FILE_MODE); - } else { - floppyPicker.launch("*/*"); - } - } else { - if (MainSettingsManager.getBuiltInFilePicker(this)) { - builtInFilePicker(PICK_DRIVE_FILE_MODE); - } else { - diskPicker.launch("*/*"); - } - } - } catch (Exception e) { - Log.e(TAG, "pickStorageFile: ", e); - IntentUtils.showErrorDialog(this); - } - } - - private void storageFileOptionDialog(int mode) { - PENDING_SELECT_FILE_MODE = mode; - - //TextInputLayout peddingTextInputLayout = getPeddingStorageInputLayout(); - TextInputEditText peddingTextInputEditText = getPeddingStorageEditText(); - - DialogUtils.threeDialog(this, - getString(R.string.change_hard_drive), - getString(R.string.do_you_want_to_change_create_or_remove), - getString(R.string.change), getString(R.string.remove), - getString(R.string.create), - true, - R.drawable.hard_drive_24px, - true, - () -> pickStorageFile(mode), - () -> { - String path = new File(Objects.requireNonNull(peddingTextInputEditText.getText()).toString()).getAbsolutePath(); - if (path.startsWith(VmFileManager.quickGetPath(vmID))) { - ProgressDialog progressDialog1 = new ProgressDialog(this); - progressDialog1.show(); - new Thread(() -> { - markDelete(path); - runOnUiThread(progressDialog1::reset); - }).start(); - } - - setDrive(mode, ""); - }, - () -> { - if (createVMFolder(true)) { - callQcow2CreatorDialog(PENDING_SELECT_FILE_MODE); - } - }, null); - } - - private void callQcow2CreatorDialog(int mode) { - PENDING_SELECT_FILE_MODE = mode; - - TextInputLayout peddingTextInputLayout = getPeddingStorageInputLayout(); - TextInputEditText peddingTextInputEditText = getPeddingStorageEditText(); - - CreateImageDialogFragment dialogFragment = new CreateImageDialogFragment(); - dialogFragment.folder = VmFileManager.getPath(vmID); - dialogFragment.customRom = true; - dialogFragment.filename = Objects.requireNonNull(binding.title.getText()).toString(); - dialogFragment.drive = peddingTextInputEditText; - dialogFragment.driveLayout = peddingTextInputLayout; - dialogFragment.isMarkPendingAdd = true; - dialogFragment.show(getSupportFragmentManager(), "CreateImageDialogFragment"); - } - - private void setRemovableDriveEndIconOnClickListener(int mode, TextInputLayout textInputLayout) { - textInputLayout.setEndIconOnClickListener(v -> { - PENDING_SELECT_FILE_MODE = mode; - PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE = Objects.requireNonNull(getPeddingStorageEditText().getText()).toString(); - setDrive(mode, null); - }); - } - - private void setDrive(Integer mode, String path) { - if (isFileReadyinUse(path)) { - DialogUtils.oopsDialog(this, getString(R.string.vm_creator_this_file_is_already_in_use_content)); - deleteTemp(new File(path).getName()); - return; - } - - if (mode != null) PENDING_SELECT_FILE_MODE = mode; - - TextInputLayout peddingTextInputLayout = getPeddingStorageInputLayout(); - TextInputEditText peddingTextInputEditText = getPeddingStorageEditText(); - - peddingTextInputEditText.setText(path != null ? path : ""); - - if (path == null || path.isEmpty()) { - if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_0_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_CDROM_1_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_A_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_B_FILE_MODE) { - peddingTextInputLayout.setEndIconMode(TextInputLayout.END_ICON_NONE); - } else { - peddingTextInputLayout.setEndIconDrawable(R.drawable.add_24px); - } - } else { - if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_0_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_CDROM_1_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_A_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_B_FILE_MODE) { - peddingTextInputLayout.setEndIconMode(TextInputLayout.END_ICON_CUSTOM); - peddingTextInputLayout.setEndIconDrawable(R.drawable.close_24px); - setRemovableDriveEndIconOnClickListener(PENDING_SELECT_FILE_MODE, peddingTextInputLayout); - } else { - peddingTextInputLayout.setEndIconDrawable(R.drawable.more_vert_24px); - } - } - - if (!PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE.isEmpty()) { - onFileChange(new File(PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE).getName()); - PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE = ""; - } - } - - private TextInputLayout getPeddingStorageInputLayout() { - if (PENDING_SELECT_FILE_MODE == SELECT_DISK_1_FILE_MODE) { - return binding.tilHd1; - } else if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_0_FILE_MODE) { - return binding.cdromField; - } else if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_1_FILE_MODE) { - return binding.tilCdrom1; - } else if (PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_A_FILE_MODE) { - return binding.tilFda; - } else if (PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_B_FILE_MODE) { - return binding.tilFdb; - } else { - return binding.driveField; - } - } - - private TextInputEditText getPeddingStorageEditText() { - if (PENDING_SELECT_FILE_MODE == SELECT_DISK_1_FILE_MODE) { - return binding.tieHd1; - } else if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_0_FILE_MODE) { - return binding.cdrom; - } else if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_1_FILE_MODE) { - return binding.tieCdrom1; - } else if (PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_A_FILE_MODE) { - return binding.tieFda; - } else if (PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_B_FILE_MODE) { - return binding.tieFdb; - } else { - return binding.drive; - } - } - private boolean isAllDriveEmpty() { - return (Objects.requireNonNull(binding.drive.getText()).toString().isEmpty()) && - (Objects.requireNonNull(binding.tieHd1.getText()).toString().isEmpty()) && - (Objects.requireNonNull(binding.cdrom.getText()).toString().isEmpty()) && - (Objects.requireNonNull(binding.tieCdrom1.getText()).toString().isEmpty()) && - (Objects.requireNonNull(binding.tieFda.getText()).toString().isEmpty()) && - (Objects.requireNonNull(binding.tieFdb.getText()).toString().isEmpty()); - } - - private boolean isFileReadyinUse(String path) { - if (path == null || path.trim().isEmpty()) return false; - - String paramCollection = Objects.requireNonNull(binding.drive.getText()).toString(); - paramCollection += "\n" + Objects.requireNonNull(binding.tieHd1.getText()); - paramCollection += "\n" + Objects.requireNonNull(binding.cdrom.getText()); - paramCollection += "\n" + Objects.requireNonNull(binding.tieCdrom1.getText()); - paramCollection += "\n" + Objects.requireNonNull(binding.tieFda.getText()); - paramCollection += "\n" + Objects.requireNonNull(binding.tieFdb.getText()); - paramCollection += "\n" + Objects.requireNonNull(binding.qemu.getText()); - - return paramCollection.contains(path); + return (current.itemPath.isEmpty() && + current.hd1.isEmpty() && + current.imgCdrom.isEmpty() && + current.cdrom1.isEmpty() && + current.fda.isEmpty() && + current.fdb.isEmpty()); } private void checkCreateCommandConfig() { @@ -1508,23 +1019,4 @@ public class VMCreatorActivity extends AppCompatActivity { }); } } - - final int PICK_DRIVE_FILE_MODE = 0; - final int PICK_OPTICAL_FILE_MODE = 1; - final int PICK_FLOPPY_FILE_MODE = 2; - - private void builtInFilePicker(int mode) { - FilePickerDialog filePickerDialog = new FilePickerDialog(); - - int finalMode; - if (mode == PICK_DRIVE_FILE_MODE) { - finalMode = filePickerDialog.FIT_PICK_DISK_FILE_MODE; - } else if (mode == PICK_OPTICAL_FILE_MODE) { - finalMode = filePickerDialog.FIT_PICK_OPTICAL_FILE_MODE; - } else { - finalMode = filePickerDialog.FIT_PICK_FLOPPY_FILE_MODE; - } - - filePickerDialog.pick(this, finalMode, (path -> handleFile(Uri.fromFile(new File(path))))); - } } diff --git a/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java b/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java index e5bbd7b..9e964c8 100644 --- a/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java +++ b/app/src/main/java/com/vectras/vm/creator/VMCreatorSelector.java @@ -2,26 +2,13 @@ package com.vectras.vm.creator; import android.app.Activity; import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; -import androidx.annotation.NonNull; -import androidx.appcompat.app.AlertDialog; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.google.android.material.color.MaterialColors; import com.vectras.vm.R; -import com.vectras.vm.databinding.DialogListSelectorLayoutBinding; -import com.vectras.vm.databinding.SimpleLayoutListViewWithCheckBinding; +import com.vectras.vm.creator.configs.ListManager; import com.vectras.vm.utils.UniversalPickerDialog; import java.util.ArrayList; import java.util.HashMap; -import java.util.Objects; public class VMCreatorSelector { private static final String TAG = "VMCreatorSelector"; @@ -54,6 +41,14 @@ public class VMCreatorSelector { showDialog(activity, ListManager.threads(arch), position, callback, activity.getString(R.string.thread)); } + public static void networkCard(Activity activity, int position, UniversalPickerDialog.UniversalPickerDialogCallback callback) { + showDialog(activity, ListManager.networkCards(activity), position, callback, activity.getString(R.string.network_card)); + } + + public static HashMap getNetworkCard(Context context, int position) { + return ListManager.networkCards(context).get(position); + } + public static HashMap getBootFrom(Context context, int position) { return ListManager.bootFrom(context).get(position); } diff --git a/app/src/main/java/com/vectras/vm/creator/ListManager.java b/app/src/main/java/com/vectras/vm/creator/configs/ListManager.java similarity index 82% rename from app/src/main/java/com/vectras/vm/creator/ListManager.java rename to app/src/main/java/com/vectras/vm/creator/configs/ListManager.java index a46766a..bc70331 100644 --- a/app/src/main/java/com/vectras/vm/creator/ListManager.java +++ b/app/src/main/java/com/vectras/vm/creator/configs/ListManager.java @@ -1,4 +1,4 @@ -package com.vectras.vm.creator; +package com.vectras.vm.creator.configs; import android.content.Context; @@ -145,4 +145,28 @@ public class ListManager { return list; } + + public static ArrayList> networkCards(Context context) { + ArrayList> list = new ArrayList<>(); + UniversalPickerDialog.putToList(list, context.getString(R.string.none), ""); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_e1000e_82574l), "e1000e"); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_igb_82576), "igb"); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_e1000_82540em), "e1000"); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_e1000_82545em), "e1000-82545em"); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_e1000_82544gc), "e1000-82544gc"); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_i82801), "i82801"); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_i82562), "i82562"); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_i82559er), "i82559er"); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_i82558b), "i82558b"); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_i82557c), "i82557c"); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_i82551), "i82551"); + UniversalPickerDialog.putToList(list, context.getString(R.string.intel_i82550), "i82550"); + UniversalPickerDialog.putToList(list, context.getString(R.string.realtek_rtl8139), "rtl8139"); + UniversalPickerDialog.putToList(list, context.getString(R.string.amd_pcnet), "pcnet"); + UniversalPickerDialog.putToList(list, context.getString(R.string.novell_ne2000), "ne2k_pci"); + UniversalPickerDialog.putToList(list, context.getString(R.string.vmware_vmxnet3), "vmxnet3"); + UniversalPickerDialog.putToList(list, context.getString(R.string.virtio_net), "virtio-net-pci"); + UniversalPickerDialog.putToList(list, context.getString(R.string.virtio_net_transitional), "virtio-net-pci-transitional"); + return list; + } } diff --git a/app/src/main/java/com/vectras/vm/creator/editor/AdvancedConfigsDialog.java b/app/src/main/java/com/vectras/vm/creator/editor/AdvancedConfigsDialog.java new file mode 100644 index 0000000..ef7633f --- /dev/null +++ b/app/src/main/java/com/vectras/vm/creator/editor/AdvancedConfigsDialog.java @@ -0,0 +1,108 @@ +package com.vectras.vm.creator.editor; + +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; + +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import com.vectras.vm.creator.QemuParamsEditorActivity; +import com.vectras.vm.databinding.CreatorAdvancedDialogBinding; +import com.vectras.vm.main.vms.DataMainRoms; + +import java.util.Objects; + +public class AdvancedConfigsDialog extends BottomSheetDialogFragment { + final String TAG = "AdvancedConfigsDialog"; + + String vmId; + DataMainRoms configs; + + public void setConfigs(DataMainRoms configs) { + this.configs = configs; + if (configs != null) { + vmId = configs.vmID; + } + } + + CreatorAdvancedDialogBinding binding; + + boolean iseditparams; + + @NonNull + @Override + public BottomSheetDialog onCreateDialog(Bundle savedInstanceState) { + binding = CreatorAdvancedDialogBinding.inflate(getLayoutInflater()); + + BottomSheetDialog dialog = new BottomSheetDialog(requireActivity()); + dialog.setContentView(binding.getRoot()); + + initialize(); + + dialog.setOnShowListener(d -> { + BottomSheetBehavior behavior = dialog.getBehavior(); + behavior.setState(BottomSheetBehavior.STATE_EXPANDED); + behavior.setSkipCollapsed(true); + }); + + return dialog; + } + + public void onResume() { + super.onResume(); + if (iseditparams) { + iseditparams = false; + binding.qemu.setText(QemuParamsEditorActivity.result); + } + } + + AdvancedConfigsDialogCallback callback; + + public void setOnDismiss(AdvancedConfigsDialogCallback callback) { + this.callback = callback; + } + + public interface AdvancedConfigsDialogCallback { + void onDismiss(DataMainRoms configs); + } + + public void onDismiss(@NonNull DialogInterface dialogInterface) { + super.onDismiss(dialogInterface); + if (callback != null) { + save(); + callback.onDismiss(configs); + } + } + + private void initialize() { + binding.qemu.setOnClickListener(v -> { + iseditparams = true; + Intent intent = new Intent(); + intent.setClass(requireContext(), QemuParamsEditorActivity.class); + intent.putExtra("content", Objects.requireNonNull(binding.qemu.getText()).toString()); + startActivity(intent); + }); + + binding.qemuField.setOnClickListener(v -> { + iseditparams = true; + Intent intent = new Intent(); + intent.setClass(requireContext(), QemuParamsEditorActivity.class); + intent.putExtra("content", Objects.requireNonNull(binding.qemu.getText()).toString()); + startActivity(intent); + }); + + load(); + } + + private void load() { + binding.qemu.setText(configs.itemExtra); + } + + private void save() { + configs.itemExtra = Objects.requireNonNull(binding.qemu.getText()).toString(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/creator/editor/BoardConfigsDialog.java b/app/src/main/java/com/vectras/vm/creator/editor/BoardConfigsDialog.java new file mode 100644 index 0000000..8956bf6 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/creator/editor/BoardConfigsDialog.java @@ -0,0 +1,102 @@ +package com.vectras.vm.creator.editor; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; + +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import com.vectras.qemu.MainSettingsManager; +import com.vectras.vm.creator.VMCreatorSelector; +import com.vectras.vm.databinding.CreatorBoardDialogBinding; +import com.vectras.vm.main.vms.DataMainRoms; + +import java.util.Objects; + +public class BoardConfigsDialog extends BottomSheetDialogFragment { + final String TAG = "BoardConfigsDialog"; + + String vmId; + DataMainRoms configs; + public void setConfigs(DataMainRoms configs) { + this.configs = configs; + if (configs != null) { + vmId = configs.vmID; + } + } + + CreatorBoardDialogBinding binding; + + @NonNull + @Override + public BottomSheetDialog onCreateDialog(Bundle savedInstanceState) { + binding = CreatorBoardDialogBinding.inflate(getLayoutInflater()); + + BottomSheetDialog dialog = new BottomSheetDialog(requireActivity()); + dialog.setContentView(binding.getRoot()); + + initialize(); + + dialog.setOnShowListener(d -> { + BottomSheetBehavior behavior = dialog.getBehavior(); + behavior.setState(BottomSheetBehavior.STATE_EXPANDED); + behavior.setSkipCollapsed(true); + }); + + return dialog; + } + + BoardConfigsDialogCallback callback; + + public void setOnDismiss(BoardConfigsDialogCallback callback) { + this.callback = callback; + } + + public interface BoardConfigsDialogCallback { + void onDismiss(DataMainRoms configs); + } + + public void onDismiss(@NonNull DialogInterface dialogInterface) { + super.onDismiss(dialogInterface); + if (callback != null) { + save(); + callback.onDismiss(configs); + } + } + + private void initialize() { + binding.sbvCpu.setOnClickListener(v -> VMCreatorSelector.cpu(requireActivity(), MainSettingsManager.getArch(requireContext()), configs.cpu, ((position, name, value) -> { + configs.cpu = position; + binding.sbvCpu.setSubtitle(name); + }))); + + binding.sbvCore.setOnClickListener(v -> VMCreatorSelector.cpuCore(requireActivity(), MainSettingsManager.getArch(requireContext()), configs.cores, ((position, name, value) -> { + configs.cores = position; + binding.sbvCore.setSubtitle(name); + }))); + + binding.sbvThread.setOnClickListener(v -> VMCreatorSelector.cpuThread(requireActivity(), MainSettingsManager.getArch(requireContext()), configs.threads, ((position, name, value) -> { + configs.threads = position; + binding.sbvThread.setSubtitle(name); + }))); + + load(); + } + + private void load() { + binding.sbvCpu.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getCpu(requireContext(), MainSettingsManager.getArch(requireContext()), configs.cpu).get("name")).toString()); + + binding.sbvCore.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getCpuCore(MainSettingsManager.getArch(requireContext()), configs.cores).get("value")).toString()); + + binding.sbvThread.setSubtitle(String.valueOf(configs.threads + 1)); + + binding.cbvBattery.setChecked(configs.battery); + } + + private void save() { + configs.battery = binding.cbvBattery.isChecked(); + } +} diff --git a/app/src/main/java/com/vectras/vm/creator/editor/FirmwareConfigsDialog.java b/app/src/main/java/com/vectras/vm/creator/editor/FirmwareConfigsDialog.java new file mode 100644 index 0000000..0f83e13 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/creator/editor/FirmwareConfigsDialog.java @@ -0,0 +1,124 @@ +package com.vectras.vm.creator.editor; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; +import androidx.appcompat.content.res.AppCompatResources; + +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import com.vectras.qemu.MainSettingsManager; +import com.vectras.vm.R; +import com.vectras.vm.creator.VMCreatorSelector; +import com.vectras.vm.databinding.CreatorFirmwareDialogBinding; +import com.vectras.vm.main.vms.DataMainRoms; + +import java.util.Objects; + +public class FirmwareConfigsDialog extends BottomSheetDialogFragment { + final String TAG = "FirmwareConfigsDialog"; + + String vmId; + DataMainRoms configs; + + public void setConfigs(DataMainRoms configs) { + this.configs = configs; + if (configs != null) { + vmId = configs.vmID; + } + } + + CreatorFirmwareDialogBinding binding; + + @NonNull + @Override + public BottomSheetDialog onCreateDialog(Bundle savedInstanceState) { + binding = CreatorFirmwareDialogBinding.inflate(getLayoutInflater()); + + BottomSheetDialog dialog = new BottomSheetDialog(requireActivity()); + dialog.setContentView(binding.getRoot()); + + initialize(); + + dialog.setOnShowListener(d -> { + BottomSheetBehavior behavior = dialog.getBehavior(); + behavior.setState(BottomSheetBehavior.STATE_EXPANDED); + behavior.setSkipCollapsed(true); + }); + + return dialog; + } + + FirmwareConfigsDialogCallback callback; + + public void setOnDismiss(FirmwareConfigsDialogCallback callback) { + this.callback = callback; + } + + public interface FirmwareConfigsDialogCallback { + void onDismiss(DataMainRoms configs); + } + + public void onDismiss(@NonNull DialogInterface dialogInterface) { + super.onDismiss(dialogInterface); + if (callback != null) { + save(); + callback.onDismiss(configs); + } + } + + private void initialize() { + binding.sbvBootfrom.setOnClickListener(v -> VMCreatorSelector.bootFrom(requireActivity(), configs.bootFrom, ((position, name, value) -> { + configs.bootFrom = position; + binding.sbvBootfrom.setSubtitle(name); + }))); + + binding.cbvShowbootmenu.setOnCheckedChangeListener((v, isChecked) -> configs.isShowBootMenu = isChecked); + + binding.cbvUselocaltime.setOnCheckedChangeListener((v, isChecked) -> configs.isUseLocalTime = isChecked); + + if (!MainSettingsManager.getArch(requireContext()).equals("X86_64")) { + binding.cbvUseuefi.setVisibility(View.GONE); + binding.cbvUseDefaultBios.setBackground(AppCompatResources.getDrawable(requireContext(), R.drawable.object_shape_single_high)); + } else { + binding.cbvUseuefi.setOnCheckedChangeListener((v, isChecked) -> configs.isUseUefi = isChecked); + } + + binding.cbvUseDefaultBios.setOnCheckedChangeListener((v, isChecked) -> { + configs.isUseDefaultBios = isChecked; + binding.cbvUseuefi.setEnabled(isChecked); + }); + + load(); + } + + private void load() { + binding.sbvBootfrom.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getBootFrom(requireActivity(), configs.bootFrom).get("name")).toString()); + + binding.cbvShowbootmenu.setChecked(configs.isShowBootMenu); + + if (MainSettingsManager.getArch(requireContext()).equals(MainSettingsManager.X86_64_ARCH)) { + binding.cbvUseuefi.setChecked(configs.isUseUefi); + } else { + binding.cbvUseuefi.setVisibility(View.GONE); + } + + binding.cbvUseDefaultBios.setChecked(configs.isUseDefaultBios); + + binding.cbvUseuefi.setEnabled(configs.isUseDefaultBios); + + binding.cbvUselocaltime.setChecked(configs.isUseLocalTime); + } + + private void save() { + configs.isShowBootMenu = binding.cbvShowbootmenu.isChecked(); + + configs.isUseUefi = binding.cbvUseuefi.isChecked(); + configs.isUseDefaultBios = binding.cbvUseDefaultBios.isChecked(); + configs.isUseLocalTime = binding.cbvUselocaltime.isChecked(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/creator/editor/NetworkConfigsDialog.java b/app/src/main/java/com/vectras/vm/creator/editor/NetworkConfigsDialog.java new file mode 100644 index 0000000..6f743ca --- /dev/null +++ b/app/src/main/java/com/vectras/vm/creator/editor/NetworkConfigsDialog.java @@ -0,0 +1,86 @@ +package com.vectras.vm.creator.editor; + +import android.content.DialogInterface; +import android.os.Bundle; +import android.widget.FrameLayout; + +import androidx.annotation.NonNull; + +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import com.vectras.qemu.MainSettingsManager; +import com.vectras.vm.creator.VMCreatorSelector; +import com.vectras.vm.databinding.CreatorNetworkDialogBinding; +import com.vectras.vm.main.vms.DataMainRoms; + +import java.util.Objects; + +public class NetworkConfigsDialog extends BottomSheetDialogFragment { + final String TAG = "NetworkConfigsDialog"; + + String vmId; + DataMainRoms configs; + public void setConfigs(DataMainRoms configs) { + this.configs = configs; + if (configs != null) { + vmId = configs.vmID; + } + } + + CreatorNetworkDialogBinding binding; + + @NonNull + @Override + public BottomSheetDialog onCreateDialog(Bundle savedInstanceState) { + binding = CreatorNetworkDialogBinding.inflate(getLayoutInflater()); + + BottomSheetDialog dialog = new BottomSheetDialog(requireActivity()); + dialog.setContentView(binding.getRoot()); + + initialize(); + + dialog.setOnShowListener(d -> { + BottomSheetBehavior behavior = dialog.getBehavior(); + behavior.setState(BottomSheetBehavior.STATE_EXPANDED); + behavior.setSkipCollapsed(true); + }); + + return dialog; + } + + NetworkConfigsDialogCallback callback; + + public void setOnDismiss(NetworkConfigsDialogCallback callback) { + this.callback = callback; + } + + public interface NetworkConfigsDialogCallback { + void onDismiss(DataMainRoms configs); + } + + public void onDismiss(@NonNull DialogInterface dialogInterface) { + super.onDismiss(dialogInterface); + if (callback != null) { + save(); + callback.onDismiss(configs); + } + } + + private void initialize() { + binding.sbvCardType.setOnClickListener(v -> VMCreatorSelector.networkCard(requireActivity(), configs.networkCard, ((position, name, value) -> { + configs.networkCard = position; + binding.sbvCardType.setSubtitle(name); + }))); + + load(); + } + + private void load() { + binding.sbvCardType.setSubtitle(Objects.requireNonNull(VMCreatorSelector.getNetworkCard(requireActivity(), configs.networkCard).get("name")).toString()); + } + + private void save() { + // It may be used in subsequent versions. + } +} \ No newline at end of file diff --git a/app/src/main/java/com/vectras/vm/creator/editor/StorageConfigsDialog.java b/app/src/main/java/com/vectras/vm/creator/editor/StorageConfigsDialog.java new file mode 100644 index 0000000..fbfa576 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/creator/editor/StorageConfigsDialog.java @@ -0,0 +1,569 @@ +package com.vectras.vm.creator.editor; + +import android.annotation.SuppressLint; +import android.content.DialogInterface; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.FrameLayout; + +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; + +import com.google.android.material.bottomsheet.BottomSheetBehavior; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import com.google.android.material.textfield.TextInputEditText; +import com.google.android.material.textfield.TextInputLayout; +import com.vectras.qemu.MainSettingsManager; +import com.vectras.vm.AppConfig; +import com.vectras.vm.Fragment.CreateImageDialogFragment; +import com.vectras.vm.R; +import com.vectras.vm.creator.utils.CreatorUtils; +import com.vectras.vm.databinding.CreatorStorageDialogBinding; +import com.vectras.vm.file.FilePickerDialog; +import com.vectras.vm.main.vms.DataMainRoms; +import com.vectras.vm.manager.FormatManager; +import com.vectras.vm.manager.VmFileManager; +import com.vectras.vm.utils.DialogUtils; +import com.vectras.vm.utils.FileUtils; +import com.vectras.vm.utils.IntentUtils; +import com.vectras.vm.utils.ProgressDialog; + +import java.io.File; +import java.util.Objects; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class StorageConfigsDialog extends BottomSheetDialogFragment { + final String TAG = "StorageConfigsDialog"; + + String vmId; + DataMainRoms configs; + public void setConfigs(DataMainRoms configs) { + this.configs = configs; + if (configs != null) { + vmId = configs.vmID; + if (isAdded()) utils = new CreatorUtils(requireActivity(), vmId); + } + } + + CreatorStorageDialogBinding binding; + private final ExecutorService executor = Executors.newSingleThreadExecutor(); + private CreatorUtils utils; + + @NonNull + @Override + public BottomSheetDialog onCreateDialog(Bundle savedInstanceState) { + binding = CreatorStorageDialogBinding.inflate(getLayoutInflater()); + + utils = new CreatorUtils(requireActivity(), vmId); + + BottomSheetDialog dialog = new BottomSheetDialog(requireActivity()); + dialog.setContentView(binding.getRoot()); + + initialize(); + + dialog.setOnShowListener(d -> { + BottomSheetBehavior behavior = dialog.getBehavior(); + behavior.setState(BottomSheetBehavior.STATE_EXPANDED); + behavior.setSkipCollapsed(true); + }); + + return dialog; + } + + StorageConfigsDialogCallback callback; + + public void setOnDismiss(StorageConfigsDialogCallback callback) { + this.callback = callback; + } + + public interface StorageConfigsDialogCallback { + void onDismiss(DataMainRoms configs); + } + + public void onDismiss(@NonNull DialogInterface dialogInterface) { + super.onDismiss(dialogInterface); + if (callback != null) { + save(); + callback.onDismiss(configs); + } + } + + private final ActivityResultLauncher diskPicker = + registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> { + if (uri == null) return; + handleDiskFile(uri); + }); + + @SuppressLint("SetTextI18n") + private final ActivityResultLauncher isoPicker = + registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> { + if (uri == null) return; + + String fileName = FileUtils.getFileNameFromUri(requireActivity(), uri); + if (fileName != null && !fileName.isEmpty() && !FormatManager.isOpticalFileFormat(fileName)) { + DialogUtils.twoDialog(requireActivity(), getString(R.string.problem_has_been_detected), getString(R.string.file_format_is_not_supported_optical_drive), getResources().getString(R.string.continuetext), getResources().getString(R.string.cancel), true, R.drawable.album_24px, true, + () -> handleFile(uri), null, null); + } else { + handleFile(uri); + } + }); + + + @SuppressLint("SetTextI18n") + private final ActivityResultLauncher floppyPicker = + registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> { + if (uri == null) return; + + String fileName = FileUtils.getFileNameFromUri(requireActivity(), uri); + if (fileName != null && !fileName.isEmpty() && !FormatManager.isFloppyFileFormat(fileName)) { + DialogUtils.twoDialog(requireActivity(), getString(R.string.problem_has_been_detected), getString(R.string.file_format_is_not_supported_floppy_drive), getResources().getString(R.string.continuetext), getResources().getString(R.string.cancel), true, R.drawable.save_24px, true, + () -> handleFile(uri), null, null); + } else { + handleFile(uri); + } + }); + + + private void handleFile(Uri uri) { + if (MainSettingsManager.copyFile(requireActivity())) { + utils.showProgressDialog(getString(R.string.copying_file)); + + executor.execute(() -> { + try { + + String path = utils.copyToTemp(uri); + + requireActivity().runOnUiThread(() -> setDrive(PENDING_SELECT_FILE_MODE, path)); + } catch (Exception e) { + requireActivity().runOnUiThread(() -> DialogUtils.oneDialog(requireActivity(), + getString(R.string.oops), + getString(R.string.unable_to_copy_file_content), + getString(R.string.ok), + true, + R.drawable.warning_48px, + true, + null, + null)); + Log.e(TAG, "isoPicker: " + e.getMessage()); + } finally { + requireActivity().runOnUiThread(() -> utils.dissmissProgressDialog()); + } + }); + } else { + executor.execute(() -> { + CreatorUtils.FilePathData filePathData = utils.getFilePath(uri); + + if (!filePathData.isValid) { + requireActivity().runOnUiThread(() -> DialogUtils.oneDialog(requireActivity(), + getString(R.string.problem_has_been_detected), + getString(R.string.invalid_file_path_content), + getString(R.string.ok), + true, + R.drawable.warning_48px, + true, + null, + null) + ); + } else { + requireActivity().runOnUiThread(() -> utils.showProgressDialog(getString(R.string.just_a_moment))); + requireActivity().runOnUiThread(() -> { + setDrive(PENDING_SELECT_FILE_MODE, new File(filePathData.path).getAbsolutePath()); + utils.dissmissProgressDialog(); + }); + } + }); + } + } + + private void handleDiskFile(Uri uri) { + ProgressDialog progressDialog1 = new ProgressDialog(requireActivity()); + progressDialog1.show(); + new Thread(() -> { + CreatorUtils.FilePathData filePathData = utils.getFilePath(uri); + + if (filePathData.isValid) { + requireActivity().runOnUiThread(() -> { + progressDialog1.reset(); + + if (FormatManager.isHardDriveFileFormat(filePathData.name)) { + startHandleHardDriveFile(uri); + } else { + DialogUtils.twoDialog(requireActivity(), getString(R.string.problem_has_been_detected), getString(R.string.file_format_is_not_supported_hard_drive), getResources().getString(R.string.continuetext), getResources().getString(R.string.cancel), true, R.drawable.hard_drive_24px, true, + () -> startHandleHardDriveFile(uri), null, null); + } + }); + } else { + requireActivity().runOnUiThread(() -> startHandleHardDriveFile(uri)); + } + }).start(); + } + + @SuppressLint("SetTextI18n") + private void startHandleHardDriveFile(Uri _content_describer) { + if (MainSettingsManager.copyFile(requireActivity())) { + + if (requireActivity().isFinishing() || requireActivity().isDestroyed()) return; + utils.showProgressDialog(getString(R.string.copying_file)); + + executor.execute(() -> { + try { + String _filename = FileUtils.getFileNameFromUri(requireActivity(), _content_describer); + if (_filename == null || _filename.isEmpty()) { + _filename = String.valueOf(System.currentTimeMillis()); + } + + String path = utils.copyToTemp(_content_describer); + + String final_filename = _filename; + requireActivity().runOnUiThread(() -> { + if (requireActivity().isFinishing() || requireActivity().isDestroyed()) { + if (!vmId.isEmpty()) + FileUtils.delete(new File(VmFileManager.getPath(vmId, final_filename))); + return; + } + + setDrive(PENDING_SELECT_FILE_MODE, path); + }); + } catch (Exception e) { + requireActivity().runOnUiThread(() -> DialogUtils.oneDialog(requireActivity(), + getString(R.string.oops), + getString(R.string.unable_to_copy_hard_drive_file_content), + getString(R.string.ok), + true, + R.drawable.warning_48px, + true, + null, + null)); + } finally { + requireActivity().runOnUiThread(() -> utils.dissmissProgressDialog()); + } + }); + } else { + ProgressDialog progressDialog1 = new ProgressDialog(requireActivity()); + progressDialog1.show(); + new Thread(() -> { + String path = FileUtils.getPath(requireContext(), _content_describer); + requireActivity().runOnUiThread(() -> { + progressDialog1.reset(); + + if (!FileUtils.isValidFilePath(requireActivity(), path, false)) { + DialogUtils.oneDialog(requireActivity(), + getString(R.string.problem_has_been_detected), + getString(R.string.invalid_file_path_content), + getString(R.string.ok), + true, + R.drawable.warning_48px, + true, + null, + null); + } else { + setDrive(PENDING_SELECT_FILE_MODE, path); + } + }); + }).start(); + } + } + + private void onFileChange(String fileName) { + utils.markDelete(VmFileManager.getPath(vmId, fileName)); + } + + // STORAGE LOGIC CORE + + private void initialize() { + binding.drive.setOnClickListener(v -> pickStorageFile(SELECT_DISK_0_FILE_MODE)); + binding.driveField.setOnClickListener(v -> pickStorageFile(SELECT_DISK_0_FILE_MODE)); + binding.driveField.setEndIconOnClickListener(v -> { + if (Objects.requireNonNull(binding.drive.getText()).toString().isEmpty()) { + callQcow2CreatorDialog(SELECT_DISK_0_FILE_MODE); + } else { + storageFileOptionDialog(SELECT_DISK_0_FILE_MODE); + } + }); + + + + binding.tieHd1.setOnClickListener(v -> pickStorageFile(SELECT_DISK_1_FILE_MODE)); + binding.tilHd1.setOnClickListener(v -> pickStorageFile(SELECT_DISK_1_FILE_MODE)); + binding.tilHd1.setEndIconOnClickListener(v -> { + if (Objects.requireNonNull(binding.tieHd1.getText()).toString().isEmpty()) { + callQcow2CreatorDialog(SELECT_DISK_1_FILE_MODE); + } else { + storageFileOptionDialog(SELECT_DISK_1_FILE_MODE); + } + }); + + + + if (MainSettingsManager.getArch(requireActivity()).equals(MainSettingsManager.ARM64_ARCH)) { + binding.lnFloppyContainer.setVisibility(View.GONE); + } + + binding.tieFda.setOnClickListener(v -> pickStorageFile(SELECT_FLOPPY_A_FILE_MODE)); + binding.tilFda.setOnClickListener(v -> pickStorageFile(SELECT_FLOPPY_A_FILE_MODE)); + binding.tilFda.setEndIconOnClickListener(v -> setDrive(SELECT_FLOPPY_A_FILE_MODE, null)); + + binding.tieFdb.setOnClickListener(v -> pickStorageFile(SELECT_FLOPPY_B_FILE_MODE)); + binding.tilFdb.setOnClickListener(v -> pickStorageFile(SELECT_FLOPPY_B_FILE_MODE)); + binding.tilFdb.setEndIconOnClickListener(v -> setDrive(SELECT_FLOPPY_B_FILE_MODE, null)); + + + binding.cdrom.setOnClickListener(v -> pickStorageFile(SELECT_CDROM_0_FILE_MODE)); + binding.cdromField.setOnClickListener(v -> pickStorageFile(SELECT_CDROM_0_FILE_MODE)); + binding.cdromField.setEndIconOnClickListener(v -> setDrive(SELECT_CDROM_0_FILE_MODE, null)); + + binding.tieCdrom1.setOnClickListener(v -> pickStorageFile(SELECT_CDROM_1_FILE_MODE)); + binding.tilCdrom1.setOnClickListener(v -> pickStorageFile(SELECT_CDROM_1_FILE_MODE)); + binding.tilCdrom1.setEndIconOnClickListener(v -> setDrive(SELECT_CDROM_1_FILE_MODE, null)); + + + binding.svSharedFolder.setSubTitle(AppConfig.sharedFolder); + + load(); + } + + private final int SELECT_DISK_0_FILE_MODE = 0; + private final int SELECT_DISK_1_FILE_MODE = 1; + public final int SELECT_CDROM_0_FILE_MODE = 2; + public final int SELECT_CDROM_1_FILE_MODE = 3; + public final int SELECT_FLOPPY_A_FILE_MODE = 4; + public final int SELECT_FLOPPY_B_FILE_MODE = 5; + private int PENDING_SELECT_FILE_MODE = 0; + private String PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE = ""; + + private void pickStorageFile(int mode) { + PENDING_SELECT_FILE_MODE = mode; + PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE = Objects.requireNonNull(getPeddingStorageEditText().getText()).toString(); + + try { + if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_0_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_CDROM_1_FILE_MODE) { + if (MainSettingsManager.getBuiltInFilePicker(requireActivity())) { + builtInFilePicker(PICK_OPTICAL_FILE_MODE); + } else { + isoPicker.launch("*/*"); + } + } else if (PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_A_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_B_FILE_MODE) { + if (MainSettingsManager.getBuiltInFilePicker(requireActivity())) { + builtInFilePicker(PICK_FLOPPY_FILE_MODE); + } else { + floppyPicker.launch("*/*"); + } + } else { + if (MainSettingsManager.getBuiltInFilePicker(requireActivity())) { + builtInFilePicker(PICK_DRIVE_FILE_MODE); + } else { + diskPicker.launch("*/*"); + } + } + } catch (Exception e) { + Log.e(TAG, "pickStorageFile: ", e); + IntentUtils.showErrorDialog(requireActivity()); + } + } + + private void storageFileOptionDialog(int mode) { + PENDING_SELECT_FILE_MODE = mode; + + //TextInputLayout peddingTextInputLayout = getPeddingStorageInputLayout(); + TextInputEditText peddingTextInputEditText = getPeddingStorageEditText(); + + DialogUtils.threeDialog(requireActivity(), + getString(R.string.change_hard_drive), + getString(R.string.do_you_want_to_change_create_or_remove), + getString(R.string.change), getString(R.string.remove), + getString(R.string.create), + true, + R.drawable.hard_drive_24px, + true, + () -> pickStorageFile(mode), + () -> { + String path = new File(Objects.requireNonNull(peddingTextInputEditText.getText()).toString()).getAbsolutePath(); + if (path.startsWith(VmFileManager.quickGetPath(vmId))) { + ProgressDialog progressDialog1 = new ProgressDialog(requireActivity()); + progressDialog1.show(); + new Thread(() -> { + utils.markDelete(path); + requireActivity().runOnUiThread(progressDialog1::reset); + }).start(); + } + + setDrive(mode, ""); + }, + () -> callQcow2CreatorDialog(PENDING_SELECT_FILE_MODE), null); + } + + private void callQcow2CreatorDialog(int mode) { + PENDING_SELECT_FILE_MODE = mode; + + TextInputLayout peddingTextInputLayout = getPeddingStorageInputLayout(); + TextInputEditText peddingTextInputEditText = getPeddingStorageEditText(); + + CreateImageDialogFragment dialogFragment = new CreateImageDialogFragment(); + dialogFragment.folder = VmFileManager.getPath(vmId); + dialogFragment.customRom = true; + dialogFragment.filename = configs.itemName; + dialogFragment.drive = peddingTextInputEditText; + dialogFragment.driveLayout = peddingTextInputLayout; + dialogFragment.isMarkPendingAdd = true; + dialogFragment.show(requireActivity().getSupportFragmentManager(), "CreateImageDialogFragment"); + } + + private void setRemovableDriveEndIconOnClickListener(int mode, TextInputLayout textInputLayout) { + textInputLayout.setEndIconOnClickListener(v -> { + PENDING_SELECT_FILE_MODE = mode; + PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE = Objects.requireNonNull(getPeddingStorageEditText().getText()).toString(); + setDrive(mode, null); + }); + } + + private void setDrive(Integer mode, String path) { + if (isFileReadyinUse(path)) { + DialogUtils.oopsDialog(requireActivity(), getString(R.string.vm_creator_this_file_is_already_in_use_content)); + utils.deleteTemp(new File(path).getName()); + return; + } + + if (mode != null) PENDING_SELECT_FILE_MODE = mode; + + TextInputLayout peddingTextInputLayout = getPeddingStorageInputLayout(); + TextInputEditText peddingTextInputEditText = getPeddingStorageEditText(); + + peddingTextInputEditText.setText(path != null ? path : ""); + + if (path == null || path.isEmpty()) { + if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_0_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_CDROM_1_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_A_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_B_FILE_MODE) { + peddingTextInputLayout.setEndIconMode(TextInputLayout.END_ICON_NONE); + } else { + peddingTextInputLayout.setEndIconDrawable(R.drawable.add_24px); + } + } else { + if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_0_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_CDROM_1_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_A_FILE_MODE || PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_B_FILE_MODE) { + peddingTextInputLayout.setEndIconMode(TextInputLayout.END_ICON_CUSTOM); + peddingTextInputLayout.setEndIconDrawable(R.drawable.close_24px); + setRemovableDriveEndIconOnClickListener(PENDING_SELECT_FILE_MODE, peddingTextInputLayout); + } else { + peddingTextInputLayout.setEndIconDrawable(R.drawable.more_vert_24px); + } + } + + if (!PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE.isEmpty()) { + onFileChange(new File(PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE).getName()); + PENDING_OLD_FILE_AFTER_SELECTED_NEW_FILE = ""; + } + } + + private TextInputLayout getPeddingStorageInputLayout() { + if (PENDING_SELECT_FILE_MODE == SELECT_DISK_1_FILE_MODE) { + return binding.tilHd1; + } else if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_0_FILE_MODE) { + return binding.cdromField; + } else if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_1_FILE_MODE) { + return binding.tilCdrom1; + } else if (PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_A_FILE_MODE) { + return binding.tilFda; + } else if (PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_B_FILE_MODE) { + return binding.tilFdb; + } else { + return binding.driveField; + } + } + + private TextInputEditText getPeddingStorageEditText() { + if (PENDING_SELECT_FILE_MODE == SELECT_DISK_1_FILE_MODE) { + return binding.tieHd1; + } else if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_0_FILE_MODE) { + return binding.cdrom; + } else if (PENDING_SELECT_FILE_MODE == SELECT_CDROM_1_FILE_MODE) { + return binding.tieCdrom1; + } else if (PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_A_FILE_MODE) { + return binding.tieFda; + } else if (PENDING_SELECT_FILE_MODE == SELECT_FLOPPY_B_FILE_MODE) { + return binding.tieFdb; + } else { + return binding.drive; + } + } + + private boolean isFileReadyinUse(String path) { + if (path == null || path.trim().isEmpty()) return false; + + String paramCollection = Objects.requireNonNull(binding.drive.getText()).toString(); + paramCollection += "\n" + Objects.requireNonNull(binding.tieHd1.getText()); + paramCollection += "\n" + Objects.requireNonNull(binding.cdrom.getText()); + paramCollection += "\n" + Objects.requireNonNull(binding.tieCdrom1.getText()); + paramCollection += "\n" + Objects.requireNonNull(binding.tieFda.getText()); + paramCollection += "\n" + Objects.requireNonNull(binding.tieFdb.getText()); + paramCollection += "\n" + Objects.requireNonNull(configs.itemExtra); + + return paramCollection.contains(path); + } + + final int PICK_DRIVE_FILE_MODE = 0; + final int PICK_OPTICAL_FILE_MODE = 1; + final int PICK_FLOPPY_FILE_MODE = 2; + + private void builtInFilePicker(int mode) { + FilePickerDialog filePickerDialog = new FilePickerDialog(); + + int finalMode; + if (mode == PICK_DRIVE_FILE_MODE) { + finalMode = FilePickerDialog.FIT_PICK_DISK_FILE_MODE; + } else if (mode == PICK_OPTICAL_FILE_MODE) { + finalMode = FilePickerDialog.FIT_PICK_OPTICAL_FILE_MODE; + } else { + finalMode = FilePickerDialog.FIT_PICK_FLOPPY_FILE_MODE; + } + + filePickerDialog.pick(requireActivity(), finalMode, (path -> handleFile(Uri.fromFile(new File(path))))); + } + + private void load() { + if (configs.itemPath != null && !configs.itemPath.isEmpty()) { + setDrive(SELECT_DISK_0_FILE_MODE, (configs.itemPath.contains("/") ? "" : VmFileManager.getPath(vmId)).concat(configs.itemPath)); + } + + if (configs.hd1 != null && !configs.hd1.isEmpty()) { + setDrive(SELECT_DISK_1_FILE_MODE, (configs.hd1.contains("/") ? "" : VmFileManager.getPath(vmId)).concat(configs.hd1)); + } + + if (MainSettingsManager.getArch(getContext()).equals(MainSettingsManager.ARM64_ARCH)) { + binding.lnFloppyContainer.setVisibility(View.GONE); + } else { + if (configs.fda!= null && !configs.fda.isEmpty()) { + setDrive(SELECT_FLOPPY_A_FILE_MODE, (configs.fda.contains("/") ? "" : VmFileManager.getPath(vmId)).concat(configs.fda)); + } + + if (configs.fdb!= null && !configs.fdb.isEmpty()) { + setDrive(SELECT_FLOPPY_B_FILE_MODE, (configs.fdb.contains("/") ? "" : VmFileManager.getPath(vmId)).concat(configs.fdb)); + } + } + + if (configs.imgCdrom != null && !configs.imgCdrom.isEmpty()) { + setDrive(SELECT_CDROM_0_FILE_MODE, (configs.imgCdrom.contains("/") ? "" : VmFileManager.getPath(vmId)).concat(configs.imgCdrom)); + } + + if (configs.cdrom1 != null && !configs.cdrom1.isEmpty()) { + setDrive(SELECT_CDROM_1_FILE_MODE, (configs.cdrom1.contains("/") ? "" : VmFileManager.getPath(vmId)).concat(configs.cdrom1)); + } + + binding.svSharedFolder.setChecked(configs.sharedFolder); + } + + private void save() { + configs.itemPath = Objects.requireNonNull(binding.drive.getText()).toString(); + configs.hd1 = Objects.requireNonNull(binding.tieHd1.getText()).toString(); + + configs.fda = Objects.requireNonNull(binding.tieFda.getText()).toString(); + configs.fdb = Objects.requireNonNull(binding.tieFdb.getText()).toString(); + + configs.imgCdrom = Objects.requireNonNull(binding.cdrom.getText()).toString(); + configs.cdrom1 = Objects.requireNonNull(binding.tieCdrom1.getText()).toString(); + + configs.sharedFolder = binding.svSharedFolder.isChecked(); + } +} diff --git a/app/src/main/java/com/vectras/vm/creator/utils/CreatorUtils.java b/app/src/main/java/com/vectras/vm/creator/utils/CreatorUtils.java new file mode 100644 index 0000000..63fe408 --- /dev/null +++ b/app/src/main/java/com/vectras/vm/creator/utils/CreatorUtils.java @@ -0,0 +1,107 @@ +package com.vectras.vm.creator.utils; + +import android.app.Activity; +import android.net.Uri; + +import com.vectras.vm.manager.VmFileManager; +import com.vectras.vm.utils.FileUtils; +import com.vectras.vm.utils.ProgressDialog; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +public class CreatorUtils { + public static final String PENDING_FOLDER = "pending/"; + + Activity activity; + String vmId; + + ProgressDialog progressDialog; + + public CreatorUtils(Activity activity, String vmId) { + this.activity = activity; + this.vmId = vmId; + } + + public void showProgressDialog(String message) { + if (progressDialog == null) progressDialog = new ProgressDialog(activity); + progressDialog.setText(message); + if (!activity.isFinishing() && !activity.isDestroyed()) progressDialog.show(); + } + + public void dissmissProgressDialog() { + if (progressDialog != null && !activity.isFinishing() && !activity.isDestroyed()) { + progressDialog.dismiss(); + } + } + + public String getTempPath(String fileName) { + return VmFileManager.getTempPath(activity, vmId, PENDING_FOLDER + fileName); + } + + public boolean removeTemp() { + return VmFileManager.removeTemp(activity, vmId, PENDING_FOLDER); + } + + public String copyToTemp(Uri uri) throws IOException { + String fileName = FileUtils.getFileNameFromUri(activity, uri); + + if (fileName == null || fileName.isEmpty()) { + fileName = String.valueOf(System.currentTimeMillis()); + } + + FileUtils.copyFileFromUri(activity, uri, VmFileManager.getTempPath(activity, vmId, PENDING_FOLDER + fileName)); + return VmFileManager.getPath(vmId, fileName); + } + + public void moveAllFromTemp() { + ArrayList fileList = new ArrayList<>(); + FileUtils.getAListOfAllFilesAndFoldersInADirectory(VmFileManager.getTempPath(activity, vmId, PENDING_FOLDER), fileList); + for (int position = 0; position < fileList.size(); position++) { + FileUtils.moveToFolder(fileList.get(position), VmFileManager.getPath(vmId)); + } + + ArrayList fileListInternal = new ArrayList<>(); + FileUtils.getAListOfAllFilesAndFoldersInADirectory(VmFileManager.getInternalTempPath(activity, vmId, PENDING_FOLDER), fileListInternal); + for (int position = 0; position < fileListInternal.size(); position++) { + FileUtils.moveToFolder(fileListInternal.get(position), VmFileManager.getPath(vmId)); + } + } + + public void deleteTemp(String fileName) { + VmFileManager.removeTemp(activity, vmId, PENDING_FOLDER + fileName); + } + + + public void markDelete(String path) { + VmFileManager.markPendingDelete(path); + deleteTemp(new File(path).getName()); + } + + public FilePathData getFilePath(Uri uri) { + try { + String filePath = FileUtils.getPath(activity, uri); + + if (filePath != null && FileUtils.isFileExists(filePath)) { + return new FilePathData() { + { + isValid = true; + path = filePath; + name = new File(filePath).getName(); + } + }; + } + } catch (Exception e) { + return new FilePathData(); + } + + return new FilePathData(); + } + + public static class FilePathData { + public boolean isValid = false; + public String path; + public String name; + } +} diff --git a/app/src/main/java/com/vectras/vm/main/vms/DataMainRoms.java b/app/src/main/java/com/vectras/vm/main/vms/DataMainRoms.java index 810b7e9..f979efd 100644 --- a/app/src/main/java/com/vectras/vm/main/vms/DataMainRoms.java +++ b/app/src/main/java/com/vectras/vm/main/vms/DataMainRoms.java @@ -3,9 +3,15 @@ package com.vectras.vm.main.vms; import com.google.gson.annotations.SerializedName; public class DataMainRoms { - public int cpu = 0; - public int cores = 0; - public int threads = 0; + public String vmID = ""; + + @SerializedName( + value = "arch", + alternate = { "imgArch" } + ) + public String itemArch = ""; + + // Personalize @SerializedName( value = "icon", @@ -19,11 +25,15 @@ public class DataMainRoms { ) public String itemName = ""; - @SerializedName( - value = "arch", - alternate = { "imgArch" } - ) - public String itemArch = ""; + // Board + + public int cpu = 0; + public int cores = 0; + public int threads = 0; + + public boolean battery = false; + + // Storage @SerializedName( value = "drive", @@ -33,11 +43,6 @@ public class DataMainRoms { public String hd1 = ""; - @SerializedName( - value = "qemu", - alternate = { "imgExtra" } - ) - public String itemExtra = ""; @SerializedName( value = "cdrom", @@ -47,15 +52,19 @@ public class DataMainRoms { public String cdrom1 = ""; + public String fda = ""; public String fdb = ""; + public boolean sharedFolder = false; - public String vmID = ""; + // Network - public int qmpPort = 0; + public int networkCard = 0; + + // Firmware public int bootFrom = 0; @@ -67,5 +76,16 @@ public class DataMainRoms { public boolean isUseDefaultBios = true; - public boolean battery = false; + // Advanced + + @SerializedName( + value = "qemu", + alternate = { "imgExtra" } + ) + public String itemExtra = ""; + + // Deprecated + + @Deprecated + public int qmpPort = 0; } diff --git a/app/src/main/java/com/vectras/vm/view/CheckBoxView.java b/app/src/main/java/com/vectras/vm/view/CheckBoxView.java index 45f3b1e..8b2f3cd 100644 --- a/app/src/main/java/com/vectras/vm/view/CheckBoxView.java +++ b/app/src/main/java/com/vectras/vm/view/CheckBoxView.java @@ -49,7 +49,7 @@ public class CheckBoxView extends LinearLayout { typedArray.recycle(); } - findViewById(R.id.root).setOnClickListener(v -> checkBox.setChecked(!checkBox.isChecked())); + setOnClickListener(v -> checkBox.setChecked(!checkBox.isChecked())); checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> { if (listener != null) { diff --git a/app/src/main/java/com/vectras/vm/view/SwitchView.java b/app/src/main/java/com/vectras/vm/view/SwitchView.java index 3af0851..9549b04 100644 --- a/app/src/main/java/com/vectras/vm/view/SwitchView.java +++ b/app/src/main/java/com/vectras/vm/view/SwitchView.java @@ -52,7 +52,7 @@ public class SwitchView extends LinearLayout { typedArray.recycle(); } - findViewById(R.id.root).setOnClickListener(v -> switchWidget.setChecked(!switchWidget.isChecked())); + setOnClickListener(v -> switchWidget.setChecked(!switchWidget.isChecked())); switchWidget.setOnCheckedChangeListener((buttonView, isChecked) -> { if (listener != null) { diff --git a/app/src/main/res/layout/activity_vm_creator.xml b/app/src/main/res/layout/activity_vm_creator.xml index 6c8aa20..ea99c08 100644 --- a/app/src/main/res/layout/activity_vm_creator.xml +++ b/app/src/main/res/layout/activity_vm_creator.xml @@ -58,87 +58,74 @@ android:orientation="vertical" android:padding="8dp"> - + android:layout_marginBottom="2dp" + android:orientation="vertical" + android:padding="16dp" + android:background="@drawable/object_shape_top_high"> - + - + - - - + android:layout_height="match_parent" + android:background="?attr/selectableItemBackground" + android:scaleType="centerCrop" + app:srcCompat="@drawable/ic_computer_180dp_with_padding" /> + + + android:id="@+id/ivAddThubnail" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:background="@drawable/backgroud_round_only_left_25_black_50_style" + android:padding="4dp" + app:srcCompat="@drawable/round_add_24" + app:tint="@android:color/white" /> + + + - + - - - - - - + android:inputType="text" + android:selectAllOnFocus="true" + android:singleLine="true" /> + - - - - - + - + android:layout_marginBottom="2dp" + android:background="@drawable/object_shape_middle_high" + android:padding="16dp"> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + android:text="@string/board" + android:textSize="18sp" /> - - - - - - - - - - + android:text="@string/board_note" + android:textColor="?android:attr/textColorSecondary" + android:textSize="14sp" /> - + - + android:layout_marginBottom="2dp" + android:background="@drawable/object_shape_middle_high" + android:padding="16dp"> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + android:text="@string/storage" + android:textSize="18sp" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:text="@string/storage_note" + android:textColor="?android:attr/textColorSecondary" + android:textSize="14sp" /> - + - + android:layout_marginBottom="2dp" + android:background="@drawable/object_shape_middle_high" + android:padding="16dp"> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + android:text="@string/network" + android:textSize="18sp" /> - - - - - - - - - - - - + android:text="@string/network_note" + android:textColor="?android:attr/textColorSecondary" + android:textSize="14sp" /> - + - + android:layout_marginBottom="2dp" + android:background="@drawable/object_shape_middle_high" + android:padding="16dp"> + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + android:text="@string/firmware" + android:textSize="18sp" /> - - - - + android:text="@string/firmware_note" + android:textColor="?android:attr/textColorSecondary" + android:textSize="14sp" /> - + + + + + + + + + + + + android:gravity="center_vertical"> + + + diff --git a/app/src/main/res/layout/creator_advanced_dialog.xml b/app/src/main/res/layout/creator_advanced_dialog.xml new file mode 100644 index 0000000..41b3ebf --- /dev/null +++ b/app/src/main/res/layout/creator_advanced_dialog.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/creator_board_dialog.xml b/app/src/main/res/layout/creator_board_dialog.xml new file mode 100644 index 0000000..f97b213 --- /dev/null +++ b/app/src/main/res/layout/creator_board_dialog.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/creator_firmware_dialog.xml b/app/src/main/res/layout/creator_firmware_dialog.xml new file mode 100644 index 0000000..a363239 --- /dev/null +++ b/app/src/main/res/layout/creator_firmware_dialog.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/creator_network_dialog.xml b/app/src/main/res/layout/creator_network_dialog.xml new file mode 100644 index 0000000..50699cf --- /dev/null +++ b/app/src/main/res/layout/creator_network_dialog.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/creator_storage_dialog.xml b/app/src/main/res/layout/creator_storage_dialog.xml new file mode 100644 index 0000000..c1fff9f --- /dev/null +++ b/app/src/main/res/layout/creator_storage_dialog.xml @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/rom_options_dialog.xml b/app/src/main/res/layout/rom_options_dialog.xml index cec6370..2a4b7a2 100644 --- a/app/src/main/res/layout/rom_options_dialog.xml +++ b/app/src/main/res/layout/rom_options_dialog.xml @@ -29,8 +29,7 @@ + app:cardBackgroundColor="?attr/colorSurfaceContainerLowest"> + android:gravity="center_vertical"> + android:paddingHorizontal="16dp" + android:gravity="center_vertical"> Đã sap chép đường dẫn thư mục vào bảng tạm. Đường phân cách Thêm các đường phân cách giữa các mục. + Các ổ lưu trữ, thư mục được chia sẻ,… + Giấy phép nguồn mở + Bộ xử lý, nhân, luồng,… + Phần mềm + UEFI, khởi động từ, tuỳ chọn khởi động,… + Các tham số mở rộng,… + Loại thẻ + Thẻ mạng + Trống diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f18d8bf..015590d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -652,6 +652,16 @@ The folder path has been copied to the clipboard. Divider Add dividers between items. + Drives, shared folder,… + Open source licenses + Processor, cores, threads,… + Firmware + UEFI, boot from, boot menu,… + Extra params,… + Network card,… + Card type + Network card + None @@ -881,6 +891,27 @@ G3 G2 (Workstation) G2 (Low-Power) + + + Intel E1000E (82574L) + Intel IGB (82576) + Intel E1000 (82540EM) + Intel E1000 (82545EM) + Intel E1000 (82544GC) + Intel i82801 + Intel i82562 + Intel i82559ER + Intel i82558B + Intel i82557C + Intel i82551 + Intel i82550 + Realtek RTL8139 + AMD PCNET + Novell NE2000 + VMWare (VMXNET3) + VirtIO Net + VirtIO Net (Transitional) + diff --git a/build.gradle b/build.gradle index 768f8e5..d402e07 100644 --- a/build.gradle +++ b/build.gradle @@ -15,6 +15,7 @@ buildscript { // Add other classpaths like Google Services and Firebase Crashlytics if needed here. classpath libs.google.services // assuming you need it for your project classpath libs.firebase.crashlytics.gradle + classpath libs.play.services.oss.licenses.plugin // assuming you need it for project } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fac00a7..6700e3a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,9 +1,7 @@ [versions] activityKtx = "1.13.0" -agp = "9.2.1" annotation = "1.10.0" appcompat = "1.7.1" -comGoogleFirebase = "firebase-crashlytics" commonsCompress = "1.28.0" commonsIo = "2.22.0" constraintlayout = "2.2.1" @@ -11,16 +9,12 @@ coreKtx = "1.19.0" documentfile = "1.1.0" drawerlayout = "1.2.0" espressoCore = "3.7.0" -firebaseBom = "34.15.0" +firebaseBom = "34.16.0" firebaseCrashlyticsGradle = "3.0.7" -firebaseMessaging = "25.1.0" -glide = "5.0.7" -googleFirebase = "firebase-analytics" -googleFirebaseCrashlytics = "3.0.7" -googleGmsGoogleServices = "4.5.0" +firebaseMessaging = "25.1.1" +glide = "5.0.9" googleServices = "4.5.0" gradle = "9.2.1" -gradleToolchainsFoojayResolverConvention = "1.0.0" gson = "2.14.0" guava = "33.6.0-jre" junit = "4.13.2" @@ -33,6 +27,8 @@ retrofit2 = "3.0.0" swiperefreshlayout = "1.2.0" viewpager = "1.1.0" window = "1.5.1" +playServicesOssLicensesPlugin = "0.12.0" +playServicesOssLicenses = "17.0.0" [libraries] androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "activityKtx" } @@ -67,11 +63,5 @@ kotlin-gradle-plugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-p lottie = { group = "com.airbnb.android", name = "lottie", version.ref = "lottie" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit2" } - -[plugins] -android-application = { id = "com.android.application", version.ref = "agp" } -com-google-firebase = { id = "com.google.firebase", version.ref = "comGoogleFirebase" } -google-firebase = { id = "com.google.firebase", version.ref = "googleFirebase" } -google-firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "googleFirebaseCrashlytics" } -google-gms-google-services = { id = "com.google.gms.google-services", version.ref = "googleGmsGoogleServices" } -foojay-resolver = { id = "org.gradle.toolchains.foojay-resolver-convention", version.ref = "gradleToolchainsFoojayResolverConvention" } +play-services-oss-licenses-plugin = { group = "com.google.android.gms", name = "oss-licenses-plugin", version.ref = "playServicesOssLicensesPlugin" } +play-services-oss-licenses = { group = "com.google.android.gms", name = "play-services-oss-licenses", version.ref = "playServicesOssLicenses" } diff --git a/web/data/UpdateConfig.json b/web/data/UpdateConfig.json index a884e99..657461a 100644 --- a/web/data/UpdateConfig.json +++ b/web/data/UpdateConfig.json @@ -5,11 +5,11 @@ "url": "https://github.com/xoureldeen/Vectras-VM-Android/releases", "Message": "

4.3.0

\nBugs fixed.", "cancellable": true, - "versionCodeBeta":"138", - "versionNameBeta":"4.3.4", - "versionNameBetas":"4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,4.0.7,4.0.8,4.0.9,4.1.1,4.1.2,4.1.3,4.1.4,4.1.5,4.1.6,4.1.7,4.1.8,4.1.9,4.2.1,4.2.2,4.2.3,4.2.4,4.2.5,4.2.6,4.2.7,4.2.8,4.2.9,4.3.0,4.3.1,4.3.2,4.3.3,4.3.4", + "versionCodeBeta":"139", + "versionNameBeta":"4.3.5", + "versionNameBetas":"4.0.1,4.0.2,4.0.3,4.0.4,4.0.5,4.0.6,4.0.7,4.0.8,4.0.9,4.1.1,4.1.2,4.1.3,4.1.4,4.1.5,4.1.6,4.1.7,4.1.8,4.1.9,4.2.1,4.2.2,4.2.3,4.2.4,4.2.5,4.2.6,4.2.7,4.2.8,4.2.9,4.3.0,4.3.1,4.3.2,4.3.3,4.3.4,4.3.5", "sizeBeta": "45 MB", "urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases", - "MessageBeta": "

4.3.4

Bugs fixed.", + "MessageBeta": "

4.3.5

Bugs fixed.", "cancellableBeta": true }