Created
April 19, 2016 14:44
-
-
Save gorodechnyj/bbfb881c0f9934d28c3eebbcac45bfb6 to your computer and use it in GitHub Desktop.
Skeleton classes of my applications
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
package ch.dotpay.skeleton.activity; | |
import android.Manifest; | |
import android.animation.Animator; | |
import android.app.Dialog; | |
import android.content.Intent; | |
import android.content.pm.PackageManager; | |
import android.os.Build; | |
import android.os.Bundle; | |
import android.os.Handler; | |
import android.support.annotation.NonNull; | |
import android.support.v4.app.ActivityCompat; | |
import android.support.v4.app.Fragment; | |
import android.support.v4.app.FragmentTransaction; | |
import android.support.v7.app.AppCompatActivity; | |
import android.transition.TransitionInflater; | |
import android.util.Log; | |
import android.view.View; | |
import ch.dotpay.DotpayApplication; | |
import ch.dotpay.R; | |
import ch.dotpay.core.shared.ProviderWrapper; | |
import ch.dotpay.network.api.ApiFactory; | |
import ch.dotpay.network.model.ServerError; | |
import ch.dotpay.ui.fragment.GenericFragment; | |
import ch.dotpay.utils.AlertUtils; | |
import ch.dotpay.utils.GMSUtils; | |
/** | |
* Created by gorodechnyj on 18.01.16. | |
*/ | |
public class BaseActivity extends AppCompatActivity { | |
private static final int REQUEST_LOCATION_PERMISSION = 4; | |
private Handler handler = new Handler(); | |
private boolean mPaused = false; | |
private View mProgressView; | |
private Dialog mCurrentDialog; | |
protected ProviderWrapper providerWrapper; | |
protected DotpayApplication dotpayApplication; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
dotpayApplication = ((DotpayApplication) getApplication()); | |
providerWrapper = dotpayApplication.getProviderWrapper(); | |
} | |
public void addFragment(final int containerResId, final Fragment fragment, final boolean addToBackStack) { | |
handler.post(new Runnable() { | |
@Override | |
public void run() { | |
if (!mPaused) { | |
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); | |
ft.add(containerResId, fragment, fragment.getClass().getName()); | |
if (addToBackStack) { | |
ft.addToBackStack(fragment.getClass().getName()); | |
} | |
ft.commitAllowingStateLoss(); | |
} | |
} | |
}); | |
} | |
public void replaceFragment(final int containerResId, final Fragment fragment, final boolean addToBackStack) { | |
replaceFragment(containerResId, fragment, addToBackStack, false); | |
} | |
public void replaceFragment(final int containerResId, final Fragment fragment, final boolean addToBackStack, final boolean animate) { | |
handler.post(new Runnable() { | |
@Override | |
public void run() { | |
if (!mPaused) { | |
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); | |
ft.replace(containerResId, fragment, fragment.getClass().getName()); | |
if (animate) { | |
if (Build.VERSION.SDK_INT >= 21) { | |
fragment.setEnterTransition(TransitionInflater.from(BaseActivity.this) | |
.inflateTransition(android.R.transition.slide_right)); | |
fragment.setExitTransition(TransitionInflater.from(BaseActivity.this) | |
.inflateTransition(android.R.transition.fade)); | |
} else { | |
ft.setCustomAnimations(R.anim.slide_left_in, R.anim.slide_left_out, R.anim.slide_right_in, R.anim.slide_right_out); | |
} | |
} | |
if (addToBackStack) { | |
ft.addToBackStack(fragment.getClass().getName()); | |
} | |
ft.commitAllowingStateLoss(); | |
} | |
} | |
}); | |
} | |
@Override | |
protected void onResume() { | |
super.onResume(); | |
if (GMSUtils.checkLocationPermission(this, REQUEST_LOCATION_PERMISSION)) { | |
dismissAlert(); | |
GMSUtils.checkGeolocationEnabled(this); | |
} | |
} | |
@Override | |
protected void onPostCreate(Bundle savedInstanceState) { | |
super.onPostCreate(savedInstanceState); | |
mProgressView = findViewById(R.id.progressView); | |
} | |
@Override | |
protected void onDestroy() { | |
super.onDestroy(); | |
mPaused = true; | |
} | |
@Override | |
protected void onActivityResult(int requestCode, int resultCode, Intent data) { | |
if (requestCode == GMSUtils.GMS_REQUEST_GEO_LOCATION && | |
!GMSUtils.isGeolocationEnabled(this)) { | |
finish(); | |
} else { | |
super.onActivityResult(requestCode, resultCode, data); | |
} | |
} | |
@Override | |
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { | |
if (requestCode == REQUEST_LOCATION_PERMISSION) { | |
if (grantResults.length == 0 | |
|| grantResults[0] != PackageManager.PERMISSION_GRANTED) { | |
if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) { | |
showAlert(AlertUtils.getAskPermissionDialog(BaseActivity.this, | |
getString(R.string.permissionRequired), | |
getString(R.string.locationPermissionRequired), | |
REQUEST_LOCATION_PERMISSION)); | |
} | |
} | |
return; | |
} | |
super.onRequestPermissionsResult(requestCode, permissions, grantResults); | |
} | |
/** | |
* Throbber, if used, shown above the any widgets and blocks user actions. | |
*/ | |
public void showThrobber() { | |
if (mProgressView != null && !mPaused) { | |
mProgressView.animate() | |
.alpha(1f) | |
.setDuration(200) | |
.setListener(new Animator.AnimatorListener() { | |
@Override | |
public void onAnimationStart(Animator animation) { | |
mProgressView.setVisibility(View.VISIBLE); | |
} | |
@Override | |
public void onAnimationEnd(Animator animation) { | |
} | |
@Override | |
public void onAnimationCancel(Animator animation) { | |
} | |
@Override | |
public void onAnimationRepeat(Animator animation) { | |
} | |
}); | |
} | |
} | |
public void hideThrobber() { | |
if (mProgressView != null && !mPaused) { | |
mProgressView.animate() | |
.alpha(0f) | |
.setDuration(200) | |
.setListener(new Animator.AnimatorListener() { | |
@Override | |
public void onAnimationStart(Animator animation) { | |
} | |
@Override | |
public void onAnimationEnd(Animator animation) { | |
mProgressView.setVisibility(View.GONE); | |
} | |
@Override | |
public void onAnimationCancel(Animator animation) { | |
} | |
@Override | |
public void onAnimationRepeat(Animator animation) { | |
} | |
}); | |
} | |
} | |
public boolean isThrobberShown() { | |
return mProgressView != null && mProgressView.getVisibility() == View.VISIBLE; | |
} | |
public View getThrobber() { | |
return mProgressView; | |
} | |
public void showAlert(Dialog dialog) { | |
dismissAlert(); | |
mCurrentDialog = dialog; | |
mCurrentDialog.show(); | |
} | |
public void dismissAlert() { | |
if (mCurrentDialog != null) { | |
mCurrentDialog.dismiss(); | |
mCurrentDialog = 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
package ch.dotpay.skeleton.binding; | |
import android.content.Context; | |
import android.databinding.BindingAdapter; | |
import android.graphics.Typeface; | |
import android.support.design.widget.TextInputLayout; | |
import android.text.Editable; | |
import android.text.TextUtils; | |
import android.text.TextWatcher; | |
import android.util.Pair; | |
import android.view.View; | |
import android.widget.AdapterView; | |
import android.widget.EditText; | |
import android.widget.ImageView; | |
import android.widget.TextView; | |
import com.squareup.picasso.Picasso; | |
import java.util.HashMap; | |
import ch.dotpay.R; | |
import ch.dotpay.skeleton.util.CircleTransformation; | |
/** | |
* Created by Belozerow on 11.10.2015. | |
*/ | |
public class BindingAttributes { | |
private static HashMap<String, Typeface> typefaceHashMap = new HashMap<>(); | |
@BindingAdapter({"bind:circleUrl"}) | |
public static void setCircleUrl(ImageView imageView, String url) { | |
if (url == null) | |
return; | |
Picasso.with(imageView.getContext()).load(url).transform(new CircleTransformation()).into(imageView); | |
} | |
@BindingAdapter({"bind:imageUrl"}) | |
public static void setImageUrl(ImageView imageView, String url) { | |
if (url == null) | |
return; | |
Picasso.with(imageView.getContext()).load(url).into(imageView); | |
} | |
@BindingAdapter("bind:typeface") | |
public static void setTypeface(TextView textView, String font) { | |
Typeface tf = typefaceHashMap.get(font); | |
if (tf == null) { | |
tf = Typeface.createFromAsset(textView.getContext().getAssets(), "fonts/" + font); | |
typefaceHashMap.put(font, tf); | |
} | |
textView.setTypeface(tf); | |
} | |
@BindingAdapter({"bind:imageRes"}) | |
public static void setImageRes(ImageView imageView, int res) { | |
imageView.setImageResource(res); | |
} | |
@BindingAdapter({"bind:imageResName"}) | |
public static void setImageResName(ImageView imageView, String resName) { | |
Context context = imageView.getContext(); | |
if (TextUtils.isEmpty(resName)) { | |
return; | |
} | |
int id = context.getResources().getIdentifier(resName, "drawable", context.getPackageName()); | |
imageView.setImageResource(id); | |
} | |
@BindingAdapter({"bind:twoWayText"}) | |
public static void bindEditText(EditText view, | |
final ObservableString observableString) { | |
Pair<ObservableString, TextWatcher> pair = | |
(Pair) view.getTag(R.id.bound_observable); | |
if (pair == null || pair.first != observableString) { | |
if (pair != null) { | |
view.removeTextChangedListener(pair.second); | |
} | |
TextWatcher watcher = new TextWatcher() { | |
@Override | |
public void beforeTextChanged(CharSequence s, int start, int count, int after) { | |
} | |
public void onTextChanged(CharSequence s, | |
int start, int before, int count) { | |
observableString.set(s.toString()); | |
} | |
@Override | |
public void afterTextChanged(Editable s) { | |
} | |
}; | |
view.setTag(R.id.bound_observable, | |
new Pair<>(observableString, watcher)); | |
view.addTextChangedListener(watcher); | |
} | |
if (observableString != null) { | |
String newValue = observableString.get(); | |
if (!view.getText().toString().equals(newValue)) { | |
view.setText(newValue); | |
} | |
} | |
if (view.getParent() != null | |
&& view.getParent() instanceof TextInputLayout) { | |
((TextInputLayout) view.getParent()).refreshDrawableState(); | |
} | |
} | |
// @BindingAdapter("app:swipeEnabled") | |
// public static void setLayoutWidth(SwipeLayout view, boolean enabled) { | |
// view.setSwipeEnabled(enabled); | |
// } | |
// @BindingAdapter({"app:twoWayBoolean"}) | |
// public static void bindCheckBox(CheckBox view, final ObservableBoolean observableBoolean) { | |
// if (observableBoolean != null) { | |
// if (view.getTag(R.id.bound_observable) != observableBoolean) { | |
// view.setTag(R.id.bound_observable, observableBoolean); | |
// view.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { | |
// @Override | |
// public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { | |
// observableBoolean.set(isChecked); | |
// } | |
// }); | |
// } | |
// boolean newValue = observableBoolean.get(); | |
// if (view.isChecked() != newValue) { | |
// view.setChecked(newValue); | |
// } | |
// } | |
// } | |
// | |
// @BindingAdapter({"app:twoWaySpinner"}) | |
// public static void bindSpinner(final Spinner spinner, final ObservableString observable) { | |
// if (observable != null) { | |
// if (spinner.getTag(R.id.bound_observable) != observable) { | |
// spinner.setTag(R.id.bound_observable, observable); | |
// spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { | |
// @Override | |
// public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { | |
// observable.set((String) spinner.getItemAtPosition(position)); | |
// } | |
// | |
// @Override | |
// public void onNothingSelected(AdapterView<?> parent) { | |
// | |
// } | |
// }); | |
// } | |
// String newValue = observable.get(); | |
// if (newValue == null) | |
// return; | |
// if (!observable.equals(spinner.getSelectedItem())) { | |
// SpinnerAdapter spinnerAdapter = spinner.getAdapter(); | |
// int selectedItem = spinner.getSelectedItemPosition(); | |
// if (spinnerAdapter != null) { | |
// for (int i = 0; i < spinnerAdapter.getCount(); i++) { | |
// if (newValue.equals(spinnerAdapter.getItem(i))) { | |
// selectedItem = i; | |
// break; | |
// } | |
// } | |
// } | |
// spinner.setSelection(selectedItem); | |
// } | |
// | |
// } | |
// } | |
// @BindingAdapter({"android:entries"}) | |
// public static void setFriendsSpinner(Spinner spinner, ArrayList<Friend> items) { | |
// ArrayList<String> strings = new ArrayList<>(); | |
// for (Friend item : items) { | |
// strings.add(item.userName.get()); | |
// } | |
// ArrayAdapter<String> adapter = new ArrayAdapter<>(spinner.getContext(), R.layout.item_friends_spinner, strings); | |
// spinner.setAdapter(adapter); | |
// } | |
@BindingAdapter({"bind:error"}) | |
public static void setTextInputError(TextInputLayout textInputLayout, String error) { | |
if (TextUtils.isEmpty(error)) { | |
textInputLayout.setError(null); | |
} else { | |
textInputLayout.setError(error); | |
} | |
} | |
@BindingAdapter({"bind:error"}) | |
public static void setTextInputError(TextInputLayout textInputLayout, int errorResId) { | |
if (errorResId == 0) { | |
textInputLayout.setError(null); | |
} else { | |
textInputLayout.setError(textInputLayout.getContext().getResources().getString(errorResId)); | |
} | |
} | |
@BindingAdapter({"bind:onActionDone"}) | |
public static void setOnDoneListener(EditText editText, TextView.OnEditorActionListener listener) { | |
editText.setOnEditorActionListener(listener); | |
} | |
@BindingAdapter({"bind:onLongClick"}) | |
public static void setOnLongClickListener(View view, View.OnLongClickListener listener) { | |
view.setOnLongClickListener(listener); | |
} | |
@BindingAdapter({"bind:onItemLongClick"}) | |
public static void setOnLongClickListener(AdapterView view, AdapterView.OnItemLongClickListener listener) { | |
view.setOnItemLongClickListener(listener); | |
} | |
@BindingAdapter({"app:onItemClick"}) | |
public static void setOnItemClickListener(AdapterView view, AdapterView.OnItemClickListener listener) { | |
view.setOnItemClickListener(listener); | |
} | |
@BindingAdapter({"app:visibility"}) | |
public static void setVisibility(View view, boolean isVisible) { | |
view.setVisibility(isVisible ? View.VISIBLE : View.GONE); | |
} | |
} |
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
package ch.dotpay.skeleton.binding; | |
import android.databinding.ViewDataBinding; | |
import android.view.LayoutInflater; | |
import android.view.ViewGroup; | |
import java.lang.reflect.InvocationTargetException; | |
import java.lang.reflect.Method; | |
/** | |
* Created by Belozerow on 29.11.2015. | |
*/ | |
public class DataBindingUtils { | |
public static ViewDataBinding getViewDataBinding(Class clazz, LayoutInflater inflater, ViewGroup container) { | |
Method method = null; | |
try { | |
method = clazz.getMethod("inflate", LayoutInflater.class, ViewGroup.class, boolean.class); | |
return (ViewDataBinding) method.invoke(null, inflater, container, false); | |
} catch (NoSuchMethodException e) { | |
e.printStackTrace(); | |
} catch (InvocationTargetException e) { | |
e.printStackTrace(); | |
} catch (IllegalAccessException e) { | |
e.printStackTrace(); | |
} | |
return 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
package ch.dotpay.skeleton.binding; | |
import android.databinding.BaseObservable; | |
import android.databinding.BindingConversion; | |
import android.os.Parcel; | |
import android.os.Parcelable; | |
import java.io.Serializable; | |
/** | |
* Created: Belozerov | |
* Company: APPGRANULA LLC | |
* Date: 15.01.2016 | |
*/ | |
public class ObservableString extends BaseObservable implements Parcelable, Serializable { | |
static final long serialVersionUID = 1L; | |
private String mValue; | |
public static final Creator<ObservableString> CREATOR = new Creator<ObservableString>() { | |
public ObservableString createFromParcel(Parcel source) { | |
return new ObservableString(source.readString()); | |
} | |
public ObservableString[] newArray(int size) { | |
return new ObservableString[size]; | |
} | |
}; | |
public ObservableString(String value) { | |
this.mValue = value; | |
} | |
public ObservableString() { | |
} | |
public String get() { | |
return this.mValue; | |
} | |
public void set(String value) { | |
if (!equals(value, this.mValue)) { | |
this.mValue = value; | |
this.notifyChange(); | |
} | |
} | |
public static boolean equals(Object a, Object b) { | |
return (a == b) || (a != null && a.equals(b)); | |
} | |
public int describeContents() { | |
return 0; | |
} | |
public void writeToParcel(Parcel dest, int flags) { | |
dest.writeString(this.mValue); | |
} | |
public boolean isEmpty() { | |
return mValue == null || mValue.isEmpty(); | |
} | |
@BindingConversion | |
public static String convertToString(ObservableString s) { | |
return s.get(); | |
} | |
} |
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
package ch.dotpay.skeleton.fragment; | |
import android.databinding.ViewDataBinding; | |
import android.os.Bundle; | |
import android.support.annotation.Nullable; | |
import android.support.v4.app.Fragment; | |
import android.support.v7.app.ActionBar; | |
import android.support.v7.app.AppCompatActivity; | |
import android.support.v7.widget.Toolbar; | |
import android.view.LayoutInflater; | |
import android.view.MenuItem; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import ch.dotpay.DotpayApplication; | |
import ch.dotpay.R; | |
import ch.dotpay.core.FragmentLauncher; | |
import ch.dotpay.core.shared.ProviderWrapper; | |
import ch.dotpay.pref.UserPref; | |
import ch.dotpay.skeleton.activity.BaseActivity; | |
import ch.dotpay.skeleton.binding.DataBindingUtils; | |
/** | |
* Created: gorodechnyj | |
* Date: 27.03.2016 | |
*/ | |
public abstract class BaseFragment<T extends ViewDataBinding> extends Fragment { | |
private final Class<T> typeParameterClass; | |
protected T binding; | |
public static final String ADD_TO_BACK_STACK = "add_to_back_stack"; | |
public abstract String getTitle(); | |
protected DotpayApplication dotpayApplication; | |
protected ProviderWrapper providerWrapper; | |
protected UserPref userPref; | |
protected ActionBar actionBar; | |
public BaseFragment(Class<T> typeParameterClass) { | |
super(); | |
this.typeParameterClass = typeParameterClass; | |
} | |
public String getFragmentTag() { | |
Class<?> enclosingClass = getClass().getEnclosingClass(); | |
if (enclosingClass != null) { | |
return enclosingClass.getName(); | |
} else { | |
return getClass().getName(); | |
} | |
} | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
dotpayApplication = ((DotpayApplication) getActivity().getApplication()); | |
providerWrapper = dotpayApplication.getProviderWrapper(); | |
userPref = UserPref.with(getActivity()); | |
setHasOptionsMenu(true); | |
} | |
public BaseActivity getBaseActivity() { | |
return (BaseActivity) getActivity(); | |
} | |
private boolean isBackStack() { | |
return getArguments().getBoolean(ADD_TO_BACK_STACK); | |
} | |
@Override | |
public void onResume() { | |
super.onResume(); | |
setTitle(getTitle()); | |
} | |
protected void setTitle(String title) { | |
if (actionBar != null) | |
actionBar.setTitle(title); | |
} | |
protected ActionBar getSupportActionBar() { | |
return ((AppCompatActivity) getActivity()).getSupportActionBar(); | |
} | |
@Override | |
public boolean onOptionsItemSelected(MenuItem item) { | |
if (item.getItemId() == android.R.id.home) { | |
getFragmentManager().popBackStack(); | |
return true; | |
} | |
return super.onOptionsItemSelected(item); | |
} | |
@Nullable | |
@Override | |
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { | |
binding = (T) DataBindingUtils.getViewDataBinding(typeParameterClass, inflater, container); | |
View view = binding.getRoot(); | |
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar); | |
if (toolbar != null) { | |
getBaseActivity().setSupportActionBar(toolbar); | |
} | |
actionBar = getSupportActionBar(); | |
return view; | |
} | |
public boolean onBackPressed() { | |
return false; | |
} | |
} |
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
package ch.dotpay.skeleton.util; | |
import android.graphics.Bitmap; | |
import android.graphics.BitmapShader; | |
import android.graphics.Canvas; | |
import android.graphics.Paint; | |
import com.squareup.picasso.Transformation; | |
public class CircleTransformation implements Transformation { | |
@Override | |
public Bitmap transform(Bitmap source) { | |
int size = Math.min(source.getWidth(), source.getHeight()); | |
int x = (source.getWidth() - size) / 2; | |
int y = (source.getHeight() - size) / 2; | |
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size); | |
if (squaredBitmap != source) { | |
source.recycle(); | |
} | |
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig()); | |
Canvas canvas = new Canvas(bitmap); | |
Paint paint = new Paint(); | |
BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP); | |
paint.setShader(shader); | |
paint.setAntiAlias(true); | |
float r = size / 2f; | |
canvas.drawCircle(r, r, r, paint); | |
squaredBitmap.recycle(); | |
return bitmap; | |
} | |
@Override | |
public String key() { | |
return "circle"; | |
} | |
} |
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
package ch.dotpay.skeleton.widget; | |
/* | |
* Copyright (C) 2014 [email protected] | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
* | |
*/ | |
import android.content.Context; | |
import android.database.Cursor; | |
import android.database.DataSetObserver; | |
import android.support.v7.widget.RecyclerView; | |
/** | |
* Created by skyfishjy on 10/31/14. | |
*/ | |
public abstract class CursorRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> { | |
protected Context mContext; | |
private Cursor mCursor; | |
private boolean mDataValid; | |
private int mRowIdColumn; | |
private DataSetObserver mDataSetObserver; | |
public CursorRecyclerViewAdapter(Context context, Cursor cursor) { | |
mContext = context; | |
mCursor = cursor; | |
mDataValid = cursor != null; | |
mRowIdColumn = mDataValid ? mCursor.getColumnIndex("_id") : -1; | |
mDataSetObserver = new NotifyingDataSetObserver(); | |
if (mCursor != null) { | |
mCursor.registerDataSetObserver(mDataSetObserver); | |
} | |
} | |
public Cursor getCursor() { | |
return mCursor; | |
} | |
@Override | |
public int getItemCount() { | |
if (mDataValid && mCursor != null) { | |
return mCursor.getCount(); | |
} | |
return 0; | |
} | |
@Override | |
public long getItemId(int position) { | |
if (mDataValid && mCursor != null && mCursor.moveToPosition(position)) { | |
return mCursor.getLong(mRowIdColumn); | |
} | |
return 0; | |
} | |
@Override | |
public void setHasStableIds(boolean hasStableIds) { | |
super.setHasStableIds(true); | |
} | |
public abstract void onBindViewHolder(VH viewHolder, Cursor cursor, int position); | |
@Override | |
public void onBindViewHolder(VH viewHolder, int position) { | |
if (!mDataValid) { | |
throw new IllegalStateException("this should only be called when the cursor is valid"); | |
} | |
if (!mCursor.moveToPosition(position)) { | |
throw new IllegalStateException("couldn't move cursor to position " + position); | |
} | |
onBindViewHolder(viewHolder, mCursor, position); | |
} | |
/** | |
* Change the underlying cursor to a new cursor. If there is an existing cursor it will be | |
* closed. | |
*/ | |
public void changeCursor(Cursor cursor) { | |
Cursor old = swapCursor(cursor); | |
if (old != null) { | |
old.close(); | |
} | |
} | |
/** | |
* Swap in a new Cursor, returning the old Cursor. Unlike | |
* {@link #changeCursor(Cursor)}, the returned old Cursor is <em>not</em> | |
* closed. | |
*/ | |
public Cursor swapCursor(Cursor newCursor) { | |
if (newCursor == mCursor) { | |
return null; | |
} | |
final Cursor oldCursor = mCursor; | |
if (oldCursor != null && mDataSetObserver != null) { | |
oldCursor.unregisterDataSetObserver(mDataSetObserver); | |
} | |
mCursor = newCursor; | |
if (mCursor != null) { | |
if (mDataSetObserver != null) { | |
mCursor.registerDataSetObserver(mDataSetObserver); | |
} | |
mRowIdColumn = newCursor.getColumnIndexOrThrow("_id"); | |
mDataValid = true; | |
notifyDataSetChanged(); | |
} else { | |
mRowIdColumn = -1; | |
mDataValid = false; | |
notifyDataSetChanged(); | |
//There is no notifyDataSetInvalidated() method in RecyclerView.Adapter | |
} | |
return oldCursor; | |
} | |
private class NotifyingDataSetObserver extends DataSetObserver { | |
@Override | |
public void onChanged() { | |
super.onChanged(); | |
mDataValid = true; | |
notifyDataSetChanged(); | |
} | |
@Override | |
public void onInvalidated() { | |
super.onInvalidated(); | |
mDataValid = false; | |
notifyDataSetChanged(); | |
//There is no notifyDataSetInvalidated() method in RecyclerView.Adapter | |
} | |
} | |
} |
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
package ch.dotpay.skeleton.widget; | |
import android.content.Context; | |
import android.os.Build; | |
import android.util.AttributeSet; | |
import android.view.WindowInsets; | |
import android.widget.FrameLayout; | |
/** | |
* @author Kevin | |
* Date Created: 3/7/14 | |
* <p/> | |
* https://code.google.com/p/android/issues/detail?id=63777 | |
* <p/> | |
* When using a translucent status bar on API 19+, the window will not | |
* resize to make room for input methods (i.e. | |
* {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} and | |
* {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_PAN} are | |
* ignored). | |
* <p/> | |
* To work around this; override {@link #fitSystemWindows(android.graphics.Rect)}, | |
* capture and override the system insets, and then call through to LinearLayout's | |
* implementation. | |
* <p/> | |
* For reasons yet unknown, modifying the bottom inset causes this workaround to | |
* fail. Modifying the top, left, and right insets works as expected. | |
*/ | |
public final class CustomInsetsFrameLayout extends FrameLayout { | |
private int[] mInsets = new int[4]; | |
public CustomInsetsFrameLayout(Context context) { | |
super(context); | |
} | |
public CustomInsetsFrameLayout(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
public CustomInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
} | |
public final int[] getInsets() { | |
return mInsets; | |
} | |
@Override | |
public final WindowInsets onApplyWindowInsets(WindowInsets insets) { | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { | |
mInsets[0] = insets.getSystemWindowInsetLeft(); | |
mInsets[1] = insets.getSystemWindowInsetTop(); | |
mInsets[2] = insets.getSystemWindowInsetRight(); | |
return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0, | |
insets.getSystemWindowInsetBottom())); | |
} else { | |
return insets; | |
} | |
} | |
} |
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
package ch.dotpay.skeleton.widget; | |
import android.content.Context; | |
import android.os.Build; | |
import android.util.AttributeSet; | |
import android.view.WindowInsets; | |
import android.widget.LinearLayout; | |
/** | |
* @author Kevin | |
* Date Created: 3/7/14 | |
* <p/> | |
* https://code.google.com/p/android/issues/detail?id=63777 | |
* <p/> | |
* When using a translucent status bar on API 19+, the window will not | |
* resize to make room for input methods (i.e. | |
* {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} and | |
* {@link android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_PAN} are | |
* ignored). | |
* <p/> | |
* To work around this; override {@link #fitSystemWindows(android.graphics.Rect)}, | |
* capture and override the system insets, and then call through to LinearLayout's | |
* implementation. | |
* <p/> | |
* For reasons yet unknown, modifying the bottom inset causes this workaround to | |
* fail. Modifying the top, left, and right insets works as expected. | |
*/ | |
public final class CustomInsetsLinearLayout extends LinearLayout { | |
private int[] mInsets = new int[4]; | |
public CustomInsetsLinearLayout(Context context) { | |
super(context); | |
} | |
public CustomInsetsLinearLayout(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
public CustomInsetsLinearLayout(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
} | |
public final int[] getInsets() { | |
return mInsets; | |
} | |
@Override | |
public final WindowInsets onApplyWindowInsets(WindowInsets insets) { | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { | |
mInsets[0] = insets.getSystemWindowInsetLeft(); | |
mInsets[1] = insets.getSystemWindowInsetTop(); | |
mInsets[2] = insets.getSystemWindowInsetRight(); | |
return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0, | |
insets.getSystemWindowInsetBottom())); | |
} else { | |
return insets; | |
} | |
} | |
} |
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
package ch.dotpay.skeleton.widget; | |
import android.support.v7.widget.RecyclerView; | |
/** | |
* Created by gorodechnyj on 30.03.2016. | |
*/ | |
public abstract class ItemClickableRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> { | |
@Override | |
public void onBindViewHolder(VH holder, int position) { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment