diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java index 96dc6b41..5a6a8520 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/GameActivity.java @@ -126,6 +126,16 @@ public class GameActivity extends BaseActivity implements EmulatorCallback { return super.dispatchGenericMotionEvent(ev); } + @Override + public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) { + super.onPictureInPictureModeChanged(isInPictureInPictureMode); + } + + @Override + protected void onUserLeaveHint() { + super.onUserLeaveHint(); + } + @Override protected void onDestroy() { if (AlberDriver.HasRomLoaded()) { diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/BasePreferenceFragment.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/BasePreferenceFragment.java index f7f12d0f..7516bc61 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/BasePreferenceFragment.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/BasePreferenceFragment.java @@ -27,4 +27,4 @@ public abstract class BasePreferenceFragment extends PreferenceFragmentCompat { header.setTitle(titleId); } } -} +} \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/BaseSheetDialog.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/BaseSheetDialog.java new file mode 100644 index 00000000..d905b844 --- /dev/null +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/BaseSheetDialog.java @@ -0,0 +1,46 @@ +package com.panda3ds.pandroid.app.base; + +import android.content.Context; +import android.util.TypedValue; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; + +import com.google.android.material.bottomsheet.BottomSheetDialog; +import com.panda3ds.pandroid.R; +import com.panda3ds.pandroid.utils.CompatUtils; + +import org.jetbrains.annotations.NotNull; + +public class BaseSheetDialog extends BottomSheetDialog { + private final LinearLayout contentView; + public BaseSheetDialog(@NonNull Context context) { + super(CompatUtils.findActivity(context)); + int width = CompatUtils.findActivity(context).getWindow().getDecorView().getMeasuredWidth(); + int height = CompatUtils.findActivity(context).getWindow().getDecorView().getMeasuredHeight(); + getBehavior().setPeekHeight((int) (height*0.87)); + getBehavior().setMaxWidth(width); + getBehavior().setMaxHeight((int) (height*0.87)); + super.setContentView(R.layout.dialog_bottom_sheet); + contentView = super.findViewById(R.id.content); + } + + @Override + public void setContentView(View view) { + contentView.removeAllViews(); + contentView.addView(view); + } + + @Override + public void setContentView(int layoutResId) { + setContentView(LayoutInflater.from(getContext()).inflate(layoutResId, null, false)); + } + + @NotNull + @Override + public T findViewById(int id) { + return contentView.findViewById(id); + } +} diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/GameAboutDialog.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/GameAboutDialog.java index ca2c3ca4..dd1393df 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/GameAboutDialog.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/base/GameAboutDialog.java @@ -1,6 +1,7 @@ package com.panda3ds.pandroid.app.base; import android.content.Context; +import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; @@ -14,28 +15,37 @@ import com.panda3ds.pandroid.utils.FileUtils; import com.panda3ds.pandroid.utils.GameUtils; import com.panda3ds.pandroid.view.gamesgrid.GameIconView; -public class GameAboutDialog extends BottomSheetDialog { +public class GameAboutDialog extends BaseSheetDialog { + private final GameMetadata game; public GameAboutDialog(@NonNull Context context, GameMetadata game) { super(context); - View content = LayoutInflater.from(context).inflate(R.layout.dialog_game_about, null, false); - setContentView(content); + this.game = game; + } - ((GameIconView)content.findViewById(R.id.game_icon)).setImageBitmap(game.getIcon()); - ((TextView)content.findViewById(R.id.game_title)).setText(game.getTitle()); - ((TextView)content.findViewById(R.id.game_publisher)).setText(game.getPublisher()); - ((TextView)content.findViewById(R.id.region)).setText(game.getRegions()[0].name()); - ((TextView)content.findViewById(R.id.directory)).setText(FileUtils.obtainUri(game.getRealPath()).getPath()); - - content.findViewById(R.id.play).setOnClickListener(v -> { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.dialog_game_about); + + ((GameIconView) findViewById(R.id.game_icon)).setImageBitmap(game.getIcon()); + ((TextView) findViewById(R.id.game_title)).setText(game.getTitle()); + ((TextView) findViewById(R.id.game_publisher)).setText(game.getPublisher()); + ((TextView) findViewById(R.id.region)).setText(game.getRegions()[0].localizedName()); + ((TextView) findViewById(R.id.directory)).setText(FileUtils.obtainUri(game.getRealPath()).getPath()); + + findViewById(R.id.play).setOnClickListener(v -> { dismiss(); GameUtils.launch(getContext(), game); }); - if (game.getRomPath().startsWith("folder:")){ - content.findViewById(R.id.remove).setVisibility(View.GONE); + if (game.getRomPath().startsWith("folder:")) { + findViewById(R.id.remove).setVisibility(View.GONE); } else { - content.findViewById(R.id.remove).setOnClickListener(v-> { + findViewById(R.id.remove).setOnClickListener(v -> { dismiss(); + if (game.getRomPath().startsWith("elf:")) { + FileUtils.delete(game.getRealPath()); + } GameUtils.removeGame(game); }); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/main/SearchFragment.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/main/SearchFragment.java index e9db7f80..6c2ee024 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/main/SearchFragment.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/main/SearchFragment.java @@ -9,6 +9,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatEditText; import androidx.fragment.app.Fragment; import com.panda3ds.pandroid.R; +import com.panda3ds.pandroid.app.base.GameAboutDialog; import com.panda3ds.pandroid.data.game.GameMetadata; import com.panda3ds.pandroid.utils.GameUtils; import com.panda3ds.pandroid.utils.SearchAgent; @@ -33,6 +34,11 @@ public class SearchFragment extends Fragment { super.onViewCreated(view, savedInstanceState); gamesListView = view.findViewById(R.id.games); + gamesListView.setItemLongClick((game)->{ + GameAboutDialog dialog = new GameAboutDialog(requireActivity(), game); + dialog.setOnDismissListener((x)-> search(((AppCompatEditText) view.findViewById(R.id.search_bar)).getText().toString())); + dialog.show(); + }); ((AppCompatEditText) view.findViewById(R.id.search_bar)).addTextChangedListener((SimpleTextWatcher) this::search); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/GamesFoldersPreferences.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/GamesFoldersPreferences.java index ce5c0f57..e76fc832 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/GamesFoldersPreferences.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/GamesFoldersPreferences.java @@ -17,6 +17,7 @@ import androidx.preference.PreferenceScreen; import com.google.android.material.bottomsheet.BottomSheetDialog; import com.panda3ds.pandroid.R; import com.panda3ds.pandroid.app.base.BasePreferenceFragment; +import com.panda3ds.pandroid.app.base.BaseSheetDialog; import com.panda3ds.pandroid.data.game.GamesFolder; import com.panda3ds.pandroid.utils.FileUtils; import com.panda3ds.pandroid.utils.GameUtils; @@ -34,13 +35,13 @@ public class GamesFoldersPreferences extends BasePreferenceFragment implements A } @SuppressLint("RestrictedApi") - private void refreshList(){ + private void refreshList() { GamesFolder[] folders = GameUtils.getFolders(); PreferenceScreen screen = getPreferenceScreen(); screen.removeAll(); - for (GamesFolder folder: folders){ + for (GamesFolder folder : folders) { Preference preference = new Preference(screen.getContext()); - preference.setOnPreferenceClickListener((item)-> { + preference.setOnPreferenceClickListener((item) -> { showFolderInfo(folder); screen.performClick(); return false; @@ -62,12 +63,12 @@ public class GamesFoldersPreferences extends BasePreferenceFragment implements A } private void showFolderInfo(GamesFolder folder) { - BottomSheetDialog dialog = new BottomSheetDialog(requireActivity()); - View layout = LayoutInflater.from(requireActivity()).inflate(R.layout.games_folder_about, null, false); + BaseSheetDialog dialog = new BaseSheetDialog(requireActivity()); + View layout = LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_games_folder, null, false); dialog.setContentView(layout); ((TextView) layout.findViewById(R.id.name)).setText(FileUtils.getName(folder.getPath())); - ((TextView) layout.findViewById(R.id.directory)).setText(folder.getPath()); + ((TextView) layout.findViewById(R.id.directory)).setText(FileUtils.obtainUri(folder.getPath()).getPath()); ((TextView) layout.findViewById(R.id.games)).setText(String.valueOf(folder.getGames().size())); layout.findViewById(R.id.ok).setOnClickListener(v -> dialog.dismiss()); @@ -83,7 +84,7 @@ public class GamesFoldersPreferences extends BasePreferenceFragment implements A @Override public void onDestroy() { super.onDestroy(); - if (pickFolderRequest != null){ + if (pickFolderRequest != null) { pickFolderRequest.unregister(); pickFolderRequest = null; } @@ -91,10 +92,10 @@ public class GamesFoldersPreferences extends BasePreferenceFragment implements A @Override public void onActivityResult(Uri result) { - if (result != null){ + if (result != null) { FileUtils.makeUriPermanent(result.toString(), "r"); GameUtils.registerFolder(result.toString()); refreshList(); } } -} +} \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/ThemeSelectorDialog.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/ThemeSelectorDialog.java index b53f673d..fa22d884 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/ThemeSelectorDialog.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/ThemeSelectorDialog.java @@ -1,7 +1,7 @@ package com.panda3ds.pandroid.app.preferences; -import android.app.Activity; import android.content.Context; +import android.os.Bundle; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; @@ -12,42 +12,43 @@ import androidx.annotation.NonNull; import androidx.appcompat.widget.AppCompatRadioButton; import androidx.recyclerview.widget.RecyclerView; -import com.google.android.material.bottomsheet.BottomSheetDialog; import com.panda3ds.pandroid.R; +import com.panda3ds.pandroid.app.base.BaseSheetDialog; +import com.panda3ds.pandroid.utils.CompatUtils; import com.panda3ds.pandroid.data.config.GlobalConfig; import com.panda3ds.pandroid.view.recycler.AutoFitGridLayout; import com.panda3ds.pandroid.view.recycler.SimpleListAdapter; -import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; -import java.util.function.Predicate; -public class ThemeSelectorDialog extends BottomSheetDialog { +public class ThemeSelectorDialog extends BaseSheetDialog { - private final SimpleListAdapter adapter; + private final SimpleListAdapter adapter = new SimpleListAdapter<>(R.layout.hold_theme_preview_base, this::bindItemView); private final int currentTheme = GlobalConfig.get(GlobalConfig.KEY_APP_THEME); - private static final Theme[] themes = { + private static final ArrayList themes = new ArrayList<>(Arrays.asList( new Theme(R.style.Theme_Pandroid, R.string.theme_device, GlobalConfig.THEME_ANDROID), new Theme(R.style.Theme_Pandroid_Light, R.string.light, GlobalConfig.THEME_LIGHT), new Theme(R.style.Theme_Pandroid_Dark, R.string.dark, GlobalConfig.THEME_DARK), new Theme(R.style.Theme_Pandroid_Black, R.string.black, GlobalConfig.THEME_BLACK) - }; + )); public ThemeSelectorDialog(@NonNull Context context) { super(context); - View content = LayoutInflater.from(context).inflate(R.layout.dialog_select_theme, null, false); - setContentView(content); - adapter = new SimpleListAdapter<>(R.layout.hold_theme_preview_summary, this::bindItemView); - adapter.clear(); - ArrayList themeList = new ArrayList<>(Arrays.asList(themes)); - themeList.sort((o1, o2) -> o1.id == currentTheme ? -1 : 0); - adapter.addAll(themeList); + } - ((RecyclerView) content.findViewById(R.id.recycler)).setAdapter(adapter); - ((RecyclerView) content.findViewById(R.id.recycler)).setLayoutManager(new AutoFitGridLayout(getContext(), 150)); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.dialog_select_theme); + adapter.clear(); + themes.sort((o1, o2) -> o1.value == currentTheme ? -1 : 0); + adapter.addAll(themes); + + RecyclerView recycler = findViewById(R.id.recycler); + recycler.setAdapter(adapter); + recycler.setLayoutManager(new AutoFitGridLayout(getContext(), 150)); } private void bindItemView(int i, Theme theme, View view) { @@ -55,12 +56,12 @@ public class ThemeSelectorDialog extends BottomSheetDialog { container.removeAllViews(); container.addView(LayoutInflater.from(new ContextThemeWrapper(getContext(), theme.style)).inflate(R.layout.hold_theme_preview, null, false)); ((TextView) view.findViewById(R.id.title)).setText(theme.name); - ((AppCompatRadioButton) view.findViewById(R.id.checkbox)).setChecked(GlobalConfig.get(GlobalConfig.KEY_APP_THEME) == theme.id); + ((AppCompatRadioButton) view.findViewById(R.id.checkbox)).setChecked(GlobalConfig.get(GlobalConfig.KEY_APP_THEME) == theme.value); view.setOnClickListener(v -> { dismiss(); - if (theme.id != GlobalConfig.get(GlobalConfig.KEY_APP_THEME)) { - GlobalConfig.set(GlobalConfig.KEY_APP_THEME, theme.id); - ((Activity) v.getContext()).recreate(); + if (theme.value != GlobalConfig.get(GlobalConfig.KEY_APP_THEME)) { + GlobalConfig.set(GlobalConfig.KEY_APP_THEME, theme.value); + CompatUtils.findActivity(getContext()).recreate(); } }); } @@ -68,12 +69,12 @@ public class ThemeSelectorDialog extends BottomSheetDialog { private static final class Theme { private final int style; private final int name; - private final int id; + private final int value; private Theme(int style, int name, int value) { this.style = style; this.name = name; - this.id = value; + this.value = value; } } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/ds/DsEditorPreferences.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/ds/DsEditorPreferences.java index aa0cdc56..b1e9c843 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/ds/DsEditorPreferences.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/preferences/ds/DsEditorPreferences.java @@ -24,6 +24,7 @@ public class DsEditorPreferences extends Fragment { @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { layout = new LinearLayout(container.getContext()); + layout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_FULLSCREEN|View.SYSTEM_UI_FLAG_IMMERSIVE); return layout; } @@ -36,12 +37,6 @@ public class DsEditorPreferences extends Fragment { ((BaseActivity)requireActivity()).getSupportActionBar().hide(); } - @Override - public void onResume() { - super.onResume(); - requireActivity().getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN|View.SYSTEM_UI_FLAG_HIDE_NAVIGATION|View.SYSTEM_UI_FLAG_IMMERSIVE); - } - @Override public void onDestroy() { super.onDestroy(); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/provider/AppDataDocumentProvider.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/provider/AppDataDocumentProvider.java index 5b8feed2..5fd25d8c 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/provider/AppDataDocumentProvider.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/app/provider/AppDataDocumentProvider.java @@ -88,10 +88,14 @@ public class AppDataDocumentProvider extends DocumentsProvider { } private void includeFile(MatrixCursor cursor, File file) { + int flags = 0; + if (file.isFile()) { + flags = Document.FLAG_SUPPORTS_WRITE; + } cursor.newRow() .add(Document.COLUMN_DOCUMENT_ID, obtainDocumentId(file)) .add(Document.COLUMN_MIME_TYPE, file.isDirectory() ? Document.MIME_TYPE_DIR : "application/octect-stream") - .add(Document.COLUMN_FLAGS, 0) + .add(Document.COLUMN_FLAGS, flags) .add(Document.COLUMN_LAST_MODIFIED, file.lastModified()) .add(Document.COLUMN_DISPLAY_NAME, file.getName()) .add(Document.COLUMN_SIZE, file.length()); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/data/game/GameRegion.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/data/game/GameRegion.java index 9b99b095..9e025163 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/data/game/GameRegion.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/data/game/GameRegion.java @@ -1,5 +1,7 @@ package com.panda3ds.pandroid.data.game; +import com.panda3ds.pandroid.R; + public enum GameRegion { NorthAmerican, Japan, @@ -8,5 +10,23 @@ public enum GameRegion { China, Korean, Taiwan, - None + None; + + public int localizedName(){ + switch (this){ + case NorthAmerican: + return R.string.region_north_armerican; + case Japan: + return R.string.region_japan; + case Europe: + return R.string.region_europe; + case Australia: + return R.string.region_australia; + case Korean: + return R.string.region_korean; + case Taiwan: + return R.string.region_taiwan; + } + return R.string.unknown; + } } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Shape.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Shape.java deleted file mode 100644 index 1f956241..00000000 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/math/Shape.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.panda3ds.pandroid.math; - -public class Shape { - public int x = 0, y = 0, width = 1, height = 1; - - public Shape() { - } - - public Shape(int x, int y, int width, int height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - } - - public void move(int x, int y) { - this.x += x; - this.y += y; - } - - public void normalize() { - this.x = Math.max(x, 0); - this.y = Math.max(y, 0); - this.width = Math.max(width, 1); - this.height = Math.max(height, 1); - } - - public void maxSize(int w, int h) { - this.width = Math.max(w, this.width); - this.height = Math.max(h, this.height); - } -} diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/CompatUtils.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/CompatUtils.java new file mode 100644 index 00000000..a125ea8a --- /dev/null +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/CompatUtils.java @@ -0,0 +1,38 @@ +package com.panda3ds.pandroid.utils; + +import android.app.Activity; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.util.TypedValue; + +import androidx.annotation.AttrRes; + +import com.panda3ds.pandroid.app.PandroidApplication; + +public class CompatUtils { + public static Activity findActivity(Context context) { + if (context instanceof Activity) { + return (Activity) context; + } else if ((context instanceof ContextWrapper)) { + return findActivity(((ContextWrapper) context).getBaseContext()); + } + return ((Activity) context); + } + + public static int resolveColor(Context context, @AttrRes int id){ + try { + TypedArray values = context.obtainStyledAttributes(new int[]{id}); + int color = values.getColor(0, Color.RED); + values.recycle(); + return color; + } catch (Exception e){ + return Color.rgb(255,0,255); + } + } + + public static float applyDimen(int unit, int size) { + return TypedValue.applyDimension(unit, size, PandroidApplication.getAppContext().getResources().getDisplayMetrics()); + } +} diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/FileUtils.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/FileUtils.java index bec8bae3..7455613a 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/FileUtils.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/FileUtils.java @@ -24,7 +24,6 @@ import java.util.Objects; public class FileUtils { public static final String MODE_READ = "r"; private static final String TREE_URI = "tree"; - public static final int CANONICAL_SEARCH_DEEP = 8; private static DocumentFile parseFile(String path) { if (path.startsWith("/")) { @@ -204,47 +203,6 @@ public class FileUtils { getContext().getContentResolver().takePersistableUriPermission(Uri.parse(uri), flags); } - /** - * When call ContentProvider.openFileDescriptor() android opens a file descriptor - * on app process in /proc/self/fd/[file descriptor id] this is a link to real file path - * can use File.getCanonicalPath() for get a link origin, but in some android version - * need use Os.readlink(path) to get a real path. - */ - public static String obtainRealPath(String uri) { - try { - ParcelFileDescriptor parcelDescriptor = getContext().getContentResolver().openFileDescriptor(Uri.parse(uri), "r"); - int fd = parcelDescriptor.getFd(); - File file = new File("/proc/self/fd/" + fd).getAbsoluteFile(); - - for (int i = 0; i < CANONICAL_SEARCH_DEEP; i++) { - try { - String canonical = file.getCanonicalPath(); - if (!Objects.equals(canonical, file.getAbsolutePath())) { - file = new File(canonical).getAbsoluteFile(); - } - } catch (Exception x) { - break; - } - } - - if (!file.getAbsolutePath().startsWith("/proc/self/")) { - parcelDescriptor.close(); - return file.getAbsolutePath(); - } - - String path = Os.readlink(file.getAbsolutePath()); - parcelDescriptor.close(); - - if (new File(path).exists()) { - return path; - } - - return null; - } catch (Exception e) { - return null; - } - } - public static void updateFile(String path) { DocumentFile file = parseFile(path); Uri uri = file.getUri(); diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/GameUtils.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/GameUtils.java index 41e26537..02b9a59e 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/GameUtils.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/utils/GameUtils.java @@ -21,7 +21,7 @@ import java.util.Objects; public class GameUtils { private static final Bitmap DEFAULT_ICON = Bitmap.createBitmap(48, 48, Bitmap.Config.ARGB_8888); - private static GsonConfigParser parser = new GsonConfigParser(Constants.PREF_GAME_UTILS); + private final static GsonConfigParser parser = new GsonConfigParser(Constants.PREF_GAME_UTILS); private static DataModel data; diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/Bounds.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/Bounds.java new file mode 100644 index 00000000..51f4d51f --- /dev/null +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/Bounds.java @@ -0,0 +1,46 @@ +package com.panda3ds.pandroid.view.ds; + +import android.graphics.Rect; + +class Bounds { + public int left = 0; + public int right = 0; + public int top = 0; + public int bottom = 0; + + public void normalize(){ + left = Math.abs(left); + right = Math.abs(right); + top = Math.abs(top); + bottom = Math.abs(bottom); + } + + public void applyWithAspect(Rect rect, int width, double aspectRatio){ + normalize(); + rect.set(left, top, width-right, (int) Math.round((width-right-left)*aspectRatio)+top); + } + + public void apply(Rect rect, int width, int height){ + normalize(); + rect.set(left, top, width-right, height-bottom); + } + + public void move(int x, int y){ + left += x; + right -= x; + + top += y; + bottom -= y; + normalize(); + } + + public void fixOverlay(int width, int height, int size) { + if (left > (width-right) - size){ + right = (width-left) - size; + } + if (top > (height - bottom) - size){ + bottom = (height - top) - size; + } + normalize(); + } +} \ No newline at end of file diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/DsEditorView.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/DsEditorView.java index ae98faa7..dbe0562c 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/DsEditorView.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/DsEditorView.java @@ -26,14 +26,14 @@ import androidx.appcompat.widget.AppCompatTextView; import com.google.android.material.checkbox.MaterialCheckBox; import com.panda3ds.pandroid.R; -import com.panda3ds.pandroid.math.Shape; import com.panda3ds.pandroid.math.Vector2; +import com.panda3ds.pandroid.utils.CompatUtils; import com.panda3ds.pandroid.utils.Constants; public class DsEditorView extends FrameLayout { - private static final int COLOR_TOP_SELECTION = Color.RED; - private static final int COLOR_BOTTOM_SELECTION = Color.BLUE; + private final int COLOR_TOP_SELECTION; + private final int COLOR_BOTTOM_SELECTION; private final float SIZE_DP; private final Paint selectionPaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -53,8 +53,9 @@ public class DsEditorView extends FrameLayout { public DsEditorView(Context context, int index) { super(context); layout = (DsLayout) DsLayoutManager.createLayout(index); - - SIZE_DP = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics()); + SIZE_DP = CompatUtils.applyDimen(TypedValue.COMPLEX_UNIT_DIP, 1); + COLOR_BOTTOM_SELECTION = CompatUtils.resolveColor(context, androidx.appcompat.R.attr.colorPrimary); + COLOR_TOP_SELECTION = CompatUtils.resolveColor(context, com.google.android.material.R.attr.colorAccent); selectionPaint.setColor(COLOR_TOP_SELECTION); selectionPaint.setStrokeWidth(SIZE_DP * 2); @@ -105,16 +106,11 @@ public class DsEditorView extends FrameLayout { }); } - { - aspectRatioFixLayout = (LinearLayout) inflater.inflate(R.layout.ds_editor_lock_aspect, this, false); - ((MaterialCheckBox) aspectRatioFixLayout.findViewById(R.id.checkbox)).setOnCheckedChangeListener((buttonView, checked) -> { - layout.getCurrentModel().lockAspect = checked; - if (checked) { - fixAspect(); - } - refreshPoints(); - }); - } + aspectRatioFixLayout = (LinearLayout) inflater.inflate(R.layout.ds_editor_lock_aspect, this, false); + ((MaterialCheckBox) aspectRatioFixLayout.findViewById(R.id.checkbox)).setOnCheckedChangeListener((buttonView, checked) -> { + layout.getCurrentModel().lockAspect = checked; + refreshPoints(); + }); spacePoint = new PointView(); spacePoint.setColor(Color.WHITE, COLOR_TOP_SELECTION); @@ -136,11 +132,13 @@ public class DsEditorView extends FrameLayout { topDisplay = new PointView(); topDisplay.setText(R.string.top_display); topDisplay.setOnTouchListener(new DisplayTouchEvent(true)); + topDisplay.setTextColor(COLOR_TOP_SELECTION); topDisplay.setBackground(new SelectionDrawable(COLOR_TOP_SELECTION)); bottomDisplay = new PointView(); bottomDisplay.setText(R.string.bottom_display); bottomDisplay.setOnTouchListener(new DisplayTouchEvent(false)); + bottomDisplay.setTextColor(COLOR_BOTTOM_SELECTION); bottomDisplay.setBackground(new SelectionDrawable(COLOR_BOTTOM_SELECTION)); topDisplayResizer = new PointView(); @@ -164,16 +162,10 @@ public class DsEditorView extends FrameLayout { } } - private void fixAspect() { - Shape top = layout.getCurrentModel().preferredTop; - Shape bottom = layout.getCurrentModel().preferredBottom; - - top.height = (int) (((float) top.width / Constants.N3DS_WIDTH) * Constants.N3DS_HALF_HEIGHT); - bottom.height = (int) (((float) bottom.width / (Constants.N3DS_WIDTH - 80)) * Constants.N3DS_HALF_HEIGHT); - } - private void refreshPoints() { Model data = layout.getCurrentModel(); + data.preferredTop.fixOverlay(width, height, (int) (SIZE_DP*5)); + data.preferredBottom.fixOverlay(width, height, (int) (SIZE_DP*30)); layout.update(width, height); Rect bottomDisplay = layout.getBottomDisplayBounds(); Rect topDisplay = layout.getTopDisplayBounds(); @@ -194,9 +186,6 @@ public class DsEditorView extends FrameLayout { break; } - data.preferredTop.maxSize((int) (SIZE_DP * 64), (int) (SIZE_DP * 64)); - data.preferredBottom.maxSize((int) (SIZE_DP * 64), (int) (SIZE_DP * 64)); - this.topDisplay.setSize(topDisplay.width(), topDisplay.height()); this.topDisplay.setPosition(topDisplay.left, topDisplay.top); @@ -305,7 +294,6 @@ public class DsEditorView extends FrameLayout { private class DisplayTouchEvent implements OnTouchListener { private final boolean topScreen; - private final Vector2 inner = new Vector2(0, 0); private Vector2 downEvent = null; private DisplayTouchEvent(boolean topScreen) { @@ -314,66 +302,39 @@ public class DsEditorView extends FrameLayout { @Override public boolean onTouch(View v, MotionEvent event) { - Shape preferred = topScreen ? layout.getCurrentModel().preferredTop : layout.getCurrentModel().preferredBottom; - if (layout.getCurrentModel().mode == Mode.ABSOLUTE) { - PointView point = (PointView) v; - if (event.getAction() != MotionEvent.ACTION_UP) { - if (downEvent == null) { - downEvent = new Vector2(event.getRawX(), event.getRawY()); - inner.set(point.x(), point.y()); - return true; - } - - preferred.x = (int) ((event.getRawX() - downEvent.x) + inner.x); - preferred.y = (int) ((event.getRawY() - downEvent.y) + inner.y); - preferred.normalize(); - - refreshPoints(); - + Bounds preferred = topScreen ? layout.getCurrentModel().preferredTop : layout.getCurrentModel().preferredBottom; + if (layout.getCurrentModel().mode == Mode.ABSOLUTE && event.getAction() != MotionEvent.ACTION_UP) { + if (downEvent == null) { + downEvent = new Vector2(event.getRawX(), event.getRawY()); return true; } - - downEvent = null; - return false; + preferred.move((int) (event.getRawX() - downEvent.x), (int) (event.getRawY() - downEvent.y)); + downEvent.set(event.getRawX(), event.getRawY()); + refreshPoints(); + return true; } else if (layout.getCurrentModel().mode == Mode.SINGLE && event.getAction() == MotionEvent.ACTION_UP) { callOnClick(); } + downEvent = null; return false; } } private class DisplayResizeTouchEvent implements OnTouchListener { private final boolean topScreen; - private final Vector2 size = new Vector2(0, 0); - private Vector2 downEvent = null; - private DisplayResizeTouchEvent(boolean topScreen) { this.topScreen = topScreen; } - @Override public boolean onTouch(View v, MotionEvent event) { - Shape preferred = topScreen ? layout.getCurrentModel().preferredTop : layout.getCurrentModel().preferredBottom; + Bounds preferred = topScreen ? layout.getCurrentModel().preferredTop : layout.getCurrentModel().preferredBottom; if (event.getAction() != MotionEvent.ACTION_UP) { - if (downEvent == null) { - downEvent = new Vector2(event.getRawX(), event.getRawY()); - size.set(preferred.width, preferred.height); - return true; - } - - preferred.width = (int) (size.x + ((event.getRawX() - downEvent.x))); - - if (layout.getCurrentModel().lockAspect) { - fixAspect(); - } else { - preferred.height = (int) (size.y + ((event.getRawY() - downEvent.y))); - } - preferred.maxSize((int) (SIZE_DP * 32), (int) (SIZE_DP * 32)); + preferred.right = (int) (width - (((PointView) v).x() + event.getX())); + preferred.bottom = (int) (height - (((PointView) v).y() + event.getY())); refreshPoints(); return true; } - downEvent = null; return false; } } @@ -389,7 +350,7 @@ public class DsEditorView extends FrameLayout { public void draw(Canvas canvas) { int color = this.getColor(); selectionPaint.setColor(color); - solidPaint.setColor(Color.argb(50, Color.red(color), Color.green(color), Color.blue(color))); + solidPaint.setColor(Color.argb(65, Color.red(color), Color.green(color), Color.blue(color))); canvas.drawRect(this.getBounds(), solidPaint); canvas.drawRect(this.getBounds(), selectionPaint); } diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/DsLayout.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/DsLayout.java index 9f0ea2e5..b9c3d065 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/DsLayout.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/DsLayout.java @@ -3,7 +3,6 @@ package com.panda3ds.pandroid.view.ds; import android.graphics.Rect; import android.view.Gravity; -import com.panda3ds.pandroid.math.Shape; import com.panda3ds.pandroid.math.Vector2; import com.panda3ds.pandroid.view.renderer.layout.ConsoleLayout; @@ -70,14 +69,13 @@ class DsLayout implements ConsoleLayout { } private void absolute(Model data) { - Shape top = data.preferredTop; - Shape bottom = data.preferredBottom; - - top.normalize(); - bottom.normalize(); - - topDisplay.set(top.x, top.y, top.x +top.width, top.y + top.height); - bottomDisplay.set(bottom.x, bottom.y, bottom.x +bottom.width, bottom.y + bottom.height); + if (data.lockAspect){ + data.preferredTop.applyWithAspect(topDisplay, (int) screenSize.x, (double) sourceTop.y/sourceTop.x); + data.preferredBottom.applyWithAspect(bottomDisplay, (int) screenSize.x, (double) sourceBottom.y/sourceBottom.x); + } else { + data.preferredTop.apply(topDisplay, (int) screenSize.x, (int) screenSize.y); + data.preferredBottom.apply(bottomDisplay, (int) screenSize.x, (int) screenSize.y); + } } /** diff --git a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/Model.java b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/Model.java index e2cf0c8a..dfefe7a4 100644 --- a/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/Model.java +++ b/src/pandroid/app/src/main/java/com/panda3ds/pandroid/view/ds/Model.java @@ -5,13 +5,12 @@ import android.view.Gravity; import androidx.annotation.NonNull; -import com.panda3ds.pandroid.math.Shape; import com.panda3ds.pandroid.utils.Constants; class Model implements Cloneable { public Mode mode = Mode.RELATIVE; - public final Shape preferredTop = new Shape(); - public final Shape preferredBottom = new Shape(); + public final Bounds preferredTop = new Bounds(); + public final Bounds preferredBottom = new Bounds(); public boolean reverse = false; public boolean singleTop = true; public float space = 0.6f; diff --git a/src/pandroid/app/src/main/res/layout/dialog_bottom_sheet.xml b/src/pandroid/app/src/main/res/layout/dialog_bottom_sheet.xml new file mode 100644 index 00000000..88124bf1 --- /dev/null +++ b/src/pandroid/app/src/main/res/layout/dialog_bottom_sheet.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/layout/dialog_game_about.xml b/src/pandroid/app/src/main/res/layout/dialog_game_about.xml index 1d4b9017..e07e3d33 100644 --- a/src/pandroid/app/src/main/res/layout/dialog_game_about.xml +++ b/src/pandroid/app/src/main/res/layout/dialog_game_about.xml @@ -6,15 +6,8 @@ android:layout_height="wrap_content" android:orientation="vertical" android:gravity="top|center" - android:padding="10dp" - android:background="@drawable/alert_dialog_background"> + android:padding="10dp"> - - - + \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/layout/games_folder_about.xml b/src/pandroid/app/src/main/res/layout/dialog_games_folder.xml similarity index 93% rename from src/pandroid/app/src/main/res/layout/games_folder_about.xml rename to src/pandroid/app/src/main/res/layout/dialog_games_folder.xml index 5fff79e5..c0b41d8f 100644 --- a/src/pandroid/app/src/main/res/layout/games_folder_about.xml +++ b/src/pandroid/app/src/main/res/layout/dialog_games_folder.xml @@ -5,14 +5,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center|top" - android:padding="10dp" - android:background="@drawable/alert_dialog_background"> - - + android:padding="10dp"> - - + android:layout_height="match_parent" + android:gravity="center"> + android:layout_height="match_parent" + android:paddingHorizontal="20dp" /> \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/layout/ds_editor_spinner.xml b/src/pandroid/app/src/main/res/layout/ds_editor_spinner.xml index ca74e81e..515f917f 100644 --- a/src/pandroid/app/src/main/res/layout/ds_editor_spinner.xml +++ b/src/pandroid/app/src/main/res/layout/ds_editor_spinner.xml @@ -4,6 +4,8 @@ android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:clickable="true" + android:focusable="true" android:padding="4dp"> \ No newline at end of file diff --git a/src/pandroid/app/src/main/res/layout/hold_theme_preview_summary.xml b/src/pandroid/app/src/main/res/layout/hold_theme_preview_base.xml similarity index 92% rename from src/pandroid/app/src/main/res/layout/hold_theme_preview_summary.xml rename to src/pandroid/app/src/main/res/layout/hold_theme_preview_base.xml index ade063bf..9e7a6e6f 100644 --- a/src/pandroid/app/src/main/res/layout/hold_theme_preview_summary.xml +++ b/src/pandroid/app/src/main/res/layout/hold_theme_preview_base.xml @@ -7,13 +7,13 @@ android:paddingVertical="10dp" android:paddingHorizontal="20dp" android:foreground="@drawable/rounded_selectable_item_background" - android:gravity="center"> + android:gravity="top|center"> + android:layout_height="125dp"> @@ -23,6 +23,7 @@ android:layout_height="wrap_content" android:textStyle="bold" android:textSize="16sp" + android:gravity="center" android:layout_margin="10dp" android:text="@string/app_name"/> diff --git a/src/pandroid/app/src/main/res/values-pt-rBR/strings.xml b/src/pandroid/app/src/main/res/values-pt-rBR/strings.xml index 2d2093e6..f6171600 100644 --- a/src/pandroid/app/src/main/res/values-pt-rBR/strings.xml +++ b/src/pandroid/app/src/main/res/values-pt-rBR/strings.xml @@ -75,4 +75,14 @@ Pastas de jogos Adicionar pasta %d Jogos + Diretorio + Remover + Jogar + Região + Estados Unidos + Japão + Europa + Australia + Coréia + Taiwan diff --git a/src/pandroid/app/src/main/res/values/strings.xml b/src/pandroid/app/src/main/res/values/strings.xml index 6684badb..beb5dcb2 100644 --- a/src/pandroid/app/src/main/res/values/strings.xml +++ b/src/pandroid/app/src/main/res/values/strings.xml @@ -83,4 +83,10 @@ Remove Play Region + North American + Japan + Europe + Australia + Korean + Taiwan