diff --git a/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java b/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java --- a/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java +++ b/app/src/main/java/it/reyboz/bustorino/ActivityPrincipal.java @@ -53,7 +53,6 @@ import it.reyboz.bustorino.data.DBUpdateCheckWorker; import it.reyboz.bustorino.data.DBUpdateWorker; import it.reyboz.bustorino.data.PreferencesHolder; -import it.reyboz.bustorino.data.gtfs.GtfsDatabase; import it.reyboz.bustorino.fragments.*; import it.reyboz.bustorino.middleware.GeneralActivity; import it.reyboz.bustorino.viewmodels.ServiceAlertsViewModel; @@ -218,7 +217,7 @@ } } if (showProgress) { - createDefaultSnackbar(); + createDatabaseUpdateSnackbar(); } else { if(snackbar!=null) { snackbar.dismiss(); @@ -493,8 +492,7 @@ * Create and show the SnackBar with the message * The fragment shown points to which view to attach the snackbar */ - private void createDefaultSnackbar() { - + private void createDatabaseUpdateSnackbar() { View baseView = null; boolean showSnackbar = true; final Fragment frag = getSupportFragmentManager().findFragmentById(R.id.mainActContentFrame); @@ -505,11 +503,13 @@ if (baseView == null) baseView = findViewById(R.id.mainActContentFrame); //if (baseView == null) Log.e(DEBUG_TAG, "baseView null for default snackbar, probably exploding now"); if (baseView !=null && showSnackbar) { - this.snackbar = Snackbar.make(baseView, R.string.database_update_msg_inapp, Snackbar.LENGTH_INDEFINITE); + snackbar = Snackbar.make(baseView, R.string.database_update_msg_inapp, Snackbar.LENGTH_INDEFINITE); + snackbar.setTextColor(getColor(android.R.color.white)); + snackbar.setBackgroundTint(getColor(R.color.grey_800)); if (frag instanceof ScreenBaseFragment){ - ((ScreenBaseFragment) frag).setSnackbarPropertiesBeforeShowing(this.snackbar); + ((ScreenBaseFragment) frag).setSnackbarPropertiesBeforeShowing(snackbar); } - this.snackbar.show(); + snackbar.show(); } else{ Log.e(DEBUG_TAG, "Asked to show the snackbar but the baseView is null"); diff --git a/app/src/main/java/it/reyboz/bustorino/backend/StopFavoritesData.kt b/app/src/main/java/it/reyboz/bustorino/backend/StopFavoritesData.kt new file mode 100644 --- /dev/null +++ b/app/src/main/java/it/reyboz/bustorino/backend/StopFavoritesData.kt @@ -0,0 +1,18 @@ +package it.reyboz.bustorino.backend + +import android.util.Log + +data class StopFavoritesData( + val stopID: String, + val stopUserName: String? = null +) { + constructor(s: Stop) : this(s.ID,s.stopUserName) + + fun addToStop(s: Stop) { + if(s.ID!=stopID){ + Log.e("BusTO-FavoritesData", "Trying to add info to stop with different ID") + } else{ + s.stopUserName =stopUserName + } + } +} diff --git a/app/src/main/java/it/reyboz/bustorino/data/AppDataProvider.java b/app/src/main/java/it/reyboz/bustorino/data/AppDataProvider.java --- a/app/src/main/java/it/reyboz/bustorino/data/AppDataProvider.java +++ b/app/src/main/java/it/reyboz/bustorino/data/AppDataProvider.java @@ -28,13 +28,12 @@ import androidx.annotation.Nullable; import it.reyboz.bustorino.BuildConfig; import it.reyboz.bustorino.backend.DBStatusManager; -import it.reyboz.bustorino.backend.Stop; import it.reyboz.bustorino.backend.utils; import it.reyboz.bustorino.data.NextGenDB.Contract.*; import java.util.List; -import static it.reyboz.bustorino.data.UserDB.getFavoritesColumnNamesAsArray; +import static it.reyboz.bustorino.data.UserDB.FAVORITES_COLUMNS_ARRAY; public class AppDataProvider extends ContentProvider { @@ -249,7 +248,7 @@ } case FAVORITES_OP: - final String stopFavSelection = getFavoritesColumnNamesAsArray[0]+" = ?"; + final String stopFavSelection = FAVORITES_COLUMNS_ARRAY[0]+" = ?"; db = userDBHelper.getReadableDatabase(); Log.d(DEBUG_TAG,"Asked information on Favorites about stop with id "+uri.getLastPathSegment()); return db.query(UserDB.TABLE_NAME,projection,stopFavSelection,new String[]{uri.getLastPathSegment()},null,null,sortOrder); diff --git a/app/src/main/java/it/reyboz/bustorino/data/FavoritesLiveData.java b/app/src/main/java/it/reyboz/bustorino/data/FavoritesLiveData.java --- a/app/src/main/java/it/reyboz/bustorino/data/FavoritesLiveData.java +++ b/app/src/main/java/it/reyboz/bustorino/data/FavoritesLiveData.java @@ -33,7 +33,6 @@ import androidx.lifecycle.LiveData; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -100,7 +99,7 @@ } isQueryRunning = true; - queryHandler.startQuery(FAV_TOKEN,null, FAVORITES_URI, UserDB.getFavoritesColumnNamesAsArray, null, null, null); + queryHandler.startQuery(FAV_TOKEN,null, FAVORITES_URI, UserDB.FAVORITES_COLUMNS_ARRAY, null, null, null); } @@ -145,7 +144,7 @@ return; } if (token == FAV_TOKEN) { - stopsFromFavorites = UserDB.getFavoritesFromCursor(cursor, UserDB.getFavoritesColumnNamesAsArray); + stopsFromFavorites = UserDB.getFavoritesFromCursor(cursor, UserDB.FAVORITES_COLUMNS_ARRAY); cursor.close(); //reset counters stopNeededCount = stopsFromFavorites.size(); diff --git a/app/src/main/java/it/reyboz/bustorino/data/FavoritesViewModel.java b/app/src/main/java/it/reyboz/bustorino/data/FavoritesViewModel.java deleted file mode 100644 --- a/app/src/main/java/it/reyboz/bustorino/data/FavoritesViewModel.java +++ /dev/null @@ -1,35 +0,0 @@ -package it.reyboz.bustorino.data; - -import android.app.Application; -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.lifecycle.AndroidViewModel; -import androidx.lifecycle.LiveData; - -import java.util.List; - -import it.reyboz.bustorino.backend.Stop; - -public class FavoritesViewModel extends AndroidViewModel { - - FavoritesLiveData favoritesLiveData; - - public FavoritesViewModel(@NonNull Application application) { - super(application); - //appContext = application.getApplicationContext(); - } - - @Override - protected void onCleared() { - favoritesLiveData.onClear(); - super.onCleared(); - } - - public FavoritesLiveData getFavorites(){ - if (favoritesLiveData==null){ - favoritesLiveData= new FavoritesLiveData(getApplication(), true); - } - return favoritesLiveData; - } -} diff --git a/app/src/main/java/it/reyboz/bustorino/data/NextGenDB.java b/app/src/main/java/it/reyboz/bustorino/data/NextGenDB.java --- a/app/src/main/java/it/reyboz/bustorino/data/NextGenDB.java +++ b/app/src/main/java/it/reyboz/bustorino/data/NextGenDB.java @@ -28,6 +28,7 @@ import android.util.Log; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import it.reyboz.bustorino.backend.Palina; import it.reyboz.bustorino.backend.Route; import it.reyboz.bustorino.backend.Stop; @@ -215,7 +216,6 @@ /** * Query stops in the database having these IDs - * REMEMBER TO CLOSE THE DB CONNECTION AFTERWARDS * @param bustoDB readable database instance * @param gtfsIDs gtfs IDs to query * @return list of stops @@ -260,6 +260,67 @@ return stops; } + public static String buildWhereClause(String colName, List args){ + final StringBuilder builder = new StringBuilder().append(colName).append(" IN "); + boolean first = true; + builder.append(" ( "); + for(int i=0; i< args.size(); i++){ + if(first){ + first = false; + } else{ + builder.append(", "); + } + builder.append("?"); + } + builder.append(") "); + return builder.toString(); + } + + /** + * Query stops in the database having these IDs + * @param bustoDB readable database instance + * @param stopIds to query + * @return list of stops + */ + @Nullable + public static synchronized ArrayList queryStopsWithStopIds(SQLiteDatabase bustoDB, List stopIds){ + ArrayList stops = null; + + if(bustoDB == null){ + Log.e(DEBUG_TAG, "Asked query for IDs but database is null"); + return stops; + } else if (stopIds == null || stopIds.isEmpty()) { + return stops; + } + + final StringBuilder builder = new StringBuilder().append(StopsTable.COL_ID).append(" IN "); + boolean first = true; + builder.append(" ( "); + for(int i=0; i< stopIds.size(); i++){ + if(first){ + first = false; + } else{ + builder.append(", "); + } + builder.append("?");//.append("\"").append(id).append("\""); + } + builder.append(") "); + final String whereClause = builder.toString(); + Log.d(DEBUG_TAG, "Asking for all stops with IDs, query: "+whereClause); + + final String[] idsQuery = stopIds.toArray(new String[0]); + + try(Cursor result = bustoDB.query(StopsTable.TABLE_NAME,QUERY_COLUMN_stops_all, whereClause, + idsQuery, + null, null, null)) { + stops = getStopsFromCursorAllFields(result); + } catch(SQLiteException e) { + Log.e(DEBUG_TAG, "SQLiteException occurred"); + } + return stops; + } + + /** * Get the list of stop in the query, with all the possible fields {NextGenDB.QUERY_COLUMN_stops_all} * @param result cursor from query diff --git a/app/src/main/java/it/reyboz/bustorino/data/OldDataRepository.kt b/app/src/main/java/it/reyboz/bustorino/data/OldDataRepository.kt --- a/app/src/main/java/it/reyboz/bustorino/data/OldDataRepository.kt +++ b/app/src/main/java/it/reyboz/bustorino/data/OldDataRepository.kt @@ -18,18 +18,21 @@ package it.reyboz.bustorino.data import android.content.Context +import android.util.Log import androidx.sqlite.SQLiteException import it.reyboz.bustorino.backend.Result import it.reyboz.bustorino.backend.Stop +import it.reyboz.bustorino.backend.StopFavoritesData import it.reyboz.bustorino.backend.utils import java.util.ArrayList import java.util.concurrent.Executor class OldDataRepository(private val executor: Executor, private val nextGenDB: NextGenDB, + private val userDB: UserDB ) { - constructor(executor: Executor, context: Context): this(executor, NextGenDB.getInstance(context)) + constructor(executor: Executor, context: Context): this(executor, NextGenDB.getInstance(context), UserDB.getInstance(context)) fun requestStopsWithGtfsIDs( gtfsIDs: List?, callback: Callback> @@ -46,6 +49,42 @@ } } } + fun requestStopsWithIds(ids: List, callback: Callback>) { + executor.execute { + try { + //final NextGenDB dbHelper = new NextGenDB(context); + val db = nextGenDB.readableDatabase + val stops: List? = NextGenDB.queryStopsWithStopIds(db, ids) + //Result> result = Result.success; + if (stops != null) { + callback.onComplete(Result.success(stops!!)) + } else { + callback.onComplete(Result.failure(android.database.sqlite.SQLiteException())) + } + } catch (e: Exception) { + callback.onComplete(Result.failure(e)) + } + } + + } + + fun getFavoritesData(ids: List, callback: Callback>){ + executor.execute { + try { + val db = userDB.readableDatabase + val data = UserDB.queryDataForStopIds(db, ids) + Log.d(DEBUG_TAG, "received favorites data: $data") + if(data != null){ + callback.onComplete(Result.success(data)) + } + else{ + callback.onComplete(Result.failure(android.database.sqlite.SQLiteException())) + } + } catch (e: Exception) { + callback.onComplete(Result.failure(e)) + } + } + } fun requestStopsInArea( latitFrom: Double, @@ -89,4 +128,8 @@ fun interface Callback { fun onComplete(result: Result) } + + companion object { + private const val DEBUG_TAG = "BusTO-OldDataRepo" + } } diff --git a/app/src/main/java/it/reyboz/bustorino/data/UserDB.java b/app/src/main/java/it/reyboz/bustorino/data/UserDB.java --- a/app/src/main/java/it/reyboz/bustorino/data/UserDB.java +++ b/app/src/main/java/it/reyboz/bustorino/data/UserDB.java @@ -28,15 +28,16 @@ import android.net.Uri; import android.util.Log; -import java.io.IOException; import java.util.*; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import de.siegmar.fastcsv.reader.CloseableIterator; import de.siegmar.fastcsv.reader.CsvReader; import de.siegmar.fastcsv.reader.CsvRecord; import de.siegmar.fastcsv.writer.CsvWriter; import it.reyboz.bustorino.backend.Stop; +import it.reyboz.bustorino.backend.StopFavoritesData; import it.reyboz.bustorino.backend.StopsDBInterface; public class UserDB extends SQLiteOpenHelper { @@ -48,8 +49,9 @@ public final static String COL_USERNAME="username"; public static final int FILE_INVALID=-10; + private static final String DEBUG_TAG = "BusTO-FavoritesUserDB"; private final static String[] usernameColumnNameAsArray = {"username"}; - public final static String[] getFavoritesColumnNamesAsArray = {COL_ID, COL_USERNAME}; + public final static String[] FAVORITES_COLUMNS_ARRAY = {COL_ID, COL_USERNAME}; private static final Uri FAVORITES_URI = AppDataProvider.getUriBuilderToComplete().appendPath( AppDataProvider.FAVORITES).build(); @@ -200,15 +202,14 @@ public static @Nullable String getStopUserName(SQLiteDatabase db, String stopID) { String username = null; - try { - Cursor c = db.query(TABLE_NAME, usernameColumnNameAsArray, "ID = ?", new String[] {stopID}, null, null, null); + try(Cursor c = db.query(TABLE_NAME, usernameColumnNameAsArray, "ID = ?", + new String[] {stopID}, null, null, null)) { if(c.moveToNext()) { int userNameIndex = c.getColumnIndex("username"); if (userNameIndex>=0) username = c.getString(userNameIndex); } - c.close(); } catch(SQLiteException e) { Log.e("BusTO-UserDB","Cannot get stop User name for stop "+stopID+":\n"+e); } @@ -229,7 +230,7 @@ String stopID, stopUserName; try { - Cursor c = db.query(TABLE_NAME, getFavoritesColumnNamesAsArray, null, null, null, null, null, null); + Cursor c = db.query(TABLE_NAME, FAVORITES_COLUMNS_ARRAY, null, null, null, null, null, null); int colID = c.getColumnIndex("ID"); int colUser = c.getColumnIndex("username"); @@ -264,7 +265,7 @@ public static ArrayList getFavoritesFromCursor(Cursor cursor, String[] columns){ List colsList = Arrays.asList(columns); - if (!colsList.contains(getFavoritesColumnNamesAsArray[0]) || !colsList.contains(getFavoritesColumnNamesAsArray[1])){ + if (!colsList.contains(FAVORITES_COLUMNS_ARRAY[0]) || !colsList.contains(FAVORITES_COLUMNS_ARRAY[1])){ throw new IllegalArgumentException(); } ArrayList l = new ArrayList<>(); @@ -285,55 +286,104 @@ return l; } + public static ArrayList queryDataForStopIds(SQLiteDatabase db, List stopIds) { + + ArrayList result = null; + + final String whereClause = NextGenDB.buildWhereClause(COL_ID, stopIds); + final String[] whereArgs = stopIds.toArray(new String[0]); + Log.d(DEBUG_TAG, "queryDtaForStopId: " + whereClause+ " args: " + Arrays.toString(whereArgs)); + try(Cursor c = db.query( + TABLE_NAME, FAVORITES_COLUMNS_ARRAY, whereClause, + whereArgs, null, null, null, null)){ + + result = getFavoritesDataFromCursor(c, FAVORITES_COLUMNS_ARRAY); + } + catch(SQLiteException e) { + Log.e(DEBUG_TAG, "queryDataForStopIds favorites failed for " + stopIds, e); + return null; + } + + return result; + } + + @NonNull + public static ArrayList getFavoritesDataFromCursor(@NonNull Cursor cursor, String[] columns){ + List colsList = Arrays.asList(columns); + if (!colsList.contains(FAVORITES_COLUMNS_ARRAY[0]) || !colsList.contains(FAVORITES_COLUMNS_ARRAY[1])){ + throw new IllegalArgumentException(); + } + ArrayList l = new ArrayList<>(); + final int colID = cursor.getColumnIndex("ID"); + final int colUser = cursor.getColumnIndex("username"); + while(cursor.moveToNext()) { + final String stopUserName = cursor.getString(colUser); + final String stopID = cursor.getString(colID); + l.add(new StopFavoritesData(stopID, stopUserName)); + } + return l; + } public static boolean addOrUpdateStop(Stop s, SQLiteDatabase db) { + return addOrUpdateStop(s.ID, s.getStopUserName(), db); + } + public static boolean addOrUpdateStop(@NonNull String stopID, @Nullable String stopUserName, @NonNull SQLiteDatabase db) { ContentValues cv = new ContentValues(); long result = -1; - String un = s.getStopUserName(); - cv.put("ID", s.ID); + cv.put("ID", stopID); // is there an username? - if(un == null) { + if(stopUserName == null) { // no: see if it's in the database - cv.put("username", getStopUserName(db, s.ID)); + cv.put("username", getStopUserName(db, stopID)); } else { // yes: use it - cv.put("username", un); + cv.put("username", stopUserName); } try { //ignore and throw -1 if the row is already in the DB result = db.insertWithOnConflict(TABLE_NAME, null, cv,SQLiteDatabase.CONFLICT_IGNORE); - } catch (SQLiteException ignored) {} - + } catch (SQLiteException ignored) { + Log.e(DEBUG_TAG, "cannot insert stop in user db, error: " + ignored); + } // Android Studio suggested this unreadable replacement: return true if insert succeeded (!= -1), or try to update and return - return (result != -1) || updateStop(s, db); + return (result != -1) || (updateStop(stopID,stopUserName, db)); } - public static boolean updateStop(Stop s, SQLiteDatabase db) { + public static boolean updateStop(@NonNull Stop s,@NonNull SQLiteDatabase db) { + return updateStop(s.ID, s.getStopUserName(), db); + } + public static boolean updateStop(@NonNull String stopID, @Nullable String stopUsername, @NonNull SQLiteDatabase db) { try { ContentValues cv = new ContentValues(); - cv.put("username", s.getStopUserName()); - db.update(TABLE_NAME, cv, "ID = ?", new String[]{s.ID}); + cv.put("username", stopUsername); + db.update(TABLE_NAME, cv, "ID = ?", new String[]{stopID}); return true; } catch(SQLiteException e) { + Log.w(DEBUG_TAG, "setStopUsername failed",e); return false; } } - public static boolean deleteStop(Stop s, SQLiteDatabase db) { + public static boolean deleteStop(@NonNull String stopID,@NonNull SQLiteDatabase db) { try { - db.delete(TABLE_NAME, "ID = ?", new String[]{s.ID}); + db.delete(TABLE_NAME, "ID = ?", new String[]{stopID}); return true; } catch(SQLiteException e) { + Log.w(DEBUG_TAG, "failed to remove stop, ID: "+stopID); return false; } } + public static boolean deleteStop(@NonNull Stop s, @NonNull SQLiteDatabase db) { + return deleteStop(s.ID, db); + } + public static boolean checkStopInFavorites(String stopID, Context con){ boolean found = false; // no stop no party if (stopID != null) { - SQLiteDatabase userDB = new UserDB(con).getReadableDatabase(); + SQLiteDatabase userDB = UserDB.getInstance(con).getReadableDatabase(); found = UserDB.isStopInFavorites(userDB, stopID); } @@ -346,7 +396,7 @@ String sortOrder = COL_ID + " DESC"; - Cursor cursor = db.query(TABLE_NAME, getFavoritesColumnNamesAsArray,null,null,null,null, sortOrder); + Cursor cursor = db.query(TABLE_NAME, FAVORITES_COLUMNS_ARRAY,null,null,null,null, sortOrder); final int nCols = 2;//cursor.getColumnCount(); writer.writeRecord(cursor.getColumnNames()); @@ -401,4 +451,6 @@ return updated; } + + //TODO: Copy method from @AppDataProvider to get all the favorites } diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt --- a/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/ArrivalsFragment.kt @@ -44,7 +44,7 @@ import it.reyboz.bustorino.data.AppDataProvider import it.reyboz.bustorino.data.NextGenDB import it.reyboz.bustorino.data.UserDB -import it.reyboz.bustorino.middleware.AsyncStopFavoriteAction +import it.reyboz.bustorino.middleware.CoroutineFavoriteAction import it.reyboz.bustorino.util.LinesNameSorter import it.reyboz.bustorino.viewmodels.ArrivalsViewModel import java.util.* @@ -61,7 +61,6 @@ private var lastUpdatedPalina: Palina? = null private var needUpdateOnAttach = false private var fetchersChangeRequestPending = false - private var stopIsInFavorites = false //Views protected lateinit var addToFavorites: ImageButton @@ -133,6 +132,8 @@ stopID = requireArguments().getString(KEY_STOP_ID) ?: "" DEBUG_TAG = DEBUG_TAG_ALL + " " + stopID + arrivalsViewModel.setStopId(stopID) + //this might really be null stopName = requireArguments().getString(KEY_STOP_NAME) val arrivalsFragment = this @@ -210,7 +211,7 @@ addToFavorites.setClickable(true) addToFavorites.setOnClickListener(View.OnClickListener { v: View? -> // add/remove the stop in the favorites - toggleLastStopToFavorites() + toggleStopFavorites() }) val displayName = requireArguments().getString(STOP_TITLE) @@ -245,9 +246,10 @@ timesSourceTextView.setText(sourcesTextViewData); }*/ //need to do this when we recreate the fragment but we haven't updated the arrival times - if(lastUpdatedPalina == null && arrivalsViewModel.palinaLiveData.value != null) { + val tentPalina = arrivalsViewModel.palinaToShow.value + if(lastUpdatedPalina == null && tentPalina != null) { //this updates lastUpdatedPalina and also shows the arrival source - updateFragmentData(arrivalsViewModel.palinaLiveData.value!!) + updateFragmentData(tentPalina) } //lastUpdatedPalina?.let { showArrivalsSources(it) } @@ -272,7 +274,7 @@ } }) - arrivalsViewModel.palinaLiveData.observe(viewLifecycleOwner){ + arrivalsViewModel.palinaToShow.observe(viewLifecycleOwner){ Log.d(DEBUG_TAG, "New result palina observed, has coords: ${it.hasCoords()}, title ${it?.stopDisplayName}, number of passages: ${it.totalNumberOfPassages}") val palinaIsValid = it!=null && (it.totalNumberOfPassages>0 || it.stopDisplayName!=null) @@ -319,6 +321,9 @@ else -> showFetcherMessage(R.string.internal_error, src) } } + arrivalsViewModel.stopInFavorites.observe(viewLifecycleOwner, { isFavorite -> + updateStarIcon(isFavorite) + }) return root } @@ -609,7 +614,7 @@ when (id) { loaderFavId -> { builder.appendPath("favorites").appendPath(stopID) - cl = CursorLoader(requireContext(), builder.build(), UserDB.getFavoritesColumnNamesAsArray, null, null, null) + cl = CursorLoader(requireContext(), builder.build(), UserDB.FAVORITES_COLUMNS_ARRAY, null, null, null) } loaderStopId -> { @@ -630,9 +635,10 @@ } override fun onLoadFinished(loader: Loader, data: Cursor) { + /* when (loader.id) { loaderFavId -> { - val colUserName = data.getColumnIndex(UserDB.getFavoritesColumnNamesAsArray[1]) + val colUserName = data.getColumnIndex(UserDB.FAVORITES_COLUMNS_ARRAY[1]) if (data.count > 0) { // IT'S IN FAVORITES data.moveToFirst() @@ -646,7 +652,7 @@ stopIsInFavorites = false } updateStarIcon() - /* + if (stopName == null) { //stop is not inside the favorites and wasn't provided Log.d("ArrivalsFragment$tag", "Stop wasn't in the favorites and has no name, looking in the DB") @@ -655,10 +661,8 @@ arguments, this ) } - 6 - */ } - /* + loaderStopId -> if (data.count > 0) { data.moveToFirst() val index = data.getColumnIndex( @@ -673,10 +677,14 @@ Log.w("ArrivalsFragment$tag", "Stop is not inside the database... CLOISTER BELL") } - */ + } + + */ } + + override fun onLoaderReset(loader: Loader) { //NOTHING TO DO } @@ -687,20 +695,23 @@ arrivalsRecyclerView.visibility = View.VISIBLE } - fun toggleLastStopToFavorites() { + fun toggleStopFavorites() { val stop: Stop? = lastUpdatedPalina if (stop != null) { // toggle the status in background + CoroutineFavoriteAction(requireContext().applicationContext, CoroutineFavoriteAction.Action.TOGGLE){ + arrivalsViewModel.checkFavoriteAsync() - AsyncStopFavoriteAction( - requireContext().applicationContext, AsyncStopFavoriteAction.Action.TOGGLE - ) { v: Boolean -> updateStarIconFromLastBusStop(v) }.execute(stop) - } else { + }.execute(stop) + + + } else { // this case have no sense, but just immediately update the favorite icon - updateStarIconFromLastBusStop(true) + //updateStarIconFromLastBusStop(true) + Log.d(DEBUG_TAG, "Stop is null!") } } - + /* /** * Update the star "Add to favorite" icon */ @@ -709,28 +720,14 @@ else toggleDone updateStarIcon() - - // check if there is a last Stop - /* - if (stopID == null) { - addToFavorites.setVisibility(View.INVISIBLE); - } else { - // filled or outline? - if (isStopInFavorites(stopID)) { - addToFavorites.setImageResource(R.drawable.ic_star_filled); - } else { - addToFavorites.setImageResource(R.drawable.ic_star_outline); - } - - addToFavorites.setVisibility(View.VISIBLE); - } - */ } + */ + /** * Update the star icon according to `stopIsInFavorites` */ - fun updateStarIcon() { + fun updateStarIcon(stopIsInFavorites: Boolean) { // no favorites no party! // check if there is a last Stop diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/BackupImportFragment.kt b/app/src/main/java/it/reyboz/bustorino/fragments/BackupImportFragment.kt --- a/app/src/main/java/it/reyboz/bustorino/fragments/BackupImportFragment.kt +++ b/app/src/main/java/it/reyboz/bustorino/fragments/BackupImportFragment.kt @@ -192,6 +192,7 @@ val csvWriter = CsvWriter.builder().build(outWriter) val userDB = UserDB.getInstance(context) userDB.writeFavoritesToCsv(csvWriter) + csvWriter.flush() outWriter.flush() zipOutputStream.closeEntry() diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/FavoritesFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/FavoritesFragment.java --- a/app/src/main/java/it/reyboz/bustorino/fragments/FavoritesFragment.java +++ b/app/src/main/java/it/reyboz/bustorino/fragments/FavoritesFragment.java @@ -35,7 +35,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.lifecycle.Observer; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; @@ -50,8 +49,8 @@ import it.reyboz.bustorino.adapters.StopRecyclerAdapter; import it.reyboz.bustorino.backend.Stop; import it.reyboz.bustorino.data.DatabaseUpdate; -import it.reyboz.bustorino.data.FavoritesViewModel; -import it.reyboz.bustorino.middleware.AsyncStopFavoriteAction; +import it.reyboz.bustorino.middleware.CoroutineFavoriteAction; +import it.reyboz.bustorino.viewmodels.FavoritesViewModel; public class FavoritesFragment extends ScreenBaseFragment { @@ -219,11 +218,9 @@ switch (item.getItemId()) { case R.id.action_favourite_entry_delete: if (getContext()!=null) - new AsyncStopFavoriteAction(getContext().getApplicationContext(), AsyncStopFavoriteAction.Action.REMOVE, - result -> { - - }).execute(busStop); - + new CoroutineFavoriteAction(requireContext().getApplicationContext(), CoroutineFavoriteAction.Action.REMOVE, + result -> {} + ).execute(busStop); return true; case R.id.action_rename_bus_stop_username: @@ -325,10 +322,17 @@ private void launchUpdate(Stop busStop){ if (getContext()!=null) - new AsyncStopFavoriteAction(getContext().getApplicationContext(), AsyncStopFavoriteAction.Action.UPDATE, + + new CoroutineFavoriteAction(requireContext().getApplicationContext(), CoroutineFavoriteAction.Action.UPDATE, + result -> { + //Toast.makeText(getApplicationContext(), R.string.tip_add_favorite, Toast.LENGTH_SHORT).show(); + }).execute(busStop); + /*new AsyncStopFavoriteAction(getContext().getApplicationContext(), AsyncStopFavoriteAction.Action.UPDATE, result -> { //Toast.makeText(getApplicationContext(), R.string.tip_add_favorite, Toast.LENGTH_SHORT).show(); }).execute(busStop); + */ + } /* THIS LOOKS TERRIBLE diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java --- a/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java +++ b/app/src/main/java/it/reyboz/bustorino/fragments/MainScreenFragment.java @@ -21,8 +21,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.location.Criteria; -import android.location.Location; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -61,13 +59,11 @@ import it.reyboz.bustorino.R; import it.reyboz.bustorino.backend.*; import it.reyboz.bustorino.data.PreferencesHolder; -import it.reyboz.bustorino.middleware.AppLocationManager; import it.reyboz.bustorino.middleware.AsyncArrivalsSearcher; import it.reyboz.bustorino.middleware.AsyncStopsSearcher; import it.reyboz.bustorino.middleware.BarcodeScanContract; import it.reyboz.bustorino.middleware.BarcodeScanOptions; import it.reyboz.bustorino.middleware.BarcodeScanUtils; -import it.reyboz.bustorino.util.LocationCriteria; import it.reyboz.bustorino.util.Permissions; import static it.reyboz.bustorino.backend.utils.getBusStopIDFromUri; @@ -112,7 +108,7 @@ private int searchMode; //private ImageButton addToFavorites; //// HIDDEN BUT IMPORTANT ELEMENTS //// - FragmentManager childFragMan; + private FragmentManager childFragMan; Handler mainHandler; private final Runnable refreshStop = new Runnable() { public void run() { @@ -171,7 +167,7 @@ boolean pendingIntroRun = false; boolean pendingNearbyStopsFragmentRequest = false; boolean locationPermissionGranted, locationPermissionAsked = false; - AppLocationManager locationManager; + //AppLocationManager locationManager; private final ActivityResultLauncher requestPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), new ActivityResultCallback<>() { @Override @@ -187,11 +183,13 @@ || Boolean.TRUE.equals(result.get(Manifest.permission.ACCESS_FINE_LOCATION))) { locationPermissionGranted = true; Log.w(DEBUG_TAG, "Starting position"); - if (mListener != null && getContext() != null) { + /*if (mListener != null && getContext() != null) { if (locationManager == null) locationManager = AppLocationManager.getInstance(getContext()); locationManager.addLocationRequestFor(requester); } + + */ // show nearby fragment //showNearbyStopsFragment(); Log.d(DEBUG_TAG, "We have location permission"); @@ -205,9 +203,9 @@ }); - private final LocationCriteria cr = new LocationCriteria(2000, 10000); + //private final LocationCriteria cr = new LocationCriteria(2000, 10000); //Location - private AppLocationManager.LocationRequester requester = new AppLocationManager.LocationRequester() { + /*private AppLocationManager.LocationRequester requester = new AppLocationManager.LocationRequester() { @Override public void onLocationChanged(Location loc) { @@ -255,7 +253,7 @@ } }; - + */ //// ACTIVITY ATTACHED (LISTENER /// private CommonFragmentListener mListener; @@ -337,15 +335,14 @@ fragmentHelper = new FragmentHelper(this, getChildFragmentManager(), getContext(), R.id.resultFrame); setSearchModeBusStopID(); - - + /* cr.setAccuracy(Criteria.ACCURACY_FINE); cr.setAltitudeRequired(false); cr.setBearingRequired(false); cr.setCostAllowed(true); cr.setPowerRequirement(Criteria.NO_REQUIREMENT); - - locationManager = AppLocationManager.getInstance(requireContext()); + */ + //locationManager = AppLocationManager.getInstance(requireContext()); Log.d(DEBUG_TAG, "OnCreateView, savedInstanceState null: "+(savedInstanceState==null)); @@ -470,8 +467,8 @@ final Context con = requireContext(); Log.w(DEBUG_TAG, "OnResume called, setupOnStart: "+ setupOnStart); - if (locationManager == null) - locationManager = AppLocationManager.getInstance(con); + //if (locationManager == null) + // locationManager = AppLocationManager.getInstance(con); //recheck the introduction activity has been run if(pendingIntroRun && PreferencesHolder.hasIntroFinishedOneShot(con)){ //request position permission if needed @@ -487,8 +484,8 @@ } if(Permissions.bothLocationPermissionsGranted(con)){ Log.d(DEBUG_TAG, "Location permission OK"); - if(!locationManager.isRequesterRegistered(requester)) - locationManager.addLocationRequestFor(requester); + //if(!locationManager.isRequesterRegistered(requester)) + // locationManager.addLocationRequestFor(requester); } //don't request permission // if we have a pending stopID request, do it Log.d(DEBUG_TAG, "Pending stop ID for arrivals: "+pendingStopID); @@ -533,7 +530,7 @@ @Override public void onPause() { //mainHandler = null; - locationManager.removeLocationRequestFor(requester); + //locationManager.removeLocationRequestFor(requester); super.onPause(); fragmentHelper.setBlockAllActivities(true); fragmentHelper.stopLastRequestIfNeeded(true); @@ -648,7 +645,6 @@ } @Nullable - @org.jetbrains.annotations.Nullable @Override public View getBaseViewForSnackBar() { return coordLayout; @@ -718,7 +714,7 @@ hideKeyboard(); if (pendingNearbyStopsFragmentRequest) { - locationManager.removeLocationRequestFor(requester); + //locationManager.removeLocationRequestFor(requester); pendingNearbyStopsFragmentRequest = false; } } diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java --- a/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java +++ b/app/src/main/java/it/reyboz/bustorino/fragments/NearbyStopsFragment.java @@ -415,6 +415,8 @@ gridRecyclerView.setAdapter(null); Log.d(DEBUG_TAG,"On paused called"); + + locationProvider.stopUpdates(); } @Override @@ -465,6 +467,10 @@ if(BuildConfig.DEBUG) Log.d(DEBUG_TAG, "Max distance for stops: "+MAX_DISTANCE+ ", Min number of stops: "+MIN_NUM_STOPS); + if(!locationProvider.isRunning()){ + startLocationUpdatesByType(); + } + } diff --git a/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java b/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java --- a/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java +++ b/app/src/main/java/it/reyboz/bustorino/fragments/ScreenBaseFragment.java @@ -15,13 +15,12 @@ import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.google.android.material.snackbar.Snackbar; import it.reyboz.bustorino.BuildConfig; -import it.reyboz.bustorino.R; import java.util.Map; @@ -33,6 +32,7 @@ protected void setOption(String optionName, boolean value) { Context mContext = getContext(); + assert mContext != null; SharedPreferences.Editor editor = mContext.getSharedPreferences(PREF_FILE, MODE_PRIVATE).edit(); editor.putBoolean(optionName, value); editor.commit(); @@ -108,7 +108,49 @@ } }); } + /*protected void runActionFavorites(@NonNull Stop s, @NonNull FavoritesChangeWorker.Action action, @NonNull FavoritesChangeWorker.Companion.ResultListener resultListener){ + Context mContext = requireContext(); + + WorkManager workManager = WorkManager.getInstance(mContext); + + WorkRequest req = FavoritesChangeWorker.makeRequest(s, action); + workManager.enqueue(req); + Context appContext = mContext.getApplicationContext(); + + //FavoritesChangeWorker.registerListener(mContext, getViewLifecycleOwner(), s, action, resultListener); + workManager.getWorkInfosByTagLiveData(FavoritesChangeWorker.getTag(s, action)) + .observe(getViewLifecycleOwner(), wi -> { + Log.d("BusTO-BaseFragment", "workinfo for stop "+s.ID+" has arrived"); + if(wi.isEmpty()){ + return; + } + WorkInfo workInfo = wi.get(wi.size() - 1); + Data progress = wi.get(wi.size()-1).getProgress(); + + int actvalue = progress.getInt(ACTION_ARG,-1); + boolean done = progress.getBoolean(DONE_ARG, false); + if (done) { + // at this point the action should be just ADD or REMOVE + + if (actvalue == FavoritesChangeWorker.Action.ADD.getValue()) { + // now added + Toast.makeText(appContext, R.string.added_in_favorites, Toast.LENGTH_SHORT).show(); + } else if (actvalue == FavoritesChangeWorker.Action.REMOVE.getValue()) { + // now removed + Toast.makeText(appContext, R.string.removed_from_favorites, Toast.LENGTH_SHORT).show(); + } + } else { + // wtf + Toast.makeText(appContext, R.string.cant_add_to_favorites, Toast.LENGTH_SHORT).show(); + } + Log.d("busTO-ScreenBaseFragm", "favorites action="+actvalue+ ",done="+done); + + // aggiorna UI + resultListener.doStuffWithResult(done); + }); + } + */ public interface LocationRequestListener{ void onPermissionResult(boolean locationGranted); diff --git a/app/src/main/java/it/reyboz/bustorino/middleware/AppLocationManager.kt b/app/src/main/java/it/reyboz/bustorino/middleware/AppLocationManager.kt --- a/app/src/main/java/it/reyboz/bustorino/middleware/AppLocationManager.kt +++ b/app/src/main/java/it/reyboz/bustorino/middleware/AppLocationManager.kt @@ -24,9 +24,7 @@ import android.os.Bundle import android.util.Log import androidx.core.content.ContextCompat -import androidx.core.location.LocationListenerCompat import it.reyboz.bustorino.util.LocationCriteria -import it.reyboz.bustorino.util.Permissions import java.lang.ref.WeakReference import kotlin.math.min diff --git a/app/src/main/java/it/reyboz/bustorino/middleware/CoroutineFavoriteAction.kt b/app/src/main/java/it/reyboz/bustorino/middleware/CoroutineFavoriteAction.kt new file mode 100644 --- /dev/null +++ b/app/src/main/java/it/reyboz/bustorino/middleware/CoroutineFavoriteAction.kt @@ -0,0 +1,67 @@ +package it.reyboz.bustorino.middleware + +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.util.Log +import android.widget.Toast +import it.reyboz.bustorino.R +import it.reyboz.bustorino.backend.Stop +import it.reyboz.bustorino.data.UserDB +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class CoroutineFavoriteAction( + context: Context, + private var action: Action, + private val listener: ResultListener +) { + private val context = context.applicationContext + + enum class Action { ADD, REMOVE, TOGGLE, UPDATE } + + fun interface ResultListener { + fun doStuffWithResult(result: Boolean) + } + + fun execute(stop: Stop) { + CoroutineScope(Dispatchers.IO).launch { + val result = doInBackground(stop) + withContext(Dispatchers.Main) { + onPostExecute(result) + } + } + } + + private fun doInBackground(stop: Stop): Boolean { + val db = UserDB.getInstance(context).writableDatabase + + if (action == Action.TOGGLE) { + action = if (UserDB.isStopInFavorites(db, stop.ID)) Action.REMOVE else Action.ADD + } + + return when (action) { + Action.ADD -> UserDB.addOrUpdateStop(stop, db) + Action.UPDATE -> UserDB.updateStop(stop, db) + Action.REMOVE -> UserDB.deleteStop(stop, db) + Action.TOGGLE -> false // irraggiungibile, ma richiesto da when exhaustive + } + } + + private fun onPostExecute(result: Boolean) { + if (result) { + UserDB.notifyContentProvider(context) + when (action) { + Action.ADD -> Toast.makeText(context, R.string.added_in_favorites, Toast.LENGTH_SHORT).show() + Action.REMOVE -> Toast.makeText(context, R.string.removed_from_favorites, Toast.LENGTH_SHORT).show() + else -> Unit + } + } else { + Toast.makeText(context, R.string.cant_add_to_favorites, Toast.LENGTH_SHORT).show() + } + listener.doStuffWithResult(result) + Log.d("BusTO FavoritesAction", "Action $action completed") + } +} \ No newline at end of file diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/ArrivalsViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/ArrivalsViewModel.kt --- a/app/src/main/java/it/reyboz/bustorino/viewmodels/ArrivalsViewModel.kt +++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/ArrivalsViewModel.kt @@ -23,6 +23,7 @@ import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MediatorLiveData import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.map import androidx.lifecycle.viewModelScope import it.reyboz.bustorino.backend.* import it.reyboz.bustorino.backend.mato.MatoAPIFetcher @@ -37,18 +38,25 @@ class ArrivalsViewModel(application: Application): AndroidViewModel(application) { // Arrivals of palina - val appContext: Context + val appContext: Context = application.applicationContext - val palinaLiveData = MediatorLiveData() + val palinaFromArrivals = MediatorLiveData() + val palinaToShow = MediatorLiveData() val sourcesLiveData = MediatorLiveData() val resultLiveData = MutableLiveData() val currentFetchers = MediatorLiveData>() - /// OLD REPO for stops instance + private val stopID = MutableLiveData() + + fun setStopId(stopId: String) { stopID.value = (stopId) } + val stopFavoritesData = MediatorLiveData() + val stopInFavorites = stopFavoritesData.map { it != null} + + /// OLD REPO for stops instance private val executor = Executors.newFixedThreadPool(2) - private val oldRepo = OldDataRepository(executor, NextGenDB.getInstance(application)) + private val oldRepo = OldDataRepository(executor, application) private var stopIdRequested = "" private val stopFromDB = MutableLiveData() @@ -72,15 +80,33 @@ } init { - appContext = application.applicationContext - palinaLiveData.addSource(stopFromDB){ + palinaFromArrivals.addSource(stopFromDB){ s -> - val hasSource = palinaLiveData.value?.passaggiSourceIfAny - Log.d(DEBUG_TAG, "Have current palina ${palinaLiveData.value!=null}, source passaggi $hasSource, new incoming stop $s from database") - val newp = if(palinaLiveData.value == null) Palina(s) else Palina.mergePaline(palinaLiveData.value, Palina(s)) - Log.d(DEBUG_TAG, "Merged palina: $newp, num passages: ${newp?.totalNumberOfPassages}, has coords: ${newp?.hasCoords()}") - newp?.let { pal -> palinaLiveData.postValue(pal) } + val hasSource = palinaFromArrivals.value?.passaggiSourceIfAny + //Log.d(DEBUG_TAG, "Have current palina ${palinaLiveData.value!=null}, source passaggi $hasSource, new incoming stop $s from database") + val newp = if(palinaFromArrivals.value == null) Palina(s) else Palina.mergePaline(palinaFromArrivals.value, Palina(s)) + //Log.d(DEBUG_TAG, "Merged palina: $newp, num passages: ${newp?.totalNumberOfPassages}, has coords: ${newp?.hasCoords()}") + newp?.let { pal -> palinaFromArrivals.postValue(pal) } + } + palinaToShow.addSource(stopFavoritesData){ dat -> + val current = palinaFromArrivals.value + Log.d(DEBUG_TAG, "have palina $current and favorites data: $dat") + if(dat?.stopUserName!=null && current!=null){ + current.stopUserName = dat.stopUserName + //set new data in palinaLiveData + palinaToShow.value = current + } + } + palinaToShow.addSource(palinaFromArrivals){ p-> + stopFavoritesData.value?.stopUserName?.let {it -> + p.stopUserName = it + } + palinaToShow.value = p + } + + stopFavoritesData.addSource(stopID){ + checkFavoriteAsync(it) } } @@ -90,6 +116,28 @@ return palina } + fun checkFavoriteAsync(stopId: String) { + viewModelScope.launch(Dispatchers.IO) { + oldRepo.getFavoritesData(listOf(stopId)){ res -> + if(res.isSuccess) { + val data =res.result!! + if (data.isEmpty()){ + stopFavoritesData.postValue(null) + } else { + stopFavoritesData.postValue(data[0]) + } + } + } + } + } + + fun checkFavoriteAsync(){ + stopID.value?.let{ + checkFavoriteAsync(it) + Log.d(DEBUG_TAG, "started favorites check for stopId: $it") + } + } + fun requestArrivalsForStop(stopId: String, fetchers: List){ val context = appContext //application.applicationContext currentFetchers.value = fetchers @@ -222,8 +270,8 @@ arrivalsRequestRunningLiveData.postValue(false) resultLiveData.postValue(fetcherResult) Log.d(DEBUG_TAG, "Have new result palina for stop ${palina.ID}, source ${palina.passaggiSourceIfAny} has coords: ${palina.hasCoords()}") - Log.d(DEBUG_TAG, "Old palina liveData is: ${palinaLiveData.value?.stopDisplayName}, has Coords ${palinaLiveData.value?.hasCoords()}") - palinaLiveData.postValue(Palina.mergePaline(palina, palinaLiveData.value)) + Log.d(DEBUG_TAG, "Old palina liveData is: ${palinaFromArrivals.value?.stopDisplayName}, has Coords ${palinaFromArrivals.value?.hasCoords()}") + palinaFromArrivals.postValue(Palina.mergePaline(palina, palinaFromArrivals.value)) } companion object{ const val DEBUG_TAG="BusTO-ArrivalsViMo" diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/FavoritesViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/FavoritesViewModel.kt new file mode 100644 --- /dev/null +++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/FavoritesViewModel.kt @@ -0,0 +1,86 @@ +package it.reyboz.bustorino.viewmodels + +import android.app.Application +import android.util.Log +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.application +import androidx.lifecycle.map +import androidx.lifecycle.viewModelScope +import androidx.work.WorkInfo +import it.reyboz.bustorino.backend.Stop +import it.reyboz.bustorino.backend.StopFavoritesData +import it.reyboz.bustorino.data.DBUpdateWorker.Companion.getWorkInfoLiveData +import it.reyboz.bustorino.data.FavoritesLiveData +import it.reyboz.bustorino.data.OldDataRepository +import kotlinx.coroutines.launch +import java.util.concurrent.Executors + +class FavoritesViewModel(application: Application) : AndroidViewModel(application) { + var favoritesLiveData: FavoritesLiveData? = null + + override fun onCleared() { + if (favoritesLiveData != null) favoritesLiveData!!.onClear() + super.onCleared() + } + + val favorites: FavoritesLiveData + get() { + if (favoritesLiveData == null) { + favoritesLiveData = FavoritesLiveData(application, true) + } + return favoritesLiveData!! + } + + val isDBUpdating = getWorkInfoLiveData(application).map { wilist -> + var isUpdating = false + if(wilist.isNotEmpty()){ + val wi = wilist[0] + isUpdating = wi.state == WorkInfo.State.RUNNING + } + isUpdating + } + + + // ---- NEW CODE ----- + // this code is not active now, but it is gonna be useful for the day when the ContentObserver is gonna be dismissed + //for all favorites + val favoritesNoStop = MediatorLiveData(ArrayList()) + val favoritesWithStop = MediatorLiveData>() + + + + + val oldRepo: OldDataRepository + + + init { + val executor = Executors.newCachedThreadPool() + oldRepo = OldDataRepository(executor, application) + + // this fetches the stops when I have gotten the favorites + favoritesWithStop.addSource(favoritesNoStop){ dat -> + val stopIds = dat.map { it.stopID } + viewModelScope.launch { + oldRepo.requestStopsWithIds(stopIds){ result -> + if(result.isSuccess) { + val stops = result.result!! + //copy favorites info + for(s in stops) { + val di = dat.first{ it.stopID == s.ID} + di.addToStop(s) + } + + favoritesWithStop.postValue(stops) + } else{ + Log.e(DEBUG_TAG, "Error getting stops from database") + } + } + } + } + + } + companion object { + const val DEBUG_TAG = "BusTO-FavoritesViewM" + } +} diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesViewModel.kt --- a/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesViewModel.kt +++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/LinesViewModel.kt @@ -40,7 +40,7 @@ init { gtfsRepo = GtfsRepository(application) - oldRepo = OldDataRepository(executor, NextGenDB.getInstance(application)) + oldRepo = OldDataRepository(executor, application) } diff --git a/app/src/main/java/it/reyboz/bustorino/viewmodels/StopsMapViewModel.kt b/app/src/main/java/it/reyboz/bustorino/viewmodels/StopsMapViewModel.kt --- a/app/src/main/java/it/reyboz/bustorino/viewmodels/StopsMapViewModel.kt +++ b/app/src/main/java/it/reyboz/bustorino/viewmodels/StopsMapViewModel.kt @@ -34,7 +34,7 @@ private val executor = Executors.newFixedThreadPool(2) - private val oldRepo = OldDataRepository(executor, NextGenDB.getInstance(application)) + private val oldRepo = OldDataRepository(executor, application) val stopsToShow = MutableLiveData(ArrayList()) private var stopsShownIDs = HashSet()