diff --git a/app/src/main/java/org/qp/android/model/archive/ArchiveUnpack.java b/app/src/main/java/org/qp/android/model/archive/ArchiveUnpack.java index 53497814..2ef8bec3 100644 --- a/app/src/main/java/org/qp/android/model/archive/ArchiveUnpack.java +++ b/app/src/main/java/org/qp/android/model/archive/ArchiveUnpack.java @@ -5,6 +5,7 @@ import android.content.Context; import android.util.Log; +import android.widget.Toast; import androidx.annotation.NonNull; @@ -38,7 +39,26 @@ public class ArchiveUnpack { private final Context context; private final File targetArchive; private File destFolder; +private String gameTitle; + public ArchiveUnpack(@NonNull Context context, + @NonNull File targetArchive, + @NonNull File destFolder, + String gameTitle) { + this.context = context; + this.targetArchive = targetArchive; + this.gameTitle =gameTitle; + if(gameTitle!=null) { + this.destFolder = findOrCreateFolder(context, destFolder, gameTitle); + this.unpackFolder=this.destFolder; + } + else this.destFolder = destFolder; + } + public ArchiveUnpack(@NonNull Context context, + @NonNull File targetArchive, + @NonNull File destFolder) { + this(context,targetArchive,destFolder,null); + } @NonNull private static int[] getPrimitiveLongArrayFromInt(Set input) { int[] ret = new int[input.size()]; @@ -49,14 +69,26 @@ private static int[] getPrimitiveLongArrayFromInt(Set input) { return ret; } - public ArchiveUnpack(@NonNull Context context, - @NonNull File targetArchive, - @NonNull File destFolder) { - this.context = context; - this.targetArchive = targetArchive; - this.destFolder = destFolder; + private void expandFolderWithGame(File dir) { + File it = dir; + File rootDirForDeletion=null; + while (true) { + File[] files = it.listFiles(); + if (files.length != 1 || !files[0].isDirectory()) { + break; + } + it = files[0]; + if(rootDirForDeletion==null) rootDirForDeletion=files[0]; //Если уровень вложенности папок больше,чем один,мы должны удалить целую вложенную папку,а не только папку на последнем уровне вложенности. } - + if (it == dir) { + return; + } + for (File file : it.listFiles()) { + File dest = new File(dir.getAbsolutePath(), file.getName()); + file.renameTo(dest); + } + rootDirForDeletion.delete(); +} public void extractArchiveEntries() { assertNonUiThread(); @@ -67,18 +99,15 @@ public void extractArchiveEntries() { var fileNames = new HashMap(); for (int ind = 0; ind < itemCount; ind++) { var fileName = inArchive.getStringProperty(ind, PropID.PATH); - if (fileName.endsWith(".qsp") || fileName.endsWith(".gam")) { - if (fileName.split("/").length == 1) { + //Прошлый код некоректно работал в игре 7.40,т.к там несколько qsp файлов. Вообще я не вижу смысла в этом коде и предлагаю использовать имя игры как название папки. + if (fileName.split("/").length == 1 &&gameTitle ==null &&(fileName.endsWith(".qsp") || fileName.endsWith(".gam"))) { var archiveName = targetArchive.getName(); var pattern = Pattern.compile(".(?:r\\d\\d|r\\d\\d\\d|rar|zip|aqsp)"); var folderName = pattern.matcher(archiveName).replaceAll(""); - if (fileName.split("/").length == 1) { destFolder = findOrCreateFolder(context, destFolder, folderName); unpackFolder = destFolder; - } } - } - if (unpackFolder == null && ind == itemCount - 1) { + if (unpackFolder == null && ind == itemCount - 1) { unpackFolder = new File(destFolder, fileName); } Log.d(TAG, "index: "+ind+"\nfilename: "+fileName+"\nitemCount: "+itemCount); @@ -93,6 +122,7 @@ public void extractArchiveEntries() { false, new ArchiveExtractCallback(destFolder, inArchive) ); +expandFolderWithGame(destFolder); } catch (IOException e) { Log.e(TAG, "", e); } diff --git a/app/src/main/java/org/qp/android/ui/game/GameItemRecycler.java b/app/src/main/java/org/qp/android/ui/game/GameItemRecycler.java index 90bc77f4..4d07f7cd 100644 --- a/app/src/main/java/org/qp/android/ui/game/GameItemRecycler.java +++ b/app/src/main/java/org/qp/android/ui/game/GameItemRecycler.java @@ -1,12 +1,16 @@ package org.qp.android.ui.game; import android.graphics.Typeface; +import android.os.Bundle; import android.text.Html; import android.util.TypedValue; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityNodeInfo; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.databinding.DataBindingUtil; import androidx.recyclerview.widget.AsyncListDiffer; import androidx.recyclerview.widget.DiffUtil; @@ -124,6 +128,14 @@ public static class ViewHolder extends RecyclerView.ViewHolder { ViewHolder(ListGameItemBinding binding){ super(binding.getRoot()); this.listGameItemBinding = binding; + //Аналогично,как мы сделали для полки игр. Вообще,на мой взгляд,этот делегат можно вынести отдельно,чтобы избежать дублирования кода. + this.listGameItemBinding.relativeLayout.setAccessibilityDelegate(new View.AccessibilityDelegate() { + @Override + public boolean performAccessibilityAction(@NonNull View host, int action, @Nullable Bundle args) { + if(action== AccessibilityNodeInfo.ACTION_CLICK) return host.performClick(); else if(action==AccessibilityNodeInfo.ACTION_LONG_CLICK) return host.performLongClick(); + return super.performAccessibilityAction(host, action, args); + } + }); } public void listItemActionObjectBinding(LibListItem libListItem) { diff --git a/app/src/main/java/org/qp/android/ui/stock/GamesListAdapter.java b/app/src/main/java/org/qp/android/ui/stock/GamesListAdapter.java index 3c0d1770..a564bd18 100644 --- a/app/src/main/java/org/qp/android/ui/stock/GamesListAdapter.java +++ b/app/src/main/java/org/qp/android/ui/stock/GamesListAdapter.java @@ -4,11 +4,15 @@ import android.content.Context; import android.net.Uri; +import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityNodeInfo; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.databinding.DataBindingUtil; import androidx.recyclerview.widget.AsyncListDiffer; import androidx.recyclerview.widget.DiffUtil; @@ -122,7 +126,15 @@ public static class GameHolder extends RecyclerView.ViewHolder { GameHolder(ListItemGameBinding listItemGameBinding){ super(listItemGameBinding.getRoot()); this.listItemGameBinding = listItemGameBinding; - } + //Если у родительской ноды одна дочерняя нода,то эта нода игнорируется и родительской нодой становится дочерняя нода. Так происходит до тех пор,пока у родительской ноды нее появятся дочерние ноды. В этом случае фреймворк отлавливает нажатие на эту ноду,или на дочерние ноды. Примерно так,на мой взгляд,это работает. + this.listItemGameBinding.relativeLayout.setAccessibilityDelegate(new View.AccessibilityDelegate() { + @Override + public boolean performAccessibilityAction(@NonNull View host, int action, @Nullable Bundle args) { + if(action== AccessibilityNodeInfo.ACTION_CLICK) return host.performClick(); else if(action==AccessibilityNodeInfo.ACTION_LONG_CLICK) return host.performLongClick(); + return super.performAccessibilityAction(host, action, args); + } +}); + } public void listItemGameBinding(GameData gameData) { listItemGameBinding.setGameData(gameData); diff --git a/app/src/main/java/org/qp/android/ui/stock/StockRecyclerFragment.java b/app/src/main/java/org/qp/android/ui/stock/StockRecyclerFragment.java index 0e693032..bf2136f6 100644 --- a/app/src/main/java/org/qp/android/ui/stock/StockRecyclerFragment.java +++ b/app/src/main/java/org/qp/android/ui/stock/StockRecyclerFragment.java @@ -5,7 +5,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.accessibility.AccessibilityNodeInfo; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -29,7 +28,7 @@ public View onCreateView(@NonNull LayoutInflater inflater , @Nullable Bundle savedInstanceState) { var recyclerBinding = FragmentRecyclerBinding.inflate(inflater); mRecyclerView = recyclerBinding.shareRecyclerView; - mRecyclerView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); + //mRecyclerView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); //Не обязательная строка. stockViewModel = new ViewModelProvider(requireActivity()).get(StockViewModel.class); stockViewModel.getGameDataList().observe(getViewLifecycleOwner(), item -> { @@ -88,17 +87,5 @@ public void onLongItemClick(View view, int position) { stockViewModel.doOnShowActionMode(); } })); - mRecyclerView.setAccessibilityDelegate(new View.AccessibilityDelegate() { - @Override - public boolean performAccessibilityAction(@NonNull View host , - int action , - @Nullable Bundle args) { - switch (action) { - case AccessibilityNodeInfo.ACTION_CLICK -> host.performClick(); - case AccessibilityNodeInfo.ACTION_LONG_CLICK -> host.performLongClick(); - } - return super.performAccessibilityAction(host , action , args); - } - }); } -} + } \ No newline at end of file diff --git a/app/src/main/java/org/qp/android/ui/stock/StockViewModel.java b/app/src/main/java/org/qp/android/ui/stock/StockViewModel.java index 7a86317b..abb2c0a3 100644 --- a/app/src/main/java/org/qp/android/ui/stock/StockViewModel.java +++ b/app/src/main/java/org/qp/android/ui/stock/StockViewModel.java @@ -953,8 +953,8 @@ public void postProcessingDownload() { var archiveUnpack = new ArchiveUnpack( getApplication(), archive, - rootInDir - ); + rootInDir, + getGameTitle()); CompletableFuture .runAsync(archiveUnpack::extractArchiveEntries, executor) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 611b3335..757cf32c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,7 +24,7 @@ recyclerview = "1.3.2" retrofit = "2.11.0" rxandroid = "3.0.2" staxApi = "1.0-2" -storage = "1.5.5" +storage = "1.5.6" webkit = "1.11.0" woodstoxCore = "6.6.2" workRuntime = "2.9.1"