Skip to content
This repository was archived by the owner on Mar 12, 2026. It is now read-only.

Commit 7875a10

Browse files
authored
Merge pull request #52 from l3ger0j/master-third-path
Master third path
2 parents 9193f69 + 086e0d8 commit 7875a10

File tree

5 files changed

+72
-36
lines changed

5 files changed

+72
-36
lines changed

app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ android {
1010
applicationId "org.qp.android"
1111
minSdk 26
1212
targetSdk 34
13-
versionCode 202502
14-
versionName "3.25.2"
13+
versionCode 202503
14+
versionName "3.25.3"
1515
resourceConfigurations += ['en', 'ru']
1616
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1717
externalNativeBuild {

app/src/main/java/org/qp/android/helpers/utils/DirUtil.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import com.anggrayudi.storage.file.DocumentFileCompat;
1515
import com.anggrayudi.storage.file.DocumentFileType;
1616
import com.anggrayudi.storage.file.DocumentFileUtils;
17+
import com.anggrayudi.storage.file.MimeType;
1718

1819
import java.util.Collections;
1920
import java.util.List;
@@ -28,12 +29,27 @@ public static boolean isDirContainsGameFile(@NonNull Context context,
2829
@NonNull Uri dirUri) {
2930
var targetDir = DocumentFileCompat.fromUri(context, dirUri);
3031
if (!isWritableDir(context, targetDir)) return false;
31-
var files = DocumentFileUtils.search(targetDir, true, DocumentFileType.FILE);
32+
var files = targetDir.listFiles();
33+
if (files == null || files.length == 0) return false;
34+
3235
for (var file : files) {
3336
var dirExtension = documentWrap(file).getExtension();
3437
var lcName = dirExtension.toLowerCase(Locale.ROOT);
3538
if (lcName.contains("qsp") || lcName.contains("gam")) return true;
3639
}
40+
41+
var allFiles = DocumentFileUtils.search(
42+
targetDir,
43+
true,
44+
DocumentFileType.FILE,
45+
new String[]{MimeType.BINARY_FILE}
46+
);
47+
for (var file : allFiles) {
48+
var dirExtension = documentWrap(file).getExtension();
49+
var lcName = dirExtension.toLowerCase(Locale.ROOT);
50+
if (lcName.contains("qsp") || lcName.contains("gam")) return true;
51+
}
52+
3753
return false;
3854
}
3955

app/src/main/java/org/qp/android/model/repository/LocalGame.java

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.nio.file.Files;
3333
import java.nio.file.Path;
3434
import java.util.ArrayList;
35+
import java.util.Arrays;
3536
import java.util.Collections;
3637
import java.util.List;
3738
import java.util.Locale;
@@ -136,17 +137,34 @@ public boolean searchAndWriteFileInfo(DocumentFile rootDir, GameData data) {
136137
return false;
137138
}
138139

139-
var gameFiles = Collections.synchronizedList(new ArrayList<Uri>());
140-
var files = DocumentFileUtils.search(rootDir, true, DocumentFileType.FILE);
140+
var files = rootDir.listFiles();
141+
if (files == null || files.length == 0) return false;
141142

142-
files.parallelStream().forEach(d -> {
143+
var gameFiles = Collections.synchronizedList(new ArrayList<Uri>());
144+
Arrays.stream(files).forEach(d -> {
143145
var dirExtension = documentWrap(d).getExtension();
144146
var lcName = dirExtension.toLowerCase(Locale.ROOT);
145147
if (lcName.endsWith("qsp") || lcName.endsWith("gam")) {
146148
gameFiles.add(d.getUri());
147149
}
148150
});
149151

152+
if (gameFiles.isEmpty()) {
153+
var allFiles = DocumentFileUtils.search(
154+
rootDir,
155+
true,
156+
DocumentFileType.FILE,
157+
new String[]{MimeType.BINARY_FILE}
158+
);
159+
allFiles.forEach(d -> {
160+
var dirExtension = documentWrap(d).getExtension();
161+
var lcName = dirExtension.toLowerCase(Locale.ROOT);
162+
if (lcName.endsWith("qsp") || lcName.endsWith("gam")) {
163+
gameFiles.add(d.getUri());
164+
}
165+
});
166+
}
167+
150168
if (!Objects.equals(data.gameDirUri.getPath(), rootDir.getUri().getPath())) {
151169
data.gameDirUri = rootDir.getUri();
152170
}
@@ -166,7 +184,6 @@ public List<GameData> lightExtractDataFromDir(File generalGamesDir) throws IOExc
166184
return Collections.emptyList();
167185
}
168186

169-
var itemsGamesDirs = Collections.synchronizedList(new ArrayList<GameData>());
170187
var subRootDir = Collections.synchronizedList(new ArrayList<File>());
171188
synchronized (subRootDir) {
172189
try (var walk = Files.walk(generalGamesDir.toPath(), 1)) {
@@ -178,26 +195,37 @@ public List<GameData> lightExtractDataFromDir(File generalGamesDir) throws IOExc
178195
}
179196
}
180197

181-
synchronized (itemsGamesDirs) {
198+
var subInfosFiles = Collections.synchronizedList(new ArrayList<File>());
199+
synchronized (subInfosFiles) {
182200
for (var dir : subRootDir) {
183-
if (!isWritableDir(context, dir)) {
201+
try (var walk = Files.walk(dir.toPath())) {
202+
walk.map(Path::toFile)
203+
.filter(f -> f.isFile() && f.getPath().contains(GAME_INFO_FILENAME))
204+
.forEach(subInfosFiles::add);
205+
} catch (IOException e) {
206+
return Collections.emptyList();
207+
}
208+
}
209+
}
210+
211+
var itemsGamesDirs = Collections.synchronizedList(new ArrayList<GameData>());
212+
synchronized (itemsGamesDirs) {
213+
for (var infos : subInfosFiles) {
214+
if (!isWritableFile(context, infos)) {
184215
continue;
185216
}
186217
var item = (GameData) null;
187-
var infoFile = fromRelPath(GAME_INFO_FILENAME, dir);
188-
if (isWritableFile(context, infoFile)) {
189-
var infoFileCont = readFileAsString(infoFile);
190-
if (isNotEmptyOrBlank(infoFileCont)) {
191-
try {
192-
item = parseGameInfo(infoFileCont);
193-
} catch (IOException e) {
194-
continue;
195-
}
196-
}
197-
if (item != null) {
198-
itemsGamesDirs.add(item);
218+
var infoFileCont = readFileAsString(infos);
219+
if (isNotEmptyOrBlank(infoFileCont)) {
220+
try {
221+
item = parseGameInfo(infoFileCont);
222+
} catch (IOException e) {
223+
continue;
199224
}
200225
}
226+
if (item != null) {
227+
itemsGamesDirs.add(item);
228+
}
201229
}
202230
}
203231

app/src/main/java/org/qp/android/ui/stock/StockActivity.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import static org.qp.android.helpers.utils.FileUtil.findOrCreateFile;
55
import static org.qp.android.helpers.utils.JsonUtil.jsonToObject;
66
import static org.qp.android.helpers.utils.JsonUtil.objectToJson;
7+
import static org.qp.android.helpers.utils.StringUtil.isNotEmptyOrBlank;
78
import static org.qp.android.helpers.utils.XmlUtil.objectToXml;
89
import static org.qp.android.helpers.utils.XmlUtil.xmlToObject;
910
import static org.qp.android.ui.stock.StockViewModel.CODE_PICK_IMAGE_FILE;
@@ -80,7 +81,6 @@
8081
import java.util.Locale;
8182
import java.util.Objects;
8283
import java.util.Optional;
83-
import java.util.stream.Collectors;
8484

8585
import info.hannes.changelog.ChangeLog;
8686
import okhttp3.ResponseBody;
@@ -578,11 +578,11 @@ public boolean onQueryTextSubmit(String query) {
578578

579579
@Override
580580
public boolean onQueryTextChange(String newText) {
581-
var gameDataList = stockViewModel.getSortedGames();
581+
var gameDataList = stockViewModel.getGamesMap().values();
582582
stockViewModel.setDataList(
583583
gameDataList.stream()
584-
.filter(d -> d.title.toLowerCase().contains(newText.toLowerCase()))
585-
.collect(Collectors.toList())
584+
.filter(r -> isNotEmptyOrBlank(r.title) && r.title.toLowerCase().contains(newText.toLowerCase()))
585+
.toList()
586586
);
587587
return true;
588588
}

app/src/main/java/org/qp/android/ui/stock/StockViewModel.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -180,16 +180,6 @@ private SettingsController getController() {
180180
return SettingsController.newInstance(getApplication());
181181
}
182182

183-
@NonNull
184-
public List<GameData> getSortedGames() {
185-
var unsortedGameData = gamesMap.values();
186-
var gameData = new ArrayList<>(unsortedGameData);
187-
if (gameData.size() < 2) return gameData;
188-
gameData.sort(Comparator.comparing(game -> game.title.toLowerCase()));
189-
gameData.sort(Comparator.comparing(game -> game.listId));
190-
return gameData;
191-
}
192-
193183
public Optional<GameData> getCurrGameData() {
194184
return Optional.ofNullable(currGameData);
195185
}
@@ -475,7 +465,7 @@ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
475465

476466
@Override
477467
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
478-
tempList.addAll(getSortedGames());
468+
tempList.addAll(gamesMap.values());
479469
isEnableDeleteMode = true;
480470
return true;
481471
}
@@ -838,6 +828,7 @@ private void syncFromDisk() {
838828
if (syncDataList.size() < 2) return syncDataList;
839829
synchronized (syncDataList) {
840830
return syncDataList.stream()
831+
.filter(game -> isNotEmptyOrBlank(game.title))
841832
.sorted(Comparator.comparing(game -> game.title.toLowerCase()))
842833
.sorted(Comparator.comparing(game -> game.listId))
843834
.filter(this::isGameInstalled)
@@ -871,6 +862,7 @@ private void syncRemote() {
871862
if (syncDataList.size() < 2) return syncDataList;
872863
synchronized (syncDataList) {
873864
return syncDataList.stream()
865+
.filter(game -> isNotEmptyOrBlank(game.title))
874866
.sorted(Comparator.comparing(game -> game.title.toLowerCase()))
875867
.filter(d -> !isGameInstalled(d))
876868
.toList();

0 commit comments

Comments
 (0)