Last active
November 26, 2016 22:52
-
-
Save jaredsburrows/9215295bfa35504ce0f5eff58347d55f to your computer and use it in GitHub Desktop.
Burrows Apps Libs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.os.Bundle; | |
import com.google.firebase.analytics.FirebaseAnalytics; | |
import com.google.firebase.crash.FirebaseCrash; | |
import com.orhanobut.logger.Logger; | |
/** | |
* https://developers.google.com/analytics/devguides/collection/android/v4/advanced?hl=es | |
* https://github.com/google/iosched/blob/0a90bf8e6b90e9226f8c15b34eb7b1e4bf6d632e/android/src/main/java/com/google/samples/apps/iosched/util/java | |
* https://github.com/google/iosched/blob/cf1f30b4c752f275518384a9b71404ee501fc473/android/src/main/java/com/google/samples/apps/iosched/ui/BaseActivity.java | |
* | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
public final class AnalyticsManager { | |
private static FirebaseAnalytics analytics; | |
private AnalyticsManager() { | |
} | |
public static synchronized void init(Context context) { | |
if (context == null) { | |
return; | |
} | |
if (analytics == null) { | |
analytics = FirebaseAnalytics.getInstance(context); | |
Logger.i("Analytics initialized."); | |
} | |
} | |
public static boolean sendException(Throwable throwable) { | |
if (isInitialized()) { | |
FirebaseCrash.report(throwable); | |
FirebaseCrash.log("Caught exception"); | |
Logger.e("Caught exception"); | |
return true; | |
} else { | |
Logger.i("Analytics event ignored (analytics disabled or not ready)."); | |
return false; | |
} | |
} | |
public static boolean sendEvent(String event) { | |
return sendEvent(event, new Bundle()); | |
} | |
public static boolean sendEvent(String event, Bundle bundle) { | |
if (isInitialized()) { | |
analytics.logEvent(event, bundle); | |
// Print the Bundle for debugging | |
for (final String key : bundle.keySet()) { | |
Logger.i(key + "\t=\t" + bundle.get(key)); | |
} | |
return true; | |
} else { | |
Logger.i("Analytics event ignored (analytics disabled or not ready)."); | |
return false; | |
} | |
} | |
private static boolean isInitialized() { | |
return analytics != null; | |
} | |
public static FirebaseAnalytics getInstance() { | |
return analytics; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.ClipData; | |
import android.content.ClipboardManager; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.content.pm.ApplicationInfo; | |
import android.content.pm.PackageManager; | |
import android.net.ConnectivityManager; | |
import android.net.Uri; | |
import android.util.TypedValue; | |
import com.orhanobut.logger.Logger; | |
import java.io.File; | |
/** | |
* Application specific utilities. | |
* | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
public final class AppUtils { | |
/** | |
* Amazon Market short. | |
*/ | |
public static final String MARKET_SHORT_AMAZON = "amzn://apps/android?p="; | |
/** | |
* Google Play Market short. | |
*/ | |
public static final String MARKET_SHORT_GOOGLE_PLAY = "market://details?id="; | |
/** | |
* Amazon Markey URL. | |
*/ | |
public static final String MARKET_URL_AMAZON = "http://www.amazon.com/gp/mas/dl/android?p="; | |
/** | |
* Google Play URL. | |
*/ | |
public static final String MARKET_URL_GOOGLE_PLAY = "https://play.google.com/store/apps/details?id="; | |
public static final String APP_GOOGLE_PLUS = "com.google.android.apps.plus"; | |
public static final String APP_FACEBOOK = "com.facebook.katana"; | |
public static final String APP_TWITTER = "com.twitter.android"; | |
private static final String EMAIL_BURROWSAPPS = "[email protected]"; | |
private static final String MAIL_TYPE = "text/html"; | |
private static final String MAIL_URI = "mailto:"; | |
private static final String MAIL_FEEDBACK = "Feedback"; | |
private static final String MAIL_BUG_REPORT = "Bug Report"; | |
private AppUtils() { | |
} | |
/** | |
* Add text to clipboard. | |
* | |
* @param context Context | |
* @param text Message | |
*/ | |
public static boolean addToTextClipBoard(Context context, String text) { | |
try { | |
final ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); | |
clipboardManager.setPrimaryClip(ClipData.newPlainText(context.getPackageName(), text)); | |
return true; | |
} catch (final Exception e) { | |
// Workaround for some Android 4.3 devices, where writing to the clipboard manager raises an exception | |
// if there is an active clipboard listener. | |
// java.lang.IllegalStateException: beginBroadcast() called while already in a broadcast at | |
Logger.e(e, "addToTextClipBoard"); | |
return false; | |
} | |
} | |
// com.amazon.venezia - amazon app | |
// null - developer | |
// com.android.vending - google play | |
/** | |
* Create the Share intent needed for the ShareActionProvider. | |
*/ | |
public static Intent createShareIntent(String packageName, String storePackage) { | |
final Intent intent = new Intent(Intent.ACTION_SEND) | |
.setType("text/plain") | |
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) | |
.putExtra(Intent.EXTRA_SUBJECT, "Check out the new app I downloaded!"); | |
// Default to Google Play | |
if (packageName == null || storePackage == null) { | |
return intent.putExtra(Intent.EXTRA_TEXT, "Take a look at: " + MARKET_URL_GOOGLE_PLAY + packageName); | |
} | |
// Create intent based on app store | |
final String storeURL = storePackage.contains("amazon") ? MARKET_URL_AMAZON : MARKET_URL_GOOGLE_PLAY; | |
intent.putExtra(Intent.EXTRA_TEXT, "Take a look at: " + storeURL + packageName); | |
return intent; | |
} | |
public static String getInstallerPackageName(Context context) { | |
if (context == null) { | |
return null; | |
} | |
return getInstallerPackageName(context.getPackageManager(), context.getPackageName()); | |
} | |
// Catch TransactionTooLargeException, getInstallerPackageName does not throw | |
public static String getInstallerPackageName(PackageManager manager, String packageName) { | |
try { | |
return manager.getInstallerPackageName(packageName); | |
} catch (Exception e) { | |
Logger.e(e, "getInstallerPackageName"); | |
return null; | |
} | |
} | |
/** | |
* Get version name and version code. | |
* | |
* @return Version release | |
*/ | |
public static String getVersionRelease(PackageManager manager, String packageName) { | |
try { | |
return manager.getPackageInfo(packageName, 0).versionName; | |
} catch (Exception e) { | |
Logger.e(e, "getVersionRelease"); | |
return ""; | |
} | |
} | |
public static Intent createSocialIntent(PackageManager manager, String url) { | |
return createSocialIntent(manager, url, null); | |
} | |
public static Intent createSocialIntent(PackageManager manager, String url, String appPackage) { | |
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); | |
if (appPackage != null) { | |
try { | |
final ApplicationInfo applicationInfo = manager.getApplicationInfo(appPackage, 0); | |
if (applicationInfo.enabled) { | |
if (APP_FACEBOOK.equals(appPackage)) { | |
intent = new Intent(Intent.ACTION_VIEW, Uri.parse("fb://facewebmodal/f?href=" + url)); | |
} | |
intent.setPackage(appPackage); | |
} | |
} catch (Exception e) { | |
Logger.e(e, "getVersionRelease"); | |
} | |
} | |
return intent; | |
} | |
public static Intent getFeedbackEmailIntent(String feedback) { | |
return getCommonEmailIntent().putExtra(Intent.EXTRA_SUBJECT, MAIL_FEEDBACK + ": " + feedback); | |
} | |
public static Intent getBugReportEmailIntent(String feedback) { | |
return getCommonEmailIntent().putExtra(Intent.EXTRA_SUBJECT, MAIL_BUG_REPORT + ": " + feedback); | |
} | |
private static Intent getCommonEmailIntent() { | |
return new Intent(Intent.ACTION_SENDTO) | |
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) | |
.setType(MAIL_TYPE) | |
.setData(Uri.parse(MAIL_URI)) | |
.putExtra(Intent.EXTRA_EMAIL, new String[]{EMAIL_BURROWSAPPS}); | |
} | |
/** | |
* Check for Internet. | |
* | |
* @param context Context | |
* @return True if available | |
*/ | |
public static boolean isNetworkAvailable(Context context) { | |
final ConnectivityManager manager = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)); | |
return manager.getActiveNetworkInfo() != null && manager.getActiveNetworkInfo().isConnected(); | |
} | |
/** | |
* Converts pixels to DP in order to make sure views look the same on all | |
* devices. | |
* | |
* @param context pass reference | |
* @param value DP value | |
* @return integer | |
*/ | |
public static int getPixels(Context context, int value) { | |
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, context.getResources().getDisplayMetrics()); | |
} | |
/** | |
* Get the "PATH" for the where applications are store in /data/data for our | |
* Burrows Applications version of BusyBox | |
* | |
* @param context Context | |
* @return PATH to /data/data/, defaults to "/data/data/ if not found | |
*/ | |
public static String getDataPath(Context context) { | |
final File filesDirectory = context.getFilesDir(); | |
final ApplicationInfo applicationInfo = context.getApplicationInfo(); | |
return (filesDirectory != null && applicationInfo != null) ? filesDirectory.getPath() | |
.replaceAll(applicationInfo.packageName, "") | |
.replaceAll("/files", "") | |
.replaceAll("files", "") | |
: context.getString(R.string.data_path); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.app.ActivityManager; | |
import android.content.Intent; | |
import android.content.res.Configuration; | |
import android.graphics.Bitmap; | |
import android.graphics.BitmapFactory; | |
import android.os.Build; | |
import android.os.Bundle; | |
import android.os.Handler; | |
import android.support.annotation.NonNull; | |
import android.support.annotation.Nullable; | |
import android.support.design.widget.AppBarLayout; | |
import android.support.design.widget.NavigationView; | |
import android.support.design.widget.NavigationView.OnNavigationItemSelectedListener; | |
import android.support.v4.content.ContextCompat; | |
import android.support.v4.view.GravityCompat; | |
import android.support.v4.view.MenuItemCompat; | |
import android.support.v4.widget.DrawerLayout; | |
import android.support.v7.app.ActionBarDrawerToggle; | |
import android.support.v7.app.AppCompatActivity; | |
import android.support.v7.widget.ShareActionProvider; | |
import android.support.v7.widget.Toolbar; | |
import android.view.Menu; | |
import android.view.MenuItem; | |
import android.view.View; | |
import butterknife.BindView; | |
import butterknife.ButterKnife; | |
import com.orhanobut.logger.Logger; | |
import io.doorbell.android.Doorbell; | |
/** | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
@SuppressWarnings("NullableProblems") | |
public abstract class BaseActivity extends AppCompatActivity { | |
private static final String MARKET_URL_GOOGLE_PLAY = "https://play.google.com/store/apps/details?id="; | |
private static final int NAV_DRAWER_LAUNCH_DELAY = 250; | |
private static final String BLOG = "http://blog.burrowsapps.com/p/"; | |
private static final String BLOG_HTML = ".html"; | |
private final Handler navigationHandler = new Handler(); | |
private ActionBarDrawerToggle drawerToggle; | |
@Nullable @BindView(R.id.drawer_layout) DrawerLayout drawerLayout; | |
@Nullable @BindView(R.id.app_bar_layout) AppBarLayout appBar; | |
@Nullable @BindView(R.id.tool_bar) Toolbar toolbar; | |
@Nullable @BindView(R.id.navigation_view) NavigationView navigationView; | |
/** | |
* @return Layout Id for the Activity. | |
*/ | |
public abstract int getLayoutResId(); | |
@Override protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(getLayoutResId()); | |
ButterKnife.bind(this); | |
// Change the recents primary color to make the name of the app text white | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { | |
final String title = getResources().getString(R.string.app_name); | |
final Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); | |
final int primaryColor = ContextCompat.getColor(this, R.color.lightBlue600); | |
setTaskDescription(new ActivityManager.TaskDescription(title, bitmap, primaryColor)); | |
bitmap.recycle(); | |
} | |
// Must call this for drawer toggle to work correctly | |
// Setup Toolbar | |
if (toolbar != null) { | |
setToolbarNavigationIcon(R.drawable.ic_menu_white_24dp); | |
setSupportActionBar(toolbar); | |
} | |
// Setup DrawerLayout | |
if (drawerLayout != null && toolbar != null) { | |
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.nav_open, R.string.nav_close); | |
drawerLayout.addDrawerListener(drawerToggle); | |
// Sync the toggle state after onRestoreInstanceState has occurred. | |
drawerToggle.syncState(); | |
} | |
// Setup NavigationView | |
if (navigationView != null) { | |
navigationView.setNavigationItemSelectedListener(new OnNavigationItemSelectedListener() { | |
@Override public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { | |
final int itemId = menuItem.getItemId(); | |
onNavDrawerItemClicked(itemId); | |
navigationView.setCheckedItem(itemId); | |
closeNavDrawer(); | |
return true; | |
} | |
}); | |
navigationView.setCheckedItem(R.id.menu_nav_home); | |
} | |
} | |
@Override protected void onDestroy() { | |
super.onDestroy(); | |
if (navigationView != null) navigationView.setNavigationItemSelectedListener(null); | |
navigationHandler.removeCallbacksAndMessages(null); | |
} | |
@Override public void onConfigurationChanged(Configuration newConfig) { | |
super.onConfigurationChanged(newConfig); | |
if (drawerLayout != null) drawerToggle.onConfigurationChanged(newConfig); | |
} | |
@Override public boolean onCreateOptionsMenu(Menu menu) { | |
getMenuInflater().inflate(R.menu.menu_activity_main, menu); | |
// This is the share action provider - dropdown of share. | |
final MenuItem item = menu.findItem(R.id.menu_share_app); | |
final ShareActionProvider provider = (ShareActionProvider) MenuItemCompat.getActionProvider(item); | |
provider.setShareIntent(new Intent(Intent.ACTION_SEND) | |
.setType("text/plain") | |
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) | |
.putExtra(Intent.EXTRA_SUBJECT, "Check out the new app I downloaded!") | |
.putExtra(Intent.EXTRA_TEXT, "Take a look at: " + MARKET_URL_GOOGLE_PLAY + getPackageName())); | |
return super.onCreateOptionsMenu(menu); | |
} | |
@Override public boolean onOptionsItemSelected(MenuItem item) { | |
// Pass the event to ActionBarDrawerToggle, if it returns | |
// true, then it has handled the app icon touch event | |
if (drawerLayout != null && drawerToggle.onOptionsItemSelected(item)) return true; | |
switch (item.getItemId()) { | |
case android.R.id.home: | |
if (drawerLayout != null) { | |
drawerLayout.openDrawer(GravityCompat.START); | |
if (App.isDebug()) Logger.i("Drawer open"); | |
} else { | |
finish(); | |
} | |
return true; | |
default: | |
return super.onOptionsItemSelected(item); | |
} | |
} | |
@Override public void onBackPressed() { | |
if (isNavDrawerOpen()) { | |
closeNavDrawer(); | |
} else { | |
super.onBackPressed(); | |
} | |
} | |
public void setToolbarTitle(CharSequence title) { | |
if (toolbar != null) toolbar.setTitle(title); | |
} | |
public void setToolbarSubtitle(CharSequence subtitle) { | |
if (toolbar != null) toolbar.setSubtitle(subtitle); | |
} | |
public void setToolbarNavigationIcon(int resId) { | |
if (toolbar != null) toolbar.setNavigationIcon(resId); | |
} | |
protected boolean isNavDrawerOpen() { | |
return drawerLayout != null && drawerLayout.isDrawerOpen(GravityCompat.START); | |
} | |
protected void openNavDrawer() { | |
if (drawerLayout != null) drawerLayout.openDrawer(GravityCompat.START); | |
} | |
protected void closeNavDrawer() { | |
if (drawerLayout != null) drawerLayout.closeDrawer(GravityCompat.START); | |
} | |
void onNavDrawerItemClicked(final int id) { | |
navigationHandler.postDelayed(new Runnable() { | |
@Override public void run() { | |
goToNavDrawerItem(id); | |
} | |
}, NAV_DRAWER_LAUNCH_DELAY); | |
} | |
// TODO possible track user actions | |
void goToNavDrawerItem(int id) { | |
if (id == R.id.menu_app_settings) { | |
if (App.isDebug()) Logger.i("Open Settings"); | |
startActivity(new Intent(this, SettingsActivity.class)); | |
} else if (id == R.id.menu_send_feedback) { | |
if (App.isDebug()) Logger.i("Send Feedback"); | |
new Doorbell(this, Integer.parseInt(getString(R.string.app_doorbell_io_app_id)), | |
getString(R.string.app_doorbell_io_api_key)) | |
.setPoweredByVisibility(View.GONE) | |
.show(); | |
} else if (id == R.id.menu_blog_help) { | |
if (App.isDebug()) Logger.i("Open Help & Support"); | |
final String blogURL = BLOG + getPackageName().replace(".", "").replace(".debug", "") + BLOG_HTML; | |
startActivity(Intent.createChooser(AppUtils.createSocialIntent(getPackageManager(), blogURL), | |
getString(R.string.menu_nav_help))); | |
} else { | |
if (App.isDebug()) Logger.i("Close drawer"); | |
closeNavDrawer(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.support.v7.widget.RecyclerView; | |
import android.util.SparseBooleanArray; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.Comparator; | |
import java.util.List; | |
/** | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
public abstract class BaseAdapter<T, VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> { | |
/** | |
* Data in the Adapter. | |
*/ | |
protected final List<T> data = new ArrayList<>(); | |
/** | |
* Selected items in the Adapter. | |
*/ | |
protected final SparseBooleanArray selectedItems = new SparseBooleanArray(); | |
/** | |
* Returns the number of elements in the data. | |
* | |
* @return the number of elements in the data. | |
*/ | |
@Override public int getItemCount() { | |
return data.size(); | |
} | |
/** | |
* Returns the instance of the data. | |
* | |
* @return instance of the data. | |
*/ | |
public List<T> getList() { | |
return data; | |
} | |
/** | |
* Returns the element at the specified location in the data. | |
* | |
* @param location the index of the element to return. | |
* @return the element at the specified location. | |
* @throws IndexOutOfBoundsException if {@code location < 0 || location >= size()} | |
*/ | |
public T getItem(int location) { | |
return data.get(location); | |
} | |
/** | |
* Searches the data for the specified object and returns the index of the | |
* first occurrence. | |
* | |
* @param object the object to search for. | |
* @return the index of the first occurrence of the object or -1 if the | |
* object was not found. | |
*/ | |
public int getLocation(T object) { | |
return data.indexOf(object); | |
} | |
/** | |
* Clear the entire adapter using {@link android.support.v7.widget.RecyclerView.Adapter#notifyItemRangeRemoved}. | |
*/ | |
public void clear() { | |
final int size = data.size(); | |
if (size > 0) { | |
for (int i = 0; i < size; i++) { | |
data.remove(0); | |
} | |
notifyItemRangeRemoved(0, size); | |
} | |
} | |
/** | |
* Adds the specified object at the end of the data. | |
* | |
* @param object the object to add. | |
* @return always true. | |
* @throws UnsupportedOperationException if adding to the data is not supported. | |
* @throws ClassCastException if the class of the object is inappropriate for this | |
* data. | |
* @throws IllegalArgumentException if the object cannot be added to the data. | |
*/ | |
public boolean add(T object) { | |
final boolean added = data.add(object); | |
notifyItemInserted(data.size() + 1); | |
return added; | |
} | |
/** | |
* Adds the objects in the specified collection to the end of the data. The | |
* objects are added in the order in which they are returned from the | |
* collection's iterator. | |
* | |
* @param collection the collection of objects. | |
* @return {@code true} if the data is modified, {@code false} otherwise | |
* (i.e. if the passed collection was empty). | |
* @throws UnsupportedOperationException if adding to the data is not supported. | |
* @throws ClassCastException if the class of an object is inappropriate for this | |
* data. | |
* @throws IllegalArgumentException if an object cannot be added to the data. | |
*/ | |
public boolean addAll(List<T> collection) { | |
final boolean added = data.addAll(collection); | |
notifyItemRangeInserted(0, data.size() + 1); | |
return added; | |
} | |
/** | |
* Inserts the specified object into the data at the specified location. | |
* The object is inserted before the current element at the specified | |
* location. If the location is equal to the size of the data, the object | |
* is added at the end. If the location is smaller than the size of the | |
* data, then all elements beyond the specified location are moved by one | |
* location towards the end of the data. | |
* | |
* @param location the index at which to insert. | |
* @param object the object to add. | |
* @throws UnsupportedOperationException if adding to the data is not supported. | |
* @throws ClassCastException if the class of the object is inappropriate for this | |
* data. | |
* @throws IllegalArgumentException if the object cannot be added to the data. | |
* @throws IndexOutOfBoundsException if {@code location < 0 || location > size()} | |
*/ | |
public void add(int location, final T object) { | |
data.add(location, object); | |
notifyItemInserted(location); | |
} | |
/** | |
* Replaces the element at the specified location in the data with the | |
* specified object. This operation does not change the size of the data. | |
* | |
* @param location the index at which to put the specified object. | |
* @param object the object to insert. | |
* @return the previous element at the index. | |
* @throws UnsupportedOperationException if replacing elements in the data is not supported. | |
* @throws ClassCastException if the class of an object is inappropriate for this | |
* data. | |
* @throws IllegalArgumentException if an object cannot be added to the data. | |
* @throws IndexOutOfBoundsException if {@code location < 0 || location >= size()} | |
*/ | |
public T set(int location, final T object) { | |
final T insertedObject = data.set(location, object); | |
notifyDataSetChanged(); | |
return insertedObject; | |
} | |
/** | |
* Removes the first occurrence of the specified object from the data. | |
* | |
* @param object the object to remove. | |
* @return true if the data was modified by this operation, false | |
* otherwise. | |
* @throws UnsupportedOperationException if removing from the data is not supported. | |
*/ | |
public boolean remove(int location, final T object) { | |
final boolean removed = data.remove(object); | |
notifyItemRangeRemoved(location, data.size()); | |
return removed; | |
} | |
/** | |
* Removes the first occurrence of the specified object from the data. | |
* | |
* @param object the object to remove. | |
* @return true if the data was modified by this operation, false | |
* otherwise. | |
* @throws UnsupportedOperationException if removing from the data is not supported. | |
*/ | |
public boolean remove(T object) { | |
final int location = getLocation(object); | |
final boolean removed = data.remove(object); | |
notifyItemRemoved(location); | |
return removed; | |
} | |
/** | |
* Removes the object at the specified location from the data. | |
* | |
* @param location the index of the object to remove. | |
* @return the removed object. | |
* @throws UnsupportedOperationException if removing from the data is not supported. | |
* @throws IndexOutOfBoundsException if {@code location < 0 || location >= size()} | |
*/ | |
public T remove(int location) { | |
final T removedObject = data.remove(location); | |
notifyItemRemoved(location); | |
notifyItemRangeChanged(location, data.size()); | |
return removedObject; | |
} | |
/** | |
* Sorts the given list using the given comparator. The algorithm is | |
* stable which means equal elements don't get reordered. | |
* | |
* @throws ClassCastException if any element does not implement {@code Comparable}, | |
* or if {@code compareTo} throws for any pair of elements. | |
*/ | |
public void sort(Comparator<? super T> comparator) { | |
Collections.sort(data, comparator); | |
notifyItemRangeChanged(0, getItemCount()); | |
} | |
/** | |
* Return the number of selected items. | |
* | |
* @return Number of selected items. | |
*/ | |
public int getItemSelectedCount() { | |
return selectedItems.size(); | |
} | |
/** | |
* Return all selected IDs. | |
* | |
* @return Selected IDs. | |
*/ | |
public SparseBooleanArray getSelectedItems() { | |
return selectedItems; | |
} | |
/** | |
* Return all selected items. | |
* | |
* @return Selected IDs. | |
*/ | |
public List<T> getSelectedList() { | |
final List<T> list = new ArrayList<>(); | |
final SparseBooleanArray selectedItems = getSelectedItems(); | |
final int size = selectedItems.size(); | |
for (int i = 0; i < size; i++) { | |
final T model = getList().get(selectedItems.keyAt(i)); | |
list.add(model); | |
} | |
return list; | |
} | |
/** | |
* Remove all current selections. | |
*/ | |
public void removeSelections() { | |
selectedItems.clear(); | |
notifyDataSetChanged(); | |
} | |
/** | |
* Toggle selection of item. | |
* | |
* @param location location of view. | |
*/ | |
public void toggleSelection(int location) { | |
selectItem(location, !selectedItems.get(location)); | |
} | |
/** | |
* Change the current view state to selected. | |
* | |
* @param location location of view. | |
* @param value True if view is selected. | |
*/ | |
public void selectItem(int location, boolean value) { | |
if (value) { | |
selectedItems.put(location, true); | |
} else { | |
selectedItems.delete(location); | |
} | |
notifyItemChanged(location); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.os.Bundle; | |
import android.support.annotation.Nullable; | |
import android.support.v4.app.Fragment; | |
import android.support.v7.widget.Toolbar; | |
/** | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
public abstract class BaseFragment extends Fragment { | |
/** | |
* @return Layout Id for the Fragment. | |
*/ | |
public abstract int getLayoutResId(); | |
@Override public void onCreate(@Nullable Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
// Child Fragments cant retain instance (FavoritesFragment and MyAppsFragment) | |
// setRetainInstance(true); | |
setHasOptionsMenu(true); | |
} | |
@Override public void onDestroy() { | |
super.onDestroy(); | |
App.getRefWatcher(getActivity()).watch(this, BaseFragment.class.getName()); | |
} | |
public void setToolbarTitle(CharSequence title) { | |
final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.tool_bar); | |
if (toolbar != null) toolbar.setTitle(title); | |
} | |
public void setToolbarSubtitle(CharSequence subtitle) { | |
final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.tool_bar); | |
if (toolbar != null) toolbar.setSubtitle(subtitle); | |
} | |
public void setToolbarNavigationIcon(int resId) { | |
final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.tool_bar); | |
if (toolbar != null) toolbar.setNavigationIcon(resId); | |
} | |
public boolean hasArguments() { | |
return getArguments() != null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
public interface BasePresenter { | |
void subscribe(); | |
void unsubscribe(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import rx.Scheduler; | |
/** | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
public interface BaseSchedulerProvider { | |
Scheduler io(); | |
Scheduler ui(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
public interface BaseView<T> { | |
void setPresenter(T presenter); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import rx.Scheduler; | |
import rx.android.schedulers.AndroidSchedulers; | |
import rx.schedulers.Schedulers; | |
/** | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
public class SchedulerProvider implements BaseSchedulerProvider { | |
private static SchedulerProvider instance; | |
private SchedulerProvider() { | |
} | |
public static synchronized SchedulerProvider getInstance() { | |
if (instance == null) { | |
instance = new SchedulerProvider(); | |
} | |
return instance; | |
} | |
@Override public Scheduler io() { | |
return Schedulers.io(); | |
} | |
@Override public Scheduler ui() { | |
return AndroidSchedulers.mainThread(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.support.v4.app.Fragment; | |
import android.support.v4.app.FragmentManager; | |
import android.support.v4.app.FragmentPagerAdapter; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
/** | |
* SectionsPagerAdapter for ViewPager. | |
* | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
public final class SectionsPagerAdapter extends FragmentPagerAdapter { | |
private final Map<Integer, Fragment> fragmentMap; | |
private final List<Integer> tabNumbers; | |
private final List<CharSequence> tabTitles; | |
private int tabCount = 0; | |
/** | |
* Initiate the adapter with a {@link FragmentManager}. | |
* | |
* @param fragmentManager FragmentManager. | |
*/ | |
public SectionsPagerAdapter(FragmentManager fragmentManager) { | |
super(fragmentManager); | |
fragmentMap = new HashMap<>(); | |
tabNumbers = new ArrayList<>(); | |
tabTitles = new ArrayList<>(); | |
} | |
@Override public int getCount() { | |
return fragmentMap.size(); | |
} | |
@Override public Fragment getItem(int position) { | |
return fragmentMap.get(tabNumbers.get(position)); | |
} | |
@Override public CharSequence getPageTitle(int position) { | |
return tabTitles.get(position); | |
} | |
/** | |
* Add tab to adapter to be displayed by a {@link android.support.v4.view.ViewPager}. | |
* | |
* @param title Title of Fragment. | |
* @param fragment Instance of Fragment. | |
* @return Updated instance of this adapter. | |
*/ | |
public SectionsPagerAdapter addTab(String title, Fragment fragment) { | |
tabCount++; | |
return addTab(title, fragment, tabCount); | |
} | |
/** | |
* Add tab to adapter to be displayed by a {@link android.support.v4.view.ViewPager}. | |
* | |
* @param title Title of Fragment. | |
* @param fragment Instance of Fragment. | |
* @param tabNumber Position of Fragment. | |
* @return Updated instance of this adapter. | |
*/ | |
public SectionsPagerAdapter addTab(String title, Fragment fragment, int tabNumber) { | |
fragmentMap.put(tabNumber, fragment); | |
tabNumbers.add(tabNumber); | |
tabTitles.add(title); | |
notifyDataSetChanged(); | |
return this; | |
} | |
/** | |
* Get Fragment based on position. Use this instead of {@link #getItem(int)} for | |
* {@link Fragment} access. | |
* | |
* @param number Position of Fragment in the adapter. | |
* @return Instance of fragment. | |
* @see #getItem(int) Used by Fragment to get current instance. | |
*/ | |
public Fragment getTabFragment(int number) { | |
return fragmentMap.get(number); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.app.Activity; | |
import android.content.pm.PackageManager; | |
import android.os.Bundle; | |
import android.preference.PreferenceFragment; | |
import android.preference.PreferenceScreen; | |
import com.mikepenz.aboutlibraries.Libs; | |
import com.mikepenz.aboutlibraries.LibsBuilder; | |
import java.util.Calendar; | |
/** | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
public final class SettingsActivity extends BaseActivity { | |
private static final String KEY_APP_VERSION = "app_version"; | |
private static final String KEY_RATE_APP = "rate_app"; | |
private static final String KEY_BURROWS_APPS = "website_burrowsapps"; | |
private static final String KEY_BURROWS_APPS_BLOG = "website_burrowsapps_blog"; | |
private static final String KEY_BURROWS_APPS_FACEBOOK = "website_facebook"; | |
private static final String KEY_BURROWS_APPS_TWITTER = "website_twitter"; | |
private static final String KEY_BURROWS_APPS_GOOGLE_PLUS = "website_google_plus"; | |
private static final String KEY_COPYRIGHT = "copyright"; | |
private static final String KEY_OPEN_SOURCE_LICENSES = "open_source_licenses"; | |
private static final String KEY_BURROWS_APPS_PRIVACY_POLICY = "privacy_policy"; | |
private static final String LOG_SCREEN_NAME = "SettingsActivity - onResume"; | |
private static final String BURROWS_APPS = "http://burrowsapps.com"; | |
public static final String BURROWS_APPS_BLOG = "http://blog.burrowsapps.com"; | |
private static final String BURROWS_APPS_FACEBOOK = "http://facebook.com/burrowsapps"; | |
private static final String BURROWS_APPS_TWITTER = "http://twitter.com/burrowsapps"; | |
private static final String BURROWS_APPS_GOOGLE = "http://plus.google.com/+burrowsapps"; | |
private static final String BURROWS_APPS_PRIVACY_POLICY = "http://www.burrowsapps.com/privacy.html"; | |
private static final String COPYRIGHT_2011 = "Copyright \u00A9 2011-"; | |
static final String[] LICENSES = new String[]{"aboutlibraries", "googleplayservices", "design", | |
"appcompat_v7", "support_v4", "support_annotations", | |
"recyclerview_v7", "butterknife", "okio", "okhttp", "retrofit", | |
"gson", "rxandroid", "rxjava", "leakcanary"}; | |
@Override public int getLayoutResId() { | |
return R.layout.activity_settings; | |
} | |
@Override protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
if (savedInstanceState == null) { | |
getFragmentManager() | |
.beginTransaction() | |
.add(R.id.content_frame, new SettingsFragment()) | |
.commit(); | |
} | |
} | |
// Must call this for drawer toggle to work correctly | |
@Override protected void onPostCreate(Bundle savedInstanceState) { | |
super.onPostCreate(savedInstanceState); | |
if (toolbar != null) { | |
toolbar.setTitle(R.string.menu_nav_settings); | |
toolbar.setNavigationIcon(R.drawable.ic_arrow_back_white_24dp); | |
setSupportActionBar(toolbar); | |
} | |
} | |
/** | |
* @author <a href="mailto:[email protected]">Jared Burrows</a> | |
*/ | |
public static final class SettingsFragment extends PreferenceFragment { | |
@Override public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
addPreferencesFromResource(R.xml.preference_about); | |
final Activity activity = getActivity(); | |
final String packageName = activity.getPackageName(); | |
final PackageManager manager = activity.getPackageManager(); | |
final PreferenceScreen screen = getPreferenceScreen(); | |
// About | |
screen.findPreference(KEY_APP_VERSION).setSummary(AppUtils.getVersionRelease(manager, packageName)); | |
screen.findPreference(KEY_RATE_APP) | |
.setIntent(AppUtils.createSocialIntent(manager, AppUtils.MARKET_URL_GOOGLE_PLAY + packageName)); | |
screen.findPreference(KEY_BURROWS_APPS).setIntent(AppUtils.createSocialIntent(manager, BURROWS_APPS)); | |
screen.findPreference(KEY_BURROWS_APPS_BLOG).setIntent(AppUtils.createSocialIntent(manager, BURROWS_APPS_BLOG)); | |
// Social | |
screen.findPreference(KEY_BURROWS_APPS_FACEBOOK) | |
.setIntent(AppUtils.createSocialIntent(manager, BURROWS_APPS_FACEBOOK, AppUtils.APP_FACEBOOK)); | |
screen.findPreference(KEY_BURROWS_APPS_TWITTER) | |
.setIntent(AppUtils.createSocialIntent(manager, BURROWS_APPS_TWITTER, AppUtils.APP_TWITTER)); | |
screen.findPreference(KEY_BURROWS_APPS_GOOGLE_PLUS) | |
.setIntent(AppUtils.createSocialIntent(manager, BURROWS_APPS_GOOGLE, AppUtils.APP_GOOGLE_PLUS)); | |
// Legal | |
screen.findPreference(KEY_COPYRIGHT).setTitle(COPYRIGHT_2011 + Calendar.getInstance().get(Calendar.YEAR)); | |
screen.findPreference(KEY_OPEN_SOURCE_LICENSES).setIntent(new LibsBuilder() | |
.withAutoDetect(true) | |
.withSortEnabled(true) | |
.withLicenseShown(true) | |
.withFields(R.string.class.getFields()) | |
.withActivityTitle(getString(R.string.title_licenses)) | |
.withActivityStyle(Libs.ActivityStyle.LIGHT_DARK_TOOLBAR) | |
// Existing libs can be found here: https://github.com/mikepenz/AboutLibraries/tree/develop/library/src/main/res/values | |
// gradlew dependencies --configuration compile | |
.withLibraries(LICENSES) | |
.intent(getActivity())); | |
screen.findPreference(KEY_BURROWS_APPS_PRIVACY_POLICY) | |
.setIntent(AppUtils.createSocialIntent(manager, BURROWS_APPS_PRIVACY_POLICY)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment