package org.mtransit.android.provider; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import org.mtransit.android.R; import org.mtransit.android.commons.CollectionUtils; import org.mtransit.android.commons.MTLog; import org.mtransit.android.commons.SqlUtils; import org.mtransit.android.commons.ToastUtils; import org.mtransit.android.commons.UriUtils; import org.mtransit.android.data.DataSourceManager; import org.mtransit.android.data.DataSourceType; import org.mtransit.android.data.Favorite; import org.mtransit.android.data.POIManager; import org.mtransit.android.data.TextMessage; import org.mtransit.android.provider.FavoriteProvider.FavoriteColumns; import org.mtransit.android.provider.FavoriteProvider.FavoriteFolderColumns; import android.app.Activity; import android.app.AlertDialog; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.database.Cursor; import android.net.Uri; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; public class FavoriteManager implements MTLog.Loggable { private static final String TAG = FavoriteManager.class.getSimpleName(); @Override public String getLogTag() { return TAG; } public static final int DEFAULT_FOLDER_ID = 0; private static FavoriteManager instance = null; public static FavoriteManager get(Context context) { if (instance == null) { initInstance(context); } return instance; } private static void initInstance(Context context) { instance = new FavoriteManager(); instance.favoriteFolders = findFolders(context); } private HashMap<Integer, Favorite.Folder> favoriteFolders = null; public HashMap<Integer, Favorite.Folder> getFavoriteFolders() { return this.favoriteFolders; } public boolean hasFavoriteFolders() { return this.favoriteFolders != null && this.favoriteFolders.size() > 0; } public boolean hasFavoriteFolder(int favoriteFolderId) { return this.favoriteFolders != null && this.favoriteFolders.containsKey(favoriteFolderId); } public Favorite.Folder getFolder(int favoriteFolderId) { return this.favoriteFolders == null ? null : this.favoriteFolders.get(favoriteFolderId); } private void addFolder(Favorite.Folder favoriteFolder) { if (this.favoriteFolders == null) { MTLog.w(this, "Try to add folder to the list before init!"); return; } this.favoriteFolders.put(favoriteFolder.getId(), favoriteFolder); } private void removeFolder(Favorite.Folder favoriteFolder) { removeFolder(favoriteFolder.getId()); } private void removeFolder(int favoriteFolderId) { if (this.favoriteFolders == null) { MTLog.w(this, "Try to remove folder to the list before init!"); return; } this.favoriteFolders.remove(favoriteFolderId); } public boolean isUsingFavoriteFolders() { if (this.favoriteFolders == null || this.favoriteFolders.size() == 0) { return false; } if (this.favoriteFolders.size() == 1 && this.favoriteFolders.get(DEFAULT_FOLDER_ID) != null) { return false; } return true; } public static boolean isFavoriteDataSourceId(int dataSourceId) { return dataSourceId > DataSourceType.MAX_ID; } public static int extractFavoriteFolderId(int dataSourceId) { return dataSourceId - DataSourceType.MAX_ID; } public static int generateFavoriteFolderId(int favoriteFolderId) { return favoriteFolderId + DataSourceType.MAX_ID; } public static int findFavoriteFolderId(Context context, String fkId) { Favorite favorite = findFavorite(context, fkId); if (favorite == null) { return -1; } return favorite.getFolderId(); } public static boolean isFavorite(Context context, String fkId) { return findFavorite(context, fkId) != null; } public static POIManager getNewEmptyFolder(Context context, long textMessageId, int favoriteFolderId) { TextMessage textMessage = new TextMessage(textMessageId++, context.getString(R.string.favorite_folder_empty)); textMessage.setDataSourceTypeId(generateFavoriteFolderId(favoriteFolderId)); return new POIManager(textMessage); } public static Favorite findFavorite(Context context, String fkId) { Favorite favorite = null; Cursor cursor = null; try { Uri uri = getFavoriteContentUri(context); String selection = SqlUtils.getWhereEqualsString(FavoriteColumns.T_FAVORITE_K_FK_ID, fkId); cursor = DataSourceManager.queryContentResolver(context.getContentResolver(), uri, FavoriteProvider.PROJECTION_FAVORITE, selection, null, null); if (cursor != null && cursor.getCount() > 0) { if (cursor.moveToFirst()) { favorite = Favorite.fromCursor(cursor); } } } catch (Exception e) { MTLog.w(TAG, e, "Error!"); } finally { SqlUtils.closeQuietly(cursor); } return favorite; } private static Favorite findFavorite(Context context, Uri uri, String selection) { Favorite cache = null; Cursor cursor = null; try { cursor = DataSourceManager.queryContentResolver(context.getContentResolver(), uri, FavoriteProvider.PROJECTION_FAVORITE, selection, null, null); if (cursor != null && cursor.getCount() > 0) { if (cursor.moveToFirst()) { cache = Favorite.fromCursor(cursor); } } } catch (Exception e) { MTLog.w(TAG, e, "Error!"); } finally { SqlUtils.closeQuietly(cursor); } return cache; } public static HashSet<String> findFavoriteUUIDs(Context context) { return extratFavoriteUUIDs(findFavorites(context)); } public static HashSet<String> extratFavoriteUUIDs(ArrayList<Favorite> favorites) { HashSet<String> favoriteUUIDs = new HashSet<String>(); if (favorites != null) { for (Favorite favorite : favorites) { favoriteUUIDs.add(favorite.getFkId()); } } return favoriteUUIDs; } public static ArrayList<Favorite> findFavorites(Context context) { ArrayList<Favorite> result = new ArrayList<Favorite>(); Cursor cursor = null; try { String selection = null; cursor = DataSourceManager.queryContentResolver(context.getContentResolver(), getFavoriteContentUri(context), FavoriteProvider.PROJECTION_FAVORITE, selection, null, null); if (cursor != null && cursor.getCount() > 0) { if (cursor.moveToFirst()) { do { result.add(Favorite.fromCursor(cursor)); } while (cursor.moveToNext()); } } } catch (Exception e) { MTLog.w(TAG, e, "Error!"); } finally { SqlUtils.closeQuietly(cursor); } return result; } private int initialWhich; private int selectedWhich; public boolean addRemoveFavorite(final Activity activity, final String fkId, final FavoriteUpdateListener listener) { final Context context = activity; final int favoriteFolderId = findFavoriteFolderId(context, fkId); boolean isFavorite = favoriteFolderId >= 0; if (isUsingFavoriteFolders()) { // show folder selector int checkedItem = -1; ArrayList<String> itemsList = new ArrayList<String>(); final ArrayList<Integer> itemsListId = new ArrayList<Integer>(); int i = 0; itemsListId.add(DEFAULT_FOLDER_ID); itemsList.add(context.getString(R.string.favorite_folder_default)); if (favoriteFolderId >= 0 && favoriteFolderId == DEFAULT_FOLDER_ID) { checkedItem = i; } i++; ArrayList<Favorite.Folder> favoriteFoldersList = new ArrayList<Favorite.Folder>(getFavoriteFolders().values()); CollectionUtils.sort(favoriteFoldersList, Favorite.Folder.NAME_COMPARATOR); for (Favorite.Folder favoriteFolder : favoriteFoldersList) { if (favoriteFolder.getId() == DEFAULT_FOLDER_ID) { continue; } itemsListId.add(favoriteFolder.getId()); itemsList.add(favoriteFolder.getName()); if (favoriteFolderId >= 0 && favoriteFolderId == favoriteFolder.getId()) { checkedItem = i; } i++; } final int newFolderId = Integer.MAX_VALUE; itemsListId.add(newFolderId); itemsList.add(context.getString(R.string.favorite_folder_new)); i++; final int removeFavoriteId = newFolderId - 1; if (favoriteFolderId >= 0) { itemsListId.add(removeFavoriteId); itemsList.add(context.getString(R.string.favorite_remove)); i++; } this.initialWhich = checkedItem; if (checkedItem < 0) { checkedItem = 0; // (default choice when adding favorite) } this.selectedWhich = checkedItem; new AlertDialog.Builder(context) // .setTitle(R.string.favorite_folder_pick) // .setSingleChoiceItems(itemsList.toArray(new String[] {}), checkedItem, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { FavoriteManager.this.selectedWhich = which; } }).setPositiveButton(R.string.favorite_folder_pick_ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { if (FavoriteManager.this.selectedWhich < 0 || FavoriteManager.this.selectedWhich == FavoriteManager.this.initialWhich) { return; } int selectedFavoriteFolderId = itemsListId.get(FavoriteManager.this.selectedWhich); if (selectedFavoriteFolderId == newFolderId) { // create new folder showAddFolderDialog(context, activity.getLayoutInflater(), listener, fkId, favoriteFolderId); } else if (selectedFavoriteFolderId == removeFavoriteId) { // delete favorite deleteFavorite(context, fkId, favoriteFolderId, listener); } else if (favoriteFolderId >= 0) { // move favorite updateFavoriteFolder(context, fkId, selectedFavoriteFolderId, listener); } else { // add new favorite addFavorite(context, fkId, selectedFavoriteFolderId, listener); } if (dialog != null) { dialog.dismiss(); } } }).setNegativeButton(R.string.favorite_folder_pick_cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { if (dialog != null) { dialog.cancel(); } } }).show(); } else { addOrDeleteFavorite(context, isFavorite, fkId, DEFAULT_FOLDER_ID, listener); } return true; // HANDLED } private static void addOrDeleteFavorite(Context context, boolean isFavorite, String fkId, int folderId, FavoriteUpdateListener listener) { if (isFavorite) { // WAS FAVORITE => TRY TO DELETE deleteFavorite(context, fkId, folderId, listener); } else { // WAS NOT FAVORITE => TRY TO ADD addFavorite(context, fkId, folderId, listener); } } public static void addFavorite(Context context, String fkId, int folderId, FavoriteUpdateListener listener) { Favorite newFavorite = new Favorite(fkId, folderId); boolean success = addFavorite(context, newFavorite) != null; if (success) { Favorite.Folder favoriteFolder = folderId == DEFAULT_FOLDER_ID ? null : get(context).getFolder(folderId); if (favoriteFolder == null) { ToastUtils.makeTextAndShowCentered(context, R.string.favorite_added); } else { ToastUtils.makeTextAndShowCentered(context, context.getString(R.string.favorite_added_to_folder_and_folder, favoriteFolder.getName())); } if (listener != null) { MTLog.d(TAG, "addFavorite() > onFavoriteUpdated()"); listener.onFavoriteUpdated(); } } else { MTLog.w(TAG, "Favorite not added!"); } } public static Favorite addFavorite(Context context, Favorite newFavorite) { Uri uri = context.getContentResolver().insert(getFavoriteContentUri(context), newFavorite.toContentValues()); if (uri == null) { return null; } return findFavorite(context, uri, null); } public static void deleteFavorite(Context context, String fkId, int folderId, FavoriteUpdateListener listener) { Favorite findFavorite = findFavorite(context, fkId); if (findFavorite == null) { return; // already deleted } boolean success = deleteFavorite(context, findFavorite.getId()); if (success) { Favorite.Folder favoriteFolder = folderId == DEFAULT_FOLDER_ID ? null : get(context).getFolder(folderId); if (favoriteFolder == null) { ToastUtils.makeTextAndShowCentered(context, R.string.favorite_removed); } else { ToastUtils.makeTextAndShowCentered(context, context.getString(R.string.favorite_removed_to_folder_and_folder, favoriteFolder.getName())); } if (listener != null) { listener.onFavoriteUpdated(); } } else { MTLog.w(TAG, "Favorite not deleted!"); } } public static boolean deleteFavorite(Context context, int id) { String selection = SqlUtils.getWhereEquals(FavoriteColumns.T_FAVORITE_K_ID, id); int deletedRows = context.getContentResolver().delete(getFavoriteContentUri(context), selection, null); return deletedRows > 0; } public static final String FAVORITE_CONTENT_DIRECTORY = "favorite"; public static Uri getFavoriteContentUri(Context context) { return Uri.withAppendedPath(getAuthorityUri(context), FAVORITE_CONTENT_DIRECTORY); } public static HashMap<Integer, Favorite.Folder> findFolders(Context context) { HashMap<Integer, Favorite.Folder> result = new HashMap<Integer, Favorite.Folder>(); Cursor cursor = null; try { String selection = null; cursor = DataSourceManager.queryContentResolver(context.getContentResolver(), getFolderContentUri(context), FavoriteProvider.PROJECTION_FOLDER, selection, null, null); if (cursor != null && cursor.getCount() > 0) { if (cursor.moveToFirst()) { do { Favorite.Folder favoriteFolder = Favorite.Folder.fromCursor(cursor); result.put(favoriteFolder.getId(), favoriteFolder); } while (cursor.moveToNext()); } } } catch (Exception e) { MTLog.w(TAG, e, "Error!"); } finally { SqlUtils.closeQuietly(cursor); } return result; } public static void showAddFolderDialog(final Context context, LayoutInflater inflater, final FavoriteUpdateListener listener, final String optUpdatedFkId, final Integer optFavoriteFolderId) { View view = inflater.inflate(R.layout.layout_favorites_folder_edit, null); final EditText newFolderNameTv = (EditText) view.findViewById(R.id.folder_name); new AlertDialog.Builder(context).setView(view).setPositiveButton(R.string.favorite_folder_new_create, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { String newFolderName = newFolderNameTv.getText().toString(); Favorite.Folder createdFolder = addFolder(context, newFolderName, TextUtils.isEmpty(optUpdatedFkId) ? listener : null); if (createdFolder != null && !TextUtils.isEmpty(optUpdatedFkId)) { if (optFavoriteFolderId != null && optFavoriteFolderId >= 0) { // move favorite updateFavoriteFolder(context, optUpdatedFkId, createdFolder.getId(), listener); } else { // add new favorite addFavorite(context, optUpdatedFkId, createdFolder.getId(), listener); } } } }).setNegativeButton(R.string.favorite_folder_new_cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { if (dialog != null) { dialog.cancel(); } } }).show(); } private static Favorite.Folder addFolder(Context context, String newFolderName, FavoriteUpdateListener listener) { if (TextUtils.isEmpty(newFolderName)) { ToastUtils.makeTextAndShowCentered(context, R.string.favorite_folder_new_invalid_name); return null; } Uri uri = context.getContentResolver().insert(getFolderContentUri(context), new Favorite.Folder(newFolderName).toContentValues()); if (uri == null) { return null; } Favorite.Folder createdFolder = findFolder(context, uri, null); if (createdFolder == null) { ToastUtils.makeTextAndShowCentered(context, context.getString(R.string.favorite_folder_new_creation_error_and_folder_name, newFolderName)); return null; } ToastUtils.makeTextAndShowCentered(context, context.getString(R.string.favorite_folder_new_created_and_folder_name, createdFolder.getName())); if (listener != null) { listener.onFavoriteUpdated(); } get(context).addFolder(createdFolder); return createdFolder; } private static Favorite.Folder findFolder(Context context, Uri uri, String selection) { Favorite.Folder cache = null; Cursor cursor = null; try { cursor = DataSourceManager.queryContentResolver(context.getContentResolver(), uri, FavoriteProvider.PROJECTION_FOLDER, selection, null, null); if (cursor != null && cursor.getCount() > 0) { if (cursor.moveToFirst()) { cache = Favorite.Folder.fromCursor(cursor); } } } catch (Exception e) { MTLog.w(TAG, e, "Error!"); } finally { SqlUtils.closeQuietly(cursor); } return cache; } public static void showDeleteFolderDialog(final Context context, final Favorite.Folder favoriteFolder, final FavoriteUpdateListener listener) { new AlertDialog.Builder(context) // .setTitle(context.getString(R.string.favorite_folder_deletion_confirmation_title_and_name, favoriteFolder.getName())) // .setMessage(context.getString(R.string.favorite_folder_deletion_confirmation_text_and_name, favoriteFolder.getName())) // .setPositiveButton(R.string.delete, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { deleteFolder(context, favoriteFolder, listener); } }) // .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { if (dialog != null) { dialog.cancel(); } } }) // .show(); } private static boolean deleteFolder(Context context, Favorite.Folder favoriteFolder, FavoriteUpdateListener listener) { if (favoriteFolder.getId() == DEFAULT_FOLDER_ID) { MTLog.w(TAG, "Try to delete default favorite folder!"); return false; } String selectionF = SqlUtils.getWhereEquals(FavoriteColumns.T_FAVORITE_K_FOLDER_ID, favoriteFolder.getId()); ContentValues updateValues = new ContentValues(); updateValues.put(FavoriteColumns.T_FAVORITE_K_FOLDER_ID, DEFAULT_FOLDER_ID); int updatedRows = context.getContentResolver().update(getFavoriteContentUri(context), updateValues, selectionF, null); String selection = SqlUtils.getWhereEquals(FavoriteFolderColumns.T_FAVORITE_FOLDER_K_ID, favoriteFolder.getId()); int deletedRows = context.getContentResolver().delete(getFolderContentUri(context), selection, null); if (deletedRows > 0) { ToastUtils.makeTextAndShowCentered(context, context.getString(R.string.favorite_folder_deleted_and_folder_name, favoriteFolder.getName())); if (listener != null) { listener.onFavoriteUpdated(); } get(context).removeFolder(favoriteFolder); } else { ToastUtils.makeTextAndShowCentered(context, context.getString(R.string.favorite_folder_deletion_error_and_folder_name, favoriteFolder.getName())); } return deletedRows > 0; } private static boolean updateFavoriteFolder(Context context, String favoriteFkId, int folderId, FavoriteUpdateListener listener) { String selectionF = SqlUtils.getWhereEqualsString(FavoriteColumns.T_FAVORITE_K_FK_ID, favoriteFkId); ContentValues updateValues = new ContentValues(); updateValues.put(FavoriteColumns.T_FAVORITE_K_FOLDER_ID, folderId); int updatedRows = context.getContentResolver().update(getFavoriteContentUri(context), updateValues, selectionF, null); if (updatedRows > 0) { Favorite.Folder favoriteFolder = folderId == DEFAULT_FOLDER_ID ? null : get(context).getFolder(folderId); if (favoriteFolder == null) { ToastUtils.makeTextAndShowCentered(context, R.string.favorite_moved); } else { ToastUtils.makeTextAndShowCentered(context, context.getString(R.string.favorite_moved_to_folder_and_folder, favoriteFolder.getName())); } if (listener != null) { listener.onFavoriteUpdated(); } } else { MTLog.w(TAG, "Favorite not moved!"); } return updatedRows > 0; } public static void showUpdateFolderDialog(final Context context, LayoutInflater layoutInflater, final Favorite.Folder favoriteFolder, final FavoriteUpdateListener listener) { View editView = layoutInflater.inflate(R.layout.layout_favorites_folder_edit, null); final EditText newFolderNameTv = (EditText) editView.findViewById(R.id.folder_name); newFolderNameTv.setText(favoriteFolder.getName()); new AlertDialog.Builder(context).setView(editView).setPositiveButton(R.string.favorite_folder_edit, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { String newFolderName = newFolderNameTv.getText().toString(); updateFolder(context, favoriteFolder.getId(), newFolderName, listener); } }).setNegativeButton(R.string.favorite_folder_new_cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { if (dialog != null) { dialog.cancel(); } } }).show(); } private static boolean updateFolder(Context context, int folderId, String newFolderName, FavoriteUpdateListener listener) { if (TextUtils.isEmpty(newFolderName)) { ToastUtils.makeTextAndShowCentered(context, R.string.favorite_folder_new_invalid_name); return false; } String selectionF = SqlUtils.getWhereEquals(FavoriteFolderColumns.T_FAVORITE_FOLDER_K_ID, folderId); ContentValues updateValues = new ContentValues(); updateValues.put(FavoriteFolderColumns.T_FAVORITE_FOLDER_K_NAME, newFolderName); int updatedRows = context.getContentResolver().update(getFolderContentUri(context), updateValues, selectionF, null); if (updatedRows > 0) { ToastUtils.makeTextAndShowCentered(context, context.getString(R.string.favorite_folder_edited_and_folder, newFolderName)); if (listener != null) { listener.onFavoriteUpdated(); } get(context).removeFolder(folderId); get(context).addFolder(new Favorite.Folder(folderId, newFolderName)); } else { MTLog.w(TAG, "Favorite folder not updated!"); } return updatedRows > 0; } public static final String FOLDER_CONTENT_DIRECTORY = "folder"; public static Uri getFolderContentUri(Context context) { return Uri.withAppendedPath(Uri.withAppendedPath(getAuthorityUri(context), FAVORITE_CONTENT_DIRECTORY), FOLDER_CONTENT_DIRECTORY); } private static String authority; public static String getAUTHORITY(Context context) { if (authority == null) { authority = context.getResources().getString(R.string.favorite_authority); } return authority; } private static Uri authorityUri; private static Uri getAuthorityUri(Context context) { if (authorityUri == null) { authorityUri = UriUtils.newContentUri(getAUTHORITY(context)); } return authorityUri; } public interface FavoriteUpdateListener { void onFavoriteUpdated(); } }