package com.hdweiss.morgand.gui.outline;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.text.Layout;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.text.style.ForegroundColorSpan;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Checkable;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.hdweiss.morgand.Application;
import com.hdweiss.morgand.R;
import com.hdweiss.morgand.data.OrgNodeUtils;
import com.hdweiss.morgand.data.dao.OrgNode;
import com.hdweiss.morgand.gui.theme.DefaultTheme;
import com.hdweiss.morgand.settings.PreferenceUtils;
import java.util.regex.Matcher;
public class OutlineItemView extends RelativeLayout implements Checkable {
private TextView titleView;
private TextView tagsView;
private boolean agendaMode;
private OrgNode node;
private DefaultTheme theme;
public OutlineItemView(Context context) {
super(context);
View.inflate(context, R.layout.outline_item, this);
titleView = (TextView) findViewById(R.id.title);
titleView.setOnTouchListener(urlClickListener);
tagsView = (TextView) findViewById(R.id.tags);
}
@Override
public void setChecked(boolean checked) {
if(checked)
setBackgroundResource(R.drawable.outline_item_selected);
else
setBackgroundResource(0);
}
@Override
public boolean isChecked() {
return false;
}
@Override
public void toggle() {
}
public void setAgendaMode(boolean enabled) {
this.agendaMode = enabled;
}
public void setup(OrgNode node, boolean expanded, int level, DefaultTheme theme) {
if (node == null)
return;
this.node = node;
this.theme = theme;
titleView.setPadding(level * 5, titleView.getPaddingTop(), titleView.getPaddingRight(), titleView.getPaddingBottom());
// if (node.type == OrgNode.Type.Table) {
// titleView.setTypeface(Typeface.MONOSPACE);
// titleView.setTextSize(android.R.style.);
// }
// else {
// titleView.setTextAppearance(getContext(), android.R.attr.textAppearanceMedium);
// }
switch (node.type) {
case Setting:
setupTitle(theme.settingsForeground);
tagsView.setText("");
break;
case Drawer:
setupTitle(theme.drawer);
tagsView.setText("");
break;
case Directory:
setupTitle(theme.directoryForeground);
tagsView.setText("");
break;
case File:
case Headline:
setupHeadlineTitle(expanded, level);
setupTags();
break;
case Date:
setupTitle(theme.drawer);
tagsView.setText("");
break;
case Body:
case Checkbox:
case Table:
default:
String formattedTitle = applyNewlineFormatting(node.title);
SpannableStringBuilder titleSpan = setupTitle(theme.defaultForeground, formattedTitle);
setupUrls(titleSpan);
titleView.setText(titleSpan);
tagsView.setText("");
break;
}
}
private SpannableStringBuilder setupTitle(int color) {
return setupTitle(color, node.title);
}
private SpannableStringBuilder setupTitle(int color, String title) {
SpannableStringBuilder titleSpan = new SpannableStringBuilder(title);
titleSpan.setSpan(new ForegroundColorSpan(color), 0, titleSpan.length(), 0);
titleView.setText(titleSpan);
titleView.setMovementMethod(null);
titleView.setFocusable(false);
return titleSpan;
}
// TODO Mark up COMMENT and Archive nodes
private void setupHeadlineTitle(boolean expanded, int level) {
SpannableStringBuilder titleSpan = new SpannableStringBuilder();
for(int i = 0; i < level; i++)
titleSpan.append("*");
titleSpan.append(" ");
titleSpan.append(node.title);
setupUrls(titleSpan);
setupTodoKeyword(titleSpan);
setupPriority(titleSpan);
if (expanded == false)
setupChildIndicator(titleSpan);
titleView.setText(titleSpan);
}
private void setupTodoKeyword(SpannableStringBuilder titleSpan) {
Matcher matcher = OrgNodeUtils.headingPattern.matcher(titleSpan);
if (matcher.find()) {
String todoKeyword = matcher.group(1);
if (PreferenceUtils.getActiveTodoKeywords().contains(todoKeyword))
titleSpan.setSpan(new ForegroundColorSpan(theme.todoKeyword), matcher.start(1), matcher.end(1), 0);
else if (PreferenceUtils.getInactiveTodoKeywords().contains(todoKeyword))
titleSpan.setSpan(new ForegroundColorSpan(theme.inactiveTodoKeyword), matcher.start(1), matcher.end(1), 0);
}
}
private void setupPriority(SpannableStringBuilder titleSpan) {
Matcher matcher = OrgNodeUtils.prioritiesPattern.matcher(titleSpan);
if (matcher.find()) {
if (PreferenceUtils.getPriorties().contains(matcher.group(1)))
titleSpan.setSpan(new ForegroundColorSpan(theme.priority), matcher.start(), matcher.end(), 0);
}
}
private void setupChildIndicator(SpannableStringBuilder titleSpan) {
if (node.getDisplayChildren().isEmpty() == false) {
titleSpan.append("...");
titleSpan.setSpan(new ForegroundColorSpan(theme.defaultForeground),
titleSpan.length() - "...".length(), titleSpan.length(), 0);
}
}
private String applyNewlineFormatting(String text) {
StringBuilder builder = new StringBuilder();
for(String line: text.trim().split("\n")) {
if (TextUtils.isEmpty(line))
builder.append("\n");
else if (line.startsWith("- ") || line.startsWith("+ "))
builder.append("\n").append(line);
else if (line.startsWith("|") && line.endsWith("|"))
builder.append("\n").append(line);
else if (line.matches("^\\d+(\\.|\\)).*"))
builder.append("\n").append(line);
else
builder.append(line);
}
return builder.toString();
}
private void setupUrls(SpannableStringBuilder stringBuilder) {
Matcher matcher = OrgNodeUtils.urlPattern.matcher(stringBuilder);
int currentIndex = 0;
while(matcher.find(currentIndex)) {
int beginIndex = matcher.start();
final String url = matcher.group(1) != null ? matcher.group(1) : matcher.group(3);
String alias = matcher.group(2) != null ? matcher.group(2) : url;
stringBuilder.delete(matcher.start(), matcher.end());
currentIndex = beginIndex + alias.length();
stringBuilder.insert(beginIndex, alias);
ClickableSpan clickable = new ClickableSpan() {
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
Application.getInstace().getApplicationContext().startActivity(intent);
} catch (ActivityNotFoundException ex) {
ex.printStackTrace();
}
}
};
stringBuilder.setSpan(clickable, beginIndex, currentIndex, 0);
matcher = OrgNodeUtils.urlPattern.matcher(stringBuilder);
}
}
private void setupTags() {
SpannableStringBuilder tagsSpan = new SpannableStringBuilder();
if (TextUtils.isEmpty(node.tags) == false)
tagsSpan.append(node.tags).append("\n");
if (agendaMode && TextUtils.isEmpty(node.inheritedTags) == false)
tagsSpan.append(node.inheritedTags);
if (TextUtils.isEmpty(tagsSpan) == false)
tagsSpan.setSpan(new ForegroundColorSpan(theme.gray), 0, tagsSpan.length(), 0);
tagsView.setText(tagsSpan);
}
/**
* Taken from: http://stackoverflow.com/a/17246463
* Allows clickable urls in listview without making textview focusable.
*/
private OnTouchListener urlClickListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
boolean ret = false;
CharSequence text = ((TextView) v).getText();
Spannable stext = Spannable.Factory.getInstance().newSpannable(text);
TextView widget = (TextView) v;
int action = event.getAction();
if (action == MotionEvent.ACTION_UP ||
action == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
x -= widget.getTotalPaddingLeft();
y -= widget.getTotalPaddingTop();
x += widget.getScrollX();
y += widget.getScrollY();
Layout layout = widget.getLayout();
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
ClickableSpan[] link = stext.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (action == MotionEvent.ACTION_UP) {
link[0].onClick(widget);
}
ret = true;
}
}
return ret;
}
};
}