mirror of
https://git.suyu.dev/suyu/suyu
synced 2024-12-25 19:02:45 -06:00
android: Convert GameDatabase to Kotlin
This commit is contained in:
parent
bbe5dee9f8
commit
4ce86a526c
2 changed files with 260 additions and 275 deletions
|
@ -1,275 +0,0 @@
|
||||||
package org.yuzu.yuzu_emu.model;
|
|
||||||
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary;
|
|
||||||
import org.yuzu.yuzu_emu.utils.FileUtil;
|
|
||||||
import org.yuzu.yuzu_emu.utils.Log;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import rx.Observable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A helper class that provides several utilities simplifying interaction with
|
|
||||||
* the SQLite database.
|
|
||||||
*/
|
|
||||||
public final class GameDatabase extends SQLiteOpenHelper {
|
|
||||||
public static final int COLUMN_DB_ID = 0;
|
|
||||||
public static final int GAME_COLUMN_PATH = 1;
|
|
||||||
public static final int GAME_COLUMN_TITLE = 2;
|
|
||||||
public static final int GAME_COLUMN_DESCRIPTION = 3;
|
|
||||||
public static final int GAME_COLUMN_REGIONS = 4;
|
|
||||||
public static final int GAME_COLUMN_GAME_ID = 5;
|
|
||||||
public static final int GAME_COLUMN_CAPTION = 6;
|
|
||||||
public static final int FOLDER_COLUMN_PATH = 1;
|
|
||||||
public static final String KEY_DB_ID = "_id";
|
|
||||||
public static final String KEY_GAME_PATH = "path";
|
|
||||||
public static final String KEY_GAME_TITLE = "title";
|
|
||||||
public static final String KEY_GAME_DESCRIPTION = "description";
|
|
||||||
public static final String KEY_GAME_REGIONS = "regions";
|
|
||||||
public static final String KEY_GAME_ID = "game_id";
|
|
||||||
public static final String KEY_GAME_COMPANY = "company";
|
|
||||||
public static final String KEY_FOLDER_PATH = "path";
|
|
||||||
public static final String TABLE_NAME_FOLDERS = "folders";
|
|
||||||
public static final String TABLE_NAME_GAMES = "games";
|
|
||||||
private static final int DB_VERSION = 2;
|
|
||||||
private static final String TYPE_PRIMARY = " INTEGER PRIMARY KEY";
|
|
||||||
private static final String TYPE_INTEGER = " INTEGER";
|
|
||||||
private static final String TYPE_STRING = " TEXT";
|
|
||||||
|
|
||||||
private static final String CONSTRAINT_UNIQUE = " UNIQUE";
|
|
||||||
|
|
||||||
private static final String SEPARATOR = ", ";
|
|
||||||
|
|
||||||
private static final String SQL_CREATE_GAMES = "CREATE TABLE " + TABLE_NAME_GAMES + "("
|
|
||||||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR
|
|
||||||
+ KEY_GAME_PATH + TYPE_STRING + SEPARATOR
|
|
||||||
+ KEY_GAME_TITLE + TYPE_STRING + SEPARATOR
|
|
||||||
+ KEY_GAME_DESCRIPTION + TYPE_STRING + SEPARATOR
|
|
||||||
+ KEY_GAME_REGIONS + TYPE_STRING + SEPARATOR
|
|
||||||
+ KEY_GAME_ID + TYPE_STRING + SEPARATOR
|
|
||||||
+ KEY_GAME_COMPANY + TYPE_STRING + ")";
|
|
||||||
|
|
||||||
private static final String SQL_CREATE_FOLDERS = "CREATE TABLE " + TABLE_NAME_FOLDERS + "("
|
|
||||||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR
|
|
||||||
+ KEY_FOLDER_PATH + TYPE_STRING + CONSTRAINT_UNIQUE + ")";
|
|
||||||
|
|
||||||
private static final String SQL_DELETE_FOLDERS = "DROP TABLE IF EXISTS " + TABLE_NAME_FOLDERS;
|
|
||||||
private static final String SQL_DELETE_GAMES = "DROP TABLE IF EXISTS " + TABLE_NAME_GAMES;
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
public GameDatabase(Context context) {
|
|
||||||
// Superclass constructor builds a database or uses an existing one.
|
|
||||||
super(context, "games.db", null, DB_VERSION);
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(SQLiteDatabase database) {
|
|
||||||
Log.debug("[GameDatabase] GameDatabase - Creating database...");
|
|
||||||
|
|
||||||
execSqlAndLog(database, SQL_CREATE_GAMES);
|
|
||||||
execSqlAndLog(database, SQL_CREATE_FOLDERS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) {
|
|
||||||
Log.verbose("[GameDatabase] Downgrades not supporting, clearing databases..");
|
|
||||||
execSqlAndLog(database, SQL_DELETE_FOLDERS);
|
|
||||||
execSqlAndLog(database, SQL_CREATE_FOLDERS);
|
|
||||||
|
|
||||||
execSqlAndLog(database, SQL_DELETE_GAMES);
|
|
||||||
execSqlAndLog(database, SQL_CREATE_GAMES);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
|
|
||||||
Log.info("[GameDatabase] Upgrading database from schema version " + oldVersion + " to " +
|
|
||||||
newVersion);
|
|
||||||
|
|
||||||
// Delete all the games
|
|
||||||
execSqlAndLog(database, SQL_DELETE_GAMES);
|
|
||||||
execSqlAndLog(database, SQL_CREATE_GAMES);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetDatabase(SQLiteDatabase database) {
|
|
||||||
execSqlAndLog(database, SQL_DELETE_FOLDERS);
|
|
||||||
execSqlAndLog(database, SQL_CREATE_FOLDERS);
|
|
||||||
|
|
||||||
execSqlAndLog(database, SQL_DELETE_GAMES);
|
|
||||||
execSqlAndLog(database, SQL_CREATE_GAMES);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void scanLibrary(SQLiteDatabase database) {
|
|
||||||
// Before scanning known folders, go through the game table and remove any entries for which the file itself is missing.
|
|
||||||
Cursor fileCursor = database.query(TABLE_NAME_GAMES,
|
|
||||||
null, // Get all columns.
|
|
||||||
null, // Get all rows.
|
|
||||||
null,
|
|
||||||
null, // No grouping.
|
|
||||||
null,
|
|
||||||
null); // Order of games is irrelevant.
|
|
||||||
|
|
||||||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row.
|
|
||||||
fileCursor.moveToPosition(-1);
|
|
||||||
|
|
||||||
while (fileCursor.moveToNext()) {
|
|
||||||
String gamePath = fileCursor.getString(GAME_COLUMN_PATH);
|
|
||||||
File game = new File(gamePath);
|
|
||||||
|
|
||||||
if (!game.exists()) {
|
|
||||||
database.delete(TABLE_NAME_GAMES,
|
|
||||||
KEY_DB_ID + " = ?",
|
|
||||||
new String[]{Long.toString(fileCursor.getLong(COLUMN_DB_ID))});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a cursor listing all the folders the user has added to the library.
|
|
||||||
Cursor folderCursor = database.query(TABLE_NAME_FOLDERS,
|
|
||||||
null, // Get all columns.
|
|
||||||
null, // Get all rows.
|
|
||||||
null,
|
|
||||||
null, // No grouping.
|
|
||||||
null,
|
|
||||||
null); // Order of folders is irrelevant.
|
|
||||||
|
|
||||||
Set<String> allowedExtensions = new HashSet<String>(Arrays.asList(
|
|
||||||
".xci", ".nsp", ".nca", ".nro"));
|
|
||||||
|
|
||||||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row.
|
|
||||||
folderCursor.moveToPosition(-1);
|
|
||||||
|
|
||||||
// Iterate through all results of the DB query (i.e. all folders in the library.)
|
|
||||||
while (folderCursor.moveToNext()) {
|
|
||||||
String folderPath = folderCursor.getString(FOLDER_COLUMN_PATH);
|
|
||||||
|
|
||||||
Uri folderUri = Uri.parse(folderPath);
|
|
||||||
// If the folder is empty because it no longer exists, remove it from the library.
|
|
||||||
if (FileUtil.listFiles(context, folderUri).length == 0) {
|
|
||||||
Log.error(
|
|
||||||
"[GameDatabase] Folder no longer exists. Removing from the library: " + folderPath);
|
|
||||||
database.delete(TABLE_NAME_FOLDERS,
|
|
||||||
KEY_DB_ID + " = ?",
|
|
||||||
new String[]{Long.toString(folderCursor.getLong(COLUMN_DB_ID))});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.addGamesRecursive(database, folderUri, allowedExtensions, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
fileCursor.close();
|
|
||||||
folderCursor.close();
|
|
||||||
|
|
||||||
database.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addGamesRecursive(SQLiteDatabase database, Uri parent, Set<String> allowedExtensions, int depth) {
|
|
||||||
if (depth <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure keys are loaded so that ROM metadata can be decrypted.
|
|
||||||
NativeLibrary.ReloadKeys();
|
|
||||||
|
|
||||||
MinimalDocumentFile[] children = FileUtil.listFiles(context, parent);
|
|
||||||
for (MinimalDocumentFile file : children) {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
Set<String> newExtensions = new HashSet<>(Arrays.asList(
|
|
||||||
".xci", ".nsp", ".nca", ".nro"));
|
|
||||||
this.addGamesRecursive(database, file.getUri(), newExtensions, depth - 1);
|
|
||||||
} else {
|
|
||||||
String filename = file.getUri().toString();
|
|
||||||
|
|
||||||
int extensionStart = filename.lastIndexOf('.');
|
|
||||||
if (extensionStart > 0) {
|
|
||||||
String fileExtension = filename.substring(extensionStart);
|
|
||||||
|
|
||||||
// Check that the file has an extension we care about before trying to read out of it.
|
|
||||||
if (allowedExtensions.contains(fileExtension.toLowerCase())) {
|
|
||||||
attemptToAddGame(database, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void attemptToAddGame(SQLiteDatabase database, String filePath) {
|
|
||||||
String name = NativeLibrary.GetTitle(filePath);
|
|
||||||
|
|
||||||
// If the game's title field is empty, use the filename.
|
|
||||||
if (name.isEmpty()) {
|
|
||||||
name = filePath.substring(filePath.lastIndexOf("/") + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
String gameId = NativeLibrary.GetGameId(filePath);
|
|
||||||
|
|
||||||
// If the game's ID field is empty, use the filename without extension.
|
|
||||||
if (gameId.isEmpty()) {
|
|
||||||
gameId = filePath.substring(filePath.lastIndexOf("/") + 1,
|
|
||||||
filePath.lastIndexOf("."));
|
|
||||||
}
|
|
||||||
|
|
||||||
ContentValues game = Game.asContentValues(name,
|
|
||||||
NativeLibrary.GetDescription(filePath).replace("\n", " "),
|
|
||||||
NativeLibrary.GetRegions(filePath),
|
|
||||||
filePath,
|
|
||||||
gameId,
|
|
||||||
NativeLibrary.GetCompany(filePath));
|
|
||||||
|
|
||||||
// Try to update an existing game first.
|
|
||||||
int rowsMatched = database.update(TABLE_NAME_GAMES, // Which table to update.
|
|
||||||
game,
|
|
||||||
// The values to fill the row with.
|
|
||||||
KEY_GAME_ID + " = ?",
|
|
||||||
// The WHERE clause used to find the right row.
|
|
||||||
new String[]{game.getAsString(
|
|
||||||
KEY_GAME_ID)}); // The ? in WHERE clause is replaced with this,
|
|
||||||
// which is provided as an array because there
|
|
||||||
// could potentially be more than one argument.
|
|
||||||
|
|
||||||
// If update fails, insert a new game instead.
|
|
||||||
if (rowsMatched == 0) {
|
|
||||||
Log.verbose("[GameDatabase] Adding game: " + game.getAsString(KEY_GAME_TITLE));
|
|
||||||
database.insert(TABLE_NAME_GAMES, null, game);
|
|
||||||
} else {
|
|
||||||
Log.verbose("[GameDatabase] Updated game: " + game.getAsString(KEY_GAME_TITLE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<Cursor> getGames() {
|
|
||||||
return Observable.create(subscriber ->
|
|
||||||
{
|
|
||||||
Log.info("[GameDatabase] Reading games list...");
|
|
||||||
|
|
||||||
SQLiteDatabase database = getReadableDatabase();
|
|
||||||
Cursor resultCursor = database.query(
|
|
||||||
TABLE_NAME_GAMES,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
KEY_GAME_TITLE + " ASC"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Pass the result cursor to the consumer.
|
|
||||||
subscriber.onNext(resultCursor);
|
|
||||||
|
|
||||||
// Tell the consumer we're done; it will unsubscribe implicitly.
|
|
||||||
subscriber.onCompleted();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void execSqlAndLog(SQLiteDatabase database, String sql) {
|
|
||||||
Log.verbose("[GameDatabase] Executing SQL: " + sql);
|
|
||||||
database.execSQL(sql);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,260 @@
|
||||||
|
package org.yuzu.yuzu_emu.model
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.database.Cursor
|
||||||
|
import android.database.sqlite.SQLiteDatabase
|
||||||
|
import android.database.sqlite.SQLiteOpenHelper
|
||||||
|
import android.net.Uri
|
||||||
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
|
import org.yuzu.yuzu_emu.utils.FileUtil
|
||||||
|
import org.yuzu.yuzu_emu.utils.Log
|
||||||
|
import rx.Observable
|
||||||
|
import rx.Subscriber
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class that provides several utilities simplifying interaction with
|
||||||
|
* the SQLite database.
|
||||||
|
*/
|
||||||
|
class GameDatabase(private val context: Context) :
|
||||||
|
SQLiteOpenHelper(context, "games.db", null, DB_VERSION) {
|
||||||
|
override fun onCreate(database: SQLiteDatabase) {
|
||||||
|
Log.debug("[GameDatabase] GameDatabase - Creating database...")
|
||||||
|
execSqlAndLog(database, SQL_CREATE_GAMES)
|
||||||
|
execSqlAndLog(database, SQL_CREATE_FOLDERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||||
|
Log.verbose("[GameDatabase] Downgrades not supporting, clearing databases..")
|
||||||
|
execSqlAndLog(database, SQL_DELETE_FOLDERS)
|
||||||
|
execSqlAndLog(database, SQL_CREATE_FOLDERS)
|
||||||
|
execSqlAndLog(database, SQL_DELETE_GAMES)
|
||||||
|
execSqlAndLog(database, SQL_CREATE_GAMES)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||||
|
Log.info(
|
||||||
|
"[GameDatabase] Upgrading database from schema version $oldVersion to $newVersion"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Delete all the games
|
||||||
|
execSqlAndLog(database, SQL_DELETE_GAMES)
|
||||||
|
execSqlAndLog(database, SQL_CREATE_GAMES)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetDatabase(database: SQLiteDatabase) {
|
||||||
|
execSqlAndLog(database, SQL_DELETE_FOLDERS)
|
||||||
|
execSqlAndLog(database, SQL_CREATE_FOLDERS)
|
||||||
|
execSqlAndLog(database, SQL_DELETE_GAMES)
|
||||||
|
execSqlAndLog(database, SQL_CREATE_GAMES)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun scanLibrary(database: SQLiteDatabase) {
|
||||||
|
// Before scanning known folders, go through the game table and remove any entries for which the file itself is missing.
|
||||||
|
val fileCursor = database.query(
|
||||||
|
TABLE_NAME_GAMES,
|
||||||
|
null, // Get all columns.
|
||||||
|
null, // Get all rows.
|
||||||
|
null,
|
||||||
|
null, // No grouping.
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
) // Order of games is irrelevant.
|
||||||
|
|
||||||
|
// Possibly overly defensive, but ensures that moveToNext() does not skip a row.
|
||||||
|
fileCursor.moveToPosition(-1)
|
||||||
|
while (fileCursor.moveToNext()) {
|
||||||
|
val gamePath = fileCursor.getString(GAME_COLUMN_PATH)
|
||||||
|
val game = File(gamePath)
|
||||||
|
if (!game.exists()) {
|
||||||
|
database.delete(
|
||||||
|
TABLE_NAME_GAMES,
|
||||||
|
"$KEY_DB_ID = ?",
|
||||||
|
arrayOf(fileCursor.getLong(COLUMN_DB_ID).toString())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a cursor listing all the folders the user has added to the library.
|
||||||
|
val folderCursor = database.query(
|
||||||
|
TABLE_NAME_FOLDERS,
|
||||||
|
null, // Get all columns.
|
||||||
|
null, // Get all rows.
|
||||||
|
null,
|
||||||
|
null, // No grouping.
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
) // Order of folders is irrelevant.
|
||||||
|
|
||||||
|
|
||||||
|
// Possibly overly defensive, but ensures that moveToNext() does not skip a row.
|
||||||
|
folderCursor.moveToPosition(-1)
|
||||||
|
|
||||||
|
// Iterate through all results of the DB query (i.e. all folders in the library.)
|
||||||
|
while (folderCursor.moveToNext()) {
|
||||||
|
val folderPath = folderCursor.getString(FOLDER_COLUMN_PATH)
|
||||||
|
val folderUri = Uri.parse(folderPath)
|
||||||
|
// If the folder is empty because it no longer exists, remove it from the library.
|
||||||
|
if (FileUtil.listFiles(context, folderUri).isEmpty()) {
|
||||||
|
Log.error(
|
||||||
|
"[GameDatabase] Folder no longer exists. Removing from the library: $folderPath"
|
||||||
|
)
|
||||||
|
database.delete(
|
||||||
|
TABLE_NAME_FOLDERS,
|
||||||
|
"$KEY_DB_ID = ?",
|
||||||
|
arrayOf(folderCursor.getLong(COLUMN_DB_ID).toString())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
addGamesRecursive(database, folderUri, Game.extensions, 3)
|
||||||
|
}
|
||||||
|
fileCursor.close()
|
||||||
|
folderCursor.close()
|
||||||
|
database.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addGamesRecursive(
|
||||||
|
database: SQLiteDatabase,
|
||||||
|
parent: Uri,
|
||||||
|
allowedExtensions: Set<String>,
|
||||||
|
depth: Int
|
||||||
|
) {
|
||||||
|
if (depth <= 0)
|
||||||
|
return
|
||||||
|
|
||||||
|
// Ensure keys are loaded so that ROM metadata can be decrypted.
|
||||||
|
NativeLibrary.ReloadKeys()
|
||||||
|
val children = FileUtil.listFiles(context, parent)
|
||||||
|
for (file in children) {
|
||||||
|
if (file.isDirectory) {
|
||||||
|
addGamesRecursive(database, file.uri, Game.extensions, depth - 1)
|
||||||
|
} else {
|
||||||
|
val filename = file.uri.toString()
|
||||||
|
val extensionStart = filename.lastIndexOf('.')
|
||||||
|
if (extensionStart > 0) {
|
||||||
|
val fileExtension = filename.substring(extensionStart)
|
||||||
|
|
||||||
|
// Check that the file has an extension we care about before trying to read out of it.
|
||||||
|
if (allowedExtensions.contains(fileExtension.lowercase(Locale.getDefault()))) {
|
||||||
|
attemptToAddGame(database, filename)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Pass the result cursor to the consumer.
|
||||||
|
|
||||||
|
// Tell the consumer we're done; it will unsubscribe implicitly.
|
||||||
|
val games: Observable<Cursor?>
|
||||||
|
get() = Observable.create { subscriber: Subscriber<in Cursor?> ->
|
||||||
|
Log.info("[GameDatabase] Reading games list...")
|
||||||
|
val database = readableDatabase
|
||||||
|
val resultCursor = database.query(
|
||||||
|
TABLE_NAME_GAMES,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
"$KEY_GAME_TITLE ASC"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Pass the result cursor to the consumer.
|
||||||
|
subscriber.onNext(resultCursor)
|
||||||
|
|
||||||
|
// Tell the consumer we're done; it will unsubscribe implicitly.
|
||||||
|
subscriber.onCompleted()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun execSqlAndLog(database: SQLiteDatabase, sql: String) {
|
||||||
|
Log.verbose("[GameDatabase] Executing SQL: $sql")
|
||||||
|
database.execSQL(sql)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val COLUMN_DB_ID = 0
|
||||||
|
const val GAME_COLUMN_PATH = 1
|
||||||
|
const val GAME_COLUMN_TITLE = 2
|
||||||
|
const val GAME_COLUMN_DESCRIPTION = 3
|
||||||
|
const val GAME_COLUMN_REGIONS = 4
|
||||||
|
const val GAME_COLUMN_GAME_ID = 5
|
||||||
|
const val GAME_COLUMN_CAPTION = 6
|
||||||
|
const val FOLDER_COLUMN_PATH = 1
|
||||||
|
const val KEY_DB_ID = "_id"
|
||||||
|
const val KEY_GAME_PATH = "path"
|
||||||
|
const val KEY_GAME_TITLE = "title"
|
||||||
|
const val KEY_GAME_DESCRIPTION = "description"
|
||||||
|
const val KEY_GAME_REGIONS = "regions"
|
||||||
|
const val KEY_GAME_ID = "game_id"
|
||||||
|
const val KEY_GAME_COMPANY = "company"
|
||||||
|
const val KEY_FOLDER_PATH = "path"
|
||||||
|
const val TABLE_NAME_FOLDERS = "folders"
|
||||||
|
const val TABLE_NAME_GAMES = "games"
|
||||||
|
private const val DB_VERSION = 2
|
||||||
|
private const val TYPE_PRIMARY = " INTEGER PRIMARY KEY"
|
||||||
|
private const val TYPE_INTEGER = " INTEGER"
|
||||||
|
private const val TYPE_STRING = " TEXT"
|
||||||
|
private const val CONSTRAINT_UNIQUE = " UNIQUE"
|
||||||
|
private const val SEPARATOR = ", "
|
||||||
|
private const val SQL_CREATE_GAMES = ("CREATE TABLE " + TABLE_NAME_GAMES + "("
|
||||||
|
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR
|
||||||
|
+ KEY_GAME_PATH + TYPE_STRING + SEPARATOR
|
||||||
|
+ KEY_GAME_TITLE + TYPE_STRING + SEPARATOR
|
||||||
|
+ KEY_GAME_DESCRIPTION + TYPE_STRING + SEPARATOR
|
||||||
|
+ KEY_GAME_REGIONS + TYPE_STRING + SEPARATOR
|
||||||
|
+ KEY_GAME_ID + TYPE_STRING + SEPARATOR
|
||||||
|
+ KEY_GAME_COMPANY + TYPE_STRING + ")")
|
||||||
|
private const val SQL_CREATE_FOLDERS = ("CREATE TABLE " + TABLE_NAME_FOLDERS + "("
|
||||||
|
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR
|
||||||
|
+ KEY_FOLDER_PATH + TYPE_STRING + CONSTRAINT_UNIQUE + ")")
|
||||||
|
private const val SQL_DELETE_FOLDERS = "DROP TABLE IF EXISTS $TABLE_NAME_FOLDERS"
|
||||||
|
private const val SQL_DELETE_GAMES = "DROP TABLE IF EXISTS $TABLE_NAME_GAMES"
|
||||||
|
private fun attemptToAddGame(database: SQLiteDatabase, filePath: String) {
|
||||||
|
var name = NativeLibrary.GetTitle(filePath)
|
||||||
|
|
||||||
|
// If the game's title field is empty, use the filename.
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
name = filePath.substring(filePath.lastIndexOf("/") + 1)
|
||||||
|
}
|
||||||
|
var gameId = NativeLibrary.GetGameId(filePath)
|
||||||
|
|
||||||
|
// If the game's ID field is empty, use the filename without extension.
|
||||||
|
if (gameId.isEmpty()) {
|
||||||
|
gameId = filePath.substring(
|
||||||
|
filePath.lastIndexOf("/") + 1,
|
||||||
|
filePath.lastIndexOf(".")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val game = Game.asContentValues(
|
||||||
|
name,
|
||||||
|
NativeLibrary.GetDescription(filePath).replace("\n", " "),
|
||||||
|
NativeLibrary.GetRegions(filePath),
|
||||||
|
filePath,
|
||||||
|
gameId,
|
||||||
|
NativeLibrary.GetCompany(filePath)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Try to update an existing game first.
|
||||||
|
val rowsMatched = database.update(
|
||||||
|
TABLE_NAME_GAMES, // Which table to update.
|
||||||
|
game, // The values to fill the row with.
|
||||||
|
"$KEY_GAME_ID = ?", arrayOf(
|
||||||
|
game.getAsString(
|
||||||
|
KEY_GAME_ID
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// The ? in WHERE clause is replaced with this,
|
||||||
|
// which is provided as an array because there
|
||||||
|
// could potentially be more than one argument.
|
||||||
|
|
||||||
|
// If update fails, insert a new game instead.
|
||||||
|
if (rowsMatched == 0) {
|
||||||
|
Log.verbose("[GameDatabase] Adding game: " + game.getAsString(KEY_GAME_TITLE))
|
||||||
|
database.insert(TABLE_NAME_GAMES, null, game)
|
||||||
|
} else {
|
||||||
|
Log.verbose("[GameDatabase] Updated game: " + game.getAsString(KEY_GAME_TITLE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue