mirror of
https://github.com/izzy2lost/WeeU.git
synced 2026-07-06 00:19:59 -07:00
Refactored code
This commit is contained in:
@@ -32,6 +32,7 @@ jobs:
|
||||
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
|
||||
if: "${{ env.ANDROID_STORE_FILE_BASE64 != '' }}"
|
||||
run: |
|
||||
echo "BUILD_TYPE=Release" >> "$GITHUB_ENV"
|
||||
cd ./src/android
|
||||
base64 --decode <<< "${ANDROID_STORE_FILE_BASE64}" > store.jks
|
||||
ANDROID_STORE_FILE=$(pwd)/store.jks
|
||||
@@ -39,13 +40,16 @@ jobs:
|
||||
|
||||
- name: Build Cemu for Android
|
||||
run: |
|
||||
if [[ -z "$BUILD_TYPE" ]]; then
|
||||
BUILD_TYPE=Debug
|
||||
fi
|
||||
cd ./src/android
|
||||
./gradlew assembleRelease
|
||||
./gradlew assemble$BUILD_TYPE
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cemu-android
|
||||
path: |
|
||||
./src/android/app/build/outputs/apk/release/*.apk
|
||||
./src/android/app/build/outputs/apk/release/*.aab
|
||||
./src/android/app/build/outputs/apk/*/*.apk
|
||||
./src/android/app/build/outputs/apk/*/*.aab
|
||||
|
||||
@@ -19,6 +19,7 @@ android {
|
||||
versionName "1.0"
|
||||
ndk {
|
||||
// abiFilters("x86_64", "arm64-v8a")
|
||||
//noinspection ChromeOsAbiSupport
|
||||
abiFilters("arm64-v8a")
|
||||
}
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
@@ -41,6 +42,7 @@ android {
|
||||
if (releaseStoreFile != null) {
|
||||
signingConfig signingConfigs.release
|
||||
} else {
|
||||
resValue("string", "app_name", "Cemu debug")
|
||||
signingConfig signingConfigs.debug
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,7 @@
|
||||
android:parentActivityName=".MainActivity" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.Cemu">
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
||||
@@ -181,13 +181,15 @@ Java_info_cemu_Cemu_nativeinterface_NativeEmulation_initializeEmulation([[maybe_
|
||||
}
|
||||
|
||||
extern "C" [[maybe_unused]] JNIEXPORT void JNICALL
|
||||
Java_info_cemu_Cemu_nativeinterface_NativeEmulation_initializerRenderer(JNIEnv* env, [[maybe_unused]] jclass clazz, jobject testSurface)
|
||||
Java_info_cemu_Cemu_nativeinterface_NativeEmulation_initializeRenderer(JNIEnv* env, [[maybe_unused]] jclass clazz, jobject j_testSurface)
|
||||
{
|
||||
JNIUtils::handleNativeException(env, [&]() {
|
||||
cemu_assert_debug(testSurface != nullptr);
|
||||
// TODO: cleanup surface
|
||||
GuiSystem::getWindowInfo().window_main.surface = ANativeWindow_fromSurface(env, testSurface);
|
||||
cemu_assert_debug(j_testSurface != nullptr);
|
||||
ANativeWindow* testSurface = ANativeWindow_fromSurface(env, j_testSurface);
|
||||
GuiSystem::getWindowInfo().window_main.surface = testSurface;
|
||||
g_renderer = std::make_unique<VulkanRenderer>();
|
||||
GuiSystem::getWindowInfo().window_main.surface = nullptr;
|
||||
ANativeWindow_release(testSurface);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ extern "C" [[maybe_unused]] JNIEXPORT jobject JNICALL
|
||||
Java_info_cemu_Cemu_nativeinterface_NativeGraphicPacks_getGraphicPackBasicInfos(JNIEnv* env, [[maybe_unused]] jclass clazz)
|
||||
{
|
||||
auto graphicPackInfoClass = env->FindClass("info/cemu/Cemu/nativeinterface/NativeGraphicPacks$GraphicPackBasicInfo");
|
||||
auto graphicPackInfoCtorId = env->GetMethodID(graphicPackInfoClass, "<init>", "(JLjava/lang/String;Ljava/util/ArrayList;)V");
|
||||
auto graphicPackInfoCtorId = env->GetMethodID(graphicPackInfoClass, "<init>", "(JLjava/lang/String;ZLjava/util/ArrayList;)V");
|
||||
|
||||
std::vector<jobject> graphicPackInfoJObjects;
|
||||
for (auto&& graphicPack : NativeGraphicPacks::s_graphicPacks)
|
||||
@@ -108,7 +108,7 @@ Java_info_cemu_Cemu_nativeinterface_NativeGraphicPacks_getGraphicPackBasicInfos(
|
||||
jstring virtualPath = env->NewStringUTF(graphicPack.second->GetVirtualPath().c_str());
|
||||
jlong id = graphicPack.first;
|
||||
jobject titleIds = JNIUtils::createJavaLongArrayList(env, graphicPack.second->GetTitleIds());
|
||||
jobject jGraphicPack = env->NewObject(graphicPackInfoClass, graphicPackInfoCtorId, id, virtualPath, titleIds);
|
||||
jobject jGraphicPack = env->NewObject(graphicPackInfoClass, graphicPackInfoCtorId, id, virtualPath, graphicPack.second->IsEnabled(), titleIds);
|
||||
graphicPackInfoJObjects.push_back(jGraphicPack);
|
||||
}
|
||||
return JNIUtils::createArrayList(env, graphicPackInfoJObjects);
|
||||
|
||||
@@ -26,8 +26,9 @@ public class CemuApplication extends Application {
|
||||
|
||||
public File getInternalFolder() {
|
||||
var externalFilesDir = getExternalFilesDir(null);
|
||||
if (externalFilesDir != null)
|
||||
if (externalFilesDir != null) {
|
||||
return externalFilesDir;
|
||||
}
|
||||
return getFilesDir();
|
||||
}
|
||||
|
||||
|
||||
+3
-5
@@ -7,7 +7,7 @@ import android.graphics.drawable.Drawable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class DrawableExtensions {
|
||||
public class Drawables {
|
||||
private static final ColorMatrix INVERTED_COLOR_MATRIX = new ColorMatrix(
|
||||
new float[]{
|
||||
-1, 0, 0, 0, 255,
|
||||
@@ -18,14 +18,12 @@ public class DrawableExtensions {
|
||||
);
|
||||
|
||||
public static Drawable getInvertedDrawable(Drawable drawable, Resources resources) {
|
||||
var newDrawable = Objects.requireNonNull(drawable.getConstantState())
|
||||
.newDrawable(resources);
|
||||
var newDrawable = Objects.requireNonNull(drawable.getConstantState()).newDrawable(resources);
|
||||
return applyInvertedColorTransform(newDrawable);
|
||||
}
|
||||
|
||||
public static Drawable applyInvertedColorTransform(Drawable drawable) {
|
||||
drawable = drawable.mutate();
|
||||
drawable.setColorFilter(new ColorMatrixColorFilter(INVERTED_COLOR_MATRIX));
|
||||
drawable.mutate().setColorFilter(new ColorMatrixColorFilter(INVERTED_COLOR_MATRIX));
|
||||
return drawable;
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,6 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.view.WindowCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
@@ -27,7 +25,7 @@ import info.cemu.Cemu.databinding.ActivityEmulationBinding;
|
||||
import info.cemu.Cemu.input.InputManager;
|
||||
import info.cemu.Cemu.nativeinterface.NativeSwkbd;
|
||||
|
||||
public class EmulationActivity extends AppCompatActivity implements Observer<EmulationData> {
|
||||
public class EmulationActivity extends AppCompatActivity {
|
||||
private boolean hasEmulationError;
|
||||
public static final String EXTRA_LAUNCH_PATH = BuildConfig.APPLICATION_ID + ".LaunchPath";
|
||||
private final InputManager inputManager = new InputManager();
|
||||
@@ -39,8 +37,9 @@ public class EmulationActivity extends AppCompatActivity implements Observer<Emu
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void showEmulationTextInput(String initialText, int maxLength) {
|
||||
if (emulationActivityInstance == null || emulationActivityInstance.emulationTextInputDialog != null)
|
||||
if (emulationActivityInstance == null || emulationActivityInstance.emulationTextInputDialog != null) {
|
||||
return;
|
||||
}
|
||||
NativeSwkbd.setCurrentInputText(initialText);
|
||||
emulationActivityInstance.runOnUiThread(() -> {
|
||||
var inputEditTextLayout = emulationActivityInstance.getLayoutInflater().inflate(R.layout.layout_emulation_input, null);
|
||||
@@ -55,8 +54,9 @@ public class EmulationActivity extends AppCompatActivity implements Observer<Emu
|
||||
doneButton.setEnabled(false);
|
||||
doneButton.setOnClickListener(v -> inputEditText.onFinishedEdit());
|
||||
inputEditText.setOnTextChangedListener(s -> doneButton.setEnabled(s.length() > 0));
|
||||
if (maxLength > 0)
|
||||
if (maxLength > 0) {
|
||||
inputEditText.appendFilter(new InputFilter.LengthFilter(maxLength));
|
||||
}
|
||||
emulationActivityInstance.emulationTextInputDialog = dialog;
|
||||
});
|
||||
}
|
||||
@@ -66,8 +66,9 @@ public class EmulationActivity extends AppCompatActivity implements Observer<Emu
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static void hideEmulationTextInput() {
|
||||
if (emulationActivityInstance == null || emulationActivityInstance.emulationTextInputDialog == null)
|
||||
if (emulationActivityInstance == null || emulationActivityInstance.emulationTextInputDialog == null) {
|
||||
return;
|
||||
}
|
||||
var textInputDialog = emulationActivityInstance.emulationTextInputDialog;
|
||||
emulationActivityInstance.emulationTextInputDialog = null;
|
||||
emulationActivityInstance.runOnUiThread(textInputDialog::dismiss);
|
||||
@@ -75,15 +76,17 @@ public class EmulationActivity extends AppCompatActivity implements Observer<Emu
|
||||
|
||||
@Override
|
||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||
if (inputManager.onMotionEvent(event))
|
||||
if (inputManager.onMotionEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.onGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (inputManager.onKeyEvent(event))
|
||||
if (inputManager.onKeyEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@@ -98,8 +101,6 @@ public class EmulationActivity extends AppCompatActivity implements Observer<Emu
|
||||
}
|
||||
});
|
||||
|
||||
EmulationViewModel viewModel = new ViewModelProvider(this).get(EmulationViewModel.class);
|
||||
viewModel.getEmulationData().observe(this, this);
|
||||
Intent intent = getIntent();
|
||||
Bundle extras = intent.getExtras();
|
||||
Uri data = intent.getData();
|
||||
@@ -114,11 +115,12 @@ public class EmulationActivity extends AppCompatActivity implements Observer<Emu
|
||||
throw new RuntimeException("launchPath is null");
|
||||
}
|
||||
setFullscreen();
|
||||
info.cemu.Cemu.databinding.ActivityEmulationBinding binding = ActivityEmulationBinding.inflate(getLayoutInflater());
|
||||
ActivityEmulationBinding binding = ActivityEmulationBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager().findFragmentById(R.id.emulation_frame);
|
||||
if (emulationFragment == null) {
|
||||
emulationFragment = new EmulationFragment(launchPath);
|
||||
emulationFragment.setOnEmulationErrorCallback(this::onEmulationError);
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.add(R.id.emulation_frame, emulationFragment)
|
||||
@@ -133,17 +135,19 @@ public class EmulationActivity extends AppCompatActivity implements Observer<Emu
|
||||
.setMessage(R.string.exit_confirm_message)
|
||||
.setPositiveButton(R.string.yes, (dialog, which) -> quit())
|
||||
.setNegativeButton(R.string.no, (dialog, which) -> dialog.cancel())
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
|
||||
private void onEmulationError(EmulationError emulationError) {
|
||||
private void onEmulationError(String emulationError) {
|
||||
if (hasEmulationError) {
|
||||
return;
|
||||
}
|
||||
hasEmulationError = true;
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
|
||||
builder.setTitle(R.string.error)
|
||||
.setMessage(emulationError.errorMessage())
|
||||
.setMessage(emulationError)
|
||||
.setNeutralButton(R.string.quit, (dialog, which) -> dialog.dismiss())
|
||||
.setOnDismissListener(dialog -> quit())
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
|
||||
@@ -158,12 +162,4 @@ public class EmulationActivity extends AppCompatActivity implements Observer<Emu
|
||||
finishAffinity();
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged(EmulationData emulationData) {
|
||||
if (emulationData.emulationError().isPresent() && !hasEmulationError) {
|
||||
hasEmulationError = true;
|
||||
onEmulationError(emulationData.emulationError().get());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package info.cemu.Cemu.emulation;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public record EmulationData(Optional<EmulationError> emulationError) {
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package info.cemu.Cemu.emulation;
|
||||
|
||||
public record EmulationError(String errorMessage) {
|
||||
}
|
||||
@@ -20,14 +20,13 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import info.cemu.Cemu.nativeinterface.NativeEmulation;
|
||||
import info.cemu.Cemu.R;
|
||||
import info.cemu.Cemu.databinding.FragmentEmulationBinding;
|
||||
import info.cemu.Cemu.input.SensorManager;
|
||||
import info.cemu.Cemu.inputoverlay.InputOverlaySettingsProvider;
|
||||
import info.cemu.Cemu.inputoverlay.InputOverlaySurfaceView;
|
||||
import info.cemu.Cemu.nativeinterface.NativeEmulation;
|
||||
import info.cemu.Cemu.nativeinterface.NativeException;
|
||||
import info.cemu.Cemu.nativeinterface.NativeInput;
|
||||
|
||||
@@ -102,43 +101,48 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnEmulationErrorCallback {
|
||||
void onEmulationError(String errorMessage);
|
||||
}
|
||||
|
||||
private final String launchPath;
|
||||
private boolean isGameRunning;
|
||||
private SurfaceView padCanvas;
|
||||
private SurfaceTexture testSurfaceTexture;
|
||||
private Surface testSurface;
|
||||
private Toast toast;
|
||||
private FragmentEmulationBinding binding;
|
||||
private boolean isMotionEnabled;
|
||||
private PopupMenu settingsMenu;
|
||||
private InputOverlaySurfaceView inputOverlaySurfaceView;
|
||||
private SensorManager sensorManager;
|
||||
private EmulationViewModel viewModel;
|
||||
private OnEmulationErrorCallback onEmulationErrorCallback;
|
||||
private boolean hasEmulationError;
|
||||
private InputOverlaySettingsProvider.OverlaySettings overlaySettings;
|
||||
|
||||
public EmulationFragment(String launchPath) {
|
||||
this.launchPath = launchPath;
|
||||
}
|
||||
|
||||
InputOverlaySettingsProvider.OverlaySettings overlaySettings;
|
||||
public void setOnEmulationErrorCallback(OnEmulationErrorCallback onEmulationErrorCallback) {
|
||||
this.onEmulationErrorCallback = onEmulationErrorCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
var inputOverlaySettingsProvider = new InputOverlaySettingsProvider(requireContext());
|
||||
if (sensorManager == null)
|
||||
if (sensorManager == null) {
|
||||
sensorManager = new SensorManager(requireContext());
|
||||
}
|
||||
sensorManager.setIsLandscape(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
|
||||
overlaySettings = inputOverlaySettingsProvider.getOverlaySettings();
|
||||
testSurfaceTexture = new SurfaceTexture(0);
|
||||
testSurface = new Surface(testSurfaceTexture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
if (sensorManager != null)
|
||||
if (sensorManager != null) {
|
||||
sensorManager.setIsLandscape(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,21 +154,23 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (isMotionEnabled)
|
||||
if (isMotionEnabled) {
|
||||
sensorManager.startListening();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (sensorManager != null)
|
||||
if (sensorManager != null) {
|
||||
sensorManager.pauseListening();
|
||||
if (testSurface != null) testSurface.release();
|
||||
if (testSurfaceTexture != null) testSurfaceTexture.release();
|
||||
}
|
||||
}
|
||||
|
||||
private void createPadCanvas() {
|
||||
if (padCanvas != null) return;
|
||||
if (padCanvas != null) {
|
||||
return;
|
||||
}
|
||||
padCanvas = new SurfaceView(requireContext());
|
||||
binding.canvasesLayout.addView(
|
||||
padCanvas,
|
||||
@@ -183,7 +189,9 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC
|
||||
}
|
||||
|
||||
private void destroyPadCanvas() {
|
||||
if (padCanvas == null) return;
|
||||
if (padCanvas == null) {
|
||||
return;
|
||||
}
|
||||
binding.canvasesLayout.removeView(padCanvas);
|
||||
padCanvas = null;
|
||||
}
|
||||
@@ -223,10 +231,11 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC
|
||||
}
|
||||
if (itemId == R.id.enable_motion) {
|
||||
isMotionEnabled = !item.isChecked();
|
||||
if (isMotionEnabled)
|
||||
if (isMotionEnabled) {
|
||||
sensorManager.startListening();
|
||||
else
|
||||
} else {
|
||||
sensorManager.pauseListening();
|
||||
}
|
||||
item.setChecked(isMotionEnabled);
|
||||
return true;
|
||||
}
|
||||
@@ -248,22 +257,22 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
viewModel = new ViewModelProvider(requireActivity()).get(EmulationViewModel.class);
|
||||
|
||||
binding = FragmentEmulationBinding.inflate(inflater, container, false);
|
||||
inputOverlaySurfaceView = binding.inputOverlay;
|
||||
|
||||
binding.moveInputsButton.setOnClickListener(v -> {
|
||||
if (inputOverlaySurfaceView.getInputMode() == InputOverlaySurfaceView.InputMode.EDIT_POSITION)
|
||||
if (inputOverlaySurfaceView.getInputMode() == InputOverlaySurfaceView.InputMode.EDIT_POSITION) {
|
||||
return;
|
||||
}
|
||||
binding.resizeInputsButton.setAlpha(0.5f);
|
||||
binding.moveInputsButton.setAlpha(1.0f);
|
||||
toastMessage(R.string.input_mode_edit_position);
|
||||
inputOverlaySurfaceView.setInputMode(InputOverlaySurfaceView.InputMode.EDIT_POSITION);
|
||||
});
|
||||
binding.resizeInputsButton.setOnClickListener(v -> {
|
||||
if (inputOverlaySurfaceView.getInputMode() == InputOverlaySurfaceView.InputMode.EDIT_SIZE)
|
||||
if (inputOverlaySurfaceView.getInputMode() == InputOverlaySurfaceView.InputMode.EDIT_SIZE) {
|
||||
return;
|
||||
}
|
||||
binding.moveInputsButton.setAlpha(0.5f);
|
||||
binding.resizeInputsButton.setAlpha(1.0f);
|
||||
toastMessage(R.string.input_mode_edit_size);
|
||||
@@ -288,7 +297,11 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC
|
||||
}
|
||||
SurfaceView mainCanvas = binding.mainCanvas;
|
||||
try {
|
||||
NativeEmulation.initializerRenderer(testSurface);
|
||||
SurfaceTexture testSurfaceTexture = new SurfaceTexture(0);
|
||||
Surface testSurface = new Surface(testSurfaceTexture);
|
||||
NativeEmulation.initializeRenderer(testSurface);
|
||||
testSurface.release();
|
||||
testSurfaceTexture.release();
|
||||
} catch (NativeException exception) {
|
||||
onEmulationError(getString(R.string.failed_initialize_renderer_error, exception.getMessage()));
|
||||
return binding.getRoot();
|
||||
@@ -303,8 +316,9 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
|
||||
if (hasEmulationError)
|
||||
if (hasEmulationError) {
|
||||
return;
|
||||
}
|
||||
if (!isGameRunning) {
|
||||
isGameRunning = true;
|
||||
startGame();
|
||||
@@ -321,22 +335,22 @@ public class EmulationFragment extends Fragment implements PopupMenu.OnMenuItemC
|
||||
|
||||
private void startGame() {
|
||||
int result = NativeEmulation.startGame(launchPath);
|
||||
if (result == NativeEmulation.START_GAME_SUCCESSFUL)
|
||||
if (result == NativeEmulation.START_GAME_SUCCESSFUL) {
|
||||
return;
|
||||
int errorMessageId = switch (result) {
|
||||
case NativeEmulation.START_GAME_ERROR_GAME_BASE_FILES_NOT_FOUND ->
|
||||
R.string.game_not_found;
|
||||
case NativeEmulation.START_GAME_ERROR_NO_DISC_KEY -> R.string.no_disk_key;
|
||||
case NativeEmulation.START_GAME_ERROR_NO_TITLE_TIK -> R.string.no_title_tik;
|
||||
default -> R.string.game_files_unknown_error;
|
||||
}
|
||||
String errorMessage = switch (result) {
|
||||
case NativeEmulation.START_GAME_ERROR_GAME_BASE_FILES_NOT_FOUND -> getString(R.string.game_not_found);
|
||||
case NativeEmulation.START_GAME_ERROR_NO_DISC_KEY -> getString(R.string.no_disk_key);
|
||||
case NativeEmulation.START_GAME_ERROR_NO_TITLE_TIK -> getString(R.string.no_title_tik);
|
||||
default -> getString(R.string.game_files_unknown_error, launchPath);
|
||||
};
|
||||
onEmulationError(getString(errorMessageId));
|
||||
}
|
||||
|
||||
private void onEmulationError(String errorMessage) {
|
||||
hasEmulationError = true;
|
||||
if (viewModel == null)
|
||||
return;
|
||||
viewModel.setEmulationError(new EmulationError(errorMessage));
|
||||
if (onEmulationErrorCallback != null) {
|
||||
onEmulationErrorCallback.onEmulationError(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-5
@@ -35,18 +35,21 @@ public class EmulationTextInputEditText extends TextInputEditText {
|
||||
|
||||
public void updateText(String text) {
|
||||
boolean hasFocus = hasFocus();
|
||||
if (hasFocus)
|
||||
if (hasFocus) {
|
||||
clearFocus();
|
||||
}
|
||||
setText(text);
|
||||
if (hasFocus)
|
||||
if (hasFocus) {
|
||||
requestFocus();
|
||||
}
|
||||
}
|
||||
|
||||
public EmulationTextInputEditText(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
appendFilter((source, start, end, dest, dstart, dend) -> {
|
||||
if (INPUT_PATTERN.matcher(source).matches())
|
||||
if (INPUT_PATTERN.matcher(source).matches()) {
|
||||
return null;
|
||||
}
|
||||
return "";
|
||||
});
|
||||
setInputType(EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_NORMAL);
|
||||
@@ -57,10 +60,12 @@ public class EmulationTextInputEditText extends TextInputEditText {
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence text, int start, int before, int count) {
|
||||
if (!hasFocus())
|
||||
if (!hasFocus()) {
|
||||
return;
|
||||
if (onTextChangedListener != null)
|
||||
}
|
||||
if (onTextChangedListener != null) {
|
||||
onTextChangedListener.onTextChanged(text);
|
||||
}
|
||||
NativeSwkbd.onTextChanged(text.toString());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
package info.cemu.Cemu.emulation;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class EmulationViewModel extends ViewModel {
|
||||
private final MutableLiveData<EmulationData> emulationData = new MutableLiveData<>(new EmulationData(Optional.empty()));
|
||||
|
||||
public void setEmulationError(EmulationError emulationError) {
|
||||
emulationData.setValue(new EmulationData(Optional.of(emulationError)));
|
||||
}
|
||||
|
||||
public LiveData<EmulationData> getEmulationData() {
|
||||
return emulationData;
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,9 @@ public class DocumentsProvider extends android.provider.DocumentsProvider {
|
||||
|
||||
@Override
|
||||
public boolean isChildDocument(String parentDocumentId, String documentId) {
|
||||
if (parentDocumentId == null || documentId == null) return false;
|
||||
if (parentDocumentId == null || documentId == null) {
|
||||
return false;
|
||||
}
|
||||
return documentId.startsWith(parentDocumentId);
|
||||
}
|
||||
|
||||
@@ -95,12 +97,14 @@ public class DocumentsProvider extends android.provider.DocumentsProvider {
|
||||
var newFile = resolveWithoutConflict(parentFile, displayName);
|
||||
|
||||
if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) {
|
||||
if (!newFile.mkdir())
|
||||
if (!newFile.mkdir()) {
|
||||
throw new FileNotFoundException("Failed to create directory");
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
if (!newFile.createNewFile())
|
||||
if (!newFile.createNewFile()) {
|
||||
throw new FileNotFoundException("Failed to create file");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -116,25 +120,31 @@ public class DocumentsProvider extends android.provider.DocumentsProvider {
|
||||
deleteFolder(file);
|
||||
return;
|
||||
}
|
||||
if (!file.delete())
|
||||
if (!file.delete()) {
|
||||
throw new FileNotFoundException("Couldn't delete document with ID " + documentId);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteFolder(File dirFile) throws FileNotFoundException {
|
||||
if (!dirFile.isDirectory())
|
||||
if (!dirFile.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
var files = dirFile.listFiles();
|
||||
if (files == null) return;
|
||||
if (files == null) {
|
||||
return;
|
||||
}
|
||||
for (var file : files) {
|
||||
if (file.isDirectory()) {
|
||||
deleteFolder(file);
|
||||
continue;
|
||||
}
|
||||
if (!file.delete())
|
||||
if (!file.delete()) {
|
||||
throw new FileNotFoundException("Couldn't delete file " + file.getPath());
|
||||
}
|
||||
}
|
||||
if (!dirFile.delete())
|
||||
if (!dirFile.delete()) {
|
||||
throw new FileNotFoundException("Couldn't delete file " + dirFile.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -142,30 +152,35 @@ public class DocumentsProvider extends android.provider.DocumentsProvider {
|
||||
var parent = getFile(parentDocumentId);
|
||||
var file = getFile(documentId);
|
||||
|
||||
if (!(parent.equals(file) || file.getParentFile() == null || file.getParentFile().equals(parent)))
|
||||
if (!(parent.equals(file) || file.getParentFile() == null || file.getParentFile().equals(parent))) {
|
||||
throw new FileNotFoundException("Couldn't delete document with ID " + documentId);
|
||||
}
|
||||
if (file.isDirectory()) {
|
||||
deleteFolder(file);
|
||||
return;
|
||||
}
|
||||
if (!file.delete())
|
||||
if (!file.delete()) {
|
||||
throw new FileNotFoundException("Couldn't delete document with ID " + documentId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String renameDocument(String documentId, String displayName) throws FileNotFoundException {
|
||||
if (displayName == null)
|
||||
if (displayName == null) {
|
||||
throw new FileNotFoundException("Couldn't rename document " + documentId + " as the new name is null");
|
||||
}
|
||||
|
||||
var sourceFile = getFile(documentId);
|
||||
var sourceParentFile = sourceFile.getParentFile();
|
||||
if (sourceParentFile == null)
|
||||
if (sourceParentFile == null) {
|
||||
throw new FileNotFoundException("Couldn't rename document '" + documentId + "' as it has no parent");
|
||||
}
|
||||
var destFile = resolve(sourceParentFile, displayName);
|
||||
|
||||
try {
|
||||
if (!sourceFile.renameTo(destFile))
|
||||
if (!sourceFile.renameTo(destFile)) {
|
||||
throw new FileNotFoundException("Couldn't rename document from '" + sourceFile.getName() + "' to '" + destFile.getName() + "'");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
throw new FileNotFoundException("Couldn't rename document from '" + sourceFile.getName() + "' to '" + destFile.getName() + "':" + exception.getMessage());
|
||||
}
|
||||
@@ -180,8 +195,9 @@ public class DocumentsProvider extends android.provider.DocumentsProvider {
|
||||
var newFile = resolveWithoutConflict(parent, oldFile.getName());
|
||||
|
||||
try {
|
||||
if (!(newFile.createNewFile() && newFile.setWritable(true) && newFile.setReadable(true)))
|
||||
if (!(newFile.createNewFile() && newFile.setWritable(true) && newFile.setReadable(true))) {
|
||||
throw new IOException("Couldn't create new file");
|
||||
}
|
||||
try (var inputStream = new FileInputStream(oldFile); var outputStream = new FileOutputStream(newFile)) {
|
||||
byte[] b = new byte[1024];
|
||||
int len;
|
||||
@@ -211,10 +227,12 @@ public class DocumentsProvider extends android.provider.DocumentsProvider {
|
||||
var cursor = new MatrixCursor(projection == null ? DEFAULT_DOCUMENT_PROJECTION : projection);
|
||||
var parent = getFile(parentDocumentId);
|
||||
var files = parent.listFiles();
|
||||
if (files == null)
|
||||
if (files == null) {
|
||||
return cursor;
|
||||
for (var file : files)
|
||||
}
|
||||
for (var file : files) {
|
||||
includeFile(cursor, null, file);
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
|
||||
@@ -230,15 +248,17 @@ public class DocumentsProvider extends android.provider.DocumentsProvider {
|
||||
}
|
||||
|
||||
private String copyDocument(String sourceDocumentId, String sourceParentDocumentId, String targetParentDocumentId) throws FileNotFoundException {
|
||||
if (!isChildDocument(sourceParentDocumentId, sourceDocumentId))
|
||||
if (!isChildDocument(sourceParentDocumentId, sourceDocumentId)) {
|
||||
throw new FileNotFoundException("Couldn't copy document '" + sourceDocumentId + "' as its parent is not '" + sourceParentDocumentId + "'");
|
||||
}
|
||||
return copyDocument(sourceDocumentId, targetParentDocumentId);
|
||||
}
|
||||
|
||||
private File resolveWithoutConflict(File originalFile, String name) {
|
||||
var file = resolve(originalFile, name);
|
||||
if (!file.exists())
|
||||
if (!file.exists()) {
|
||||
return file;
|
||||
}
|
||||
|
||||
// Makes sure two files don't have the same name by adding a number to the end
|
||||
var noConflictId = 1;
|
||||
@@ -276,13 +296,15 @@ public class DocumentsProvider extends android.provider.DocumentsProvider {
|
||||
.add(DocumentsContract.Document.COLUMN_MIME_TYPE, getTypeForFile(localFile))
|
||||
.add(DocumentsContract.Document.COLUMN_LAST_MODIFIED, localFile.lastModified())
|
||||
.add(DocumentsContract.Document.COLUMN_FLAGS, flags);
|
||||
if (localFile.equals(baseDirectory))
|
||||
if (localFile.equals(baseDirectory)) {
|
||||
curorRowBuilder.add(DocumentsContract.Root.COLUMN_ICON, R.mipmap.ic_launcher);
|
||||
}
|
||||
}
|
||||
|
||||
private String getTypeForFile(File file) {
|
||||
if (file.isDirectory())
|
||||
if (file.isDirectory()) {
|
||||
return DocumentsContract.Document.MIME_TYPE_DIR;
|
||||
}
|
||||
return getTypeForName(file.getName());
|
||||
}
|
||||
|
||||
@@ -291,8 +313,9 @@ public class DocumentsProvider extends android.provider.DocumentsProvider {
|
||||
if (lastDot >= 0) {
|
||||
var extension = name.substring(lastDot + 1);
|
||||
var mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||
if (mime != null)
|
||||
if (mime != null) {
|
||||
return mime;
|
||||
}
|
||||
}
|
||||
return "application/octect-stream";
|
||||
}
|
||||
@@ -301,8 +324,9 @@ public class DocumentsProvider extends android.provider.DocumentsProvider {
|
||||
Objects.requireNonNull(documentId);
|
||||
if (documentId.startsWith(ROOT_ID)) {
|
||||
var file = resolve(baseDirectory, documentId.substring(ROOT_ID.length() + 1));
|
||||
if (!file.exists())
|
||||
if (!file.exists()) {
|
||||
throw new FileNotFoundException(file.getAbsolutePath() + " " + documentId + " not found");
|
||||
}
|
||||
return file;
|
||||
} else {
|
||||
throw new FileNotFoundException(documentId + " is not in any known root");
|
||||
|
||||
@@ -79,7 +79,9 @@ public class GameAdapter extends ListAdapter<Game, GameAdapter.ViewHolder> {
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull GameAdapter.ViewHolder holder, int position) {
|
||||
Game game = getItem(position);
|
||||
if (game == null) return;
|
||||
if (game == null) {
|
||||
return;
|
||||
}
|
||||
holder.icon.setImageBitmap(game.icon());
|
||||
holder.favoriteIcon.setVisibility(game.isFavorite() ? View.VISIBLE : View.GONE);
|
||||
holder.text.setText(game.name());
|
||||
|
||||
@@ -23,7 +23,7 @@ import info.cemu.Cemu.nativeinterface.NativeGameTitles;
|
||||
import info.cemu.Cemu.nativeinterface.NativeGameTitles.Game;
|
||||
|
||||
public class GameDetailsFragment extends Fragment {
|
||||
private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
@@ -31,10 +31,12 @@ public class GameDetailsFragment extends Fragment {
|
||||
var game = new ViewModelProvider(requireActivity()).get(GameViewModel.class).getGame();
|
||||
binding.gameTitleName.setText(game.name());
|
||||
binding.titleVersion.setText(String.valueOf(game.version()));
|
||||
if (game.icon() != null)
|
||||
if (game.icon() != null) {
|
||||
binding.titleIcon.setImageBitmap(game.icon());
|
||||
if (game.dlc() != 0)
|
||||
}
|
||||
if (game.dlc() != 0) {
|
||||
binding.titleDlc.setText(String.valueOf(game.dlc()));
|
||||
}
|
||||
binding.titleTimePlayed.setText(getTimePlayed(game));
|
||||
binding.titleLastPlayed.setText(getLastPlayedDate(game));
|
||||
binding.titleId.setText(String.format("%016x", game.titleId()));
|
||||
@@ -44,15 +46,20 @@ public class GameDetailsFragment extends Fragment {
|
||||
}
|
||||
|
||||
private String getLastPlayedDate(Game game) {
|
||||
if (game.lastPlayedYear() == 0) return getString(R.string.never_played);
|
||||
if (game.lastPlayedYear() == 0) {
|
||||
return getString(R.string.never_played);
|
||||
}
|
||||
LocalDate lastPlayedDate = LocalDate.of(game.lastPlayedYear(), game.lastPlayedMonth(), game.lastPlayedDay());
|
||||
return dateFormatter.format(lastPlayedDate);
|
||||
return DATE_FORMATTER.format(lastPlayedDate);
|
||||
}
|
||||
|
||||
private String getTimePlayed(Game game) {
|
||||
if (game.minutesPlayed() == 0) return getString(R.string.never_played);
|
||||
if (game.minutesPlayed() < 60)
|
||||
if (game.minutesPlayed() == 0) {
|
||||
return getString(R.string.never_played);
|
||||
}
|
||||
if (game.minutesPlayed() < 60) {
|
||||
return getString(R.string.minutes_played, game.minutesPlayed());
|
||||
}
|
||||
return getString(R.string.hours_minutes_played, game.minutesPlayed() / 60, game.minutesPlayed() % 60);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@ public class GameListViewModel extends ViewModel {
|
||||
public GameListViewModel() {
|
||||
this.gamesData = new MutableLiveData<>();
|
||||
NativeGameTitles.setGameTitleLoadedCallback(game -> {
|
||||
if (!isGameValid(game)) {
|
||||
return;
|
||||
}
|
||||
synchronized (GameListViewModel.this) {
|
||||
games.add(game);
|
||||
gamesData.postValue(new ArrayList<>(games));
|
||||
@@ -30,9 +33,15 @@ public class GameListViewModel extends ViewModel {
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isGameValid(Game game) {
|
||||
return game.path() != null && game.name() != null;
|
||||
}
|
||||
|
||||
public void setGameTitleFavorite(Game game, boolean isFavorite) {
|
||||
synchronized (this) {
|
||||
if (!games.contains(game)) return;
|
||||
if (!games.contains(game)) {
|
||||
return;
|
||||
}
|
||||
NativeGameTitles.setGameTitleFavorite(game.titleId(), isFavorite);
|
||||
games.remove(game);
|
||||
Game newGame = new Game(
|
||||
|
||||
@@ -28,12 +28,9 @@ public class GameProfileEditFragment extends Fragment {
|
||||
|
||||
private String cpuModeToString(int cpuMode) {
|
||||
int resourceId = switch (cpuMode) {
|
||||
case NativeGameTitles.CPU_MODE_SINGLECOREINTERPRETER ->
|
||||
R.string.cpu_mode_single_core_interpreter;
|
||||
case NativeGameTitles.CPU_MODE_SINGLECORERECOMPILER ->
|
||||
R.string.cpu_mode_single_core_recompiler;
|
||||
case NativeGameTitles.CPU_MODE_MULTICORERECOMPILER ->
|
||||
R.string.cpu_mode_multi_core_recompiler;
|
||||
case NativeGameTitles.CPU_MODE_SINGLECOREINTERPRETER -> R.string.cpu_mode_single_core_interpreter;
|
||||
case NativeGameTitles.CPU_MODE_SINGLECORERECOMPILER -> R.string.cpu_mode_single_core_recompiler;
|
||||
case NativeGameTitles.CPU_MODE_MULTICORERECOMPILER -> R.string.cpu_mode_multi_core_recompiler;
|
||||
default -> R.string.cpu_mode_auto;
|
||||
};
|
||||
return getString(resourceId);
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package info.cemu.Cemu.gameview;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@@ -21,6 +25,7 @@ import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -47,7 +52,7 @@ public class GamesFragment extends Fragment {
|
||||
super.onCreate(savedInstanceState);
|
||||
currentGamePaths = new HashSet<>(NativeSettings.getGamesPaths());
|
||||
gameAdapter = new GameAdapter(game -> {
|
||||
Intent intent = new Intent(getContext(), EmulationActivity.class);
|
||||
Intent intent = new Intent(requireContext(), EmulationActivity.class);
|
||||
intent.putExtra(EmulationActivity.EXTRA_LAUNCH_PATH, game.path());
|
||||
startActivity(intent);
|
||||
});
|
||||
@@ -74,8 +79,9 @@ public class GamesFragment extends Fragment {
|
||||
MenuInflater inflater = requireActivity().getMenuInflater();
|
||||
inflater.inflate(R.menu.game, menu);
|
||||
Game selectedGame = gameAdapter.getSelectedGame();
|
||||
if (selectedGame == null)
|
||||
if (selectedGame == null) {
|
||||
return;
|
||||
}
|
||||
menu.findItem(R.id.favorite).setChecked(selectedGame.isFavorite());
|
||||
menu.findItem(R.id.remove_shader_caches).setEnabled(NativeGameTitles.titleHasShaderCacheFiles(selectedGame.titleId()));
|
||||
}
|
||||
@@ -105,9 +111,36 @@ public class GamesFragment extends Fragment {
|
||||
NavHostFragment.findNavController(this).navigate(R.id.action_games_fragment_to_game_details_fragment);
|
||||
return true;
|
||||
}
|
||||
if (itemId == R.id.create_shortcut) {
|
||||
createShortcutForGame(game);
|
||||
return true;
|
||||
}
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
||||
private void createShortcutForGame(Game game) {
|
||||
var context = requireContext();
|
||||
ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class);
|
||||
if (!shortcutManager.isRequestPinShortcutSupported()) {
|
||||
Toast.makeText(context, R.string.shortcut_not_supported, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if (game.icon() == null) {
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(requireContext(), EmulationActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.putExtra(EmulationActivity.EXTRA_LAUNCH_PATH, game.path());
|
||||
ShortcutInfo pinShortcutInfo = new ShortcutInfo.Builder(context, String.valueOf(game.titleId()))
|
||||
.setShortLabel(game.name())
|
||||
.setIntent(intent)
|
||||
.setIcon(Icon.createWithBitmap(game.icon()))
|
||||
.build();
|
||||
Intent pinnedShortcutCallbackIntent = shortcutManager.createShortcutResultIntent(pinShortcutInfo);
|
||||
PendingIntent successCallback = PendingIntent.getBroadcast(context, 0, pinnedShortcutCallbackIntent, PendingIntent.FLAG_IMMUTABLE);
|
||||
shortcutManager.requestPinShortcut(pinShortcutInfo, successCallback.getIntentSender());
|
||||
}
|
||||
|
||||
private void removeShaderCachesForGame(Game game) {
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(requireContext());
|
||||
builder.setTitle(R.string.remove_shader_caches)
|
||||
@@ -153,7 +186,9 @@ public class GamesFragment extends Fragment {
|
||||
});
|
||||
|
||||
binding.gamesSwipeRefresh.setOnRefreshListener(() -> {
|
||||
if (refreshing) return;
|
||||
if (refreshing) {
|
||||
return;
|
||||
}
|
||||
refreshing = true;
|
||||
handler.postDelayed(() -> {
|
||||
binding.gamesSwipeRefresh.setRefreshing(false);
|
||||
@@ -161,6 +196,8 @@ public class GamesFragment extends Fragment {
|
||||
}, 1000);
|
||||
gameListViewModel.refreshGames();
|
||||
});
|
||||
binding.gamesSwipeRefresh.setColorSchemeColors(MaterialColors.getColor(requireContext(), com.google.android.material.R.attr.colorOnSurfaceVariant, Color.BLACK));
|
||||
binding.gamesSwipeRefresh.setProgressBackgroundColorSchemeColor(MaterialColors.getColor(requireContext(), com.google.android.material.R.attr.colorSurfaceVariant, Color.WHITE));
|
||||
recyclerView.setAdapter(gameAdapter);
|
||||
|
||||
return binding.getRoot();
|
||||
|
||||
+2
-1
@@ -34,8 +34,9 @@ public abstract class BaseSelectionAdapter<T> extends BaseAdapter {
|
||||
|
||||
@Override
|
||||
public View getView(int position, View view, ViewGroup viewGroup) {
|
||||
if (view == null)
|
||||
if (view == null) {
|
||||
view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_single_selection_item, viewGroup, false);
|
||||
}
|
||||
MaterialRadioButton radioButton = view.findViewById(R.id.single_selection_item_radio_button);
|
||||
radioButton.setEnabled(isEnabled(position));
|
||||
setRadioButtonText(radioButton, position);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user