diff --git a/app/build.gradle b/app/build.gradle
index 0662fe0044..ff023ad3fa 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -129,8 +129,10 @@ dependencies {
implementation project(path: ':common:toolbar')
implementation project(path: ':common:upgrade')
implementation project(path: ':common:ui:core')
+ implementation project(path: ':common:util')
implementation project(path: ':feature:audio')
+ implementation project(path: ':feature:audioshare')
implementation project(path: ':feature:downloadmanager')
implementation project(path: ':feature:qarilist')
@@ -170,7 +172,7 @@ dependencies {
kapt("com.squareup.moshi:moshi-kotlin-codegen:${moshiVersion}")
implementation "dev.chrisbanes:insetter-ktx:0.3.1"
- implementation 'com.jakewharton.timber:timber:5.0.1'
+ implementation "com.jakewharton.timber:timber:${timberVersion}"
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
implementation 'com.google.firebase:firebase-crashlytics:18.2.13'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a7d698a0ec..22a51739d9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -101,7 +101,7 @@
android:exported="false">
+ android:resource="@xml/file_paths" />
diff --git a/app/src/main/java/com/quran/labs/androidquran/dao/audio/AudioRequest.kt b/app/src/main/java/com/quran/labs/androidquran/dao/audio/AudioRequest.kt
index d24f389fff..02a73133b3 100644
--- a/app/src/main/java/com/quran/labs/androidquran/dao/audio/AudioRequest.kt
+++ b/app/src/main/java/com/quran/labs/androidquran/dao/audio/AudioRequest.kt
@@ -3,6 +3,7 @@ package com.quran.labs.androidquran.dao.audio
import android.os.Parcelable
import com.quran.labs.androidquran.common.audio.model.QariItem
import com.quran.data.model.SuraAyah
+import com.quran.labs.androidquran.common.audio.model.AudioPathInfo
import kotlinx.parcelize.Parcelize
@Parcelize
@@ -13,7 +14,8 @@ data class AudioRequest(val start: SuraAyah,
val rangeRepeatInfo: Int = 0,
val enforceBounds: Boolean,
val shouldStream: Boolean,
- val audioPathInfo: AudioPathInfo) : Parcelable {
+ val audioPathInfo: AudioPathInfo
+) : Parcelable {
fun isGapless() = qari.isGapless
fun needsIsti3athaAudio() =
!isGapless() || audioPathInfo.gaplessDatabase?.contains("minshawi_murattal") ?: false
diff --git a/app/src/main/java/com/quran/labs/androidquran/data/AyahInfoDatabaseHandler.java b/app/src/main/java/com/quran/labs/androidquran/data/AyahInfoDatabaseHandler.java
index 79040def61..be1715f33d 100644
--- a/app/src/main/java/com/quran/labs/androidquran/data/AyahInfoDatabaseHandler.java
+++ b/app/src/main/java/com/quran/labs/androidquran/data/AyahInfoDatabaseHandler.java
@@ -7,7 +7,7 @@
import android.graphics.RectF;
import androidx.annotation.NonNull;
-import com.quran.labs.androidquran.database.DatabaseUtils;
+import com.quran.common.util.database.DatabaseUtils;
import com.quran.labs.androidquran.util.QuranFileUtils;
import com.quran.page.common.data.AyahBounds;
import com.quran.page.common.data.AyahCoordinates;
diff --git a/app/src/main/java/com/quran/labs/androidquran/data/QuranDataProvider.java b/app/src/main/java/com/quran/labs/androidquran/data/QuranDataProvider.java
index e7da9e8bb6..43e96f1dee 100644
--- a/app/src/main/java/com/quran/labs/androidquran/data/QuranDataProvider.java
+++ b/app/src/main/java/com/quran/labs/androidquran/data/QuranDataProvider.java
@@ -11,13 +11,13 @@
import android.net.Uri;
import android.provider.BaseColumns;
+import com.quran.common.util.database.DatabaseUtils;
import com.quran.data.core.QuranInfo;
import com.quran.labs.androidquran.BuildConfig;
import com.quran.labs.androidquran.QuranApplication;
import com.quran.labs.androidquran.R;
import com.quran.labs.androidquran.common.LocalTranslation;
import com.quran.labs.androidquran.database.DatabaseHandler;
-import com.quran.labs.androidquran.database.DatabaseUtils;
import com.quran.labs.androidquran.database.TranslationsDBAdapter;
import com.quran.labs.androidquran.util.QuranFileUtils;
import com.quran.labs.androidquran.util.QuranUtils;
diff --git a/app/src/main/java/com/quran/labs/androidquran/database/AudioDatabaseVersionChecker.kt b/app/src/main/java/com/quran/labs/androidquran/database/AudioDatabaseVersionChecker.kt
index 1bb60957e8..964cf60d7f 100644
--- a/app/src/main/java/com/quran/labs/androidquran/database/AudioDatabaseVersionChecker.kt
+++ b/app/src/main/java/com/quran/labs/androidquran/database/AudioDatabaseVersionChecker.kt
@@ -1,5 +1,6 @@
package com.quran.labs.androidquran.database
+import com.quran.labs.androidquran.common.audio.timing.SuraTimingDatabaseHandler
import com.quran.labs.androidquran.feature.audio.VersionableDatabaseChecker
import javax.inject.Inject
diff --git a/app/src/main/java/com/quran/labs/androidquran/database/DatabaseHandler.kt b/app/src/main/java/com/quran/labs/androidquran/database/DatabaseHandler.kt
index ccb254ea9b..f1b241ed71 100644
--- a/app/src/main/java/com/quran/labs/androidquran/database/DatabaseHandler.kt
+++ b/app/src/main/java/com/quran/labs/androidquran/database/DatabaseHandler.kt
@@ -13,6 +13,7 @@ import androidx.core.content.ContextCompat
import com.quran.common.search.ArabicSearcher
import com.quran.common.search.DefaultSearcher
import com.quran.common.search.Searcher
+import com.quran.common.util.database.DatabaseUtils
import com.quran.data.model.QuranText
import com.quran.data.model.VerseRange
import com.quran.labs.androidquran.R
diff --git a/app/src/main/java/com/quran/labs/androidquran/model/translation/ArabicDatabaseUtils.java b/app/src/main/java/com/quran/labs/androidquran/model/translation/ArabicDatabaseUtils.java
index 54937c461a..3da020fcd3 100644
--- a/app/src/main/java/com/quran/labs/androidquran/model/translation/ArabicDatabaseUtils.java
+++ b/app/src/main/java/com/quran/labs/androidquran/model/translation/ArabicDatabaseUtils.java
@@ -3,6 +3,7 @@
import android.content.Context;
import android.database.Cursor;
+import com.quran.common.util.database.DatabaseUtils;
import com.quran.data.core.QuranInfo;
import com.quran.data.model.QuranText;
import com.quran.data.model.bookmark.Bookmark;
@@ -10,7 +11,6 @@
import com.quran.labs.androidquran.data.QuranFileConstants;
import com.quran.data.model.SuraAyah;
import com.quran.labs.androidquran.database.DatabaseHandler;
-import com.quran.labs.androidquran.database.DatabaseUtils;
import com.quran.labs.androidquran.util.QuranFileUtils;
import java.util.ArrayList;
diff --git a/app/src/main/java/com/quran/labs/androidquran/presenter/audio/AudioPresenter.kt b/app/src/main/java/com/quran/labs/androidquran/presenter/audio/AudioPresenter.kt
index 43536c5264..f42fb30e01 100644
--- a/app/src/main/java/com/quran/labs/androidquran/presenter/audio/AudioPresenter.kt
+++ b/app/src/main/java/com/quran/labs/androidquran/presenter/audio/AudioPresenter.kt
@@ -4,13 +4,14 @@ import android.content.Context
import android.content.Intent
import com.quran.data.model.SuraAyah
import com.quran.labs.androidquran.R
+import com.quran.labs.androidquran.common.audio.model.AudioDownloadMetadata
+import com.quran.labs.androidquran.common.audio.model.AudioPathInfo
import com.quran.labs.androidquran.common.audio.model.QariItem
-import com.quran.labs.androidquran.dao.audio.AudioPathInfo
+import com.quran.labs.androidquran.common.audio.util.AudioFileUtil
import com.quran.labs.androidquran.dao.audio.AudioRequest
import com.quran.labs.androidquran.data.QuranDisplayData
import com.quran.labs.androidquran.presenter.Presenter
import com.quran.labs.androidquran.service.QuranDownloadService
-import com.quran.labs.androidquran.common.audio.model.AudioDownloadMetadata
import com.quran.labs.androidquran.service.util.ServiceIntentHelper
import com.quran.labs.androidquran.ui.PagerActivity
import com.quran.labs.androidquran.util.AudioUtils
@@ -22,6 +23,7 @@ import javax.inject.Inject
class AudioPresenter @Inject
constructor(private val quranDisplayData: QuranDisplayData,
private val audioUtil: AudioUtils,
+ private val audioFileUtil: AudioFileUtil,
private val quranFileUtils: QuranFileUtils) : Presenter {
private var pagerActivity: PagerActivity? = null
private var lastAudioRequest: AudioRequest? = null
@@ -33,7 +35,7 @@ constructor(private val quranDisplayData: QuranDisplayData,
rangeRepeat: Int,
enforceRange: Boolean,
shouldStream: Boolean) {
- val audioPathInfo = getLocalAudioPathInfo(qari)
+ val audioPathInfo = audioFileUtil.getLocalAudioPathInfo(qari)
if (audioPathInfo != null) {
// override streaming if all the files are already downloaded
val stream = if (shouldStream) {
@@ -88,7 +90,7 @@ constructor(private val quranDisplayData: QuranDisplayData,
lastAudioRequest?.let { play(it) }
}
- private fun getDownloadIntent(context: Context, request: AudioRequest): Intent? {
+ fun getDownloadIntent(context: Context, request: AudioRequest): Intent? {
val qari = request.qari
val audioPathInfo = request.audioPathInfo
val path = audioPathInfo.localDirectory
@@ -136,23 +138,6 @@ constructor(private val quranDisplayData: QuranDisplayData,
return ServiceIntentHelper.getAudioDownloadIntent(context, url, destination, title)
}
- private fun getLocalAudioPathInfo(qari: QariItem): AudioPathInfo? {
- pagerActivity?.let {
- val localPath = audioUtil.getLocalQariUrl(qari)
- if (localPath != null) {
- val databasePath = audioUtil.getQariDatabasePathIfGapless(qari)
- val urlFormat = if (databasePath.isNullOrEmpty()) {
- localPath + File.separator + "%d" + File.separator +
- "%d" + AudioUtils.AUDIO_EXTENSION
- } else {
- localPath + File.separator + "%03d" + AudioUtils.AUDIO_EXTENSION
- }
- return AudioPathInfo(urlFormat, localPath, databasePath)
- }
- }
- return null
- }
-
private fun haveAllFiles(audioPathInfo: AudioPathInfo, start: SuraAyah, end: SuraAyah): Boolean {
return audioUtil.haveAllFiles(audioPathInfo.urlFormat,
audioPathInfo.localDirectory, start, end, audioPathInfo.gaplessDatabase != null)
diff --git a/app/src/main/java/com/quran/labs/androidquran/service/AudioService.kt b/app/src/main/java/com/quran/labs/androidquran/service/AudioService.kt
index 06ac074ba6..cd49367b2e 100644
--- a/app/src/main/java/com/quran/labs/androidquran/service/AudioService.kt
+++ b/app/src/main/java/com/quran/labs/androidquran/service/AudioService.kt
@@ -57,17 +57,17 @@ import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.media.session.MediaButtonReceiver
+import com.quran.common.util.database.DatabaseUtils
import com.quran.data.core.QuranInfo
import com.quran.data.model.SuraAyah
import com.quran.labs.androidquran.QuranApplication
import com.quran.labs.androidquran.R
+import com.quran.labs.androidquran.common.audio.timing.SuraTimingDatabaseHandler.Companion.getDatabaseHandler
import com.quran.labs.androidquran.dao.audio.AudioPlaybackInfo
import com.quran.labs.androidquran.dao.audio.AudioRequest
import com.quran.labs.androidquran.data.Constants
import com.quran.labs.androidquran.data.QuranDisplayData
import com.quran.labs.androidquran.data.QuranFileConstants
-import com.quran.labs.androidquran.database.DatabaseUtils.closeCursor
-import com.quran.labs.androidquran.database.SuraTimingDatabaseHandler.Companion.getDatabaseHandler
import com.quran.labs.androidquran.extension.requiresBasmallah
import com.quran.labs.androidquran.presenter.audio.service.AudioQueue
import com.quran.labs.androidquran.service.util.AudioFocusHelper
@@ -410,27 +410,7 @@ class AudioService : Service(), OnCompletionListener, OnPreparedListener,
timingDisposable?.dispose()
timingDisposable = Single.fromCallable {
val db = getDatabaseHandler(databasePath)
-
- val map = SparseIntArray()
- var cursor: Cursor? = null
- try {
- cursor = db.getAyahTimings(sura)
- Timber.d("got cursor of data")
- if (cursor != null && cursor.moveToFirst()) {
- do {
- val ayah = cursor.getInt(1)
- val time = cursor.getInt(2)
- map.put(ayah, time)
- } while (cursor.moveToNext())
- }
- } catch (se: SQLException) {
- // don't crash the app if the database is corrupt
- Timber.e(se)
- } finally {
- closeCursor(cursor)
- }
-
- map
+ db.getAyahTimings(sura)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
diff --git a/app/src/main/java/com/quran/labs/androidquran/ui/PagerActivity.java b/app/src/main/java/com/quran/labs/androidquran/ui/PagerActivity.java
index 3ab6630463..8ba6af7a6a 100644
--- a/app/src/main/java/com/quran/labs/androidquran/ui/PagerActivity.java
+++ b/app/src/main/java/com/quran/labs/androidquran/ui/PagerActivity.java
@@ -1,5 +1,9 @@
package com.quran.labs.androidquran.ui;
+import static com.quran.labs.androidquran.ui.helpers.SlidingPagerAdapter.AUDIO_PAGE;
+import static com.quran.labs.androidquran.ui.helpers.SlidingPagerAdapter.TAG_PAGE;
+import static com.quran.labs.androidquran.ui.helpers.SlidingPagerAdapter.TRANSLATION_PAGE;
+
import android.app.ProgressDialog;
import android.app.SearchManager;
import android.content.BroadcastReceiver;
@@ -28,6 +32,7 @@
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.Toast;
+
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
@@ -45,6 +50,7 @@
import androidx.viewpager.widget.NonRestoringViewPager;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
+
import com.quran.data.core.QuranInfo;
import com.quran.data.model.SuraAyah;
import com.quran.data.model.selection.AyahSelection;
@@ -65,6 +71,8 @@
import com.quran.labs.androidquran.common.LocalTranslationDisplaySort;
import com.quran.labs.androidquran.common.QuranAyahInfo;
import com.quran.labs.androidquran.common.audio.model.QariItem;
+import com.quran.labs.androidquran.common.audio.model.AudioPathInfo;
+import com.quran.labs.androidquran.common.audio.util.AudioFileUtil;
import com.quran.labs.androidquran.dao.audio.AudioRequest;
import com.quran.labs.androidquran.data.Constants;
import com.quran.labs.androidquran.data.QuranDataProvider;
@@ -73,6 +81,7 @@
import com.quran.labs.androidquran.di.component.activity.PagerActivityComponent;
import com.quran.labs.androidquran.di.module.activity.PagerActivityModule;
import com.quran.labs.androidquran.di.module.fragment.QuranPageModule;
+import com.quran.labs.androidquran.feature.audioshare.AudioShareUtils;
import com.quran.labs.androidquran.model.bookmark.BookmarkModel;
import com.quran.labs.androidquran.model.translation.ArabicDatabaseUtils;
import com.quran.labs.androidquran.presenter.audio.AudioPresenter;
@@ -120,14 +129,8 @@
import com.quran.page.common.toolbar.di.AyahToolBarInjector;
import com.quran.reading.common.AudioEventPresenter;
import com.quran.reading.common.ReadingEventPresenter;
-import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
-import io.reactivex.rxjava3.core.Completable;
-import io.reactivex.rxjava3.core.Observable;
-import io.reactivex.rxjava3.core.Single;
-import io.reactivex.rxjava3.disposables.CompositeDisposable;
-import io.reactivex.rxjava3.observers.DisposableObserver;
-import io.reactivex.rxjava3.observers.DisposableSingleObserver;
-import io.reactivex.rxjava3.schedulers.Schedulers;
+
+import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
@@ -135,12 +138,18 @@
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+
import javax.inject.Inject;
-import timber.log.Timber;
-import static com.quran.labs.androidquran.ui.helpers.SlidingPagerAdapter.AUDIO_PAGE;
-import static com.quran.labs.androidquran.ui.helpers.SlidingPagerAdapter.TAG_PAGE;
-import static com.quran.labs.androidquran.ui.helpers.SlidingPagerAdapter.TRANSLATION_PAGE;
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
+import io.reactivex.rxjava3.core.Completable;
+import io.reactivex.rxjava3.core.Observable;
+import io.reactivex.rxjava3.core.Single;
+import io.reactivex.rxjava3.disposables.CompositeDisposable;
+import io.reactivex.rxjava3.observers.DisposableObserver;
+import io.reactivex.rxjava3.observers.DisposableSingleObserver;
+import io.reactivex.rxjava3.schedulers.Schedulers;
+import timber.log.Timber;
/**
* Activity that displays the Quran (in Arabic or translation mode).
@@ -231,6 +240,7 @@ public class PagerActivity extends AppCompatActivity implements
@Inject QuranAppUtils quranAppUtils;
@Inject ShareUtil shareUtil;
@Inject AudioUtils audioUtils;
+ @Inject AudioFileUtil audioFileUtil;
@Inject QuranDisplayData quranDisplayData;
@Inject QuranInfo quranInfo;
@Inject QuranFileUtils quranFileUtils;
@@ -251,6 +261,7 @@ public class PagerActivity extends AppCompatActivity implements
private final PagerHandler handler = new PagerHandler(this);
+
private static class PagerHandler extends Handler {
private final WeakReference activity;
@@ -287,12 +298,21 @@ public void onCreate(Bundle savedInstanceState) {
isSplitScreen = quranSettings.isQuranSplitWithTranslation();
audioEventPresenterBridge = new AudioEventPresenterBridge(
audioEventPresenter,
- suraAyah -> { onAudioPlaybackAyahChanged(suraAyah); return null; }
+ suraAyah -> {
+ onAudioPlaybackAyahChanged(suraAyah);
+ return null;
+ }
);
readingEventPresenterBridge = new ReadingEventPresenterBridge(
readingEventPresenter,
- () -> { onPageClicked(); return null; },
- ayahSelection -> { onAyahSelectionChanged(ayahSelection); return null; }
+ () -> {
+ onPageClicked();
+ return null;
+ },
+ ayahSelection -> {
+ onAyahSelectionChanged(ayahSelection);
+ return null;
+ }
);
// remove the window background to avoid overdraw. note that, per Romain's blog, this is
@@ -421,7 +441,8 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse
} else if (position == barPos - 1 || position == barPos + 1) {
// Swiping to previous or next ViewPager page (i.e. next or previous quran page)
final SelectionIndicator updatedSelectionIndicator =
- SelectionIndicatorKt.withXScroll(selectionIndicator, viewPager.getWidth() - positionOffsetPixels);
+ SelectionIndicatorKt.withXScroll(selectionIndicator,
+ viewPager.getWidth() - positionOffsetPixels);
readingEventPresenterBridge.withSelectionIndicator(updatedSelectionIndicator);
} else {
readingEventPresenterBridge.clearSelectedAyah();
@@ -541,8 +562,14 @@ public void onPageSelected(int position) {
this::getCurrentPage,
() -> audioStatusBar,
() -> ayahToolBar,
- ayah -> { ensurePage(ayah.sura, ayah.ayah); return null; },
- sliderPage -> { showSlider(slidingPagerAdapter.getPagePosition(sliderPage)); return null; }
+ ayah -> {
+ ensurePage(ayah.sura, ayah.ayah);
+ return null;
+ },
+ sliderPage -> {
+ showSlider(slidingPagerAdapter.getPagePosition(sliderPage));
+ return null;
+ }
));
}
@@ -1374,16 +1401,16 @@ private void ensurePage(int sura, int ayah) {
private void requestTranslationsList() {
compositeDisposable.add(
Single.fromCallable(() ->
- translationsDBAdapter.getTranslations())
+ translationsDBAdapter.getTranslations())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSingleObserver>() {
@Override
public void onSuccess(@NonNull List translationList) {
final List sortedTranslations = new ArrayList<>(translationList);
- Collections.sort(sortedTranslations, new LocalTranslationDisplaySort());
+ Collections.sort(sortedTranslations, new LocalTranslationDisplaySort());
- int items = sortedTranslations.size();
+ int items = sortedTranslations.size();
String[] titles = new String[items];
for (int i = 0; i < items; i++) {
LocalTranslation item = sortedTranslations.get(i);
@@ -1400,7 +1427,8 @@ public void onSuccess(@NonNull List translationList) {
if (currentActiveTranslationsFilesNames.isEmpty() && items > 0) {
currentActiveTranslationsFilesNames = new HashSet<>();
for (int i = 0; i < items; i++) {
- currentActiveTranslationsFilesNames.add(sortedTranslations.get(i).getFilename());
+ currentActiveTranslationsFilesNames.add(
+ sortedTranslations.get(i).getFilename());
}
}
activeTranslationsFilesNames = currentActiveTranslationsFilesNames;
@@ -1433,7 +1461,8 @@ public void onSuccess(@NonNull Boolean isBookmarked) {
if (sura == null || ayah == null) {
// page bookmark
bookmarksCache.put(page, isBookmarked);
- bookmarksMenuItem.setIcon(isBookmarked ? com.quran.labs.androidquran.common.toolbar.R.drawable.ic_favorite : com.quran.labs.androidquran.common.toolbar.R.drawable.ic_not_favorite);
+ bookmarksMenuItem.setIcon(
+ isBookmarked ? com.quran.labs.androidquran.common.toolbar.R.drawable.ic_favorite : com.quran.labs.androidquran.common.toolbar.R.drawable.ic_not_favorite);
} else {
// ayah bookmark
SuraAyah suraAyah = new SuraAyah(sura, ayah);
@@ -1482,7 +1511,8 @@ private void refreshBookmarksMenu() {
bookmarked = bookmarksCache.get(page - 1);
}
- menuItem.setIcon(bookmarked ? com.quran.labs.androidquran.common.toolbar.R.drawable.ic_favorite : com.quran.labs.androidquran.common.toolbar.R.drawable.ic_not_favorite);
+ menuItem.setIcon(
+ bookmarked ? com.quran.labs.androidquran.common.toolbar.R.drawable.ic_favorite : com.quran.labs.androidquran.common.toolbar.R.drawable.ic_not_favorite);
} else {
supportInvalidateOptionsMenu();
}
@@ -1523,7 +1553,7 @@ private void playFromAyah(int page, int startSura, int startAyah) {
final SuraAyah start = new SuraAyah(startSura, startAyah);
final SuraAyah end = getSelectionEnd();
// handle the case of multiple ayat being selected and play them as a range if so
- final SuraAyah ending = (end == null || start.equals(end) || start.after(end))? null : end;
+ final SuraAyah ending = (end == null || start.equals(end) || start.after(end)) ? null : end;
playFromAyah(start, ending, page, 0, 0, ending != null);
}
@@ -1786,6 +1816,8 @@ public boolean onMenuItemClick(MenuItem item) {
shareAyahLink(startSuraAyah, endSuraAyah);
} else if (itemId == com.quran.labs.androidquran.common.toolbar.R.id.cab_share_ayah_text) {
shareAyah(startSuraAyah, endSuraAyah, false);
+ } else if (itemId == com.quran.labs.androidquran.common.toolbar.R.id.cab_share_ayah_audio) {
+ shareAyahAudio(startSuraAyah, endSuraAyah);
} else if (itemId == com.quran.labs.androidquran.common.toolbar.R.id.cab_copy_ayah) {
shareAyah(startSuraAyah, endSuraAyah, true);
} else {
@@ -1822,7 +1854,8 @@ private void shareAyah(SuraAyah start, SuraAyah end, final boolean isCopy) {
if (isCopy) {
shareUtil.copyToClipboard(this, shareText);
} else {
- shareUtil.shareViaIntent(this, shareText, com.quran.labs.androidquran.common.toolbar.R.string.share_ayah_text);
+ shareUtil.shareViaIntent(this, shareText,
+ com.quran.labs.androidquran.common.toolbar.R.string.share_ayah_text);
}
}
@@ -1851,7 +1884,8 @@ public void shareAyahLink(SuraAyah start, SuraAyah end) {
.subscribeWith(new DisposableSingleObserver() {
@Override
public void onSuccess(@NonNull String url) {
- shareUtil.shareViaIntent(PagerActivity.this, url, com.quran.labs.androidquran.common.toolbar.R.string.share_ayah);
+ shareUtil.shareViaIntent(PagerActivity.this, url,
+ com.quran.labs.androidquran.common.toolbar.R.string.share_ayah);
dismissProgressDialog();
}
@@ -1863,6 +1897,55 @@ public void onError(@NonNull Throwable e) {
);
}
+ public void shareAyahAudio(SuraAyah start, SuraAyah end) {
+ final QariItem selectedQari = audioStatusBar.getAudioInfo();
+ AudioPathInfo audioPathInfo = audioFileUtil.getLocalAudioPathInfo(selectedQari);
+
+ assert audioPathInfo != null;
+ boolean gaplessDatabaseExists = audioPathInfo.getGaplessDatabase() != null;
+
+ if (gaplessDatabaseExists) {
+ if (audioFilesExist(audioPathInfo, start, end)) {
+ AudioShareUtils audioShareUtils = new AudioShareUtils();
+ String path = audioShareUtils.createBlockingSharableAudioFile(
+ this,
+ start,
+ end,
+ selectedQari,
+ audioPathInfo.getUrlFormat(),
+ audioPathInfo.getGaplessDatabase()
+ );
+
+ if (path != null && !path.isEmpty()){
+ shareAudioSegment(path);
+ } else {
+ Toast.makeText(this, "could not share audio ayah", Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ requestDownload(audioPathInfo, selectedQari, start, end);
+ }
+ }
+ }
+
+ private boolean audioFilesExist(AudioPathInfo audioPathInfo, SuraAyah start, SuraAyah end) {
+ return audioUtils.haveAllFiles(audioPathInfo.getUrlFormat(), audioPathInfo.getLocalDirectory(),
+ start, end, true);
+ }
+
+ private void shareAudioSegment(String path) {
+ shareUtil.shareAudioFileIntent(PagerActivity.this, new File(path));
+ }
+
+ private void requestDownload(AudioPathInfo audioPathInfo, QariItem qari, SuraAyah start, SuraAyah end) {
+ AudioRequest audioRequest = new AudioRequest(
+ start, end, qari, 0, 0, true, false, audioPathInfo);
+
+ Intent downloadIntent = audioPresenter.getDownloadIntent(this, audioRequest);
+ if (downloadIntent != null) {
+ handleRequiredDownload(downloadIntent);
+ }
+ }
+
private void showProgressDialog() {
if (progressDialog == null) {
progressDialog = new ProgressDialog(this);
diff --git a/app/src/main/java/com/quran/labs/androidquran/util/AudioUtils.kt b/app/src/main/java/com/quran/labs/androidquran/util/AudioUtils.kt
index 14136a3157..ab6d7d4485 100644
--- a/app/src/main/java/com/quran/labs/androidquran/util/AudioUtils.kt
+++ b/app/src/main/java/com/quran/labs/androidquran/util/AudioUtils.kt
@@ -9,10 +9,10 @@ import com.quran.data.model.audio.Qari
import com.quran.labs.androidquran.common.audio.model.QariItem
import com.quran.labs.androidquran.common.audio.util.QariUtil
import com.quran.labs.androidquran.service.AudioService
+import timber.log.Timber
import java.io.File
import java.util.Locale
import javax.inject.Inject
-import timber.log.Timber
class AudioUtils @Inject constructor(
private val quranInfo: QuranInfo,
@@ -77,32 +77,6 @@ class AudioUtils @Inject constructor(
}
}
- fun getLocalQariUrl(item: QariItem): String? {
- val rootDirectory = quranFileUtils.audioFileDirectory()
- return if (rootDirectory == null) null else rootDirectory + item.path
- }
-
- fun getLocalQariUri(item: QariItem): String? {
- val rootDirectory = quranFileUtils.audioFileDirectory()
- return if (rootDirectory == null) null else
- rootDirectory + item.path + File.separator + if (item.isGapless) {
- "%03d$AUDIO_EXTENSION"
- } else {
- "%d" + File.separator + "%d" + AUDIO_EXTENSION
- }
- }
-
- fun getQariDatabasePathIfGapless(item: QariItem): String? {
- var databaseName = item.databaseName
- if (databaseName != null) {
- val path = getLocalQariUrl(item)
- if (path != null) {
- databaseName = path + File.separator + databaseName + DB_EXTENSION
- }
- }
- return databaseName
- }
-
fun getLastAyahToPlay(
startAyah: SuraAyah,
currentPage: Int,
@@ -293,7 +267,5 @@ class AudioUtils @Inject constructor(
companion object {
const val ZIP_EXTENSION = ".zip"
const val AUDIO_EXTENSION = ".mp3"
-
- private const val DB_EXTENSION = ".db"
}
}
diff --git a/app/src/main/java/com/quran/labs/androidquran/util/ShareUtil.kt b/app/src/main/java/com/quran/labs/androidquran/util/ShareUtil.kt
index 4823b1629e..839ad13844 100644
--- a/app/src/main/java/com/quran/labs/androidquran/util/ShareUtil.kt
+++ b/app/src/main/java/com/quran/labs/androidquran/util/ShareUtil.kt
@@ -7,7 +7,10 @@ import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.annotation.StringRes
+import androidx.core.content.ContextCompat
+import androidx.core.content.FileProvider
import com.quran.data.model.QuranText
+import com.quran.labs.androidquran.BuildConfig
import com.quran.labs.androidquran.R
import com.quran.labs.androidquran.common.LocalTranslation
import com.quran.labs.androidquran.common.QuranAyahInfo
@@ -16,6 +19,7 @@ import com.quran.labs.androidquran.model.translation.ArabicDatabaseUtils
import com.quran.labs.androidquran.ui.util.ToastCompat
import com.quran.labs.androidquran.ui.util.TypefaceManager
import dagger.Reusable
+import java.io.File
import java.text.NumberFormat
import java.util.Locale
import javax.inject.Inject
@@ -130,4 +134,15 @@ class ShareUtil @Inject internal constructor(private val quranDisplayData: Quran
append("]")
}
}
+
+
+ fun shareAudioFileIntent(activity: Activity, file: File) {
+ val authorities = BuildConfig.APPLICATION_ID + ".fileprovider"
+ val uri = FileProvider.getUriForFile(activity, authorities, file)
+ val shareIntent = Intent(Intent.ACTION_SEND)
+ shareIntent.putExtra(Intent.EXTRA_STREAM, uri)
+ shareIntent.type = "audio/mp3"
+ shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ activity.startActivity(Intent.createChooser(shareIntent, activity.getString(R.string.share_audio_file_title)))
+ }
}
diff --git a/app/src/main/java/com/quran/labs/androidquran/worker/AudioUpdateWorker.kt b/app/src/main/java/com/quran/labs/androidquran/worker/AudioUpdateWorker.kt
index 2801e3d249..116c7fc325 100644
--- a/app/src/main/java/com/quran/labs/androidquran/worker/AudioUpdateWorker.kt
+++ b/app/src/main/java/com/quran/labs/androidquran/worker/AudioUpdateWorker.kt
@@ -8,10 +8,11 @@ import androidx.work.CoroutineWorker
import androidx.work.ListenableWorker
import androidx.work.WorkerParameters
import com.quran.labs.androidquran.R
+import com.quran.labs.androidquran.common.audio.timing.SuraTimingDatabaseHandler
+import com.quran.labs.androidquran.common.audio.util.AudioFileUtil
import com.quran.labs.androidquran.core.worker.WorkerTaskFactory
import com.quran.labs.androidquran.data.Constants
import com.quran.labs.androidquran.database.AudioDatabaseVersionChecker
-import com.quran.labs.androidquran.database.SuraTimingDatabaseHandler
import com.quran.labs.androidquran.feature.audio.AudioUpdater
import com.quran.labs.androidquran.feature.audio.api.AudioUpdateService
import com.quran.labs.androidquran.feature.audio.util.AudioFileCheckerImpl
@@ -31,7 +32,8 @@ class AudioUpdateWorker(
private val audioUpdateService: AudioUpdateService,
private val audioUtils: AudioUtils,
private val quranFileUtils: QuranFileUtils,
- private val quranSettings: QuranSettings
+ private val quranSettings: QuranSettings,
+ private val audioFileUtil: AudioFileUtil
) : CoroutineWorker(context, params) {
override suspend fun doWork(): Result = coroutineScope {
@@ -54,14 +56,14 @@ class AudioUpdateWorker(
localFilesToDelete.forEach { localUpdate ->
if (localUpdate.needsDatabaseUpgrade) {
// delete the database
- val dbPath = audioUtils.getQariDatabasePathIfGapless(localUpdate.qari)
+ val dbPath = audioFileUtil.getQariDatabasePathIfGapless(localUpdate.qari)
dbPath?.let { SuraTimingDatabaseHandler.clearDatabaseHandlerIfExists(it) }
Timber.d("would remove %s", dbPath)
File(dbPath).delete()
}
val qari = localUpdate.qari
- val path = audioUtils.getLocalQariUrl(qari)
+ val path = audioFileUtil.getLocalQariUrl(qari)
localUpdate.files.forEach {
// delete the file
val filePath = if (qari.isGapless) {
@@ -116,15 +118,21 @@ class AudioUpdateWorker(
private val audioUpdateService: AudioUpdateService,
private val audioUtils: AudioUtils,
private val quranFileUtils: QuranFileUtils,
- private val quranSettings: QuranSettings
+ private val quranSettings: QuranSettings,
+ private val audioFileUtil: AudioFileUtil
) : WorkerTaskFactory {
override fun makeWorker(
appContext: Context,
workerParameters: WorkerParameters
): ListenableWorker {
return AudioUpdateWorker(
- appContext, workerParameters, audioUpdateService, audioUtils, quranFileUtils,
- quranSettings
+ appContext,
+ workerParameters,
+ audioUpdateService,
+ audioUtils,
+ quranFileUtils,
+ quranSettings,
+ audioFileUtil
)
}
}
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 6fd31b4f32..9e61707603 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -223,6 +223,7 @@
تم نسخ الآية
+ Share Audio File
تصنيف المرجعية
diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml
index 30a1b6b71b..286fe718a9 100644
--- a/app/src/main/res/values-az/strings.xml
+++ b/app/src/main/res/values-az/strings.xml
@@ -272,6 +272,7 @@
Âyet kopyalandı
+ Share Audio File
Sayfa işareti etiketi
diff --git a/app/src/main/res/values-bs/strings.xml b/app/src/main/res/values-bs/strings.xml
index 0fa7371c9f..54eaba0048 100644
--- a/app/src/main/res/values-bs/strings.xml
+++ b/app/src/main/res/values-bs/strings.xml
@@ -290,6 +290,7 @@
Ajet kopiran
+ Share Audio File
Označi zabilješku
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index ffc587ed00..8e69e2a542 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -298,6 +298,7 @@
Vers kopiert
+ Share Audio File
Ein Schlagwort zum Lesezeichen hinzufügen
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 7858a9be06..6e8be4412f 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -164,6 +164,7 @@
Versículo copiado
+ Share Audio File
Etiquetar Favorito
Borrar Etiqueta
diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml
index 8d7214050f..cec19ff3c8 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -163,6 +163,7 @@
آیه کپی شد
+ Share Audio File
تعیین برچسب برای نشانک
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 481a38b7a6..5598b181fe 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -249,6 +249,7 @@
Aya copiée
+ Share Audio File
Étiqueter le favori
diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml
index b55e7bac1a..4e11fb4018 100644
--- a/app/src/main/res/values-hr/strings.xml
+++ b/app/src/main/res/values-hr/strings.xml
@@ -290,6 +290,7 @@
Ajet kopiran
+ Share Audio File
Označi zabilješku
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 35a08fe5ab..cdc367ebd3 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -221,6 +221,7 @@
Ája kimásolva
+ Share Audio File
Könyvelző címkézése
diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml
index a3a4edc90d..a6d76b5fef 100644
--- a/app/src/main/res/values-id/strings.xml
+++ b/app/src/main/res/values-id/strings.xml
@@ -277,6 +277,7 @@
Ayat telah tersalin
+ Share Audio File
Labeli Penanda
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 7d353ec686..de12d412e8 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -118,6 +118,7 @@
Avviare la riproduzione da:
Inizio della pagina
Ayah Copiato
+ Share Audio File
Segnalibro
Cancellare il tag
Modifica tag
diff --git a/app/src/main/res/values-kk/strings.xml b/app/src/main/res/values-kk/strings.xml
index 24cedcb0b8..6f12409874 100644
--- a/app/src/main/res/values-kk/strings.xml
+++ b/app/src/main/res/values-kk/strings.xml
@@ -277,6 +277,7 @@
Аят көшірілді
+ Share Audio File
Бетбелгіні белгілеу
diff --git a/app/src/main/res/values-ku/strings.xml b/app/src/main/res/values-ku/strings.xml
index 6186cd0aab..8bd8ffb6d1 100644
--- a/app/src/main/res/values-ku/strings.xml
+++ b/app/src/main/res/values-ku/strings.xml
@@ -183,6 +183,7 @@
ئایەت لەبەریگیراوە
+ Share Audio File
بڕگە نیشانەکرا
diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml
index 5d69155c37..1aabaf99d3 100644
--- a/app/src/main/res/values-ms/strings.xml
+++ b/app/src/main/res/values-ms/strings.xml
@@ -248,6 +248,7 @@
Ayat telah disalin
+ Share Audio File
Beri Label pada Penanda
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 4fa7dab4ec..326605d63a 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -268,6 +268,7 @@ Voor de vertaalde pagina\'s (/voor vertalingen): Ga naar instellingen en wijzig
Ayah Gekopieerd
+ Share Audio File
Label Bladwijzer
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 43df4b0538..5c1ed73611 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -280,6 +280,7 @@
Ayah Skopiowany
+ Share Audio File
Tag Zakładka
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index e283b0fab6..e055cc6a44 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -201,6 +201,7 @@ escolher um leitor-qari diferente. Clique play para baixar e reproduzir a págin
Ayah Copiada
+ Share Audio File
Tagear Marcador
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index c91cfb7e8c..e00ac30244 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -328,6 +328,7 @@
Аят скопирован
+ Share Audio File
Отметить закладку
diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml
index d912cba534..8368cdec80 100644
--- a/app/src/main/res/values-sq/strings.xml
+++ b/app/src/main/res/values-sq/strings.xml
@@ -279,6 +279,7 @@
Ajahu kopjon
+ Share Audio File
Tag Libërshënues
diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml
index e0b7005b1a..1d0a5e4ba9 100644
--- a/app/src/main/res/values-sr/strings.xml
+++ b/app/src/main/res/values-sr/strings.xml
@@ -290,6 +290,7 @@
Ajet kopiran
+ Share Audio File
Označi zabelešku
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index 4dcbee5e99..be7efb0168 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -279,6 +279,7 @@
Ayah Kopierad
+ Share Audio File
Tag Bookmark
diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml
index 41f006d4fe..8285170438 100644
--- a/app/src/main/res/values-th/strings.xml
+++ b/app/src/main/res/values-th/strings.xml
@@ -270,6 +270,7 @@
อายะห์ คัดลอก
+ Share Audio File
ที่คั่นหน้าแท็ก
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 30a1b6b71b..286fe718a9 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -272,6 +272,7 @@
Âyet kopyalandı
+ Share Audio File
Sayfa işareti etiketi
diff --git a/app/src/main/res/values-ug/strings.xml b/app/src/main/res/values-ug/strings.xml
index 7f6e4876d6..d0f58f584b 100644
--- a/app/src/main/res/values-ug/strings.xml
+++ b/app/src/main/res/values-ug/strings.xml
@@ -156,6 +156,7 @@
ئايەت كۆچۈرۈلدى
+ Share Audio File
خەتكۈچكە بەلگە قوش
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index f051400537..77de7df876 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -281,6 +281,7 @@
Ая скопійований
+ Share Audio File
Закладка тега
diff --git a/app/src/main/res/values-uz/strings.xml b/app/src/main/res/values-uz/strings.xml
index 35efd2ea7e..ee6855682c 100644
--- a/app/src/main/res/values-uz/strings.xml
+++ b/app/src/main/res/values-uz/strings.xml
@@ -305,6 +305,7 @@
Oyat xotiraga koʻchirildi
+ Share Audio File
Xatchoʻpni teglash
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index 2ce0b5f1b3..52574218cb 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -171,6 +171,7 @@
复制成功
+ Share Audio File
为收藏加标签
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index fca7f16f62..4494ca74aa 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -355,6 +355,7 @@
Ayah Copied
+ Share Audio File
Tag Bookmark
diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml
index 783bd79240..15ebff8dcc 100644
--- a/app/src/main/res/xml/file_paths.xml
+++ b/app/src/main/res/xml/file_paths.xml
@@ -3,4 +3,13 @@
+
+
+
+
+
+
diff --git a/build.gradle b/build.gradle
index a3af6b15dd..172a41322e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -21,6 +21,7 @@ buildscript {
workManagerVersion = '2.7.1'
materialComponentsVersion = '1.6.1'
coreKtxVersion = '1.7.0'
+ timberVersion = '5.0.1'
anvilVersion = '2.4.2'
moshiVersion = '1.14.0'
diff --git a/common/audio/build.gradle b/common/audio/build.gradle
index 123f2cdaba..8ea48773cd 100644
--- a/common/audio/build.gradle
+++ b/common/audio/build.gradle
@@ -16,11 +16,13 @@ android {
dependencies {
implementation project(":common:data")
implementation project(":common:download")
+ implementation project(path: ':common:util')
implementation deps.dagger.runtime
implementation "androidx.annotation:annotation:${androidxAnnotationVersion}"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${coroutinesVersion}"
implementation "com.squareup.okio:okio:${okioVersion}"
+ implementation "com.jakewharton.timber:timber:${timberVersion}"
testImplementation "junit:junit:${junitVersion}"
testImplementation "com.google.truth:truth:${truthVersion}"
diff --git a/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/cache/command/GaplessAudioInfoCommand.kt b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/cache/command/GaplessAudioInfoCommand.kt
index 248f36de6b..1be405e6cf 100644
--- a/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/cache/command/GaplessAudioInfoCommand.kt
+++ b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/cache/command/GaplessAudioInfoCommand.kt
@@ -1,6 +1,6 @@
package com.quran.labs.androidquran.common.audio.cache.command
-import com.quran.labs.androidquran.common.audio.util.AudioFileUtil
+import com.quran.labs.androidquran.common.audio.util.AudioFileTools
import okio.FileSystem
import okio.Path
import javax.inject.Inject
@@ -12,7 +12,7 @@ class GaplessAudioInfoCommand @Inject constructor(private val fileSystem: FileSy
}
private fun fullGaplessDownloads(path: Path): List {
- val paths = AudioFileUtil.filesMatchingSuffixWithSuffixRemoved(fileSystem, path, ".mp3")
+ val paths = AudioFileTools.filesMatchingSuffixWithSuffixRemoved(fileSystem, path, ".mp3")
return paths
.filter { it.length == 3 }
.mapNotNull { it.toIntOrNull() }
@@ -20,7 +20,7 @@ class GaplessAudioInfoCommand @Inject constructor(private val fileSystem: FileSy
}
private fun partialGaplessDownloads(path: Path): List {
- val paths = AudioFileUtil.filesMatchingSuffixWithSuffixRemoved(fileSystem, path, ".mp3.part")
+ val paths = AudioFileTools.filesMatchingSuffixWithSuffixRemoved(fileSystem, path, ".mp3.part")
return paths
.filter { it.length == 3 }
.mapNotNull { it.toIntOrNull() }
diff --git a/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/cache/command/GappedAudioInfoCommand.kt b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/cache/command/GappedAudioInfoCommand.kt
index 1cad0ca264..fc51123cd3 100644
--- a/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/cache/command/GappedAudioInfoCommand.kt
+++ b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/cache/command/GappedAudioInfoCommand.kt
@@ -2,7 +2,7 @@ package com.quran.labs.androidquran.common.audio.cache.command
import com.quran.data.core.QuranInfo
import com.quran.labs.androidquran.common.audio.model.PartiallyDownloadedSura
-import com.quran.labs.androidquran.common.audio.util.AudioFileUtil
+import com.quran.labs.androidquran.common.audio.util.AudioFileTools
import okio.FileSystem
import okio.Path
import javax.inject.Inject
@@ -17,7 +17,7 @@ class GappedAudioInfoCommand @Inject constructor(
.filter { it.name.toIntOrNull() in 1..114 }
.associate { directory ->
val gappedDownloads =
- AudioFileUtil.filesMatchingSuffixWithSuffixRemoved(fileSystem, directory, ".mp3")
+ AudioFileTools.filesMatchingSuffixWithSuffixRemoved(fileSystem, directory, ".mp3")
.mapNotNull { it.toIntOrNull() }
.filter { it in 1..286 }
directory.toFile().nameWithoutExtension.toInt() to gappedDownloads
diff --git a/app/src/main/java/com/quran/labs/androidquran/dao/audio/AudioPathInfo.kt b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/model/AudioPathInfo.kt
similarity index 81%
rename from app/src/main/java/com/quran/labs/androidquran/dao/audio/AudioPathInfo.kt
rename to common/audio/src/main/java/com/quran/labs/androidquran/common/audio/model/AudioPathInfo.kt
index 7a1cd0e563..ff9f483d49 100644
--- a/app/src/main/java/com/quran/labs/androidquran/dao/audio/AudioPathInfo.kt
+++ b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/model/AudioPathInfo.kt
@@ -1,4 +1,4 @@
-package com.quran.labs.androidquran.dao.audio
+package com.quran.labs.androidquran.common.audio.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
diff --git a/app/src/main/java/com/quran/labs/androidquran/database/SuraTimingDatabaseHandler.kt b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/timing/SuraTimingDatabaseHandler.kt
similarity index 80%
rename from app/src/main/java/com/quran/labs/androidquran/database/SuraTimingDatabaseHandler.kt
rename to common/audio/src/main/java/com/quran/labs/androidquran/common/audio/timing/SuraTimingDatabaseHandler.kt
index 42e06615b2..b56090f113 100644
--- a/app/src/main/java/com/quran/labs/androidquran/database/SuraTimingDatabaseHandler.kt
+++ b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/timing/SuraTimingDatabaseHandler.kt
@@ -1,14 +1,14 @@
-package com.quran.labs.androidquran.database
+package com.quran.labs.androidquran.common.audio.timing
import android.database.Cursor
import android.database.DefaultDatabaseErrorHandler
import android.database.SQLException
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteDatabaseCorruptException
+import android.util.SparseIntArray
+import com.quran.common.util.database.DatabaseUtils
import timber.log.Timber
import java.io.File
-import java.lang.Exception
-import java.util.HashMap
class SuraTimingDatabaseHandler private constructor(path: String) {
private var database: SQLiteDatabase? = null
@@ -73,7 +73,7 @@ class SuraTimingDatabaseHandler private constructor(path: String) {
private fun validDatabase(): Boolean = database?.isOpen ?: false
- fun getAyahTimings(sura: Int): Cursor? {
+ private fun getAyahTimingsCursor(sura: Int): Cursor? {
if (!validDatabase()) return null
return try {
@@ -90,6 +90,28 @@ class SuraTimingDatabaseHandler private constructor(path: String) {
}
}
+ fun getAyahTimings(sura: Int): SparseIntArray {
+ val map = SparseIntArray()
+
+ var cursor: Cursor? = null
+ try {
+ cursor = getAyahTimingsCursor(sura)
+ if (cursor != null && cursor.moveToFirst()) {
+ do {
+ val ayah = cursor.getInt(1)
+ val time = cursor.getInt(2)
+ map.put(ayah, time)
+ } while (cursor.moveToNext())
+ }
+ } catch (exception: SQLException) {
+ Timber.e(exception)
+ } finally {
+ DatabaseUtils.closeCursor(cursor)
+ }
+
+ return map
+ }
+
fun getVersion(): Int {
if (!validDatabase()) {
return -1
diff --git a/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/util/AudioFileTools.kt b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/util/AudioFileTools.kt
new file mode 100644
index 0000000000..7a5643decb
--- /dev/null
+++ b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/util/AudioFileTools.kt
@@ -0,0 +1,18 @@
+package com.quran.labs.androidquran.common.audio.util
+
+import okio.FileSystem
+import okio.Path
+
+object AudioFileTools {
+
+ fun filesMatchingSuffixWithSuffixRemoved(fileSystem: FileSystem, path: Path, suffix: String): List {
+ return fileNamesMatchingSuffix(fileSystem, path, suffix)
+ .map { it.name.removeSuffix(suffix) }
+ }
+
+ private fun fileNamesMatchingSuffix(fileSystem: FileSystem, path: Path, suffix: String): List {
+ return fileSystem.listOrNull(path)
+ ?.filter { it.name.endsWith(suffix) }
+ ?: emptyList()
+ }
+}
diff --git a/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/util/AudioFileUtil.kt b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/util/AudioFileUtil.kt
index 1ee5f44793..5a40fb24f2 100644
--- a/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/util/AudioFileUtil.kt
+++ b/common/audio/src/main/java/com/quran/labs/androidquran/common/audio/util/AudioFileUtil.kt
@@ -1,18 +1,47 @@
package com.quran.labs.androidquran.common.audio.util
-import okio.FileSystem
-import okio.Path
+import com.quran.data.core.QuranFileManager
+import com.quran.labs.androidquran.common.audio.model.AudioPathInfo
+import com.quran.labs.androidquran.common.audio.model.QariItem
+import java.io.File
+import javax.inject.Inject
-object AudioFileUtil {
+class AudioFileUtil @Inject constructor(private val quranFileManager: QuranFileManager) {
- fun filesMatchingSuffixWithSuffixRemoved(fileSystem: FileSystem, path: Path, suffix: String): List {
- return fileNamesMatchingSuffix(fileSystem, path, suffix)
- .map { it.name.removeSuffix(suffix) }
+ fun getLocalQariUrl(item: QariItem): String? {
+ val rootDirectory = quranFileManager.audioFileDirectory()
+ return if (rootDirectory == null) null else rootDirectory + item.path
}
- private fun fileNamesMatchingSuffix(fileSystem: FileSystem, path: Path, suffix: String): List {
- return fileSystem.listOrNull(path)
- ?.filter { it.name.endsWith(suffix) }
- ?: emptyList()
+ fun getQariDatabasePathIfGapless(item: QariItem): String? {
+ var databaseName = item.databaseName
+ if (databaseName != null) {
+ val path = getLocalQariUrl(item)
+ if (path != null) {
+ databaseName = path + File.separator + databaseName + DB_EXTENSION
+ }
+ }
+ return databaseName
+ }
+
+ fun getLocalAudioPathInfo(qari: QariItem): AudioPathInfo? {
+ val localPath = getLocalQariUrl(qari)
+ if (localPath != null) {
+ val databasePath = getQariDatabasePathIfGapless(qari)
+ val urlFormat = if (databasePath.isNullOrEmpty()) {
+ localPath + File.separator + "%d" + File.separator +
+ "%d" + AUDIO_EXTENSION
+ } else {
+ localPath + File.separator + "%03d" + AUDIO_EXTENSION
+ }
+ return AudioPathInfo(urlFormat, localPath, databasePath)
+ }
+ return null
+ }
+
+ companion object {
+ const val AUDIO_EXTENSION = ".mp3"
+
+ private const val DB_EXTENSION = ".db"
}
}
diff --git a/common/toolbar/src/main/res/drawable-hdpi/ic_qaf.png b/common/toolbar/src/main/res/drawable-hdpi/ic_qaf.png
new file mode 100644
index 0000000000..efeb74fc25
Binary files /dev/null and b/common/toolbar/src/main/res/drawable-hdpi/ic_qaf.png differ
diff --git a/common/toolbar/src/main/res/drawable-hdpi/ic_speaker.png b/common/toolbar/src/main/res/drawable-hdpi/ic_speaker.png
new file mode 100644
index 0000000000..22d33dd552
Binary files /dev/null and b/common/toolbar/src/main/res/drawable-hdpi/ic_speaker.png differ
diff --git a/common/toolbar/src/main/res/drawable-mdpi/ic_qaf.png b/common/toolbar/src/main/res/drawable-mdpi/ic_qaf.png
new file mode 100644
index 0000000000..51bed2d502
Binary files /dev/null and b/common/toolbar/src/main/res/drawable-mdpi/ic_qaf.png differ
diff --git a/common/toolbar/src/main/res/drawable-mdpi/ic_speaker.png b/common/toolbar/src/main/res/drawable-mdpi/ic_speaker.png
new file mode 100644
index 0000000000..795d731b64
Binary files /dev/null and b/common/toolbar/src/main/res/drawable-mdpi/ic_speaker.png differ
diff --git a/common/toolbar/src/main/res/drawable-xhdpi/ic_qaf.png b/common/toolbar/src/main/res/drawable-xhdpi/ic_qaf.png
new file mode 100644
index 0000000000..002c076522
Binary files /dev/null and b/common/toolbar/src/main/res/drawable-xhdpi/ic_qaf.png differ
diff --git a/common/toolbar/src/main/res/drawable-xhdpi/ic_speaker.png b/common/toolbar/src/main/res/drawable-xhdpi/ic_speaker.png
new file mode 100644
index 0000000000..3784a535a1
Binary files /dev/null and b/common/toolbar/src/main/res/drawable-xhdpi/ic_speaker.png differ
diff --git a/common/toolbar/src/main/res/drawable-xxhdpi/ic_qaf.png b/common/toolbar/src/main/res/drawable-xxhdpi/ic_qaf.png
new file mode 100644
index 0000000000..5a00a55a55
Binary files /dev/null and b/common/toolbar/src/main/res/drawable-xxhdpi/ic_qaf.png differ
diff --git a/common/toolbar/src/main/res/drawable-xxhdpi/ic_speaker.png b/common/toolbar/src/main/res/drawable-xxhdpi/ic_speaker.png
new file mode 100644
index 0000000000..d6ebc4cc6a
Binary files /dev/null and b/common/toolbar/src/main/res/drawable-xxhdpi/ic_speaker.png differ
diff --git a/common/toolbar/src/main/res/drawable-xxxhdpi/ic_qaf.png b/common/toolbar/src/main/res/drawable-xxxhdpi/ic_qaf.png
new file mode 100644
index 0000000000..81ff927acf
Binary files /dev/null and b/common/toolbar/src/main/res/drawable-xxxhdpi/ic_qaf.png differ
diff --git a/common/toolbar/src/main/res/drawable-xxxhdpi/ic_speaker.png b/common/toolbar/src/main/res/drawable-xxxhdpi/ic_speaker.png
new file mode 100644
index 0000000000..8f09e81ad5
Binary files /dev/null and b/common/toolbar/src/main/res/drawable-xxxhdpi/ic_speaker.png differ
diff --git a/common/toolbar/src/main/res/drawable/ic_text.xml b/common/toolbar/src/main/res/drawable/ic_text.xml
new file mode 100644
index 0000000000..772216cef6
--- /dev/null
+++ b/common/toolbar/src/main/res/drawable/ic_text.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/common/toolbar/src/main/res/menu/ayah_menu.xml b/common/toolbar/src/main/res/menu/ayah_menu.xml
index bd95395f6a..7dffef4cb9 100644
--- a/common/toolbar/src/main/res/menu/ayah_menu.xml
+++ b/common/toolbar/src/main/res/menu/ayah_menu.xml
@@ -1,34 +1,47 @@
-