diff --git a/app/src/main/java/awais/instagrabber/db/AppDatabase.java b/app/src/main/java/awais/instagrabber/db/AppDatabase.java new file mode 100644 index 00000000..6190575a --- /dev/null +++ b/app/src/main/java/awais/instagrabber/db/AppDatabase.java @@ -0,0 +1,229 @@ +package awais.instagrabber.db; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.util.Log; +import android.util.Pair; + +import androidx.annotation.NonNull; +import androidx.room.Database; +import androidx.room.Room; +import androidx.room.RoomDatabase; +import androidx.room.TypeConverters; +import androidx.room.migration.Migration; +import androidx.sqlite.db.SupportSQLiteDatabase; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import awais.instagrabber.db.dao.AccountDao; +import awais.instagrabber.db.dao.FavoriteDao; +import awais.instagrabber.db.entities.Account; +import awais.instagrabber.db.entities.Favorite; +import awais.instagrabber.models.enums.FavoriteType; +import awais.instagrabber.utils.Utils; + +@Database(entities = {Account.class, Favorite.class}, + version = 4) +@TypeConverters({Converters.class}) +public abstract class AppDatabase extends RoomDatabase { + private static final String TAG = AppDatabase.class.getSimpleName(); + + private static AppDatabase INSTANCE; + + public abstract AccountDao accountDao(); + + public abstract FavoriteDao favoriteDao(); + + public static AppDatabase getDatabase(final Context context) { + if (INSTANCE == null) { + synchronized (AppDatabase.class) { + if (INSTANCE == null) { + INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "cookiebox.db") + .addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4) + .build(); + } + } + } + return INSTANCE; + } + + static final Migration MIGRATION_1_2 = new Migration(1, 2) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase db) { + db.execSQL("ALTER TABLE cookies ADD " + Account.COL_FULL_NAME + " TEXT"); + db.execSQL("ALTER TABLE cookies ADD " + Account.COL_PROFILE_PIC + " TEXT"); + } + }; + + static final Migration MIGRATION_2_3 = new Migration(2, 3) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase db) { + final List oldFavorites = backupOldFavorites(db); + // recreate with new columns (as there will be no doubt about the `query_display` column being present or not in the future versions) + db.execSQL("DROP TABLE " + Favorite.TABLE_NAME); + db.execSQL("CREATE TABLE " + Favorite.TABLE_NAME + " (" + + Favorite.COL_ID + " INTEGER PRIMARY KEY," + + Favorite.COL_QUERY + " TEXT," + + Favorite.COL_TYPE + " TEXT," + + Favorite.COL_DISPLAY_NAME + " TEXT," + + Favorite.COL_PIC_URL + " TEXT," + + Favorite.COL_DATE_ADDED + " INTEGER)"); + // add the old favorites back + for (final Favorite oldFavorite : oldFavorites) { + insertOrUpdateFavorite(db, oldFavorite); + } + } + }; + + static final Migration MIGRATION_3_4 = new Migration(3, 4) { + @Override + public void migrate(@NonNull SupportSQLiteDatabase db) { + // Required when migrating to Room. + // The original table primary keys were not 'NOT NULL', so the migration to Room were failing without the below migration. + // Taking this opportunity to rename cookies table to accounts + + // Create new table with name 'accounts' + db.execSQL("CREATE TABLE " + Account.TABLE_NAME + " (" + + Account.COL_ID + " INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," + + Account.COL_UID + " TEXT," + + Account.COL_USERNAME + " TEXT," + + Account.COL_COOKIE + " TEXT," + + Account.COL_FULL_NAME + " TEXT," + + Account.COL_PROFILE_PIC + " TEXT)"); + // Insert all data from table 'cookies' to 'accounts' + db.execSQL("INSERT INTO " + Account.TABLE_NAME + " (" + + Account.COL_UID + "," + + Account.COL_USERNAME + "," + + Account.COL_COOKIE + "," + + Account.COL_FULL_NAME + "," + + Account.COL_PROFILE_PIC + ") " + + "SELECT " + + Account.COL_UID + "," + + Account.COL_USERNAME + "," + + Account.COL_COOKIE + "," + + Account.COL_FULL_NAME + "," + + Account.COL_PROFILE_PIC + + " FROM cookies"); + // Drop old cookies table + db.execSQL("DROP TABLE cookies"); + + // Create favorite backup table + db.execSQL("CREATE TABLE " + Favorite.TABLE_NAME + "_backup (" + + Favorite.COL_ID + " INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," + + Favorite.COL_QUERY + " TEXT," + + Favorite.COL_TYPE + " TEXT," + + Favorite.COL_DISPLAY_NAME + " TEXT," + + Favorite.COL_PIC_URL + " TEXT," + + Favorite.COL_DATE_ADDED + " INTEGER)"); + // Insert all data from table 'favorite' to 'favorite_backup' + db.execSQL("INSERT INTO " + Favorite.TABLE_NAME + "_backup (" + + Favorite.COL_QUERY + "," + + Favorite.COL_TYPE + "," + + Favorite.COL_DISPLAY_NAME + "," + + Favorite.COL_PIC_URL + "," + + Favorite.COL_DATE_ADDED + ") " + + "SELECT " + + Favorite.COL_QUERY + "," + + Favorite.COL_TYPE + "," + + Favorite.COL_DISPLAY_NAME + "," + + Favorite.COL_PIC_URL + "," + + Favorite.COL_DATE_ADDED + + " FROM " + Favorite.TABLE_NAME); + // Drop favorites + db.execSQL("DROP TABLE " + Favorite.TABLE_NAME); + // Rename favorite_backup to favorites + db.execSQL("ALTER TABLE " + Favorite.TABLE_NAME + "_backup RENAME TO " + Favorite.TABLE_NAME); + } + }; + + @NonNull + private static List backupOldFavorites(@NonNull final SupportSQLiteDatabase db) { + // check if old favorites table had the column query_display + final boolean queryDisplayExists = checkColumnExists(db, Favorite.TABLE_NAME, "query_display"); + Log.d(TAG, "backupOldFavorites: queryDisplayExists: " + queryDisplayExists); + final List oldModels = new ArrayList<>(); + final String sql = "SELECT " + + "query_text," + + "date_added" + + (queryDisplayExists ? ",query_display" : "") + + " FROM " + Favorite.TABLE_NAME; + try (final Cursor cursor = db.query(sql)) { + if (cursor != null && cursor.moveToFirst()) { + do { + try { + final String queryText = cursor.getString(cursor.getColumnIndex("query_text")); + final Pair favoriteTypeQueryPair = Utils.migrateOldFavQuery(queryText); + if (favoriteTypeQueryPair == null) continue; + final FavoriteType type = favoriteTypeQueryPair.first; + final String query = favoriteTypeQueryPair.second; + oldModels.add(new Favorite( + -1, + query, + type, + queryDisplayExists ? cursor.getString(cursor.getColumnIndex("query_display")) + : null, + null, + new Date(cursor.getLong(cursor.getColumnIndex("date_added"))) + )); + } catch (Exception e) { + Log.e(TAG, "onUpgrade", e); + } + } while (cursor.moveToNext()); + } + } catch (Exception e) { + Log.e(TAG, "onUpgrade", e); + } + Log.d(TAG, "backupOldFavorites: oldModels:" + oldModels); + return oldModels; + } + + private static synchronized void insertOrUpdateFavorite(@NonNull final SupportSQLiteDatabase db, @NonNull final Favorite model) { + final ContentValues values = new ContentValues(); + values.put(Favorite.COL_QUERY, model.getQuery()); + values.put(Favorite.COL_TYPE, model.getType().toString()); + values.put(Favorite.COL_DISPLAY_NAME, model.getDisplayName()); + values.put(Favorite.COL_PIC_URL, model.getPicUrl()); + values.put(Favorite.COL_DATE_ADDED, model.getDateAdded().getTime()); + int rows; + if (model.getId() >= 1) { + rows = db.update(Favorite.TABLE_NAME, + SQLiteDatabase.CONFLICT_IGNORE, + values, + Favorite.COL_ID + "=?", + new String[]{String.valueOf(model.getId())}); + } else { + rows = db.update(Favorite.TABLE_NAME, + SQLiteDatabase.CONFLICT_IGNORE, + values, + Favorite.COL_QUERY + "=?" + " AND " + Favorite.COL_TYPE + "=?", + new String[]{model.getQuery(), model.getType().toString()}); + } + if (rows != 1) { + db.insert(Favorite.TABLE_NAME, SQLiteDatabase.CONFLICT_IGNORE, values); + } + } + + private static boolean checkColumnExists(@NonNull final SupportSQLiteDatabase db, + @NonNull final String tableName, + @NonNull final String columnName) { + boolean exists = false; + try (Cursor cursor = db.query("PRAGMA table_info(" + tableName + ")")) { + if (cursor.moveToFirst()) { + do { + final String currentColumn = cursor.getString(cursor.getColumnIndex("name")); + if (currentColumn.equals(columnName)) { + exists = true; + } + } while (cursor.moveToNext()); + + } + } catch (Exception ex) { + Log.e(TAG, "checkColumnExists", ex); + } + return exists; + } +} diff --git a/app/src/main/java/awais/instagrabber/db/Converters.java b/app/src/main/java/awais/instagrabber/db/Converters.java new file mode 100644 index 00000000..50252755 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/db/Converters.java @@ -0,0 +1,33 @@ +package awais.instagrabber.db; + +import androidx.room.TypeConverter; + +import java.util.Date; + +import awais.instagrabber.models.enums.FavoriteType; + +public class Converters { + @TypeConverter + public static Date fromTimestamp(Long value) { + return value == null ? null : new Date(value); + } + + @TypeConverter + public static Long dateToTimestamp(Date date) { + return date == null ? null : date.getTime(); + } + + @TypeConverter + public static FavoriteType fromFavoriteTypeString(String value) { + try { + return FavoriteType.valueOf(value); + } catch (Exception e) { + return null; + } + } + + @TypeConverter + public static String favoriteTypeToString(FavoriteType favoriteType) { + return favoriteType == null ? null : favoriteType.toString(); + } +} diff --git a/app/src/main/java/awais/instagrabber/db/dao/AccountDao.java b/app/src/main/java/awais/instagrabber/db/dao/AccountDao.java new file mode 100644 index 00000000..8524f192 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/db/dao/AccountDao.java @@ -0,0 +1,34 @@ +package awais.instagrabber.db.dao; + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; +import androidx.room.Update; + +import java.util.List; + +import awais.instagrabber.db.entities.Account; + +@Dao +public interface AccountDao { + + @Query("SELECT * FROM accounts") + List getAllAccounts(); + + @Query("SELECT * FROM accounts WHERE uid = :uid") + Account findAccountByUid(String uid); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + List insertAccounts(Account... accounts); + + @Update + void updateAccounts(Account... accounts); + + @Delete + void deleteAccounts(Account... accounts); + + @Query("DELETE from accounts") + void deleteAllAccounts(); +} diff --git a/app/src/main/java/awais/instagrabber/db/dao/FavoriteDao.java b/app/src/main/java/awais/instagrabber/db/dao/FavoriteDao.java new file mode 100644 index 00000000..50dc3129 --- /dev/null +++ b/app/src/main/java/awais/instagrabber/db/dao/FavoriteDao.java @@ -0,0 +1,35 @@ +package awais.instagrabber.db.dao; + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; +import androidx.room.Update; + +import java.util.List; + +import awais.instagrabber.db.entities.Favorite; +import awais.instagrabber.models.enums.FavoriteType; + +@Dao +public interface FavoriteDao { + + @Query("SELECT * FROM favorites") + List getAllFavorites(); + + @Query("SELECT * FROM favorites WHERE query_text = :query and type = :type") + Favorite findFavoriteByQueryAndType(String query, FavoriteType type); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + List insertFavorites(Favorite... favorites); + + @Update + void updateFavorites(Favorite... favorites); + + @Delete + void deleteFavorites(Favorite... favorites); + + @Query("DELETE from favorites") + void deleteAllFavorites(); +} diff --git a/app/src/main/java/awais/instagrabber/db/datasources/AccountDataSource.java b/app/src/main/java/awais/instagrabber/db/datasources/AccountDataSource.java index 2aaa2f8a..a2ffe515 100644 --- a/app/src/main/java/awais/instagrabber/db/datasources/AccountDataSource.java +++ b/app/src/main/java/awais/instagrabber/db/datasources/AccountDataSource.java @@ -1,182 +1,68 @@ package awais.instagrabber.db.datasources; -import android.content.ContentValues; import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.util.ArrayList; import java.util.List; -import awais.instagrabber.BuildConfig; +import awais.instagrabber.db.AppDatabase; +import awais.instagrabber.db.dao.AccountDao; import awais.instagrabber.db.entities.Account; -import awais.instagrabber.utils.DataBox; -import awais.instagrabber.utils.TextUtils; - -import static awais.instagrabber.utils.DataBox.KEY_COOKIE; -import static awais.instagrabber.utils.DataBox.KEY_FULL_NAME; -import static awais.instagrabber.utils.DataBox.KEY_ID; -import static awais.instagrabber.utils.DataBox.KEY_PROFILE_PIC; -import static awais.instagrabber.utils.DataBox.KEY_UID; -import static awais.instagrabber.utils.DataBox.KEY_USERNAME; -import static awais.instagrabber.utils.DataBox.TABLE_COOKIES; public class AccountDataSource { private static final String TAG = AccountDataSource.class.getSimpleName(); private static AccountDataSource INSTANCE; - private final DataBox dataBox; + private final AccountDao accountDao; - private AccountDataSource(@NonNull Context context) { - dataBox = DataBox.getInstance(context); + private AccountDataSource(final AccountDao accountDao) { + this.accountDao = accountDao; } - public static synchronized AccountDataSource getInstance(@NonNull Context context) { + public static AccountDataSource getInstance(@NonNull Context context) { if (INSTANCE == null) { - INSTANCE = new AccountDataSource(context); + synchronized (AccountDataSource.class) { + if (INSTANCE == null) { + final AppDatabase database = AppDatabase.getDatabase(context); + INSTANCE = new AccountDataSource(database.accountDao()); + } + } } return INSTANCE; } @Nullable public final Account getAccount(final String uid) { - Account cookie = null; - try (final SQLiteDatabase db = dataBox.getReadableDatabase(); - final Cursor cursor = db.query(TABLE_COOKIES, - new String[]{ - KEY_ID, - KEY_UID, - KEY_USERNAME, - KEY_COOKIE, - KEY_FULL_NAME, - KEY_PROFILE_PIC - }, - KEY_UID + "=?", - new String[]{uid}, - null, - null, - null)) { - if (cursor != null && cursor.moveToFirst()) - cookie = new Account( - cursor.getInt(cursor.getColumnIndex(KEY_ID)), - cursor.getString(cursor.getColumnIndex(KEY_UID)), - cursor.getString(cursor.getColumnIndex(KEY_USERNAME)), - cursor.getString(cursor.getColumnIndex(KEY_COOKIE)), - cursor.getString(cursor.getColumnIndex(KEY_FULL_NAME)), - cursor.getString(cursor.getColumnIndex(KEY_PROFILE_PIC)) - ); - } - return cookie; + return accountDao.findAccountByUid(uid); } @NonNull public final List getAllAccounts() { - final List cookies = new ArrayList<>(); - try (final SQLiteDatabase db = dataBox.getReadableDatabase(); - final Cursor cursor = db.query(TABLE_COOKIES, - new String[]{ - KEY_ID, - KEY_UID, - KEY_USERNAME, - KEY_COOKIE, - KEY_FULL_NAME, - KEY_PROFILE_PIC - }, - null, - null, - null, - null, - null)) { - if (cursor != null && cursor.moveToFirst()) { - do { - cookies.add(new Account( - cursor.getInt(cursor.getColumnIndex(KEY_ID)), - cursor.getString(cursor.getColumnIndex(KEY_UID)), - cursor.getString(cursor.getColumnIndex(KEY_USERNAME)), - cursor.getString(cursor.getColumnIndex(KEY_COOKIE)), - cursor.getString(cursor.getColumnIndex(KEY_FULL_NAME)), - cursor.getString(cursor.getColumnIndex(KEY_PROFILE_PIC)) - )); - } while (cursor.moveToNext()); - } - } - return cookies; + return accountDao.getAllAccounts(); } - // public final void insertOrUpdateAccount(@NonNull final Account account) { - // insertOrUpdateAccount( - // account.getUid(), - // account.getUsername(), - // account.getCookie(), - // account.getFullName(), - // account.getProfilePic() - // ); - // } - public final void insertOrUpdateAccount(final String uid, final String username, final String cookie, final String fullName, final String profilePicUrl) { - if (TextUtils.isEmpty(uid)) return; - try (final SQLiteDatabase db = dataBox.getWritableDatabase()) { - db.beginTransaction(); - try { - final ContentValues values = new ContentValues(); - values.put(KEY_USERNAME, username); - values.put(KEY_COOKIE, cookie); - values.put(KEY_UID, uid); - values.put(KEY_FULL_NAME, fullName); - values.put(KEY_PROFILE_PIC, profilePicUrl); - final int rows = db.update(TABLE_COOKIES, values, KEY_UID + "=?", new String[]{uid}); - if (rows != 1) { - db.insert(TABLE_COOKIES, null, values); - } - db.setTransactionSuccessful(); - } catch (final Exception e) { - if (BuildConfig.DEBUG) Log.e(TAG, "Error", e); - } finally { - db.endTransaction(); - } + final Account account = getAccount(uid); + final Account toUpdate = new Account(account == null ? 0 : account.getId(), uid, username, cookie, fullName, profilePicUrl); + if (account != null) { + accountDao.updateAccounts(toUpdate); + return; } + accountDao.insertAccounts(toUpdate); } - public final synchronized void deleteAccount(@NonNull final Account account) { - final String cookieModelUid = account.getUid(); - if (!TextUtils.isEmpty(cookieModelUid)) { - try (final SQLiteDatabase db = dataBox.getWritableDatabase()) { - db.beginTransaction(); - try { - final int rowsDeleted = db.delete(TABLE_COOKIES, KEY_UID + "=? AND " + KEY_USERNAME + "=? AND " + KEY_COOKIE + "=?", - new String[]{cookieModelUid, account.getUsername(), account.getCookie()}); - - if (rowsDeleted > 0) db.setTransactionSuccessful(); - } catch (final Exception e) { - if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); - } finally { - db.endTransaction(); - } - } - } + public final void deleteAccount(@NonNull final Account account) { + accountDao.deleteAccounts(account); } - public final synchronized void deleteAllAccounts() { - try (final SQLiteDatabase db = dataBox.getWritableDatabase()) { - db.beginTransaction(); - try { - final int rowsDeleted = db.delete(TABLE_COOKIES, null, null); - - if (rowsDeleted > 0) db.setTransactionSuccessful(); - } catch (final Exception e) { - if (BuildConfig.DEBUG) Log.e("AWAISKING_APP", "", e); - } finally { - db.endTransaction(); - } - } + public final void deleteAllAccounts() { + accountDao.deleteAllAccounts(); } } diff --git a/app/src/main/java/awais/instagrabber/db/datasources/FavoriteDataSource.java b/app/src/main/java/awais/instagrabber/db/datasources/FavoriteDataSource.java index 92a566c6..36798b08 100644 --- a/app/src/main/java/awais/instagrabber/db/datasources/FavoriteDataSource.java +++ b/app/src/main/java/awais/instagrabber/db/datasources/FavoriteDataSource.java @@ -1,180 +1,62 @@ package awais.instagrabber.db.datasources; import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.util.ArrayList; -import java.util.Date; import java.util.List; -import awais.instagrabber.BuildConfig; +import awais.instagrabber.db.AppDatabase; +import awais.instagrabber.db.dao.FavoriteDao; import awais.instagrabber.db.entities.Favorite; import awais.instagrabber.models.enums.FavoriteType; -import awais.instagrabber.utils.DataBox; -import awais.instagrabber.utils.TextUtils; -import awaisomereport.LogCollector; - -import static awais.instagrabber.utils.DataBox.FAV_COL_DATE_ADDED; -import static awais.instagrabber.utils.DataBox.FAV_COL_DISPLAY_NAME; -import static awais.instagrabber.utils.DataBox.FAV_COL_ID; -import static awais.instagrabber.utils.DataBox.FAV_COL_PIC_URL; -import static awais.instagrabber.utils.DataBox.FAV_COL_QUERY; -import static awais.instagrabber.utils.DataBox.FAV_COL_TYPE; -import static awais.instagrabber.utils.DataBox.TABLE_FAVORITES; -import static awais.instagrabber.utils.Utils.logCollector; public class FavoriteDataSource { private static final String TAG = FavoriteDataSource.class.getSimpleName(); private static FavoriteDataSource INSTANCE; - private final DataBox dataBox; + private final FavoriteDao favoriteDao; - private FavoriteDataSource(@NonNull Context context) { - dataBox = DataBox.getInstance(context); + private FavoriteDataSource(final FavoriteDao favoriteDao) { + this.favoriteDao = favoriteDao; } public static synchronized FavoriteDataSource getInstance(@NonNull Context context) { if (INSTANCE == null) { - INSTANCE = new FavoriteDataSource(context); + synchronized (FavoriteDataSource.class) { + if (INSTANCE == null) { + final AppDatabase database = AppDatabase.getDatabase(context); + INSTANCE = new FavoriteDataSource(database.favoriteDao()); + } + } } return INSTANCE; } + @Nullable public final Favorite getFavorite(@NonNull final String query, @NonNull final FavoriteType type) { - try (final SQLiteDatabase db = dataBox.getReadableDatabase(); - final Cursor cursor = db.query(TABLE_FAVORITES, - new String[]{ - FAV_COL_ID, - FAV_COL_QUERY, - FAV_COL_TYPE, - FAV_COL_DISPLAY_NAME, - FAV_COL_PIC_URL, - FAV_COL_DATE_ADDED - }, - FAV_COL_QUERY + "=?" + " AND " + FAV_COL_TYPE + "=?", - new String[]{ - query, - type.toString() - }, - null, - null, - null)) { - if (cursor != null && cursor.moveToFirst()) { - FavoriteType favoriteType = null; - try { - favoriteType = FavoriteType.valueOf(cursor.getString(cursor.getColumnIndex(FAV_COL_TYPE))); - } catch (IllegalArgumentException ignored) {} - return new Favorite( - cursor.getInt(cursor.getColumnIndex(FAV_COL_ID)), - cursor.getString(cursor.getColumnIndex(FAV_COL_QUERY)), - favoriteType, - cursor.getString(cursor.getColumnIndex(FAV_COL_DISPLAY_NAME)), - cursor.getString(cursor.getColumnIndex(FAV_COL_PIC_URL)), - new Date(cursor.getLong(cursor.getColumnIndex(FAV_COL_DATE_ADDED))) - ); - } - } - return null; + return favoriteDao.findFavoriteByQueryAndType(query, type); } @NonNull public final List getAllFavorites() { - final List favorites = new ArrayList<>(); - try (final SQLiteDatabase db = dataBox.getWritableDatabase()) { - try (final Cursor cursor = db.query(TABLE_FAVORITES, - new String[]{ - FAV_COL_ID, - FAV_COL_QUERY, - FAV_COL_TYPE, - FAV_COL_DISPLAY_NAME, - FAV_COL_PIC_URL, - FAV_COL_DATE_ADDED - }, - null, - null, - null, - null, - null)) { - if (cursor != null && cursor.moveToFirst()) { - db.beginTransaction(); - Favorite tempFav; - do { - FavoriteType type = null; - try { - type = FavoriteType.valueOf(cursor.getString(cursor.getColumnIndex(FAV_COL_TYPE))); - } catch (IllegalArgumentException ignored) {} - tempFav = new Favorite( - cursor.getInt(cursor.getColumnIndex(FAV_COL_ID)), - cursor.getString(cursor.getColumnIndex(FAV_COL_QUERY)), - type, - cursor.getString(cursor.getColumnIndex(FAV_COL_DISPLAY_NAME)), - cursor.getString(cursor.getColumnIndex(FAV_COL_PIC_URL)), - new Date(cursor.getLong(cursor.getColumnIndex(FAV_COL_DATE_ADDED))) - ); - favorites.add(tempFav); - } while (cursor.moveToNext()); - db.endTransaction(); - } - } catch (final Exception e) { - Log.e(TAG, "", e); - } - } - return favorites; + return favoriteDao.getAllFavorites(); } - public final synchronized Favorite insertOrUpdateFavorite(@NonNull final Favorite model) { - final String query = model.getQuery(); - if (!TextUtils.isEmpty(query)) { - try (final SQLiteDatabase db = dataBox.getWritableDatabase()) { - db.beginTransaction(); - try { - dataBox.insertOrUpdateFavorite(db, model); - db.setTransactionSuccessful(); - } catch (Exception e) { - if (logCollector != null) { - logCollector.appendException(e, LogCollector.LogFile.DATA_BOX_FAVORITES, "insertOrUpdateFavorite"); - } - if (BuildConfig.DEBUG) { - Log.e(TAG, "Error adding/updating favorite", e); - } - } finally { - db.endTransaction(); - } - } - return getFavorite(model.getQuery(), model.getType()); + public final void insertOrUpdateFavorite(@NonNull final Favorite favorite) { + if (favorite.getId() > 0) { + favoriteDao.updateFavorites(favorite); + return; } - return null; + favoriteDao.insertFavorites(favorite); } - public final synchronized void deleteFavorite(@NonNull final String query, @NonNull final FavoriteType type) { - if (!TextUtils.isEmpty(query)) { - try (final SQLiteDatabase db = dataBox.getWritableDatabase()) { - db.beginTransaction(); - try { - final int rowsDeleted = db.delete(TABLE_FAVORITES, - FAV_COL_QUERY + "=?" + - " AND " + FAV_COL_TYPE + "=?", - new String[]{query, type.toString()}); - - if (rowsDeleted > 0) db.setTransactionSuccessful(); - } catch (final Exception e) { - if (logCollector != null) { - logCollector.appendException(e, LogCollector.LogFile.DATA_BOX_FAVORITES, "deleteFavorite"); - } - if (BuildConfig.DEBUG) { - Log.e(TAG, "Error", e); - } - } finally { - db.endTransaction(); - } - } - } + public final void deleteFavorite(@NonNull final String query, @NonNull final FavoriteType type) { + final Favorite favorite = getFavorite(query, type); + if (favorite == null) return; + favoriteDao.deleteFavorites(favorite); } } diff --git a/app/src/main/java/awais/instagrabber/db/entities/Account.java b/app/src/main/java/awais/instagrabber/db/entities/Account.java index 7f849c6f..57faa716 100644 --- a/app/src/main/java/awais/instagrabber/db/entities/Account.java +++ b/app/src/main/java/awais/instagrabber/db/entities/Account.java @@ -4,32 +4,42 @@ import androidx.annotation.NonNull; import androidx.core.util.ObjectsCompat; import androidx.room.ColumnInfo; import androidx.room.Entity; +import androidx.room.Ignore; import androidx.room.PrimaryKey; +import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.TextUtils; -@Entity(tableName = "cookies") +@Entity(tableName = Account.TABLE_NAME) public class Account { + public final static String TABLE_NAME = "accounts"; + public final static String COL_ID = "id"; + public final static String COL_USERNAME = Constants.EXTRAS_USERNAME; + public final static String COL_COOKIE = "cookie"; + public final static String COL_UID = "uid"; + public final static String COL_FULL_NAME = "full_name"; + public final static String COL_PROFILE_PIC = "profile_pic"; - @PrimaryKey - @ColumnInfo(name = "id") + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = COL_ID) private final int id; - @ColumnInfo(name = "uid") + @ColumnInfo(name = COL_UID) private final String uid; - @ColumnInfo(name = "username") + @ColumnInfo(name = COL_USERNAME) private final String username; - @ColumnInfo(name = "cookie") + @ColumnInfo(name = COL_COOKIE) private final String cookie; - @ColumnInfo(name = "full_name") + @ColumnInfo(name = COL_FULL_NAME) private final String fullName; - @ColumnInfo(name = "profile_pic") + @ColumnInfo(name = COL_PROFILE_PIC) private final String profilePic; + @Ignore private boolean selected; public Account(final int id, diff --git a/app/src/main/java/awais/instagrabber/db/entities/Favorite.java b/app/src/main/java/awais/instagrabber/db/entities/Favorite.java index 7e3bada4..614ba167 100644 --- a/app/src/main/java/awais/instagrabber/db/entities/Favorite.java +++ b/app/src/main/java/awais/instagrabber/db/entities/Favorite.java @@ -10,26 +10,33 @@ import java.util.Date; import awais.instagrabber.models.enums.FavoriteType; -@Entity(tableName = "favorites") +@Entity(tableName = Favorite.TABLE_NAME) public class Favorite { + public final static String TABLE_NAME = "favorites"; + public final static String COL_ID = "id"; + public final static String COL_QUERY = "query_text"; + public final static String COL_TYPE = "type"; + public final static String COL_DISPLAY_NAME = "display_name"; + public final static String COL_PIC_URL = "pic_url"; + public final static String COL_DATE_ADDED = "date_added"; - @PrimaryKey - @ColumnInfo(name = "id") + @PrimaryKey(autoGenerate = true) + @ColumnInfo(name = COL_ID) private final int id; - @ColumnInfo(name = "query_text") + @ColumnInfo(name = COL_QUERY) private final String query; - @ColumnInfo(name = "type") + @ColumnInfo(name = COL_TYPE) private final FavoriteType type; - @ColumnInfo(name = "display_name") + @ColumnInfo(name = COL_DISPLAY_NAME) private final String displayName; - @ColumnInfo(name = "pic_url") + @ColumnInfo(name = COL_PIC_URL) private final String picUrl; - @ColumnInfo(name = "date_added") + @ColumnInfo(name = COL_DATE_ADDED) private final Date dateAdded; public Favorite(final int id, diff --git a/app/src/main/java/awais/instagrabber/db/repositories/AccountRepository.java b/app/src/main/java/awais/instagrabber/db/repositories/AccountRepository.java index 529d848d..bb7c48fd 100644 --- a/app/src/main/java/awais/instagrabber/db/repositories/AccountRepository.java +++ b/app/src/main/java/awais/instagrabber/db/repositories/AccountRepository.java @@ -21,9 +21,9 @@ public class AccountRepository { this.accountDataSource = accountDataSource; } - public static AccountRepository getInstance(final AppExecutors appExecutors, final AccountDataSource accountDataSource) { + public static AccountRepository getInstance(final AccountDataSource accountDataSource) { if (instance == null) { - instance = new AccountRepository(appExecutors, accountDataSource); + instance = new AccountRepository(AppExecutors.getInstance(), accountDataSource); } return instance; } diff --git a/app/src/main/java/awais/instagrabber/db/repositories/FavoriteRepository.java b/app/src/main/java/awais/instagrabber/db/repositories/FavoriteRepository.java index 3f942b6b..926692f7 100644 --- a/app/src/main/java/awais/instagrabber/db/repositories/FavoriteRepository.java +++ b/app/src/main/java/awais/instagrabber/db/repositories/FavoriteRepository.java @@ -20,9 +20,9 @@ public class FavoriteRepository { this.favoriteDataSource = favoriteDataSource; } - public static FavoriteRepository getInstance(final AppExecutors appExecutors, final FavoriteDataSource favoriteDataSource) { + public static FavoriteRepository getInstance(final FavoriteDataSource favoriteDataSource) { if (instance == null) { - instance = new FavoriteRepository(appExecutors, favoriteDataSource); + instance = new FavoriteRepository(AppExecutors.getInstance(), favoriteDataSource); } return instance; } @@ -60,18 +60,14 @@ public class FavoriteRepository { } public void insertOrUpdateFavorite(final Favorite favorite, - final RepositoryCallback callback) { + final RepositoryCallback callback) { // request on the I/O thread appExecutors.diskIO().execute(() -> { - final Favorite updated = favoriteDataSource.insertOrUpdateFavorite(favorite); + favoriteDataSource.insertOrUpdateFavorite(favorite); // notify on the main thread appExecutors.mainThread().execute(() -> { if (callback == null) return; - if (updated == null) { - callback.onDataNotAvailable(); - return; - } - callback.onSuccess(updated); + callback.onSuccess(null); }); }); } diff --git a/app/src/main/java/awais/instagrabber/dialogs/AccountSwitcherDialogFragment.java b/app/src/main/java/awais/instagrabber/dialogs/AccountSwitcherDialogFragment.java index d1830243..91afa7d1 100644 --- a/app/src/main/java/awais/instagrabber/dialogs/AccountSwitcherDialogFragment.java +++ b/app/src/main/java/awais/instagrabber/dialogs/AccountSwitcherDialogFragment.java @@ -25,7 +25,6 @@ import awais.instagrabber.db.datasources.AccountDataSource; import awais.instagrabber.db.entities.Account; import awais.instagrabber.db.repositories.AccountRepository; import awais.instagrabber.db.repositories.RepositoryCallback; -import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.TextUtils; @@ -41,12 +40,12 @@ public class AccountSwitcherDialogFragment extends DialogFragment { private DialogAccountSwitcherBinding binding; public AccountSwitcherDialogFragment() { - accountRepository = AccountRepository.getInstance(new AppExecutors(), AccountDataSource.getInstance(getContext())); + accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext())); } public AccountSwitcherDialogFragment(final OnAddAccountClickListener onAddAccountClickListener) { this.onAddAccountClickListener = onAddAccountClickListener; - accountRepository = AccountRepository.getInstance(new AppExecutors(), AccountDataSource.getInstance(getContext())); + accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext())); } private final AccountSwitcherAdapter.OnAccountClickListener accountClickListener = (model, isCurrent) -> { diff --git a/app/src/main/java/awais/instagrabber/fragments/FavoritesFragment.java b/app/src/main/java/awais/instagrabber/fragments/FavoritesFragment.java index 8631add3..190e9a59 100644 --- a/app/src/main/java/awais/instagrabber/fragments/FavoritesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/FavoritesFragment.java @@ -32,7 +32,6 @@ import awais.instagrabber.db.datasources.FavoriteDataSource; import awais.instagrabber.db.entities.Favorite; import awais.instagrabber.db.repositories.FavoriteRepository; import awais.instagrabber.db.repositories.RepositoryCallback; -import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.TextUtils; import awais.instagrabber.viewmodels.FavoritesViewModel; @@ -49,7 +48,7 @@ public class FavoritesFragment extends Fragment { @Override public void onCreate(@Nullable final Bundle savedInstanceState) { super.onCreate(savedInstanceState); - favoriteRepository = FavoriteRepository.getInstance(new AppExecutors(), FavoriteDataSource.getInstance(getContext())); + favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext())); } @NonNull @@ -186,9 +185,9 @@ public class FavoritesFragment extends Fragment { result.getSdProfilePic(), model.getDateAdded() ); - favoriteRepository.insertOrUpdateFavorite(updated, new RepositoryCallback() { + favoriteRepository.insertOrUpdateFavorite(updated, new RepositoryCallback() { @Override - public void onSuccess(final Favorite result) { + public void onSuccess(final Void result) { updatedList.add(i, updated); try { cyclicBarrier.await(); @@ -225,9 +224,9 @@ public class FavoritesFragment extends Fragment { result.getSdProfilePic(), model.getDateAdded() ); - favoriteRepository.insertOrUpdateFavorite(updated, new RepositoryCallback() { + favoriteRepository.insertOrUpdateFavorite(updated, new RepositoryCallback() { @Override - public void onSuccess(final Favorite result) { + public void onSuccess(final Void result) { try { cyclicBarrier.await(); } catch (BrokenBarrierException | InterruptedException e) { diff --git a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java index 3400d4f6..26733e12 100644 --- a/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/HashTagFragment.java @@ -59,7 +59,6 @@ import awais.instagrabber.models.HashtagModel; import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.enums.FavoriteType; -import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.DownloadUtils; @@ -459,8 +458,7 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe hashtagDetailsBinding.btnFollowTag.setVisibility(View.GONE); } hashtagDetailsBinding.favChip.setVisibility(View.VISIBLE); - final FavoriteRepository favoriteRepository = FavoriteRepository - .getInstance(new AppExecutors(), FavoriteDataSource.getInstance(getContext())); + final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext())); favoriteRepository.getFavorite(hashtag.substring(1), FavoriteType.HASHTAG, new RepositoryCallback() { @Override public void onSuccess(final Favorite result) { @@ -500,9 +498,9 @@ public class HashTagFragment extends Fragment implements SwipeRefreshLayout.OnRe hashtagModel.getName(), null, new Date() - ), new RepositoryCallback() { + ), new RepositoryCallback() { @Override - public void onSuccess(final Favorite result) { + public void onSuccess(final Void result) { hashtagDetailsBinding.favChip.setText(R.string.favorite_short); hashtagDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24); showSnackbar(getString(R.string.added_to_favs)); diff --git a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java index 0ddde3fb..acccc0b9 100644 --- a/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/LocationFragment.java @@ -62,7 +62,6 @@ import awais.instagrabber.models.LocationModel; import awais.instagrabber.models.PostsLayoutPreferences; import awais.instagrabber.models.StoryModel; import awais.instagrabber.models.enums.FavoriteType; -import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.DownloadUtils; @@ -448,7 +447,7 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR locationDetailsBinding.locationUrl.setText(TextUtils.getSpannableUrl(url)); } final FavoriteDataSource dataSource = FavoriteDataSource.getInstance(getContext()); - final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(new AppExecutors(), dataSource); + final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(dataSource); locationDetailsBinding.favChip.setVisibility(View.VISIBLE); favoriteRepository.getFavorite(locationId, FavoriteType.LOCATION, new RepositoryCallback() { @Override @@ -491,9 +490,9 @@ public class LocationFragment extends Fragment implements SwipeRefreshLayout.OnR locationModel.getName(), locationModel.getSdProfilePic(), new Date() - ), new RepositoryCallback() { + ), new RepositoryCallback() { @Override - public void onSuccess(final Favorite result) { + public void onSuccess(final Void result) { locationDetailsBinding.favChip.setText(R.string.favorite_short); locationDetailsBinding.favChip.setChipIconResource(R.drawable.ic_star_check_24); showSnackbar(getString(R.string.added_to_favs)); diff --git a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java index 2dc2238f..4c12b4e3 100644 --- a/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/main/ProfileFragment.java @@ -82,7 +82,6 @@ import awais.instagrabber.models.enums.FavoriteType; import awais.instagrabber.models.enums.PostItemType; import awais.instagrabber.repositories.responses.FriendshipRepoChangeRootResponse; import awais.instagrabber.repositories.responses.FriendshipRepoRestrictRootResponse; -import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.DownloadUtils; @@ -299,9 +298,8 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe fragmentActivity = (MainActivity) requireActivity(); friendshipService = FriendshipService.getInstance(); storiesService = StoriesService.getInstance(); - final AppExecutors appExecutors = new AppExecutors(); - accountRepository = AccountRepository.getInstance(appExecutors, AccountDataSource.getInstance(getContext())); - favoriteRepository = FavoriteRepository.getInstance(appExecutors, FavoriteDataSource.getInstance(getContext())); + accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext())); + favoriteRepository = FavoriteRepository.getInstance(FavoriteDataSource.getInstance(getContext())); setHasOptionsMenu(true); } @@ -907,9 +905,9 @@ public class ProfileFragment extends Fragment implements SwipeRefreshLayout.OnRe profileModel.getSdProfilePic(), new Date() ); - favoriteRepository.insertOrUpdateFavorite(model, new RepositoryCallback() { + favoriteRepository.insertOrUpdateFavorite(model, new RepositoryCallback() { @Override - public void onSuccess(final Favorite result) { + public void onSuccess(final Void result) { profileDetailsBinding.favCb.setButtonDrawable(R.drawable.ic_star_check_24); profileDetailsBinding.favProgress.setVisibility(View.GONE); profileDetailsBinding.favCb.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java index 3c8398ea..5dcdde7a 100644 --- a/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/settings/MorePreferencesFragment.java @@ -33,7 +33,6 @@ import awais.instagrabber.db.repositories.AccountRepository; import awais.instagrabber.db.repositories.RepositoryCallback; import awais.instagrabber.dialogs.AccountSwitcherDialogFragment; import awais.instagrabber.repositories.responses.UserInfo; -import awais.instagrabber.utils.AppExecutors; import awais.instagrabber.utils.Constants; import awais.instagrabber.utils.CookieUtils; import awais.instagrabber.utils.FlavorTown; @@ -49,7 +48,7 @@ public class MorePreferencesFragment extends BasePreferencesFragment { private final AccountRepository accountRepository; public MorePreferencesFragment() { - accountRepository = AccountRepository.getInstance(new AppExecutors(), AccountDataSource.getInstance(getContext())); + accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(getContext())); } @Override diff --git a/app/src/main/java/awais/instagrabber/utils/AppExecutors.java b/app/src/main/java/awais/instagrabber/utils/AppExecutors.java index ca5b498b..aaf86807 100644 --- a/app/src/main/java/awais/instagrabber/utils/AppExecutors.java +++ b/app/src/main/java/awais/instagrabber/utils/AppExecutors.java @@ -35,37 +35,48 @@ import java.util.concurrent.Executors; */ public class AppExecutors { - // private static final int THREAD_COUNT = 3; + private static final int THREAD_COUNT = 3; + private static final Object LOCK = new Object(); + + private static AppExecutors instance; private final Executor diskIO; - // private final Executor networkIO; + private final Executor networkIO; private final Executor mainThread; private final ListeningExecutorService tasksThread; private AppExecutors(Executor diskIO, - // Executor networkIO, + Executor networkIO, Executor mainThread, ListeningExecutorService tasksThread) { this.diskIO = diskIO; - // this.networkIO = networkIO; + this.networkIO = networkIO; this.mainThread = mainThread; this.tasksThread = tasksThread; } - public AppExecutors() { - this(Executors.newSingleThreadExecutor(), - // Executors.newFixedThreadPool(THREAD_COUNT), - new MainThreadExecutor(), - MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10))); + public static AppExecutors getInstance() { + if (instance == null) { + synchronized (LOCK) { + if (instance == null) { + instance = new AppExecutors(Executors.newSingleThreadExecutor(), + Executors.newFixedThreadPool(THREAD_COUNT), + new MainThreadExecutor(), + MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10))); + } + } + } + return instance; } + public Executor diskIO() { return diskIO; } - // public Executor networkIO() { - // return networkIO; - // } + public Executor networkIO() { + return networkIO; + } public ListeningExecutorService tasksThread() { diff --git a/app/src/main/java/awais/instagrabber/utils/CookieUtils.java b/app/src/main/java/awais/instagrabber/utils/CookieUtils.java index 5a1a5e12..78a6998e 100644 --- a/app/src/main/java/awais/instagrabber/utils/CookieUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/CookieUtils.java @@ -63,7 +63,7 @@ public final class CookieUtils { if (cookieStore == null) return; cookieStore.removeAll(); try { - AccountRepository.getInstance(new AppExecutors(), AccountDataSource.getInstance(context)) + AccountRepository.getInstance(AccountDataSource.getInstance(context)) .deleteAllAccounts(callback); } catch (Exception e) { Log.e(TAG, "setupCookies", e); diff --git a/app/src/main/java/awais/instagrabber/utils/DataBox.java b/app/src/main/java/awais/instagrabber/utils/DataBox.java index 3df698f3..23f5d889 100755 --- a/app/src/main/java/awais/instagrabber/utils/DataBox.java +++ b/app/src/main/java/awais/instagrabber/utils/DataBox.java @@ -1,45 +1,19 @@ package awais.instagrabber.utils; -import android.content.ContentValues; import android.content.Context; -import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; -import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import awais.instagrabber.db.entities.Favorite; -import awais.instagrabber.models.enums.FavoriteType; - public final class DataBox extends SQLiteOpenHelper { private static final String TAG = "DataBox"; private static DataBox sInstance; private final static int VERSION = 3; - public final static String TABLE_COOKIES = "cookies"; - public final static String TABLE_FAVORITES = "favorites"; - - public final static String KEY_ID = "id"; - public final static String KEY_USERNAME = Constants.EXTRAS_USERNAME; - public final static String KEY_COOKIE = "cookie"; - public final static String KEY_UID = "uid"; - public final static String KEY_FULL_NAME = "full_name"; - public final static String KEY_PROFILE_PIC = "profile_pic"; - - public final static String FAV_COL_ID = "id"; - public final static String FAV_COL_QUERY = "query_text"; - public final static String FAV_COL_TYPE = "type"; - public final static String FAV_COL_DISPLAY_NAME = "display_name"; - public final static String FAV_COL_PIC_URL = "pic_url"; - public final static String FAV_COL_DATE_ADDED = "date_added"; public static synchronized DataBox getInstance(final Context context) { if (sInstance == null) sInstance = new DataBox(context.getApplicationContext()); @@ -53,21 +27,6 @@ public final class DataBox extends SQLiteOpenHelper { @Override public void onCreate(@NonNull final SQLiteDatabase db) { Log.i(TAG, "Creating tables..."); - db.execSQL("CREATE TABLE " + TABLE_COOKIES + " (" - + KEY_ID + " INTEGER PRIMARY KEY," - + KEY_UID + " TEXT," - + KEY_USERNAME + " TEXT," - + KEY_COOKIE + " TEXT," - + KEY_FULL_NAME + " TEXT," - + KEY_PROFILE_PIC + " TEXT)"); - // db.execSQL("CREATE TABLE favorites (id INTEGER PRIMARY KEY, query_text TEXT, date_added INTEGER, query_display TEXT)"); - db.execSQL("CREATE TABLE " + TABLE_FAVORITES + " (" - + FAV_COL_ID + " INTEGER PRIMARY KEY," - + FAV_COL_QUERY + " TEXT," - + FAV_COL_TYPE + " TEXT," - + FAV_COL_DISPLAY_NAME + " TEXT," - + FAV_COL_PIC_URL + " TEXT," - + FAV_COL_DATE_ADDED + " INTEGER)"); Log.i(TAG, "Tables created!"); } @@ -77,107 +36,8 @@ public final class DataBox extends SQLiteOpenHelper { // switch without break, so that all migrations from a previous version to new are run switch (oldVersion) { case 1: - db.execSQL("ALTER TABLE " + TABLE_COOKIES + " ADD " + KEY_FULL_NAME + " TEXT"); - db.execSQL("ALTER TABLE " + TABLE_COOKIES + " ADD " + KEY_PROFILE_PIC + " TEXT"); case 2: - final List oldFavorites = backupOldFavorites(db); - // recreate with new columns (as there will be no doubt about the `query_display` column being present or not in the future versions) - db.execSQL("DROP TABLE " + TABLE_FAVORITES); - db.execSQL("CREATE TABLE " + TABLE_FAVORITES + " (" - + FAV_COL_ID + " INTEGER PRIMARY KEY," - + FAV_COL_QUERY + " TEXT," - + FAV_COL_TYPE + " TEXT," - + FAV_COL_DISPLAY_NAME + " TEXT," - + FAV_COL_PIC_URL + " TEXT," - + FAV_COL_DATE_ADDED + " INTEGER)"); - // add the old favorites back - for (final Favorite oldFavorite : oldFavorites) { - insertOrUpdateFavorite(db, oldFavorite); - } } Log.i(TAG, String.format("DB update from v%d to v%d completed!", oldVersion, newVersion)); } - - public synchronized void insertOrUpdateFavorite(@NonNull final SQLiteDatabase db, @NonNull final Favorite model) { - final ContentValues values = new ContentValues(); - values.put(FAV_COL_QUERY, model.getQuery()); - values.put(FAV_COL_TYPE, model.getType().toString()); - values.put(FAV_COL_DISPLAY_NAME, model.getDisplayName()); - values.put(FAV_COL_PIC_URL, model.getPicUrl()); - values.put(FAV_COL_DATE_ADDED, model.getDateAdded().getTime()); - int rows; - if (model.getId() >= 1) { - rows = db.update(TABLE_FAVORITES, values, FAV_COL_ID + "=?", new String[]{String.valueOf(model.getId())}); - } else { - rows = db.update(TABLE_FAVORITES, - values, - FAV_COL_QUERY + "=?" + - " AND " + FAV_COL_TYPE + "=?", - new String[]{model.getQuery(), model.getType().toString()}); - } - if (rows != 1) { - db.insert(TABLE_FAVORITES, null, values); - } - } - - @NonNull - private List backupOldFavorites(@NonNull final SQLiteDatabase db) { - // check if old favorites table had the column query_display - final boolean queryDisplayExists = checkColumnExists(db, TABLE_FAVORITES, "query_display"); - Log.d(TAG, "backupOldFavorites: queryDisplayExists: " + queryDisplayExists); - final List oldModels = new ArrayList<>(); - final String sql = "SELECT " - + "query_text," - + "date_added" - + (queryDisplayExists ? ",query_display" : "") - + " FROM " + TABLE_FAVORITES; - try (final Cursor cursor = db.rawQuery(sql, null)) { - if (cursor != null && cursor.moveToFirst()) { - do { - try { - final String queryText = cursor.getString(cursor.getColumnIndex("query_text")); - final Pair favoriteTypeQueryPair = Utils.migrateOldFavQuery(queryText); - if (favoriteTypeQueryPair == null) continue; - final FavoriteType type = favoriteTypeQueryPair.first; - final String query = favoriteTypeQueryPair.second; - oldModels.add(new Favorite( - -1, - query, - type, - queryDisplayExists ? cursor.getString(cursor.getColumnIndex("query_display")) - : null, - null, - new Date(cursor.getLong(cursor.getColumnIndex("date_added"))) - )); - } catch (Exception e) { - Log.e(TAG, "onUpgrade", e); - } - } while (cursor.moveToNext()); - } - } catch (Exception e) { - Log.e(TAG, "onUpgrade", e); - } - Log.d(TAG, "backupOldFavorites: oldModels:" + oldModels); - return oldModels; - } - - public boolean checkColumnExists(@NonNull final SQLiteDatabase db, - @NonNull final String tableName, - @NonNull final String columnName) { - boolean exists = false; - try (Cursor cursor = db.rawQuery("PRAGMA table_info(" + tableName + ")", null)) { - if (cursor.moveToFirst()) { - do { - final String currentColumn = cursor.getString(cursor.getColumnIndex("name")); - if (currentColumn.equals(columnName)) { - exists = true; - } - } while (cursor.moveToNext()); - - } - } catch (Exception ex) { - Log.e(TAG, "checkColumnExists", ex); - } - return exists; - } } \ No newline at end of file diff --git a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java index 5f195562..2d57bd82 100755 --- a/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java +++ b/app/src/main/java/awais/instagrabber/utils/ExportImportUtils.java @@ -198,7 +198,7 @@ public final class ExportImportUtils { : favsObject.optString("pic_url"), new Date(favsObject.getLong("d"))); // Log.d(TAG, "importJson: favoriteModel: " + favoriteModel); - FavoriteRepository.getInstance(new AppExecutors(), FavoriteDataSource.getInstance(context)) + FavoriteRepository.getInstance(FavoriteDataSource.getInstance(context)) .insertOrUpdateFavorite(favorite, null); } } @@ -225,7 +225,7 @@ public final class ExportImportUtils { Log.e(TAG, "importAccounts: Error parsing json", e); return; } - AccountRepository.getInstance(new AppExecutors(), AccountDataSource.getInstance(context)) + AccountRepository.getInstance(AccountDataSource.getInstance(context)) .insertOrUpdateAccounts(accounts, null); } @@ -266,9 +266,8 @@ public final class ExportImportUtils { private static void getExportString(@ExportImportFlags final int flags, @NonNull final Context context, final OnExportStringCreatedCallback callback) { - final AppExecutors appExecutors = new AppExecutors(); final Handler innerHandler = new Handler(); - appExecutors.tasksThread().execute(() -> { + AppExecutors.getInstance().tasksThread().execute(() -> { final CountDownLatch responseWaiter = new CountDownLatch(3); try { final JSONObject jsonObject = new JSONObject(); @@ -341,7 +340,7 @@ public final class ExportImportUtils { private static void getFavorites(final Context context, final OnFavoritesJsonLoadedCallback callback) { final FavoriteDataSource dataSource = FavoriteDataSource.getInstance(context); - final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(new AppExecutors(), dataSource); + final FavoriteRepository favoriteRepository = FavoriteRepository.getInstance(dataSource); try { favoriteRepository.getAllFavorites(new RepositoryCallback>() { @Override @@ -379,7 +378,7 @@ public final class ExportImportUtils { } private static void getCookies(final Context context, final OnAccountJsonLoadedCallback callback) { - final AccountRepository accountRepository = AccountRepository.getInstance(new AppExecutors(), AccountDataSource.getInstance(context)); + final AccountRepository accountRepository = AccountRepository.getInstance(AccountDataSource.getInstance(context)); accountRepository.getAllAccounts(new RepositoryCallback>() { @Override public void onSuccess(final List accounts) {