diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 6249a0e..52608a7 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -5,8 +5,8 @@ android:versionName="1.0" > + android:minSdkVersion="16" + android:targetSdkVersion="16" /> diff --git a/src/com/mhalka/qurantranslationdisplay/QuranReader.java b/src/com/mhalka/qurantranslationdisplay/QuranReader.java index 1a89d81..93c55ff 100644 --- a/src/com/mhalka/qurantranslationdisplay/QuranReader.java +++ b/src/com/mhalka/qurantranslationdisplay/QuranReader.java @@ -53,6 +53,12 @@ public class QuranReader { } + public String getChapterName() throws XPathExpressionException { + String expression = "string(/Chapter/@ChapterName)"; + String text = xPath.compile(expression).evaluate(this.document); + return text; + } + public String getVerse(int num) throws XPathExpressionException { String expression = "/Chapter/Verse[@VerseID='"+num+"']/text()"; String text = xPath.compile(expression).evaluate(this.document); diff --git a/src/com/mhalka/qurantranslationdisplay/ShowAyah.java b/src/com/mhalka/qurantranslationdisplay/ShowAyah.java index a097a8a..f036767 100644 --- a/src/com/mhalka/qurantranslationdisplay/ShowAyah.java +++ b/src/com/mhalka/qurantranslationdisplay/ShowAyah.java @@ -1,9 +1,13 @@ package com.mhalka.qurantranslationdisplay; +import com.mhalka.qurantranslationdisplay.VerticalMarqueeTextView.ScrollingStoppedListener; + import android.app.Activity; +import android.content.res.AssetManager; import android.os.Bundle; import android.text.method.ScrollingMovementMethod; import android.util.DisplayMetrics; +import android.util.Log; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; import android.view.animation.TranslateAnimation; @@ -19,7 +23,11 @@ import android.widget.TextView; */ public class ShowAyah extends Activity { + private static int NUMBER_OF_MILISECONDS_TO_READ_ONE_LINE = 2500; private VerticalMarqueeTextView ayah; + private TextView chapterName; + int currentChapter=1; + int currentVerse=1; @Override @@ -28,32 +36,83 @@ public class ShowAyah extends Activity { setContentView(R.layout.activity_show_ayah); ayah = (VerticalMarqueeTextView) findViewById(R.id.ayah); + chapterName = (TextView) findViewById(R.id.chapter_name_verse_number); ayah.setMovementMethod(new ScrollingMovementMethod()); ayah.pauseMarquee(); - ayah.setDuration(150); - ayah.setPixelYOffSet(10); - - -// -// DisplayMetrics dm = getResources().getDisplayMetrics(); -// -// TranslateAnimation m_ta = new TranslateAnimation(0f,0f, dm.heightPixels, -1 * (dm.heightPixels)); -// -// m_ta.setDuration(10000); -// m_ta.setInterpolator(new LinearInterpolator()); -// m_ta.setRepeatCount(Animation.INFINITE); -// -// -// ayah.startAnimation(m_ta); + + + + + + ayah.setPixelYOffSet(ayah.getMaxLines() * ayah.getLineHeight()); + + ayah.setOnScrollingStoppedListener(new ScrollingStoppedListener() { + + @Override + public void scrollingStopped(VerticalMarqueeTextView v) { + nextAyah(); + + } + + + }); + showAyah(currentChapter, currentVerse); - // Example of use of QuranReader - // AssetManager assetManager = getAssets(); - // QuranReader reader = new QuranReader(assetManager, "quran_content"); - // reader.setChapter(2); - // String verseText = reader.getVerse(16); + } + + public void nextAyah() { + currentVerse++; + boolean verseExists = showAyah(currentChapter, currentVerse); + if (!verseExists) { + currentChapter++; + if(currentChapter > 114)currentChapter = 1; + currentVerse = 1; + showAyah(currentChapter, currentVerse); + } + + + + } + + public boolean showAyah(int chapter, int verse ) { + + + + try { + ayah.setText(""); + ayah.scrollTo(0, 0); + AssetManager assetManager = getAssets(); + QuranReader reader = new QuranReader(assetManager, "quran_content"); + reader.setChapter(chapter); + String verseText = reader.getVerse(verse); + + if(verseText.equals("")) return false; + // Start or restart the Marquee if paused. + + + ayah.setText(verseText); + chapterName.setText(reader.getChapterName() + " " + String.valueOf(chapter) + ":" + String.valueOf(verse)); + int duration = ayah.getLineCount() * NUMBER_OF_MILISECONDS_TO_READ_ONE_LINE; + + // let them reflect a bit on one liners ! :) (also solves a bug ) + if(duration <= NUMBER_OF_MILISECONDS_TO_READ_ONE_LINE) duration = 2 * NUMBER_OF_MILISECONDS_TO_READ_ONE_LINE; + if(ayah.getLineCount() > ayah.getMaxLines()) duration = ayah.getMaxLines() * NUMBER_OF_MILISECONDS_TO_READ_ONE_LINE; + ayah.setDuration(duration); + if (ayah.isPaused()) { + ayah.resumeMarquee(); + } + return true; + } + catch (Exception e) { + Log.d("SHOWAYAH",e.toString()); + return false; + } + + + } @Override protected void onResume() { diff --git a/src/com/mhalka/qurantranslationdisplay/VerticalMarqueeTextView.java b/src/com/mhalka/qurantranslationdisplay/VerticalMarqueeTextView.java new file mode 100644 index 0000000..fdbe697 --- /dev/null +++ b/src/com/mhalka/qurantranslationdisplay/VerticalMarqueeTextView.java @@ -0,0 +1,303 @@ +package com.mhalka.qurantranslationdisplay; + +import android.app.Activity; +import android.content.Context; +import android.os.AsyncTask; +import android.util.AttributeSet; +import android.util.Log; +import android.widget.TextView; + +public class VerticalMarqueeTextView extends TextView { + + private boolean isUserScrolling, isPaused, stop; + private boolean isNotDrawn = true; + private final Activity activity; + private long duration; + private int pixelYOffSet; + private ScrollingStoppedListener onScrollingStoppedListener; + + public ScrollingStoppedListener getOnScrollingStoppedListener() { + return onScrollingStoppedListener; + } + + public void setOnScrollingStoppedListener( + ScrollingStoppedListener onScrollingStoppedListener) { + this.onScrollingStoppedListener = onScrollingStoppedListener; + } + + /** + * + * Creates a vertically auto scrolling marquee of a TextView within an + * Activity. The (long) duration in milliseconds between calls to the next + * scrollBy(0, pixelYOffSet). Defaults to 65L. The (int) amount of Y pixels + * to scroll by defaults to 1. + * + */ + public VerticalMarqueeTextView(Context context, AttributeSet attrs, + int defStyle) { + super(context, attrs, defStyle); + + this.activity = (Activity) context; + + init(); + } + + /** + * + * Creates a vertically auto scrolling marquee of a TextView within an + * Activity. The (long) duration in milliseconds between calls to the next + * scrollBy(0, pixelYOffSet). Defaults to 65L. The (int) amount of Y pixels + * to scroll by defaults to 1. + * + */ + public VerticalMarqueeTextView(Context context, AttributeSet attrs) { + + super(context, attrs); + + this.activity = (Activity) context; + + init(); + } + + /** + * + * Creates a vertically auto scrolling marquee of a TextView within an + * Activity. The (long) duration in milliseconds between calls to the next + * scrollBy(0, pixelYOffSet). Defaults to 65L. The (int) amount of Y pixels + * to scroll by defaults to 1. + * + */ + public VerticalMarqueeTextView(Context context) { + super(context); + + this.activity = (Activity) context; + + init(); + } + + /** + * Initialize fields and start the marquee. + */ + private void init() { + setDuration(65l); + setPixelYOffSet(1); + + isUserScrolling = isPaused = stop = false; + setOnScrollingStoppedListener(new ScrollingStoppedListener() { + + @Override + public void scrollingStopped(VerticalMarqueeTextView v) { + // dummy listener + + } + }); + + startMarquee(); + + } + + /** + * @return Returns the (long) duration in milliseconds between calls to the + * next scrollBy(0, pixelYOffSet). + */ + public long getDuration() { + return duration; + } + + /** + * @param duration + * Sets the (long) duration in milliseconds between calls to the + * next scrollBy(0, pixelYOffSet). Defaults to 65L if value is + * less than or equal to 0. + */ + public void setDuration(long duration) { + if (duration <= 0) { + this.duration = 65l; + } else { + this.duration = duration; + } + + } + + /** + * @return Returns the (int) amount of Y pixels to scroll by. + */ + public int getPixelYOffSet() { + return pixelYOffSet; + } + + /** + * @param pixelYOffSet + * Sets the (int) amount of Y pixels to scroll by. Defaults to 1 + * if value is less. + */ + public void setPixelYOffSet(int pixelYOffSet) { + if (pixelYOffSet < 1) { + this.pixelYOffSet = 1; + } else { + this.pixelYOffSet = pixelYOffSet; + } + } + + /** + * Starts the marquee. May only be called once. + */ + private void startMarquee() { + new AutoScrollTextView().execute(); + } + + /** + * Stop the marquee. Cannot be restarted. + */ + public void stopMarquee() { + stop = true; + } + + /** + * Pauses the marquee. + */ + public void pauseMarquee() { + isPaused = true; + } + + /** + * Resumes marquee from a call to pauseMarquee(); + */ + public void resumeMarquee() { + isPaused = false; + } + + /** + * @return Returns true if paused (including if paused do to user manually + * scrolling), false otherwise. + */ + public boolean isPaused() { + if (isPaused || isUserScrolling) { + return true; + } + return false; + } + + private class AutoScrollTextView extends AsyncTask { + + private int pixelCount; + + @Override + protected Void doInBackground(Void... params) { + + // Check to see if the VMTV has been drawn to get proper sizing. + while (textViewNotDrawn()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + // Changing stop to true will permanently cancel autoscrolling. + // Cannot be restarted. + while (!stop) { + + // Allows scrolling to resume after VMTV has been released. + if (!(VerticalMarqueeTextView.this).isPressed() + && isUserScrolling && !isPaused) { + isUserScrolling = false; + } + + while (!isUserScrolling && !stop && !isPaused) { + + // Sleep duration amount between scrollBy pixelYOffSet + try { + Thread.sleep(duration); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + activity.runOnUiThread(new Runnable() { + + @Override + public void run() { + + // If the user is manually scrolling pause the auto + // scrolling marquee + if ((VerticalMarqueeTextView.this).isPressed()) { + + isUserScrolling = true; + + } else { // Otherwise auto scroll marquee + + // if VMTV has reached or exceeded the last + // Y pixel scroll back to top + int scrolly = (VerticalMarqueeTextView.this) + .getScrollY(); + + + if (pixelCount < (getMaxLines() * getLineHeight()) || scrolly >= pixelCount) { + + /* + * (VerticalMarqueeTextView.this).scrollTo(0, + * 0); + */ + (VerticalMarqueeTextView.this) + .pauseMarquee(); + (VerticalMarqueeTextView.this).onScrollingStoppedListener + .scrollingStopped(VerticalMarqueeTextView.this); + + + } else { // Otherwise scroll by the pixelYOffSet + + (VerticalMarqueeTextView.this).scrollBy(0, + pixelYOffSet); + } + + (VerticalMarqueeTextView.this).invalidate(); + } + + } + }); + } + } + + return null; + } + + @Override + protected void onProgressUpdate(Void... values) { + // TODO Auto-generated method stub + super.onProgressUpdate(values); + } + + private boolean textViewNotDrawn() { + + activity.runOnUiThread(new Runnable() { + + @Override + public void run() { + // Checks to see if VMTV has been drawn. + // In theory line count should be greater than 0 if drawn. + if ((VerticalMarqueeTextView.this).getLineCount() > 0) { + // Calculate the total pixel height that needs to be + // scrolled. + // May need additional calculations if there is + // additional padding. + pixelCount = (VerticalMarqueeTextView.this) + .getLineHeight() + * (VerticalMarqueeTextView.this).getLineCount(); + isNotDrawn = false; + } + + } + }); + + return isNotDrawn; + } + + } + + public interface ScrollingStoppedListener { + public void scrollingStopped(VerticalMarqueeTextView v); + } + +} \ No newline at end of file