Skip to content

Commit

Permalink
Fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
CullyCross committed Nov 6, 2015
1 parent 217e5a5 commit 81ab948
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package me.cullycross.test4tabs.activities;

import android.content.ContentUris;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.TabLayout;
Expand All @@ -19,7 +17,6 @@
import butterknife.OnClick;
import butterknife.OnPageChange;
import me.cullycross.test4tabs.R;
import me.cullycross.test4tabs.content.EntityContentProvider;
import me.cullycross.test4tabs.fragments.ContactsFragment;
import me.cullycross.test4tabs.fragments.DatabaseFragment;
import me.cullycross.test4tabs.fragments.EmailDialogFragment;
Expand Down Expand Up @@ -77,27 +74,20 @@ public class FourTabsActivity extends AppCompatActivity

final Object o = currentFragment();

if(!(o instanceof RowUpdateListener)) {
if (!(o instanceof RowUpdateListener)) {
return;
}

if (id != DatabaseFragment.FLAG_NEW_ENTITY) {
final SomeEntity entity = SomeEntity.fromDatabase(this, id);
SomeEntity.fromDatabase(this, id, entity -> {
if (entity != null) {
entity.setName(title);
entity.setDescription(body);
final Uri uri = ContentUris.withAppendedId(EntityContentProvider.ENTITY_CONTENT_URI, id);
getContentResolver().update(uri, entity.toContentValues(), null, null);
} else {
Toast.makeText(FourTabsActivity.this, "Entity not found", Toast.LENGTH_SHORT).show();
entity = new SomeEntity(title, body);
}
} else {
final SomeEntity entity = new SomeEntity(title, body);
getContentResolver().insert(EntityContentProvider.ENTITY_CONTENT_URI,
entity.toContentValues());
}

((RowUpdateListener) o).onRowUpdate(row);
entity.save(this);
((RowUpdateListener) o).onRowUpdate(row);
});
}

@OnPageChange(R.id.container) public void onPageSelected(int position) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import butterknife.Bind;
Expand All @@ -16,8 +18,10 @@
import java.util.Locale;
import me.cullycross.test4tabs.R;
import me.cullycross.test4tabs.activities.FourTabsActivity;
import me.cullycross.test4tabs.fragments.DatabaseFragment;
import me.cullycross.test4tabs.fragments.EntityDialogFragment;
import me.cullycross.test4tabs.pojos.SomeEntity;
import me.cullycross.test4tabs.utils.ColorUtils;

/**
* Created by: Anton Shkurenko (cullycross)
Expand All @@ -31,8 +35,13 @@ public class EntityCursorAdapter extends CursorRecyclerViewAdapter<EntityCursorA
private static final SimpleDateFormat DATE_FORMAT =
new SimpleDateFormat("EEEE, MMMM dd yyyy", Locale.getDefault());

public EntityCursorAdapter(Context context, Cursor cursor) {
super(context, cursor);
private Context mContext;
private DatabaseFragment mFragment;

public EntityCursorAdapter(DatabaseFragment fragment, Cursor cursor) {
super(fragment.getContext(), cursor);
mFragment = fragment;
mContext = fragment.getContext();
}

@Override public EntityItem onCreateViewHolder(ViewGroup parent, int viewType) {
Expand All @@ -47,25 +56,62 @@ public EntityCursorAdapter(Context context, Cursor cursor) {
final SomeEntity entity = SomeEntity.fromCursor(cursor);

holder.mLayout.setTag(entity.getId());

if (entity.isActive()) {
holder.mLayout.setBackgroundColor(
ColorUtils.getColor(mContext, android.R.color.holo_blue_light));
} else {
holder.mLayout.setBackgroundColor(ColorUtils.getColor(mContext, android.R.color.white));
}

holder.mActive.setTag(R.id.tag_key_id, entity.getId());
holder.mActive.setTag(R.id.tag_key_row, holder.getAdapterPosition());
holder.mName.setText(entity.getName());
holder.mDescription.setText(entity.getDescription());
holder.mLastUpdated.setText(DATE_FORMAT.format(new Date(entity.getUpdatedMillis())));

/**
* I use setOnCheckedChangeListener after setChecked() call
* and not Butterknife's @OnCheckedChange
* because of conflict setChecked() and SomeEntity#save()
* together they make infinite cycle calls
* because of content observer in base cursor adapter
*/
holder.mActive.setOnCheckedChangeListener(null);
holder.mActive.setChecked(entity.isActive());
holder.mActive.setOnCheckedChangeListener(mCheckedChangeListener);
}

final private CompoundButton.OnCheckedChangeListener mCheckedChangeListener = (c, flag) -> {

if (mContext == null) {
return; // should never happen, but still
}

SomeEntity.fromDatabase(mContext, ((int) c.getTag(R.id.tag_key_id)), e -> {
if (e != null) {
e.setIsActive(flag);
e.save(mContext);
mFragment.setPositionToScroll(((int) c.getTag(R.id.tag_key_row)));
}
});
};

class EntityItem extends RecyclerView.ViewHolder {

@Bind(R.id.entity_layout) LinearLayout mLayout;
@Bind(R.id.name) TextView mName;
@Bind(R.id.last_updated) TextView mLastUpdated;
@Bind(R.id.description) TextView mDescription;
@Bind(R.id.active) CheckBox mActive;

public EntityItem(View view) {
super(view);
ButterKnife.bind(this, view);
}

@OnClick(R.id.entity_layout) void edit(View v) {
final FourTabsActivity ctx = ((FourTabsActivity) v.getContext());
final FourTabsActivity ctx = ((FourTabsActivity) mContext);
EntityDialogFragment.newInstance(((int) v.getTag()), mName.getText().toString(),
mDescription.getText().toString(), getAdapterPosition())
.show(ctx.getSupportFragmentManager(), null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,21 @@
import me.cullycross.test4tabs.activities.FourTabsActivity;
import me.cullycross.test4tabs.adapters.EntityCursorAdapter;
import me.cullycross.test4tabs.content.EntityContentProvider;
import me.cullycross.test4tabs.pojos.SomeEntity;

public class DatabaseFragment extends Fragment
implements LoaderManager.LoaderCallbacks<Cursor>, FourTabsActivity.FabClickListener,
FourTabsActivity.RowUpdateListener {

public static final int FLAG_NEW_ENTITY = -1;
public static final int FLAG_START = -2;

@Bind(R.id.recycler_view_entities) RecyclerView mRecyclerViewEntities;

private ProgressDialog mDialog;
private EntityCursorAdapter mAdapter;

private int mPositionToScroll = FLAG_START; // save here position to scroll after loader is restarted
private int mPositionToScroll = FLAG_START;
// save here position to scroll after loader is restarted

public static DatabaseFragment newInstance() {
final DatabaseFragment fragment = new DatabaseFragment();
Expand All @@ -57,7 +58,7 @@ public DatabaseFragment() {
View view = inflater.inflate(R.layout.fragment_database, container, false);
ButterKnife.bind(this, view);

mAdapter = new EntityCursorAdapter(getContext(), null);
mAdapter = new EntityCursorAdapter(this, null);
mRecyclerViewEntities.setLayoutManager(new LinearLayoutManager(getContext()));
mRecyclerViewEntities.setAdapter(mAdapter);

Expand All @@ -78,8 +79,8 @@ public DatabaseFragment() {
mDialog.dismiss();
}

if(mPositionToScroll != FLAG_START) {
if(mPositionToScroll == FLAG_NEW_ENTITY) {
if (mPositionToScroll != FLAG_START) {
if (mPositionToScroll == SomeEntity.FLAG_NEW_ENTITY) {
mRecyclerViewEntities.smoothScrollToPosition(mAdapter.getItemCount() - 1);
} else {
mRecyclerViewEntities.smoothScrollToPosition(mPositionToScroll);
Expand All @@ -98,8 +99,8 @@ public DatabaseFragment() {

@Override public void onFabClick() {

EntityDialogFragment.newInstance(FLAG_NEW_ENTITY, null, null, FLAG_NEW_ENTITY)
.show(getActivity().getSupportFragmentManager(), null);
EntityDialogFragment.newInstance(SomeEntity.FLAG_NEW_ENTITY, null, null,
SomeEntity.FLAG_NEW_ENTITY).show(getActivity().getSupportFragmentManager(), null);
}

@Override public void onRowUpdate(int position) {
Expand All @@ -109,6 +110,10 @@ public DatabaseFragment() {
mPositionToScroll = position;
}

public void setPositionToScroll(int positionToScroll) {
mPositionToScroll = positionToScroll;
}

private void restartLoader() {
final Loader<Object> loader = getLoaderManager().getLoader(0);
if (loader != null && !loader.isReset()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public EntityDialogFragment() {
ButterKnife.bind(this, dialogView);

if (getArguments() != null) {
mTitle.setText(getArguments().getString(ARGS_BODY));
mTitle.setText(getArguments().getString(ARGS_TITLE));
mBody.setText(getArguments().getString(ARGS_BODY));
}

Expand Down
66 changes: 57 additions & 9 deletions app/src/main/java/me/cullycross/test4tabs/pojos/SomeEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
import android.database.Cursor;
import android.net.Uri;
import android.support.annotation.Nullable;
import me.cullycross.test4tabs.content.EntityContentProvider;
import me.cullycross.test4tabs.utils.RxHelper;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;

import static me.cullycross.test4tabs.content.EntityContentProvider.ENTITY_ACTIVE;
import static me.cullycross.test4tabs.content.EntityContentProvider.ENTITY_CONTENT_URI;
Expand All @@ -23,20 +28,35 @@
*/
public class SomeEntity {

private int mId;
public static final int FLAG_NEW_ENTITY = -1;

private int mId = FLAG_NEW_ENTITY;
private String mName;
private String mDescription;
private boolean mIsActive;
private long mUpdatedMillis;

@Nullable public static SomeEntity fromDatabase(Context ctx, int id) {
final Uri uri = ContentUris.withAppendedId(ENTITY_CONTENT_URI, id);
final Cursor c = ctx.getContentResolver().query(uri, null, null, null, null);
if (c != null && c.moveToFirst()) {
return fromCursor(c);
} else {
return null;
public static void fromDatabase(Context ctx, int id, FromDatabaseCallback callback) {

if (id == FLAG_NEW_ENTITY) {
callback.fromDatabase(null);
return;
}

final Uri uri = ContentUris.withAppendedId(ENTITY_CONTENT_URI, id);

RxHelper.makeColdObservable(() -> ctx.getContentResolver().query(uri, null, null, null, null))
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(c -> {
if (c != null && c.moveToFirst()) {
final SomeEntity entity = fromCursor(c);
c.close();
callback.fromDatabase(entity);
} else {
callback.fromDatabase(null);
}
});
}

public static SomeEntity fromCursor(Cursor c) {
Expand All @@ -60,20 +80,44 @@ public SomeEntity(String name, String description) {

/**
* for fabric methods
*
* @param id database id
* @param name entity name
* @param description entity description
* @param isActive is entity active
* @param updatedMillis last update time
*/
private SomeEntity(int id, String name, String description, boolean isActive, long updatedMillis) {
private SomeEntity(int id, String name, String description, boolean isActive,
long updatedMillis) {
mId = id;
mName = name;
mDescription = description;
mIsActive = isActive;
mUpdatedMillis = updatedMillis;
}

public void save(Context ctx) {

Observable<Void> obs;
if (mId == FLAG_NEW_ENTITY) {
obs = RxHelper.makeColdObservable(() -> {
ctx.getContentResolver()
.insert(EntityContentProvider.ENTITY_CONTENT_URI, toContentValues());
return null;
});

} else {
final Uri uri = ContentUris.withAppendedId(EntityContentProvider.ENTITY_CONTENT_URI, mId);
obs = RxHelper.makeColdObservable(() -> {
ctx.getContentResolver().update(uri, toContentValues(), null, null);
return null;
});
}
obs.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe();
}

public ContentValues toContentValues() {
return toContentValues(mUpdatedMillis);
}
Expand Down Expand Up @@ -139,4 +183,8 @@ public long getUpdatedMillis() {
}

/***********************/

public interface FromDatabaseCallback {
void fromDatabase(@Nullable SomeEntity entity);
}
}
28 changes: 28 additions & 0 deletions app/src/main/java/me/cullycross/test4tabs/utils/ColorUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package me.cullycross.test4tabs.utils;

import android.content.Context;
import android.os.Build;
import android.support.annotation.ColorRes;

/**
* Created by: Anton Shkurenko (cullycross)
* Project: Test4tabs
* Date: 11/6/15
* Code style: SquareAndroid (https://github.com/square/java-code-styles)
* Follow me: @tonyshkurenko
*/
public class ColorUtils {

private ColorUtils() {

}

public static int getColor(Context ctx, @ColorRes int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return ctx.getColor(color);
} else {
//noinspection deprecation
return ctx.getResources().getColor(color);
}
}
}
32 changes: 32 additions & 0 deletions app/src/main/java/me/cullycross/test4tabs/utils/RxHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package me.cullycross.test4tabs.utils;

import android.util.Log;
import java.util.concurrent.Callable;
import rx.Observable;
import rx.Subscriber;

/**
* Created by: Anton Shkurenko (cullycross)
* Project: Test4tabs
* Date: 11/6/15
* Code style: SquareAndroid (https://github.com/square/java-code-styles)
* Follow me: @tonyshkurenko
*/
public class RxHelper {

private static final String TAG = RxHelper.class.getSimpleName();

public static <T> Observable<T> makeColdObservable(final Callable<T> func) {
return Observable.create(
new Observable.OnSubscribe<T>() {
@Override
public void call(Subscriber<? super T> subscriber) {
try {
subscriber.onNext(func.call());
} catch(Exception e) {
Log.e(TAG, "Something wrong happened", e);
}
}
});
}
}
Loading

0 comments on commit 81ab948

Please sign in to comment.