Files
fheroes2/android/app/src/main/java/org/fheroes2/ToolsetActivity.java
T

268 lines
12 KiB
Java

/***************************************************************************
* fheroes2: https://github.com/ihhub/fheroes2 *
* Copyright (C) 2023 - 2025 *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
package org.fheroes2;
import java.io.File;
import java.io.InputStream;
import java.util.Objects;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
public final class ToolsetActivity extends AppCompatActivity
{
public static final class ToolsetActivityViewModel extends ViewModel
{
private enum BackgroundTaskResult
{
RESULT_NONE,
RESULT_SUCCESS,
RESULT_NO_ASSETS,
RESULT_ERROR
}
private static final class Status
{
private boolean isHoMM2AssetsPresent;
private boolean isBackgroundTaskExecuting;
private final BackgroundTaskResult backgroundTaskResult;
private final String backgroundTaskError;
private Status( final boolean isHoMM2AssetsPresent, final boolean isBackgroundTaskExecuting, final BackgroundTaskResult backgroundTaskResult,
final String backgroundTaskError )
{
this.isHoMM2AssetsPresent = isHoMM2AssetsPresent;
this.isBackgroundTaskExecuting = isBackgroundTaskExecuting;
this.backgroundTaskResult = backgroundTaskResult;
this.backgroundTaskError = backgroundTaskError;
}
private Status setIsHoMM2AssetsPresent( final boolean isHoMM2AssetsPresent )
{
this.isHoMM2AssetsPresent = isHoMM2AssetsPresent;
return this;
}
@SuppressWarnings( "SameParameterValue" )
private Status setIsBackgroundTaskExecuting( final boolean isBackgroundTaskExecuting )
{
this.isBackgroundTaskExecuting = isBackgroundTaskExecuting;
return this;
}
}
private final MutableLiveData<Status> liveStatus = new MutableLiveData<>( new Status( false, false, BackgroundTaskResult.RESULT_NONE, "" ) );
private void validateAssets( final File externalFilesDir )
{
final Status status = Objects.requireNonNull( liveStatus.getValue() );
liveStatus.setValue( status.setIsHoMM2AssetsPresent( HoMM2AssetManagement.isHoMM2AssetsPresent( externalFilesDir ) ) );
}
private void extractAssets( final File externalFilesDir, final File cacheDir, final Uri zipFileUri, final ContentResolver contentResolver )
{
final Status status = Objects.requireNonNull( liveStatus.getValue() );
if ( status.isBackgroundTaskExecuting ) {
return;
}
liveStatus.setValue( status.setIsBackgroundTaskExecuting( true ) );
new Thread( () -> {
try ( final InputStream in = contentResolver.openInputStream( zipFileUri ) ) {
if ( HoMM2AssetManagement.extractHoMM2AssetsFromZip( externalFilesDir, cacheDir, in ) ) {
liveStatus.postValue(
new Status( HoMM2AssetManagement.isHoMM2AssetsPresent( externalFilesDir ), false, BackgroundTaskResult.RESULT_SUCCESS, "" ) );
}
else {
liveStatus.postValue(
new Status( HoMM2AssetManagement.isHoMM2AssetsPresent( externalFilesDir ), false, BackgroundTaskResult.RESULT_NO_ASSETS, "" ) );
}
}
catch ( final Exception ex ) {
Log.e( "fheroes2", "Failed to extract the assets.", ex );
liveStatus.postValue( new Status( HoMM2AssetManagement.isHoMM2AssetsPresent( externalFilesDir ), false, BackgroundTaskResult.RESULT_ERROR,
String.format( "%s", ex ) ) );
}
} ).start();
}
}
private ToolsetActivityViewModel viewModel = null;
private final ActivityResultLauncher<String> zipFileChooserLauncher = registerForActivityResult( new ActivityResultContracts.GetContent(), result -> {
// No ZIP file was selected
if ( result == null ) {
return;
}
viewModel.extractAssets( getExternalFilesDir( null ), getCacheDir(), result, getContentResolver() );
} );
@Override
protected void onCreate( final Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
setContentView( R.layout.activity_toolset );
ViewCompat.setOnApplyWindowInsetsListener( findViewById( R.id.activity_toolset_root_sv ), ( v, insets ) -> {
final Insets paddingInsets = insets.getInsets( WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout() );
v.setPadding( paddingInsets.left, paddingInsets.top, paddingInsets.right, paddingInsets.bottom );
return WindowInsetsCompat.CONSUMED;
} );
viewModel = new ViewModelProvider( this ).get( ToolsetActivityViewModel.class );
viewModel.liveStatus.observe( this, this::updateUI );
}
@Override
protected void onResume()
{
super.onResume();
viewModel.validateAssets( getExternalFilesDir( null ) );
}
@SuppressWarnings( "java:S1172" ) // SonarQube warning "Remove unused method parameter"
public void startGameButtonClicked( final View view )
{
startActivity( new Intent( this, GameActivity.class ) );
// Replace this activity with the newly launched activity
finish();
}
@SuppressWarnings( "java:S1172" ) // SonarQube warning "Remove unused method parameter"
public void extractHoMM2AssetsButtonClicked( final View view )
{
try {
zipFileChooserLauncher.launch( "application/zip" );
}
catch ( final Exception ex ) {
Log.e( "fheroes2", "Failed to extract HoMM2 assets.", ex );
( new AlertDialog.Builder( this ) )
.setTitle( R.string.activity_toolset_extract_homm2_assets_error_title )
.setMessage( R.string.activity_toolset_extract_homm2_assets_error_message )
.setPositiveButton( R.string.activity_toolset_extract_homm2_assets_error_positive_btn_text, ( dialog, which ) -> {} )
.create()
.show();
}
}
@SuppressWarnings( "java:S1172" ) // SonarQube warning "Remove unused method parameter"
public void downloadHoMM2DemoButtonClicked( final View view )
{
try {
startActivity( new Intent( Intent.ACTION_VIEW, Uri.parse( getString( R.string.activity_toolset_homm2_demo_url ) ) ) );
}
catch ( final Exception ex ) {
Log.e( "fheroes2", "Failed to download the HoMM2 demo archive.", ex );
( new AlertDialog.Builder( this ) )
.setTitle( R.string.activity_toolset_download_homm2_demo_error_title )
.setMessage( R.string.activity_toolset_download_homm2_demo_error_message )
.setPositiveButton( R.string.activity_toolset_download_homm2_demo_error_positive_btn_text, ( dialog, which ) -> {} )
.create()
.show();
}
}
@SuppressWarnings( "java:S1172" ) // SonarQube warning "Remove unused method parameter"
public void saveFileManagerButtonClicked( final View view )
{
startActivity( new Intent( this, SaveFileManagerActivity.class ) );
}
@SuppressWarnings( "java:S1172" ) // SonarQube warning "Remove unused method parameter"
public void mapFileManagerButtonClicked( final View view )
{
startActivity( new Intent( this, MapFileManagerActivity.class ) );
}
private void updateUI( final ToolsetActivityViewModel.Status modelStatus )
{
final Button startGameButton = findViewById( R.id.activity_toolset_start_game_btn );
final Button extractHoMM2AssetsButton = findViewById( R.id.activity_toolset_extract_homm2_assets_btn );
final Button downloadHoMM2DemoButton = findViewById( R.id.activity_toolset_download_homm2_demo_btn );
final Button saveFileManagerButton = findViewById( R.id.activity_toolset_save_file_manager_btn );
final Button mapFileManagerButton = findViewById( R.id.activity_toolset_map_file_manager_btn );
final TextView gameStatusTextView = findViewById( R.id.activity_toolset_game_status_lbl );
final TextView lastTaskStatusTextView = findViewById( R.id.activity_toolset_last_task_status_lbl );
final ProgressBar backgroundTaskProgressBar = findViewById( R.id.activity_toolset_background_task_pb );
startGameButton.setEnabled( !modelStatus.isBackgroundTaskExecuting && modelStatus.isHoMM2AssetsPresent );
extractHoMM2AssetsButton.setEnabled( !modelStatus.isBackgroundTaskExecuting );
downloadHoMM2DemoButton.setEnabled( !modelStatus.isBackgroundTaskExecuting );
saveFileManagerButton.setEnabled( !modelStatus.isBackgroundTaskExecuting );
mapFileManagerButton.setEnabled( !modelStatus.isBackgroundTaskExecuting );
switch ( modelStatus.backgroundTaskResult ) {
case RESULT_NONE:
break;
case RESULT_SUCCESS:
lastTaskStatusTextView.setText( getString( R.string.activity_toolset_last_task_status_lbl_text_completed_successfully ) );
break;
case RESULT_NO_ASSETS:
lastTaskStatusTextView.setText( getString( R.string.activity_toolset_last_task_status_lbl_text_no_assets_found ) );
break;
case RESULT_ERROR:
lastTaskStatusTextView.setText( String.format( getString( R.string.activity_toolset_last_task_status_lbl_text_failed ), modelStatus.backgroundTaskError ) );
break;
default:
assert false;
break;
}
gameStatusTextView.setVisibility( modelStatus.isHoMM2AssetsPresent ? View.GONE : View.VISIBLE );
backgroundTaskProgressBar.setVisibility( !modelStatus.isBackgroundTaskExecuting ? View.GONE : View.VISIBLE );
lastTaskStatusTextView.setVisibility( modelStatus.isBackgroundTaskExecuting ? View.GONE : View.VISIBLE );
}
}