package com.orgzly.android.ui;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.Cursor;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.orgzly.R;
import com.orgzly.android.Note;
import com.orgzly.android.Shelf;
import com.orgzly.android.prefs.AppPreferences;
import com.orgzly.android.provider.ProviderContract;
import com.orgzly.android.provider.clients.NotesClient;
import com.orgzly.android.ui.util.TitleGenerator;
import com.orgzly.android.ui.views.GesturedListViewItemMenus;
import com.orgzly.android.util.NoteContentParser;
import com.orgzly.android.util.UserTimeFormatter;
import com.orgzly.org.OrgHead;
public class HeadsListViewAdapter extends SimpleCursorAdapter {
private static final String TAG = HeadsListViewAdapter.class.getName();
private final Selection selection;
private final GesturedListViewItemMenus quickMenu;
/** Can be in book or search results. */
private final boolean inBook;
private TitleGenerator titleGenerator;
private final UserTimeFormatter userTimeFormatter;
public HeadsListViewAdapter(Context context, Selection selection, GesturedListViewItemMenus toolbars, boolean inBook) {
super(context, R.layout.item_head, null, new String[0], new int[0], 0);
this.selection = selection;
this.quickMenu = toolbars;
this.inBook = inBook;
this.userTimeFormatter = new UserTimeFormatter(context);
this.titleGenerator = new TitleGenerator(context, inBook, getTitleAttributes());
}
private TitleGenerator.TitleAttributes getTitleAttributes() {
TypedArray typedArray = mContext.obtainStyledAttributes(new int[] {
R.attr.item_head_state_todo_color,
R.attr.item_head_state_done_color,
R.attr.item_head_state_unknown_color,
R.attr.item_head_post_title_text_size,
R.attr.item_head_post_title_text_color
});
TitleGenerator.TitleAttributes attributes = new TitleGenerator.TitleAttributes(
typedArray.getColor(0, 0),
typedArray.getColor(1, 0),
typedArray.getColor(2, 0),
typedArray.getDimensionPixelSize(3, 0),
typedArray.getColor(4, 0));
typedArray.recycle();
return attributes;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return super.getView(position, convertView, parent);
}
@Override
public View newView(Context context, final Cursor cursor, ViewGroup parent) {
View view = super.newView(context, cursor, parent);
/* Get or create new view holder. */
ViewHolder holder = (ViewHolder) view.getTag();
if (holder == null) {
holder = new ViewHolder(view);
view.setTag(holder);
}
/*
* Setup margins and padding for different list density options.
*/
int itemMargins;
int belowTitleMargins;
String density = AppPreferences.notesListDensity(context);
if (context.getString(R.string.pref_value_list_density_comfortable).equals(density)) { // Comfortable
itemMargins = (int) context.getResources().getDimension(R.dimen.item_head_padding_comfortable);
belowTitleMargins = (int) context.getResources().getDimension(R.dimen.item_head_below_title_padding_comfortable);
} else if (context.getString(R.string.pref_value_list_density_compact).equals(density)) { // Compact
itemMargins = (int) context.getResources().getDimension(R.dimen.item_head_padding_compact);
belowTitleMargins = (int) context.getResources().getDimension(R.dimen.item_head_below_title_padding_compact);
} else { // Cozy
itemMargins = (int) context.getResources().getDimension(R.dimen.item_head_padding_cozy);
belowTitleMargins = (int) context.getResources().getDimension(R.dimen.item_head_below_title_padding_cozy);
}
RelativeLayout.LayoutParams payloadParams = (RelativeLayout.LayoutParams) holder.payload.getLayoutParams();
payloadParams.setMargins(payloadParams.leftMargin, itemMargins, payloadParams.rightMargin, 0);
LinearLayout.LayoutParams[] params = new LinearLayout.LayoutParams[] {
(LinearLayout.LayoutParams) holder.scheduled.getLayoutParams(),
(LinearLayout.LayoutParams) holder.deadline.getLayoutParams(),
(LinearLayout.LayoutParams) holder.closed.getLayoutParams(),
(LinearLayout.LayoutParams) holder.content.getLayoutParams()
};
for (LinearLayout.LayoutParams p: params) {
p.setMargins(0, belowTitleMargins, 0, 0);
}
return view;
}
@Override
public void bindView(final View view, final Context context, Cursor cursor) {
final Note note = NotesClient.fromCursor(cursor);
final OrgHead head = note.getHead();
final ViewHolder holder = (ViewHolder) view.getTag();
if (inBook) {
if (note.getPosition().getFoldedUnderId() == 0) {
view.setVisibility(View.VISIBLE);
} else {
view.setVisibility(View.GONE);
}
}
setupIndentContainer(context, holder.indentContainer, inBook ? note.getPosition().getLevel() - 1 : 0);
updateFoldingButton(context, note, holder);
updateBullet(context, note, holder);
/* Book name. */
if (inBook) {
holder.bookNameUnderNote.setVisibility(View.GONE);
holder.bookNameLeftFromNoteText.setVisibility(View.GONE);
} else {
switch (Integer.valueOf(AppPreferences.bookNameInSearchResults(context))) {
case 0:
holder.bookNameLeftFromNoteText.setVisibility(View.GONE);
holder.bookNameUnderNote.setVisibility(View.GONE);
break;
case 1:
holder.bookNameLeftFromNoteText.setText(cursor.getString(cursor.getColumnIndex(ProviderContract.Notes.QueryParam.BOOK_NAME)));
holder.bookNameLeftFromNoteText.setVisibility(View.VISIBLE);
holder.bookNameUnderNote.setVisibility(View.GONE);
break;
case 2:
holder.bookNameUnderNoteText.setText(cursor.getString(cursor.getColumnIndex(ProviderContract.Notes.QueryParam.BOOK_NAME)));
holder.bookNameLeftFromNoteText.setVisibility(View.GONE);
holder.bookNameUnderNote.setVisibility(View.VISIBLE);
break;
}
}
/* Title. */
holder.title.setText(titleGenerator.generateTitle(note, head));
/* Content. */
if (head.hasContent() && AppPreferences.isNotesContentDisplayedInList(context) && (!note.getPosition().isFolded() || !AppPreferences.isNotesContentFoldable(context)) && (inBook || AppPreferences.isNotesContentDisplayedInSearch(context))) {
if (AppPreferences.isFontMonospaced(context)) {
holder.content.setTypeface(Typeface.MONOSPACE);
}
holder.content.setText(NoteContentParser.fromOrg(head.getContent()));
holder.content.setVisibility(View.VISIBLE);
} else {
holder.content.setVisibility(View.GONE);
}
/* Closed time. */
if (head.hasClosed() && AppPreferences.displayPlanning(context)) {
holder.closedText.setText(userTimeFormatter.formatAll(head.getClosed()));
holder.closed.setVisibility(View.VISIBLE);
} else {
holder.closed.setVisibility(View.GONE);
}
/* see also ListWidgetViewsFactory.setContent */
/* Deadline time. */
if (head.hasDeadline() && AppPreferences.displayPlanning(context)) {
holder.deadlineText.setText(userTimeFormatter.formatAll(head.getDeadline()));
holder.deadline.setVisibility(View.VISIBLE);
} else {
holder.deadline.setVisibility(View.GONE);
}
/* Scheduled time. */
if (head.hasScheduled() && AppPreferences.displayPlanning(context)) {
holder.scheduledText.setText(userTimeFormatter.formatAll(head.getScheduled()));
holder.scheduled.setVisibility(View.VISIBLE);
} else {
holder.scheduled.setVisibility(View.GONE);
}
/* Set alpha for done items. */
if (head.getState() != null && AppPreferences.doneKeywordsSet(context).contains(head.getState())) {
holder.payload.setAlpha(0.45f);
} else {
holder.payload.setAlpha(1.0f);
}
quickMenu.updateView(view, note.getId(), holder.menuContainer, holder.menuFlipper);
selection.updateView(view, note.getId());
/* Toggle folded state. */
holder.foldButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggleFoldedState(context, note.getId());
}
});
}
private void toggleFoldedState(final Context context, final long id) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
new Shelf(context).toggleFoldedState(id);
return null;
}
}.execute();
}
/**
* Change folding button appearance.
*/
private void updateFoldingButton(Context context, Note note, ViewHolder holder) {
boolean isVisible = false;
if (inBook) {
boolean contentFoldable = note.getHead().hasContent() &&
AppPreferences.isNotesContentFoldable(context) &&
AppPreferences.isNotesContentDisplayedInList(context);
if (note.getPosition().getDescendantsCount() > 0 || contentFoldable) {
isVisible = true;
/* Type of the fold button. */
if (note.getPosition().isFolded()) {
holder.foldButtonText.setText(R.string.unfold_button_character);
} else {
holder.foldButtonText.setText(R.string.fold_button_character);
}
}
} // else: No indentation (in search results)
if (isVisible) {
holder.foldButton.setVisibility(View.VISIBLE);
holder.foldButtonText.setVisibility(View.VISIBLE);
} else {
holder.foldButton.setVisibility(View.INVISIBLE);
holder.foldButtonText.setVisibility(View.INVISIBLE);
}
}
/**
* Change bullet appearance depending on folding state and number of descendants.
*/
private void updateBullet(Context context, Note note, ViewHolder holder) {
if (inBook) {
if (note.getPosition().getDescendantsCount() > 0) { // Has descendants
if (note.getPosition().isFolded()) {
holder.bullet.setText(R.string.bullet_with_children_folded);
} else {
holder.bullet.setText(R.string.bullet_with_children_unfolded);
}
holder.bullet.setTypeface(Typeface.DEFAULT);
} else { // Has no descendants
holder.bullet.setText(R.string.bullet);
holder.bullet.setTypeface(Typeface.DEFAULT_BOLD);
}
} else { // No indentation (in search results)
holder.bullet.setTypeface(Typeface.DEFAULT_BOLD);
}
}
/**
* Set indentation views, depending on note level.
*/
private void setupIndentContainer(Context context, ViewGroup container, int level) {
if (container.getChildCount() < level) {
/* We need more lines. */
/* Make all existing visible. */
for (int i = 1; i <= container.getChildCount(); i++) {
container.getChildAt(i - 1).setVisibility(View.VISIBLE);
}
/* Inflate the rest. */
for (int i = container.getChildCount() + 1; i <= level; i++) {
View.inflate(context, R.layout.indent, container);
}
} else if (level < container.getChildCount()) {
/* Has more lines then needed. */
/* Make required lines visible. */
for (int i = 1; i <= level; i++) {
container.getChildAt(i - 1).setVisibility(View.VISIBLE);
}
/* Hide the rest. */
for (int i = level + 1; i <= container.getChildCount(); i++) {
container.getChildAt(i - 1).setVisibility(View.GONE);
}
} else {
/* Make all visible. */
for (int i = 1; i <= container.getChildCount(); i++) {
container.getChildAt(i - 1).setVisibility(View.VISIBLE);
}
}
}
}