package com.door43.translationstudio.newui.translate;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.support.design.widget.TabLayout;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.door43.tools.reporting.Logger;
import com.door43.translationstudio.R;
import com.door43.translationstudio.core.Chapter;
import com.door43.translationstudio.core.ChapterTranslation;
import com.door43.translationstudio.core.FrameTranslation;
import com.door43.translationstudio.core.LinedEditText;
import com.door43.translationstudio.core.ProjectTranslation;
import com.door43.translationstudio.core.SourceLanguage;
import com.door43.translationstudio.core.TargetLanguage;
import com.door43.translationstudio.core.TranslationFormat;
import com.door43.translationstudio.core.Frame;
import com.door43.translationstudio.core.Library;
import com.door43.translationstudio.core.SourceTranslation;
import com.door43.translationstudio.core.TargetTranslation;
import com.door43.translationstudio.core.Translator;
import com.door43.translationstudio.core.Typography;
import com.door43.translationstudio.dialogs.CustomAlertDialog;
import com.door43.translationstudio.rendering.ClickableRenderingEngine;
import com.door43.translationstudio.rendering.Clickables;
import com.door43.translationstudio.rendering.DefaultRenderer;
import com.door43.translationstudio.rendering.RenderingGroup;
import com.door43.translationstudio.AppContext;
import com.door43.translationstudio.spannables.NoteSpan;
import com.door43.translationstudio.spannables.Span;
import com.door43.widget.ViewUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by joel on 9/9/2015.
*/
public class ChunkModeAdapter extends ViewModeAdapter<ChunkModeAdapter.ViewHolder> {
private SourceLanguage mSourceLanguage;
private final TargetLanguage mTargetLanguage;
private final Activity mContext;
private static final int BOTTOM_ELEVATION = 2;
private static final int TOP_ELEVATION = 3;
private final TargetTranslation mTargetTranslation;
private SourceTranslation mSourceTranslation;
private final Library mLibrary;
private final Translator mTranslator;
private ListItem[] mListItems;
private Map<String, Chapter> mChapters = new HashMap<>();
private int mLayoutBuildNumber = 0;
private ContentValues[] mTabs;
private TranslationFormat mTargetFormat;
public ChunkModeAdapter(Activity context, String targetTranslationId, String sourceTranslationId, String startingChapterSlug, String startingFrameSlug, boolean openSelectedTarget) {
mLibrary = AppContext.getLibrary();
mTranslator = AppContext.getTranslator();
mContext = context;
mTargetTranslation = mTranslator.getTargetTranslation(targetTranslationId);
mSourceTranslation = mLibrary.getSourceTranslation(sourceTranslationId);
mSourceLanguage = mLibrary.getSourceLanguage(mSourceTranslation.projectSlug, mSourceTranslation.sourceLanguageSlug);
mTargetLanguage = mLibrary.getTargetLanguage(mTargetTranslation.getTargetLanguageId());
Chapter[] chapters = mLibrary.getChapters(mSourceTranslation);
List<ListItem> listItems = new ArrayList<>();
// add project title card
ListItem projectTitleItem = new ListItem(null, null);
projectTitleItem.isProjectTitle = true;
listItems.add(projectTitleItem);
for(Chapter c:chapters) {
// add title and reference cards for chapter
if(!c.title.isEmpty()) {
ListItem item = new ListItem(null, c.getId());
item.isChapterTitle = true;
listItems.add(item);
}
if(!c.reference.isEmpty()) {
ListItem item = new ListItem(null, c.getId());
item.isChapterReference = true;
listItems.add(item);
}
// put in map for easier retrieval
mChapters.put(c.getId(), c);
String[] chapterFrameSlugs = mLibrary.getFrameSlugs(mSourceTranslation, c.getId());
boolean setStartPosition = startingChapterSlug != null && c.getId().equals(startingChapterSlug) && chapterFrameSlugs.length > 0;
// identify starting selection
if(setStartPosition) {
setListStartPosition(listItems.size());
}
for(String frameSlug:chapterFrameSlugs) {
if(setStartPosition && startingFrameSlug != null && frameSlug.equals(startingFrameSlug)) {
setListStartPosition(listItems.size());
}
listItems.add(new ListItem(frameSlug, c.getId()));
}
}
mListItems = listItems.toArray(new ListItem[listItems.size()]);
mListItems[getListStartPosition()].isTargetCardOpen = openSelectedTarget;
loadTabInfo();
}
/**
* Rebuilds the card tabs
*/
private void loadTabInfo() {
List<ContentValues> tabContents = new ArrayList<>();
String[] sourceTranslationIds = AppContext.getOpenSourceTranslationIds(mTargetTranslation.getId());
for(String id:sourceTranslationIds) {
SourceTranslation sourceTranslation = mLibrary.getSourceTranslation(id);
if(sourceTranslation != null) {
ContentValues values = new ContentValues();
// include the resource id if there are more than one
if(mLibrary.getResources(sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug).length > 1) {
values.put("title", sourceTranslation.getSourceLanguageTitle() + " " + sourceTranslation.resourceSlug.toUpperCase());
} else {
values.put("title", sourceTranslation.getSourceLanguageTitle());
}
values.put("tag", sourceTranslation.getId());
tabContents.add(values);
}
}
mTabs = tabContents.toArray(new ContentValues[tabContents.size()]);
}
/**
* Updates the source translation displayed
* @param sourceTranslationId
*/
public void setSourceTranslation(String sourceTranslationId) {
mSourceTranslation = mLibrary.getSourceTranslation(sourceTranslationId);
mSourceLanguage = mLibrary.getSourceLanguage(mSourceTranslation.projectSlug, mSourceTranslation.sourceLanguageSlug);
mChapters = new HashMap<>();
Chapter[] chapters = mLibrary.getChapters(mSourceTranslation);
List<ListItem> listItems = new ArrayList<>();
// add project title card
ListItem projectTitleItem = new ListItem(null, null);
projectTitleItem.isProjectTitle = true;
listItems.add(projectTitleItem);
for(Chapter c:chapters) {
// add title and reference cards for chapter
if(!c.title.isEmpty()) {
ListItem item = new ListItem(null, c.getId());
item.isChapterTitle = true;
listItems.add(item);
}
if(!c.reference.isEmpty()) {
ListItem item = new ListItem(null, c.getId());
item.isChapterReference = true;
listItems.add(item);
}
// put in map for easier retrieval
mChapters.put(c.getId(), c);
String[] chapterFrameSlugs = mLibrary.getFrameSlugs(mSourceTranslation, c.getId());
for(String frameSlug:chapterFrameSlugs) {
listItems.add(new ListItem(frameSlug, c.getId()));
}
}
mListItems = listItems.toArray(new ListItem[listItems.size()]);
loadTabInfo();
notifyDataSetChanged();
}
@Override
void onCoordinate(ViewHolder holder) {
}
@Override
public String getFocusedFrameId(int position) {
if(position >= 0 && position < mListItems.length) {
return mListItems[position].frameSlug;
}
return null;
}
@Override
public String getFocusedChapterId(int position) {
if(position >= 0 && position < mListItems.length) {
return mListItems[position].chapterSlug;
}
return null;
}
@Override
public int getItemPosition(String chapterSlug, String frameSlug) {
for(int i = 0; i < mListItems.length; i ++) {
ListItem item = mListItems[i];
if(item.isFrame() && item.chapterSlug.equals(chapterSlug) && item.frameSlug.equals(frameSlug)) {
return i;
}
}
return -1;
}
@Override
public void reload() {
setSourceTranslation(mSourceTranslation.getId());
}
@Override
public ViewHolder onCreateManagedViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_chunk_list_item, parent, false);
ViewHolder vh = new ViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
int cardMargin = mContext.getResources().getDimensionPixelSize(R.dimen.card_margin);
int stackedCardMargin = mContext.getResources().getDimensionPixelSize(R.dimen.stacked_card_margin);
ListItem item = mListItems[position];
if(item.isTargetCardOpen) {
// target on top
// elevation takes precedence for API 21+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
holder.mSourceCard.setElevation(BOTTOM_ELEVATION);
holder.mTargetCard.setElevation(TOP_ELEVATION);
}
holder.mTargetCard.bringToFront();
CardView.LayoutParams targetParams = (CardView.LayoutParams)holder.mTargetCard.getLayoutParams();
targetParams.setMargins(cardMargin, cardMargin, stackedCardMargin, stackedCardMargin);
holder.mTargetCard.setLayoutParams(targetParams);
CardView.LayoutParams sourceParams = (CardView.LayoutParams)holder.mSourceCard.getLayoutParams();
sourceParams.setMargins(stackedCardMargin, stackedCardMargin, cardMargin, cardMargin);
holder.mSourceCard.setLayoutParams(sourceParams);
((View) holder.mTargetCard.getParent()).requestLayout();
((View) holder.mTargetCard.getParent()).invalidate();
// disable new tab button so we don't accidently open it
holder.mNewTabButton.setEnabled(false);
} else {
// source on top
// elevation takes precedence for API 21+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
holder.mTargetCard.setElevation(BOTTOM_ELEVATION);
holder.mSourceCard.setElevation(TOP_ELEVATION);
}
holder.mSourceCard.bringToFront();
CardView.LayoutParams sourceParams = (CardView.LayoutParams)holder.mSourceCard.getLayoutParams();
sourceParams.setMargins(cardMargin, cardMargin, stackedCardMargin, stackedCardMargin);
holder.mSourceCard.setLayoutParams(sourceParams);
CardView.LayoutParams targetParams = (CardView.LayoutParams)holder.mTargetCard.getLayoutParams();
targetParams.setMargins(stackedCardMargin, stackedCardMargin, cardMargin, cardMargin);
holder.mTargetCard.setLayoutParams(targetParams);
((View) holder.mSourceCard.getParent()).requestLayout();
((View) holder.mSourceCard.getParent()).invalidate();
// re-enable new tab button
holder.mNewTabButton.setEnabled(true);
}
holder.mTargetCard.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) { // for touches on card other than edit area
if(MotionEvent.ACTION_UP == event.getAction()) {
return checkForPromptToEditDoneTargetCard( holder, mListItems[position]);
}
return false;
}
});
holder.mTargetBody.setOnTouchListener(new View.OnTouchListener() { //for touches on edit area
@Override
public boolean onTouch(View v, MotionEvent event) {
if(MotionEvent.ACTION_UP == event.getAction()) {
return checkForPromptToEditDoneTargetCard( holder, mListItems[position]);
}
return false;
}
});
holder.mTargetCard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean targetCardOpened = openTargetTranslationCard(holder, position);
// Accept clicks anywhere on card as if they were on the text box --
// but only if the text is actually editable (i.e., not yet done).
if(!targetCardOpened && holder.mTargetBody.isEnabled()) {
editTarget( holder.mTargetBody, mListItems[position]);
}
// if marked as done (disabled for edit), enable to allow capture of click events, but do not make it focusable so they can't edit
else {
enableClicksIfChunkIsDone(holder);
}
}
});
holder.mSourceCard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
closeTargetTranslationCard(holder, position);
}
});
// load tabs
holder.mTabLayout.setOnTabSelectedListener(null);
holder.mTabLayout.removeAllTabs();
for(ContentValues values:mTabs) {
TabLayout.Tab tab = holder.mTabLayout.newTab();
tab.setText(values.getAsString("title"));
tab.setTag(values.getAsString("tag"));
holder.mTabLayout.addTab(tab);
}
// select correct tab
for(int i = 0; i < holder.mTabLayout.getTabCount(); i ++) {
TabLayout.Tab tab = holder.mTabLayout.getTabAt(i);
if(tab.getTag().equals(mSourceTranslation.getId())) {
tab.select();
break;
}
}
// hook up listener
holder.mTabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
final String sourceTranslationId = (String) tab.getTag();
if (getListener() != null) {
Handler hand = new Handler(Looper.getMainLooper());
hand.post(new Runnable() {
@Override
public void run() {
getListener().onSourceTranslationTabClick(sourceTranslationId);
}
});
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
holder.mNewTabButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getListener() != null) {
getListener().onNewSourceTranslationTabClick();
}
}
});
// set up fonts
if(holder.mLayoutBuildNumber != mLayoutBuildNumber) {
holder.mLayoutBuildNumber = mLayoutBuildNumber;
Typography.formatSub(mContext, holder.mSourceTitle, mSourceLanguage.getId(), mSourceLanguage.getDirection());
Typography.format(mContext, holder.mSourceBody, mSourceLanguage.getId(), mSourceLanguage.getDirection());
Typography.formatSub(mContext, holder.mTargetTitle, mTargetLanguage.getId(), mTargetLanguage.getDirection());
Typography.format(mContext, holder.mTargetBody, mTargetLanguage.getId(), mTargetLanguage.getDirection());
}
ViewUtil.makeLinksClickable(holder.mSourceBody);
// render the content
if(item.isChapterReference) {
renderChapterReference(holder, position, item.chapterSlug);
} else if(item.isChapterTitle) {
renderChapterTitle(holder, position, item.chapterSlug);
} else if(item.isProjectTitle) {
renderProjectTitle(holder, position);
} else {
renderFrame(holder, position);
}
}
/**
* Renders the project title card
* @param holder
* @param position
*/
private void renderProjectTitle(final ViewHolder holder, final int position) {
holder.mSourceTitle.setText("");
holder.mSourceBody.setText(mSourceTranslation.getProjectTitle());
holder.mTargetTitle.setText(mTargetTranslation.getTargetLanguageName());
if(holder.mTextWatcher != null) {
holder.mTargetBody.removeTextChangedListener(holder.mTextWatcher);
}
final ProjectTranslation projectTranslation = mTargetTranslation.getProjectTranslation();
holder.mTargetBody.setText(projectTranslation.getTitle());
indicateCardCompleted(projectTranslation.isTitleFinished(), holder);
// editing
holder.mTextWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
mTargetTranslation.applyProjectTitleTranslation(s.toString());
} catch (IOException e) {
Logger.e(ChunkModeFragment.class.getName(), "Failed to save the project title translation", e);
}
}
@Override
public void afterTextChanged(Editable s) {
}
};
holder.mTargetBody.addTextChangedListener(holder.mTextWatcher);
}
/**
* Renders the chapter title card
* begin edit of target card
* @param target
*/
public void editTarget(final EditText target, final ListItem item) {
// flag that chunk is open for edit
if (item.isChapterReference) {
Chapter chapter = mLibrary.getChapter(mSourceTranslation, item.chapterSlug);
if (null != chapter) {
mTargetTranslation.reopenChapterReference(chapter);
}
} else if (item.isChapterTitle) {
Chapter chapter = mLibrary.getChapter(mSourceTranslation, item.chapterSlug);
if (null != chapter) {
mTargetTranslation.reopenChapterTitle(chapter);
}
} else if(item.isProjectTitle) {
mTargetTranslation.openProjectTitle();
} else {
Frame frame = mLibrary.getFrame(mSourceTranslation, item.chapterSlug, item.frameSlug);
if(null != frame) {
mTargetTranslation.reopenFrame(frame);
}
}
// set focus on edit text
boolean gotFocus = target.requestFocus();
InputMethodManager mgr = (InputMethodManager)
mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.showSoftInput(target, InputMethodManager.SHOW_IMPLICIT);
}
/**
* if chunk that is marked done, then enable click event
* @param holder
*/
public void enableClicksIfChunkIsDone(final ViewHolder holder) {
if (!holder.mTargetBody.isEnabled()) {
holder.mTargetBody.setEnabled(true);
holder.mTargetBody.setFocusable(false);
}
}
/**
* prompt to edit chunk that is marked done
* @param holder
* @param item
*/
public boolean checkForPromptToEditDoneTargetCard(final ViewHolder holder, final ListItem item) {
if (item.isTargetCardOpen) { // if page is already in front and they are tapping on it, then see if they want to open for edit
boolean enabled = holder.mTargetBody.isEnabled();
boolean focusable = holder.mTargetBody.isFocusable();
if (enabled && !focusable) { //if we have enabled for touch events but not focusable for edit then prompt to enable editing
promptToEditDoneChunk( holder, item);
return true;
}
}
return false;
}
/**
* prompt to edit chunk that is marked done
* @param holder
*/
public void promptToEditDoneChunk(final ViewHolder holder, final ListItem item) {
CustomAlertDialog.Create(mContext)
.setTitle(R.string.chunk_done_title)
// .setIcon(R.drawable.ic_local_library_black_24dp)
.setMessage(R.string.chunk_done_prompt)
.setPositiveButton(R.string.edit, new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.mTargetBody.setEnabled(true);
holder.mTargetBody.setFocusable(true);
holder.mTargetBody.setFocusableInTouchMode(true);
holder.mTargetBody.setEnableLines(true);
editTarget(holder.mTargetBody, item);
}
})
.setNegativeButton(R.string.dismiss, null)
.show("ChunkDone");
}
/**
* Renders the chapter title card
* @param holder
* @param position
* @param chapterId
*/
private void renderChapterTitle(final ViewHolder holder, final int position, String chapterId) {
final ListItem item = mListItems[position];
Chapter chapter = mChapters.get(chapterId);
if(chapter != null) {
// source title
String sourceChapterTitle = mSourceTranslation.getProjectTitle() + " " + Integer.parseInt(chapter.getId());
holder.mSourceTitle.setText(sourceChapterTitle);
// source chapter title
if(item.renderedSourceBody == null) {
item.renderedSourceBody = chapter.title;
}
holder.mSourceBody.setText(item.renderedSourceBody);
// target chapter reference
final ChapterTranslation chapterTranslation = mTargetTranslation.getChapterTranslation(chapter);
if(item.renderedTargetBody == null) {
item.renderedTargetBody = chapterTranslation.title;
}
if(holder.mTextWatcher != null) {
holder.mTargetBody.removeTextChangedListener(holder.mTextWatcher);
}
holder.mTargetBody.setText(item.renderedTargetBody);
// target title
holder.mTargetTitle.setText(sourceChapterTitle + " - " + mTargetLanguage.name);
// indicate completed frame translations
indicateCardCompleted(chapterTranslation.isTitleFinished(), holder);
// editing
holder.mTextWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// save
// TODO: do this so we don't have to wait for compiling
// Translator.applyFrameTranslation(frameTranslation, (Editable)s);
String translation = Translator.compileTranslation((Editable)s);
mTargetTranslation.applyChapterTitleTranslation(chapterTranslation, translation);
item.renderedTargetBody = translation;
}
@Override
public void afterTextChanged(Editable s) {
}
};
holder.mTargetBody.addTextChangedListener(holder.mTextWatcher);
}
}
/**
* Renders the chapter reference card
* @param holder
* @param position
* @param chapterId
*/
private void renderChapterReference(final ViewHolder holder, final int position, String chapterId) {
final ListItem item = mListItems[position];
Chapter chapter = mChapters.get(chapterId);
if(chapter != null) {
// source title
String sourceChapterTitle = mSourceTranslation.getProjectTitle() + " " + Integer.parseInt(chapter.getId());
holder.mSourceTitle.setText(sourceChapterTitle);
// source chapter reference
if(item.renderedSourceBody == null) {
item.renderedSourceBody = chapter.reference;
}
holder.mSourceBody.setText(item.renderedSourceBody);
// target chapter reference
final ChapterTranslation chapterTranslation = mTargetTranslation.getChapterTranslation(chapter);
if(item.renderedTargetBody == null) {
item.renderedTargetBody = chapterTranslation.reference;
}
if(holder.mTextWatcher != null) {
holder.mTargetBody.removeTextChangedListener(holder.mTextWatcher);
}
holder.mTargetBody.setText(item.renderedTargetBody);
// target title
holder.mTargetTitle.setText(sourceChapterTitle + " - " + mTargetLanguage.name);
// indicate completed frame translations
indicateCardCompleted(chapterTranslation.isReferenceFinished(), holder);
// editing
holder.mTextWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// save
// TODO: do this so we don't have to wait for compiling
// Translator.applyFrameTranslation(frameTranslation, (Editable)s);
String translation = Translator.compileTranslation((Editable)s);
mTargetTranslation.applyChapterReferenceTranslation(chapterTranslation, translation);
item.renderedTargetBody = translation;
}
@Override
public void afterTextChanged(Editable s) {
}
};
holder.mTargetBody.addTextChangedListener(holder.mTextWatcher);
}
}
/**
* Renders the frame cards
* @param holder
* @param position
*/
private void renderFrame(final ViewHolder holder, final int position) {
final ListItem item = mListItems[position];
Frame frame = mLibrary.getFrame(mSourceTranslation, item.chapterSlug, item.frameSlug);
// render the source frame body
if(item.renderedSourceBody == null) {
item.renderedSourceBody = renderText(frame.body, frame.getFormat());
}
holder.mSourceBody.setText(item.renderedSourceBody);
// render source frame title
Chapter chapter = mChapters.get(frame.getChapterId());
String sourceChapterTitle = chapter.title;
if(chapter.title.isEmpty()) {
sourceChapterTitle = mSourceTranslation.getProjectTitle() + " " + Integer.parseInt(chapter.getId());
}
sourceChapterTitle += ":" + frame.getTitle();
holder.mSourceTitle.setText(sourceChapterTitle);
// render the target frame body
mTargetFormat = mTargetTranslation.getFormat();
final FrameTranslation frameTranslation = mTargetTranslation.getFrameTranslation(frame);
if(item.renderedTargetBody == null) {
item.renderedTargetBody = renderText(frameTranslation.body, mTargetFormat);
}
if(holder.mTextWatcher != null) {
holder.mTargetBody.removeTextChangedListener(holder.mTextWatcher);
}
holder.mTargetBody.setText(TextUtils.concat(item.renderedTargetBody, "\n"));
// render target frame title
ChapterTranslation chapterTranslation = mTargetTranslation.getChapterTranslation(chapter);
String targetChapterTitle = chapterTranslation.title;
if(!targetChapterTitle.isEmpty()) {
targetChapterTitle += ":" + frameTranslation.getTitle();
} else {
targetChapterTitle = sourceChapterTitle;
}
holder.mTargetTitle.setText(targetChapterTitle + " - " + mTargetLanguage.name);
// indicate completed frame translations
indicateCardCompleted(frameTranslation.isFinished(), holder);
holder.mTextWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// save
// TODO: do this so we don't have to wait for compiling
// Translator.applyFrameTranslation(frameTranslation, (Editable)s);
String translation = Translator.compileTranslation((Editable)s);
mTargetTranslation.applyFrameTranslation(frameTranslation, translation);
item.renderedTargetBody = renderText(translation, mTargetFormat);
}
@Override
public void afterTextChanged(Editable s) {
}
};
holder.mTargetBody.addTextChangedListener(holder.mTextWatcher);
}
private void indicateCardCompleted(boolean finished, ViewHolder holder) {
if(finished) {
holder.mTargetBody.setEnabled(false);
holder.mTargetBody.setEnableLines(false);
holder.mTargetInnerCard.setBackgroundResource(R.color.white);
} else {
holder.mTargetBody.setEnabled(true);
holder.mTargetBody.setEnableLines(true);
holder.mTargetInnerCard.setBackgroundResource(R.color.white);
}
}
/**
* Trigers some aspects of the children views to be rebuilt
*/
public void rebuild() {
mLayoutBuildNumber ++;
notifyDataSetChanged();
}
private CharSequence renderText(String text, TranslationFormat format) {
RenderingGroup renderingGroup = new RenderingGroup();
if (Clickables.isClickableFormat(format)) {
// TODO: add click listeners for verses and notes
Span.OnClickListener noteClickListener = new Span.OnClickListener() {
@Override
public void onClick(View view, Span span, int start, int end) {
if(span instanceof NoteSpan) {
CustomAlertDialog.Create(mContext)
.setTitle(R.string.title_note)
.setMessage(((NoteSpan)span).getNotes())
.setPositiveButton(R.string.dismiss, null)
.show("note");
}
}
@Override
public void onLongClick(View view, Span span, int start, int end) {
}
};
ClickableRenderingEngine renderer = Clickables.setupRenderingGroup(format, renderingGroup, null, noteClickListener, true);
renderer.setVersesEnabled(false);
} else {
// TODO: add note click listener
renderingGroup.addEngine(new DefaultRenderer(null));
}
renderingGroup.init(text);
return renderingGroup.start();
}
@Override
public int getItemCount() {
return mListItems.length;
}
/**
* removes text selection from the target card
* @param holder
*/
public void clearSelectionFromTarget(ViewHolder holder) {
EditText translationEditText = (EditText) holder.mTargetCard.findViewById(R.id.target_translation_body);
if (translationEditText != null) {
translationEditText.clearFocus();
}
}
/**
* Toggle the target translation card between front and back
* @param holder
* @param position
* @param swipeLeft
* @return true if action was taken, else false
*/
public boolean toggleTargetTranslationCard(final ViewHolder holder, final int position, final boolean swipeLeft) {
final ListItem item = mListItems[position];
if (item.isTargetCardOpen) {
return closeTargetTranslationCard( holder, position, !swipeLeft);
}
boolean success = openTargetTranslationCard( holder, position, !swipeLeft);
enableClicksIfChunkIsDone(holder);
return success;
}
/**
* Moves the target translation card to the back
* @param holder
* @param position
* @param leftToRight
* @return true if action was taken, else false
*/
public boolean closeTargetTranslationCard(final ViewHolder holder, final int position, final boolean leftToRight) {
final ListItem item = mListItems[position];
if(item.isTargetCardOpen) {
clearSelectionFromTarget(holder);
ViewUtil.animateSwapCards(holder.mTargetCard, holder.mSourceCard, TOP_ELEVATION, BOTTOM_ELEVATION, leftToRight, new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
item.isTargetCardOpen = false;
if (getListener() != null) {
getListener().closeKeyboard();
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
if (getListener() != null) {
getListener().closeKeyboard();
}
// re-enable new tab button
holder.mNewTabButton.setEnabled(true);
return true;
} else {
return false;
}
}
/**
* Moves the target translation card to the back - left to right
* @param holder
* @param position
* @return true if action was taken, else false
*/
public boolean closeTargetTranslationCard(final ViewHolder holder, final int position) {
return closeTargetTranslationCard ( holder, position, true);
}
/**
* Moves the target translation to the top
* @param holder
* @param position
* @param leftToRight
* @return true if action was taken, else false
*/
public boolean openTargetTranslationCard(final ViewHolder holder, final int position, final boolean leftToRight) {
final ListItem item = mListItems[position];
if(!item.isTargetCardOpen) {
ViewUtil.animateSwapCards(holder.mSourceCard, holder.mTargetCard, TOP_ELEVATION, BOTTOM_ELEVATION, leftToRight, new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
item.isTargetCardOpen = true;
if (getListener() != null) {
getListener().closeKeyboard();
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
if (getListener() != null) {
getListener().closeKeyboard();
}
// disable new tab button so we don't accidently open it
holder.mNewTabButton.setEnabled(false);
return true;
} else {
return false;
}
}
/**
* Moves the target translation to the top
* @param holder
* @param position
* @return true if action was taken, else false
*/
public boolean openTargetTranslationCard(final ViewHolder holder, final int position) {
return openTargetTranslationCard( holder, position, false);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public int mLayoutBuildNumber = -1;
public TextWatcher mTextWatcher;
public final TextView mTargetTitle;
public final LinedEditText mTargetBody;
public final CardView mTargetCard;
public final CardView mSourceCard;
public final TabLayout mTabLayout;
public final ImageButton mNewTabButton;
public TextView mSourceTitle;
public TextView mSourceBody;
public LinearLayout mTargetInnerCard;
public ViewHolder(View v) {
super(v);
mSourceCard = (CardView)v.findViewById(R.id.source_translation_card);
mSourceTitle = (TextView)v.findViewById(R.id.source_translation_title);
mSourceBody = (TextView)v.findViewById(R.id.source_translation_body);
mTargetCard = (CardView)v.findViewById(R.id.target_translation_card);
mTargetInnerCard = (LinearLayout)v.findViewById(R.id.target_translation_inner_card);
mTargetTitle = (TextView)v.findViewById(R.id.target_translation_title);
mTargetBody = (LinedEditText)v.findViewById(R.id.target_translation_body);
mTabLayout = (TabLayout)v.findViewById(R.id.source_translation_tabs);
mTabLayout.setTabTextColors(R.color.dark_disabled_text, R.color.dark_secondary_text);
mNewTabButton = (ImageButton) v.findViewById(R.id.new_tab_button);
}
}
/**
* A simple container for list items
*/
private static class ListItem {
private final String frameSlug;
private final String chapterSlug;
private boolean isChapterReference = false;
private boolean isChapterTitle = false;
public boolean isProjectTitle = false;
private boolean isTargetCardOpen = false;
private CharSequence renderedSourceBody;
private CharSequence renderedTargetBody;
public ListItem(String frameSlug, String chapterSlug) {
this.frameSlug = frameSlug;
this.chapterSlug = chapterSlug;
}
/**
* Checks if this item is a frame
* @return
*/
public boolean isFrame() {
return this.frameSlug != null;
}
/**
* Checks if this item is a chapter (either title or reference)
* @return
*/
public boolean isChapter() {
return this.frameSlug == null && this.chapterSlug != null;
}
}
}