- Improved VNC display.
- Fixed crash issue when selecting files.
- Bugs fixed.
This commit is contained in:
An Bui 2026-04-26 14:24:15 +07:00
parent 13bf9e8718
commit 4f1f6bd802
13 changed files with 283 additions and 115 deletions

View file

@ -12,8 +12,8 @@ android {
applicationId "com.vectras.vm"
minSdk minApi
targetSdk targetApi
versionCode 105
versionName "4.0.1"
versionCode 106
versionName "4.0.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true

View file

@ -156,7 +156,7 @@
android:name="com.vectras.qemu.MainVNCActivity"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize"
android:launchMode="singleTask"
android:screenOrientation="landscape"
android:screenOrientation="sensorLandscape"
android:theme="@style/Theme.FullScreen"
android:windowSoftInputMode="adjustPan" />
<activity
@ -187,6 +187,11 @@
android:resizeableActivity="true"
android:windowSoftInputMode="adjustResize|stateAlwaysVisible" />
<activity
android:name="com.termux.app.TermuxHelpActivity"
android:configChanges="orientation|screenSize|keyboardHidden|smallestScreenSize|screenLayout"
android:exported="false" />
<service
android:name="com.termux.app.TermuxService"
android:exported="false" />

View file

@ -303,22 +303,8 @@ public class VncCanvas extends AppCompatImageView {
Log.i(TAG, "Desktop name is " + rfb.desktopName);
Log.i(TAG, "Desktop size is " + rfb.framebufferWidth + " x " + rfb.framebufferHeight);
boolean useFull = false;
int capacity = BCFactory.getInstance().getBCActivityManager()
.getMemoryClass(Utils.getActivityManager(getContext()));
if (connection.getForceFull() == BitmapImplHint.AUTO) {
if (rfb.framebufferWidth * rfb.framebufferHeight * FullBufferBitmapData.CAPACITY_MULTIPLIER <= capacity
* 1024 * 1024) {
useFull = true;
}
} else {
useFull = (connection.getForceFull() == BitmapImplHint.FULL);
}
if (!useFull) {
bitmapData = new LargeBitmapData(rfb, this, dx, dy, capacity);
} else {
bitmapData = new FullBufferBitmapData(rfb, this, capacity);
}
initBitmapData(dx, dy);
mouseX = rfb.framebufferWidth / 2;
mouseY = rfb.framebufferHeight / 2;
@ -333,6 +319,29 @@ public class VncCanvas extends AppCompatImageView {
pendingColorModel = null;
}
void initBitmapData(int dx, int dy) {
int capacity = BCFactory.getInstance().getBCActivityManager()
.getMemoryClass(Utils.getActivityManager(getContext()));
boolean useFull = false;
if (connection.getForceFull() == BitmapImplHint.AUTO) {
if (rfb.framebufferWidth * rfb.framebufferHeight * FullBufferBitmapData.CAPACITY_MULTIPLIER
<= capacity * 1024 * 1024) {
useFull = true;
}
} else {
useFull = (connection.getForceFull() == BitmapImplHint.FULL);
}
if (bitmapData != null) bitmapData.dispose();
if (!useFull) {
bitmapData = new LargeBitmapData(rfb, this, dx, dy, capacity);
} else {
bitmapData = new FullBufferBitmapData(rfb, this, capacity);
}
}
public void setColorModel(COLORMODEL cm) {
// Only update if color model changes
if (colorModel == null || !colorModel.equals(cm)) {
@ -395,6 +404,11 @@ public class VncCanvas extends AppCompatImageView {
rfb.setFramebufferSize(rw, rh);
// - updateFramebufferSize();
Log.v(TAG, "rfb.EncodingNewFBSize");
Point size = new Point();
VncCanvasActivity.display.getSize(size);
initBitmapData(size.x, size.y);
reload();
break;
}

View file

@ -1821,6 +1821,12 @@ public abstract class VncCanvasActivity extends AppCompatActivity {
// Remove old canvas
ViewGroup parent = findViewById(R.id.vnc_canvas_layout);
if (vncCanvas != null) {
vncCanvas.closeConnection();
vncCanvas.onDestroy();
}
parent.removeView(vncCanvas);
// Create new canvas

View file

@ -1046,7 +1046,7 @@ public class MainSettingsManager extends AppCompatActivity
public static Boolean getForceRefeshVNCDisplay(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean("forceRefeshVNCDisplay", true);
return prefs.getBoolean("forceRefeshVNCDisplay", false);
}
public static void setQuickStart(Context context, Boolean _boolean) {

View file

@ -114,6 +114,8 @@ public class MainVNCActivity extends VncCanvasActivity {
super.onCreate(b);
getContext = this;
UIUtils.edgeToEdge(this);
UIUtils.setOnApplyWindowInsetsListener(binding.vncMainLayout);
initializeControlFragment();
initializeDesktopControl();
initializeGameControl();
@ -175,6 +177,8 @@ public class MainVNCActivity extends VncCanvasActivity {
streamAudio = new StreamAudio(this);
streamAudio.setFile(VmFileManager.findAudioRaw(this, Config.vmID));
if (!isConnected) tryReconnect();
}
private void setDefaulViewMode() {
@ -187,7 +191,7 @@ public class MainVNCActivity extends VncCanvasActivity {
// screenMode = VNCScreenMode.FitToScreen;
setLayout(getResources().getConfiguration());
UIUtils.setOrientation(this);
//UIUtils.setOrientation(this);
}
@Override
@ -766,12 +770,14 @@ public class MainVNCActivity extends VncCanvasActivity {
setUIModeMobile(screenMode == VNCScreenMode.FitToScreen);
binding.lnNosignal.setVisibility(View.GONE);
binding.lnConnecting.setVisibility(View.GONE);
this.vncCanvas.setFocusableInTouchMode(true);
// syncCursorViewWithBitmap();
if (VmAudioManager.currentVmId.equals(Config.vmID) && VmAudioManager.streamAudio.isPlaying())
streamAudio.setCross(VmAudioManager.streamAudio);
if (!streamAudio.isPlaying()) streamAudio.play();
});
}
@ -847,14 +853,16 @@ public class MainVNCActivity extends VncCanvasActivity {
binding.lnNosignal.setVisibility(View.VISIBLE);
binding.lnConnecting.setVisibility(View.GONE);
} else {
isTrying = false;
if (Config.forceRefeshVNCDisplay) {
runOnUiThread(() -> {
startActivity(new Intent(MainVNCActivity.this, MainVNCActivity.class));
overridePendingTransition(0, 0);
finish();
});
} else {
isTrying = false;
binding.lnNosignal.setVisibility(View.GONE);
binding.lnConnecting.setVisibility(View.GONE);
}
}
}

View file

@ -25,6 +25,7 @@ import com.vectras.vm.databinding.ActivityRomInfoBinding;
import com.vectras.vm.utils.DialogUtils;
import com.vectras.vm.utils.FileUtils;
import com.vectras.vm.utils.ImageUtils;
import com.vectras.vm.utils.IntentUtils;
import com.vectras.vm.utils.PackageUtils;
import java.io.File;
@ -165,7 +166,13 @@ public class RomInfo extends AppCompatActivity {
});
if (getIntent().hasExtra("isRomInfo") && getIntent().getBooleanExtra("isRomInfo", false)) {
binding.btnPick.setOnClickListener(v -> romPicker.launch("*/*"));
binding.btnPick.setOnClickListener(v -> {
try {
romPicker.launch("*/*");
} catch (Exception e) {
IntentUtils.showErrorDialog(this);
}
});
} else {
binding.btnPick.setVisibility(View.GONE);
}
@ -326,7 +333,8 @@ public class RomInfo extends AppCompatActivity {
String likeContent = getString(R.string.like);
boolean isLiked = interaction.isLiked();
likeContent = (likes == 0) ? getString(R.string.like) : interaction.getFormatedLikeCount();
if (isLiked) binding.btnLike.setIcon(ContextCompat.getDrawable(RomInfo.this, R.drawable.thumb_up_filled_24px));
if (isLiked)
binding.btnLike.setIcon(ContextCompat.getDrawable(RomInfo.this, R.drawable.thumb_up_filled_24px));
binding.btnLike.setText(likeContent);
binding.lnAllViews.setVisibility(View.VISIBLE);

View file

@ -44,6 +44,7 @@ import com.vectras.vm.utils.ImageUtils;
import com.vectras.vm.utils.IntentUtils;
import com.vectras.vm.utils.JSONUtils;
import com.vectras.vm.utils.PackageUtils;
import com.vectras.vm.utils.ProgressDialog;
import com.vectras.vm.utils.UIUtils;
import org.json.JSONException;
@ -87,7 +88,11 @@ public class VMCreatorActivity extends AppCompatActivity {
finish();
return true;
} else if (id == R.id.add_file) {
try {
filePicker.launch("*/*");
} catch (Exception e) {
IntentUtils.showErrorDialog(this);
}
return true;
} else if (id == R.id.show_in_folder) {
FileUtils.openFolder(this, VmFileManager.getPath(vmID));
@ -126,8 +131,20 @@ public class VMCreatorActivity extends AppCompatActivity {
binding.btnCreate.setOnClickListener(v -> startCreateVM());
binding.drive.setOnClickListener(v -> diskPicker.launch("*/*"));
binding.driveField.setOnClickListener(v -> diskPicker.launch("*/*"));
binding.drive.setOnClickListener(v -> {
try {
diskPicker.launch("*/*");
} catch (Exception e) {
IntentUtils.showErrorDialog(this);
}
});
binding.driveField.setOnClickListener(v -> {
try {
diskPicker.launch("*/*");
} catch (Exception e) {
IntentUtils.showErrorDialog(this);
}
});
binding.driveField.setEndIconOnClickListener(v -> {
if (Objects.requireNonNull(binding.drive.getText()).toString().isEmpty()) {
@ -147,10 +164,21 @@ public class VMCreatorActivity extends AppCompatActivity {
true,
R.drawable.hard_drive_24px,
true,
() -> diskPicker.launch("*/*"),
() -> {
try {
diskPicker.launch("*/*");
} catch (Exception e) {
IntentUtils.showErrorDialog(this);
}
},
() -> {
if (binding.drive.getText().toString().contains(VmFileManager.quickGetPath(vmID))) {
FileUtils.delete(new File(Objects.requireNonNull(binding.drive.getText()).toString()));
ProgressDialog progressDialog1 = new ProgressDialog(this);
progressDialog1.show();
new Thread(() -> {
FileUtils.delete(new File(Objects.requireNonNull(binding.drive.getText()).toString()));
runOnUiThread(progressDialog1::reset);
}).start();
}
binding.drive.setText("");
binding.driveField.setEndIconDrawable(R.drawable.add_24px);
@ -168,7 +196,13 @@ public class VMCreatorActivity extends AppCompatActivity {
}
});
View.OnClickListener cdromClickListener = v -> isoPicker.launch("*/*");
View.OnClickListener cdromClickListener = v -> {
try {
isoPicker.launch("*/*");
} catch (Exception e) {
IntentUtils.showErrorDialog(this);
}
};
binding.cdrom.setOnClickListener(cdromClickListener);
binding.cdromField.setOnClickListener(cdromClickListener);
@ -310,7 +344,11 @@ public class VMCreatorActivity extends AppCompatActivity {
} else if (getIntent().hasExtra("importcvbinow")) {
setDefault();
cvbiPicker.launch("*/*");
try {
cvbiPicker.launch("*/*");
} catch (Exception e) {
IntentUtils.showErrorDialog(this);
}
} else {
setDefault();
if (MainSettingsManager.autoCreateDisk(this)) {
@ -777,10 +815,14 @@ public class VMCreatorActivity extends AppCompatActivity {
}
private void selectedDiskFile(Uri _content_describer, boolean _addtodrive) {
ProgressDialog progressDialog1 = new ProgressDialog(this);
progressDialog1.show();
new Thread(() -> {
if (FileUtils.isValidFilePath(this, FileUtils.getPath(this, _content_describer), false)) {
File selectedFilePath = new File(getPath(_content_describer));
runOnUiThread(() -> {
progressDialog1.reset();
if (VMManager.isADiskFile(selectedFilePath.getPath())) {
startProcessingHardDriveFile(_content_describer, _addtodrive);
} else {
@ -849,9 +891,17 @@ public class VMCreatorActivity extends AppCompatActivity {
null);
return;
}
File selectedFilePath = new File(getPath(_content_describer));
binding.drive.setText(selectedFilePath.getPath());
binding.driveField.setEndIconDrawable(R.drawable.more_vert_24px);
ProgressDialog progressDialog1 = new ProgressDialog(this);
progressDialog1.show();
new Thread(() -> {
File selectedFilePath = new File(getPath(_content_describer));
runOnUiThread(() -> {
progressDialog1.reset();
binding.drive.setText(selectedFilePath.getPath());
binding.driveField.setEndIconDrawable(R.drawable.more_vert_24px);
});
}).start();
}
}
@ -1030,7 +1080,7 @@ public class VMCreatorActivity extends AppCompatActivity {
if (jObj.has("vmID")) {
if (!jObj.isNull("vmID")) {
if (!jObj.getString("vmID").isEmpty()) {
FileUtils.move(VmFileManager.getConfigFile(vmID), VmFileManager.getConfigFile( jObj.getString("vmID")));
FileUtils.move(VmFileManager.getConfigFile(vmID), VmFileManager.getConfigFile(jObj.getString("vmID")));
vmID = jObj.getString("vmID");
}
}

View file

@ -18,6 +18,7 @@ import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.vectras.qemu.Config;
import com.vectras.qemu.MainSettingsManager;
@ -388,12 +389,16 @@ public class MainStartVM {
.load(new File(thumbnailFile))
.placeholder(R.drawable.ic_computer_180dp_with_padding)
.error(R.drawable.ic_computer_180dp_with_padding)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(ivThumbnail);
} else if (VmFileManager.isScreenshotPngExists(vmID)) {
Glide.with(context.getApplicationContext())
.load(new File(VmFileManager.getScreenshotPng(vmID)))
.placeholder(R.drawable.ic_computer_180dp_with_padding)
.error(R.drawable.ic_computer_180dp_with_padding)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(ivThumbnail);
} else {
VMManager.setIconWithName(ivThumbnail, _content);

View file

@ -22,6 +22,7 @@ import com.vectras.qemu.VNCConfig;
import com.vectras.vm.AppConfig;
import com.vectras.vm.R;
import com.vectras.vm.VMManager;
import com.vectras.vm.VectrasApp;
import com.vectras.vm.creator.VMCreatorActivity;
import com.vectras.vm.databinding.DialogChangeRemovableDevicesBinding;
import com.vectras.vm.main.core.DisplaySystem;
@ -108,6 +109,7 @@ public class VmControllerDialog extends DialogFragment {
});
if (isAdded() && (!(requireActivity() instanceof MainVNCActivity))) {
if (streamAudio == null) streamAudio = new StreamAudio(requireActivity().getApplicationContext());
if (!streamAudio.isPlaying()) VmAudioManager.set(Config.vmID);
}
@ -143,7 +145,8 @@ public class VmControllerDialog extends DialogFragment {
dismiss();
});
if (!isHavingSecondaryOpticalDisc()) binding.tvCdrom.setText(R.string.cdrom);
if (!isHavingSecondaryOpticalDisc())
binding.tvCdrom.setText(R.string.cdrom);
} else {
binding.lnCdrom.setVisibility(View.GONE);
}
@ -156,7 +159,8 @@ public class VmControllerDialog extends DialogFragment {
dismiss();
});
if (!isHavingOpticalDisc()) binding.tvSecondaryCdrom.setText(R.string.cdrom);
if (!isHavingOpticalDisc())
binding.tvSecondaryCdrom.setText(R.string.cdrom);
} else {
binding.lnSecondaryCdrom.setVisibility(View.GONE);
}
@ -351,13 +355,20 @@ public class VmControllerDialog extends DialogFragment {
registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> {
if (uri != null) {
try {
File selectedFilePath = new File(Objects.requireNonNull(FileUtils.getPath(requireActivity(), uri)));
QmpSender.changeOpticalDisc(requireActivity(), selectedFilePath.getAbsolutePath(), infoBlock);
new Thread(() -> {
File selectedFilePath = new File(Objects.requireNonNull(FileUtils.getPath(getContext(), uri)));
if (isAdded()) {
requireActivity().runOnUiThread(() -> {
QmpSender.changeOpticalDisc(requireActivity(), selectedFilePath.getAbsolutePath(), infoBlock);
dismiss();
});
}
}).start();
} catch (Exception e) {
showErrorSelectedFileDialog();
dismiss();
}
dismiss();
}
});
@ -365,13 +376,20 @@ public class VmControllerDialog extends DialogFragment {
registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> {
if (uri != null) {
try {
File selectedFilePath = new File(Objects.requireNonNull(FileUtils.getPath(requireActivity(), uri)));
QmpSender.changeSecondaryOpticalDisc(requireActivity(), selectedFilePath.getAbsolutePath(), infoBlock);
new Thread(() -> {
File selectedFilePath = new File(Objects.requireNonNull(FileUtils.getPath(getContext(), uri)));
if (isAdded()) {
requireActivity().runOnUiThread(() -> {
QmpSender.changeSecondaryOpticalDisc(requireActivity(), selectedFilePath.getAbsolutePath(), infoBlock);
dismiss();
});
}
}).start();
} catch (Exception e) {
showErrorSelectedFileDialog();
dismiss();
}
dismiss();
}
});
@ -379,13 +397,20 @@ public class VmControllerDialog extends DialogFragment {
registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> {
if (uri != null) {
try {
File selectedFilePath = new File(Objects.requireNonNull(FileUtils.getPath(requireActivity(), uri)));
QmpSender.changeFloppyDiskA(requireActivity(), selectedFilePath.getAbsolutePath());
new Thread(() -> {
File selectedFilePath = new File(Objects.requireNonNull(FileUtils.getPath(getContext(), uri)));
if (isAdded()) {
requireActivity().runOnUiThread(() -> {
QmpSender.changeFloppyDiskA(requireActivity(), selectedFilePath.getAbsolutePath());
dismiss();
});
}
}).start();
} catch (Exception e) {
showErrorSelectedFileDialog();
dismiss();
}
dismiss();
}
});
@ -393,13 +418,20 @@ public class VmControllerDialog extends DialogFragment {
registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> {
if (uri != null) {
try {
File selectedFilePath = new File(Objects.requireNonNull(FileUtils.getPath(requireActivity(), uri)));
QmpSender.changeFloppyDiskB(requireActivity(), selectedFilePath.getAbsolutePath());
new Thread(() -> {
File selectedFilePath = new File(Objects.requireNonNull(FileUtils.getPath(getContext(), uri)));
if (isAdded()) {
requireActivity().runOnUiThread(() -> {
QmpSender.changeFloppyDiskB(requireActivity(), selectedFilePath.getAbsolutePath());
dismiss();
});
}
}).start();
} catch (Exception e) {
showErrorSelectedFileDialog();
dismiss();
}
dismiss();
}
});
@ -407,13 +439,20 @@ public class VmControllerDialog extends DialogFragment {
registerForActivityResult(new ActivityResultContracts.GetContent(), uri -> {
if (uri != null) {
try {
File selectedFilePath = new File(Objects.requireNonNull(FileUtils.getPath(requireActivity(), uri)));
QmpSender.changeMemoryCard(requireActivity(), selectedFilePath.getAbsolutePath());
new Thread(() -> {
File selectedFilePath = new File(Objects.requireNonNull(FileUtils.getPath(getContext(), uri)));
if (isAdded()) {
requireActivity().runOnUiThread(() -> {
QmpSender.changeMemoryCard(requireActivity(), selectedFilePath.getAbsolutePath());
dismiss();
});
}
}).start();
} catch (Exception e) {
showErrorSelectedFileDialog();
dismiss();
}
dismiss();
}
});

View file

@ -30,70 +30,103 @@
android:keepScreenOn="true" />
</RelativeLayout>
<!-- <LinearLayout-->
<!-- android:id="@+id/cursorViewContianer"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- android:gravity="center">-->
<!-- <android.androidVNC.VncCursorView-->
<!-- android:id="@+id/cursorView"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"/>-->
<!-- </LinearLayout>-->
<RelativeLayout
android:id="@+id/vnc_main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/controlsfragment"
layout="@layout/controls_fragment" />
<include
android:id="@+id/controlsfragment"
layout="@layout/controls_fragment" />
<include
android:id="@+id/sendkeysdialog"
layout="@layout/send_key_dialog" />
<include
android:id="@+id/sendkeysdialog"
layout="@layout/send_key_dialog" />
</RelativeLayout>
<!-- <LinearLayout-->
<!-- android:id="@+id/cursorViewContianer"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->
<!-- android:gravity="center">-->
<!-- <android.androidVNC.VncCursorView-->
<!-- android:id="@+id/cursorView"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"/>-->
<!-- </LinearLayout>-->
<LinearLayout
android:id="@+id/ln_nosignal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E6000000"
android:gravity="center"
android:animateLayoutChanges="true"
android:orientation="vertical">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/cast_warning_24px"
app:tint="@android:color/white" />
<FrameLayout
android:id="@+id/ln_nosignal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/no_signal"
android:textColor="@android:color/white"
android:textSize="20sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.8"
android:background="?attr/colorSurfaceContainer" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tap_to_try_again"
android:textColor="@android:color/white" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/cast_warning_24px"
app:tint="?attr/colorOnSurface" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/no_signal"
android:textColor="?attr/colorOnSurface"
android:textSize="20sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tap_to_try_again"
android:textColor="?attr/colorOnSurface" />
</LinearLayout>
</FrameLayout>
<FrameLayout
android:id="@+id/ln_connecting"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0.8"
android:background="?attr/colorSurfaceContainer" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</LinearLayout>
</FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/ln_connecting"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E6000000"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<com.google.android.material.progressindicator.CircularProgressIndicator
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout

View file

@ -5,7 +5,7 @@ annotation = "1.10.0"
appcompat = "1.7.1"
comGoogleFirebase = "firebase-crashlytics"
commonsCompress = "1.28.0"
commonsIo = "2.21.0"
commonsIo = "2.22.0"
constraintlayout = "2.2.1"
coreKtx = "1.18.0"
documentfile = "1.1.0"

View file

@ -5,11 +5,11 @@
"url": "https://github.com/xoureldeen/Vectras-VM-Android/releases",
"Message": "<h2>4.0.0</h2>\nBugs fixed.",
"cancellable": true,
"versionCodeBeta":"105",
"versionNameBeta":"4.0.1",
"versionNameBetas":"3.0.0,3.1.0,3.2.1,3.2.2,3.2.3,3.2.4,3.2.5,3.2.6,3.2.7,3.2.8,3.2.9,3.2.10,3.3.1,3.3.2,3.3.3,3.3.4,3.3.5,3.3.6,3.3.7,3.3.8,3.3.9,3.4.1,3.4.2,3.4.3,3.4.4,3.4.5,3.4.6,3.4.7,3.4.8,3.4.9,3.5.1,3.5.2,3.5.3,3.5.4,3.5.5,3.5.6,3.5.7,3.5.8,3.5.9,3.6.1,3.6.2,3.6.3,3.6.4,3.6.5,3.6.6,3.6.7,3.6.8,3.6.9,3.7.1,3.7.2,3.7.3,3.7.4,3.7.5,3.7.6,3.7.7,3.7.8,3.7.9,3.8.0,3.8.1,3.8.2,3.8.3,3.8.4,3.8.5,3.8.6,3.8.7,3.8.8,3.8.9,3.9.0,3.9.1,3.9.2,3.9.3,3.9.4,3.9.5,3.9.6,3.9.7,3.9.8,3.9.9,4.0.0,4.0.1",
"versionCodeBeta":"106",
"versionNameBeta":"4.0.2",
"versionNameBetas":"3.0.0,3.1.0,3.2.1,3.2.2,3.2.3,3.2.4,3.2.5,3.2.6,3.2.7,3.2.8,3.2.9,3.2.10,3.3.1,3.3.2,3.3.3,3.3.4,3.3.5,3.3.6,3.3.7,3.3.8,3.3.9,3.4.1,3.4.2,3.4.3,3.4.4,3.4.5,3.4.6,3.4.7,3.4.8,3.4.9,3.5.1,3.5.2,3.5.3,3.5.4,3.5.5,3.5.6,3.5.7,3.5.8,3.5.9,3.6.1,3.6.2,3.6.3,3.6.4,3.6.5,3.6.6,3.6.7,3.6.8,3.6.9,3.7.1,3.7.2,3.7.3,3.7.4,3.7.5,3.7.6,3.7.7,3.7.8,3.7.9,3.8.0,3.8.1,3.8.2,3.8.3,3.8.4,3.8.5,3.8.6,3.8.7,3.8.8,3.8.9,3.9.0,3.9.1,3.9.2,3.9.3,3.9.4,3.9.5,3.9.6,3.9.7,3.9.8,3.9.9,4.0.0,4.0.1,4.0.2",
"sizeBeta": "45 MB",
"urlBeta": "https://github.com/AnBui2004/Vectras-VM-Emu-Android/releases",
"MessageBeta": "<h2>4.0.1</h2>Bugs fixed.",
"MessageBeta": "<h2>4.0.2</h2>Bugs fixed.",
"cancellableBeta": true
}