A|K2*!d0Yt=sz=^;Pz_K|T9t19y^kprAkphT_
z&2sAQku;)buj$0)38HEmj|_nG9XK7h05Cu5m)AYyBt2IXg;4_761W!F7We@87FY?`
zxB+OI&q(^M6htQg$#FIUK9}@!$z>672yh4RybD;;+=%d`z8^5Xwzw8fmh@4HPM_%t
zU>(z6=d&bp`c{dE!+^Uog=QFdrj_}UL6{SnZcmZ)VynVDPz@lxe>AYayNM*HL#sr@
z5x_mb%fPcq@-_svw$TZ|j~+AA2U-;l0ATIx7_R~|CAovNN&|q;E&!Y+lk>0X$kQav
zXjM1>fW0$)&X@F9=|vGS6}U5d|DrzgJaBpzNmU9(#PTk(973l^dbj8nAR;!&8L&^w
zH`hq=9YsrUn`EC59q~l5z*G9nodM0qjL_bU-!cn=}b7GhPjs;Eyoc|A(
zda2}GMC_FjczT!s&IOJ%2uTl>7*={FB96-TJWG-v{zX!oLM~umr(Oo&9prhp&*
zj>2V<&MH-03*gdZl-{gOljJ?mKoSvaWnCSRoyk1u=2E4#0NkJ5DLj3r=f-VbbMIMl
zagsQ1Ds}B32dLaynE($8xYsWTlpTa
z(QoDt8>ZKtq!WPNP04Fqq%KgiO?Q(uvRIvN&Ta2|<|Y6CFpJ#{U_sZ7^gt=p$xTE2
vXrKrT(XL|EV*tgj8q&dW1cv0;Vzqw(+|Xh`^N!J|00000NkvXXu0mjf)y^n2
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..22d33dd552b195a4a16b663b85f1a0427452fa85
GIT binary patch
literal 1150
zcmV-^1cCdBP)Px(I7vi7RA@u(m|3iyV;F^>rDkFlW9X0w<-*K`;l@0RDG?!2lqhN*f|wFBHPjFi
z7eZRxxG+SD8%-oGL<~_N>Epg#-R6LSGhlmr
z;4I)~U{~NJN#`{IupL|W2L1%Tl9b=ZH822Wz;xg$;2dDby8U%Yr!`q(dp7WBy_es2
zB>mO2Z;$}?2Ob6v0yb;8xLW}G#b{s~;6vbAN%`%#`UYToJ>XQ}86e^F?=#y1u)Q%b
zP15hS*9YbU_XF|#s|Di6P6*lpsE}v^xH)hga09SWn~Np{U^|}v6j%ma0em6Jw&RG4
zfi=MO!1I#+Xa}MbfPH{HJD`uplB_2I8+LfF9e|x;G_V!$GH|1$mA1D8-Ubc@-UsGN
z`nneY@xRuwuEcoxVz7XpjgRi#c0Jnf(ShM$)&oX8=zF#{!FiImwfWE?SoW64&u?67(+M
z-ZJQ9;BjDgV4kFfwiA+9);qrfvnBmJYydk0PXMO_Yk^skezKjC`&fm_a$t{2=2Hsr
zF2&4}p#sR|w$BD00bd6A&wF;wOfEkij+dd9>Dt`kfN_x|Fq(~Sz
z19(AFs?nriV9Em+522OCKtd?8I}#!xbhxAss+5L-6C&~?T{CnBY^QT486&grk#ySx
zNjzQBceW!610cyfUs5X7@IuITDo@I2q;+coYK$FYj#SA3vW`cGA
zwk-f(*8a~cdBZ}4Tz>;i7ojositTAN#4iB0>vp89i7ypMEhA;*dz7h5Mu(N&M#^ph
zv}l||fQNtsDt5;obvxAWTSI-ASz7b(M@@D#g-Fx>f1Z~|XVqYyi7FK)t6Kocw}ekV
z62uWp5>ibD3=BXE6EQphZmK5qqNJ3`j;kE7SB1~AZoUcSz<~p(yvV1;d?%VyQuvc5
z0KGo{UjX!KOfUOJ0DAG-Aoq+I7^F9QIcvl~FJ2quo)H6s^ky$-O?d|X2BpK+K-#iZ
QtpET307*qoM6N<$f_?P?egFUf
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..51bed2d502f70542236fd8c3b421133d30292317
GIT binary patch
literal 640
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
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..3784a535a1e9b28f9377b2016bd0c0448113e40e
GIT binary patch
literal 1528
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
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..81ff927acfa729b483ef5d6e9cefc67248b197ee
GIT binary patch
literal 3202
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
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..8f09e81ad5f53ff4a9ee4cf7e42ced8ab08ec95d
GIT binary patch
literal 3451
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
F{{Wh2AKCx_
literal 0
HcmV?d00001
diff --git a/common/toolbar/src/main/res/drawable/ic_audio.xml b/common/toolbar/src/main/res/drawable/ic_audio.xml
deleted file mode 100644
index c0d2d8d87b..0000000000
--- a/common/toolbar/src/main/res/drawable/ic_audio.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/common/toolbar/src/main/res/menu/ayah_menu.xml b/common/toolbar/src/main/res/menu/ayah_menu.xml
index 20750b1d80..7dffef4cb9 100644
--- a/common/toolbar/src/main/res/menu/ayah_menu.xml
+++ b/common/toolbar/src/main/res/menu/ayah_menu.xml
@@ -19,11 +19,11 @@
android:title="@string/share_ayah" />
-
Date: Thu, 7 Jul 2022 14:34:50 +0300
Subject: [PATCH 05/13] proper "sharable audio" name
---
.../labs/androidquran/ui/PagerActivity.java | 37 ++++++++++++++-----
1 file changed, 27 insertions(+), 10 deletions(-)
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 dd2ed639fb..e925927471 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
@@ -261,11 +261,12 @@ public class PagerActivity extends AppCompatActivity implements
private final PagerHandler handler = new PagerHandler(this);
- private Disposable timingDisposable;
- private int gaplessSura;
- private SparseIntArray gaplessSuraData = new SparseIntArray();
public static final File audioCacheDirectory= new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getPath() +
File.separator +"quran_android_cache");
+ private ArrayList audioCacheFilePaths = new ArrayList<>();
+ private SuraAyah selectedStartSuraAyah = null;
+ private SuraAyah selectedEndSuraAyah = null;
+ private QariItem selectedQari = null;
private static class PagerHandler extends Handler {
@@ -1864,7 +1865,7 @@ public void onError(@NonNull Throwable e) {
}
public void shareAyahAudio(SuraAyah start, SuraAyah end) {
- SuraAyah actualStart,actualEnd;
+ audioCacheFilePaths.clear();
if (start == null || end == null) {
return;
}else {
@@ -1877,16 +1878,16 @@ public void shareAyahAudio(SuraAyah start, SuraAyah end) {
}
kotlin.Pair pair2 = pair;
- actualStart = (SuraAyah) pair2.component1();
- actualEnd = (SuraAyah) pair2.component2();
+ selectedStartSuraAyah = (SuraAyah) pair2.component1();
+ selectedEndSuraAyah = (SuraAyah) pair2.component2();
}
- final QariItem qari = audioStatusBar.getAudioInfo();
- AudioPathInfo audioPathInfo = audioUtils.getLocalAudioPathInfo(this,qari);
+ selectedQari = audioStatusBar.getAudioInfo();
+ AudioPathInfo audioPathInfo = audioUtils.getLocalAudioPathInfo(this,selectedQari);
assert audioPathInfo != null;
if (audioPathInfo.getGaplessDatabase() != null) {
- createAndShareAudio(actualStart,actualEnd,audioPathInfo);
+ createAndShareAudio(selectedStartSuraAyah,selectedEndSuraAyah,audioPathInfo);
}
}
@@ -1942,7 +1943,10 @@ public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull ArrayList paths = new ArrayList<>();
String path1 = audioUtils.getSurahAudioPath(audioPathInfo,start.sura);
@@ -1963,7 +1967,9 @@ public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull ArrayList
Date: Thu, 7 Jul 2022 14:57:20 +0300
Subject: [PATCH 06/13] share intent title
---
app/src/main/java/com/quran/labs/androidquran/util/ShareUtil.kt | 2 +-
app/src/main/res/values-ar/strings.xml | 1 +
app/src/main/res/values-az/strings.xml | 1 +
app/src/main/res/values-bs/strings.xml | 1 +
app/src/main/res/values-de/strings.xml | 1 +
app/src/main/res/values-es/strings.xml | 1 +
app/src/main/res/values-fa/strings.xml | 1 +
app/src/main/res/values-fr/strings.xml | 1 +
app/src/main/res/values-hr/strings.xml | 1 +
app/src/main/res/values-hu/strings.xml | 1 +
app/src/main/res/values-id/strings.xml | 1 +
app/src/main/res/values-it/strings.xml | 1 +
app/src/main/res/values-kk/strings.xml | 1 +
app/src/main/res/values-ku/strings.xml | 1 +
app/src/main/res/values-ms/strings.xml | 1 +
app/src/main/res/values-nl/strings.xml | 1 +
app/src/main/res/values-pl/strings.xml | 1 +
app/src/main/res/values-pt-rBR/strings.xml | 1 +
app/src/main/res/values-ru/strings.xml | 1 +
app/src/main/res/values-sq/strings.xml | 1 +
app/src/main/res/values-sr/strings.xml | 1 +
app/src/main/res/values-sv/strings.xml | 1 +
app/src/main/res/values-th/strings.xml | 1 +
app/src/main/res/values-tr/strings.xml | 1 +
app/src/main/res/values-ug/strings.xml | 1 +
app/src/main/res/values-uk/strings.xml | 1 +
app/src/main/res/values-uz/strings.xml | 1 +
app/src/main/res/values-zh/strings.xml | 1 +
app/src/main/res/values/strings.xml | 2 ++
29 files changed, 30 insertions(+), 1 deletion(-)
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 06b8661605..7680397dcf 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
@@ -137,6 +137,6 @@ class ShareUtil @Inject internal constructor(private val quranDisplayData: Quran
shareIntent.putExtra(Intent.EXTRA_STREAM, uri)
shareIntent.type = "audio/mp3"
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- activity.startActivity(Intent.createChooser(shareIntent, "Share"))
+ activity.startActivity(Intent.createChooser(shareIntent, activity.getString(R.string.share_audio_file_title)))
}
}
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 73bc2d4901..5b205754d8 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -240,6 +240,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 9ec44ee78d..11195285fa 100644
--- a/app/src/main/res/values-az/strings.xml
+++ b/app/src/main/res/values-az/strings.xml
@@ -286,6 +286,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 e338fbdf8b..0f34787ecd 100644
--- a/app/src/main/res/values-bs/strings.xml
+++ b/app/src/main/res/values-bs/strings.xml
@@ -305,6 +305,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 bab66e2b91..ae8670b660 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -311,6 +311,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 137dbd1829..339b705e93 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -170,6 +170,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 3834c97f48..649ecb3d82 100644
--- a/app/src/main/res/values-fa/strings.xml
+++ b/app/src/main/res/values-fa/strings.xml
@@ -167,6 +167,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 b1172bd431..05d65e6d42 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -258,6 +258,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 86a3318dcc..4a1fa3d20d 100644
--- a/app/src/main/res/values-hr/strings.xml
+++ b/app/src/main/res/values-hr/strings.xml
@@ -305,6 +305,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 ad25141740..228bcf8c5b 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -234,6 +234,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 eda7bd57b3..23ac5275cf 100644
--- a/app/src/main/res/values-id/strings.xml
+++ b/app/src/main/res/values-id/strings.xml
@@ -290,6 +290,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 b7bee30bae..66b23401ea 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -123,6 +123,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 77500bfc18..f030f479ab 100644
--- a/app/src/main/res/values-kk/strings.xml
+++ b/app/src/main/res/values-kk/strings.xml
@@ -291,6 +291,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 c34e4e6625..0eebc3becd 100644
--- a/app/src/main/res/values-ku/strings.xml
+++ b/app/src/main/res/values-ku/strings.xml
@@ -187,6 +187,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 ebf680ce38..749c5f8da2 100644
--- a/app/src/main/res/values-ms/strings.xml
+++ b/app/src/main/res/values-ms/strings.xml
@@ -260,6 +260,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 6545623e91..b182bbc86c 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -282,6 +282,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 0945ece736..d2423a99b6 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -295,6 +295,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 286e311cad..3d9ddaf84d 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -205,6 +205,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 5af0673500..d3da9addd8 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -344,6 +344,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 51def7be8c..13d074e440 100644
--- a/app/src/main/res/values-sq/strings.xml
+++ b/app/src/main/res/values-sq/strings.xml
@@ -293,6 +293,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 05009fcd2a..d37de82a85 100644
--- a/app/src/main/res/values-sr/strings.xml
+++ b/app/src/main/res/values-sr/strings.xml
@@ -305,6 +305,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 43c1d06432..6e12fc4138 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -293,6 +293,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 ee9dacdc34..a38f9f2193 100644
--- a/app/src/main/res/values-th/strings.xml
+++ b/app/src/main/res/values-th/strings.xml
@@ -284,6 +284,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 9ec44ee78d..11195285fa 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -286,6 +286,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 eb2bf74b2a..497a034ad0 100644
--- a/app/src/main/res/values-ug/strings.xml
+++ b/app/src/main/res/values-ug/strings.xml
@@ -160,6 +160,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 4de0b3641e..519ed660b8 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -296,6 +296,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 f6a801f835..2187c221b0 100644
--- a/app/src/main/res/values-uz/strings.xml
+++ b/app/src/main/res/values-uz/strings.xml
@@ -319,6 +319,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 61d3a72da6..672ee8cf84 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -175,6 +175,7 @@
复制成功
+ Share Audio File
为收藏加标签
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index af568b9731..7aded67319 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -365,6 +365,7 @@
Ayah Copied
+ Share Audio File
Tag Bookmark
@@ -411,6 +412,7 @@
Download selection
Delete selection
+
Quran Audio files Update
Several Quran audio files have been updated. Quran has removed
From 4162f19436b4ae59bc69bf99f1cff55966225b71 Mon Sep 17 00:00:00 2001
From: Doozy
Date: Thu, 7 Jul 2022 15:12:00 +0300
Subject: [PATCH 07/13] [bugfix] - app was crushing when full surah is selected
---
.../quran/labs/androidquran/ui/PagerActivity.java | 12 +++++++++---
.../com/quran/labs/androidquran/util/AudioUtils.kt | 2 +-
2 files changed, 10 insertions(+), 4 deletions(-)
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 e925927471..6b4e7cb1e7 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
@@ -1883,7 +1883,7 @@ public void shareAyahAudio(SuraAyah start, SuraAyah end) {
}
selectedQari = audioStatusBar.getAudioInfo();
- AudioPathInfo audioPathInfo = audioUtils.getLocalAudioPathInfo(this,selectedQari);
+ AudioPathInfo audioPathInfo = audioUtils.getLocalAudioPathInfo(selectedQari);
assert audioPathInfo != null;
if (audioPathInfo.getGaplessDatabase() != null) {
@@ -1939,8 +1939,14 @@ public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull ArrayList
Date: Thu, 7 Jul 2022 15:23:47 +0300
Subject: [PATCH 08/13] [bugfix] - app was crushing when full surah is selected
2
---
.../java/com/quran/labs/androidquran/ui/PagerActivity.java | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
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 6b4e7cb1e7..6e7483fd3c 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
@@ -1940,10 +1940,11 @@ public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull ArrayList
Date: Thu, 7 Jul 2022 16:53:13 +0300
Subject: [PATCH 09/13] request user to download files if not present
---
.../presenter/audio/AudioPresenter.kt | 2 +-
.../labs/androidquran/ui/PagerActivity.java | 31 +++++++++++++------
.../labs/androidquran/util/AudioUtils.kt | 4 +--
3 files changed, 24 insertions(+), 13 deletions(-)
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 3f9736d8da..9bc73b3ec1 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
@@ -87,7 +87,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
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 6e7483fd3c..8f9d48c3b9 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
@@ -1866,6 +1866,7 @@ public void onError(@NonNull Throwable e) {
public void shareAyahAudio(SuraAyah start, SuraAyah end) {
audioCacheFilePaths.clear();
+
if (start == null || end == null) {
return;
}else {
@@ -1887,7 +1888,16 @@ public void shareAyahAudio(SuraAyah start, SuraAyah end) {
assert audioPathInfo != null;
if (audioPathInfo.getGaplessDatabase() != null) {
- createAndShareAudio(selectedStartSuraAyah,selectedEndSuraAyah,audioPathInfo);
+ if (!audioUtils.haveAllFiles(audioPathInfo.getUrlFormat(),audioPathInfo.getLocalDirectory(),selectedStartSuraAyah,selectedEndSuraAyah,true)){
+ AudioRequest audioRequest = new AudioRequest(
+ selectedStartSuraAyah, selectedEndSuraAyah, selectedQari, 0, 0, true, false, audioPathInfo);
+ Intent downloadIntent = audioPresenter.getDownloadIntent(this, audioRequest);
+ if (downloadIntent != null) {
+ handleRequiredDownload(downloadIntent);
+ }
+ }else{
+ createAndShareAudio(selectedStartSuraAyah,selectedEndSuraAyah,audioPathInfo);
+ }
}
}
@@ -1939,15 +1949,16 @@ public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull ArrayList
Date: Mon, 11 Jul 2022 13:47:16 +0300
Subject: [PATCH 10/13] clean up
---
.../labs/androidquran/ui/PagerActivity.java | 328 +++++++++++-------
.../labs/androidquran/util/AudioUtils.kt | 14 +-
2 files changed, 213 insertions(+), 129 deletions(-)
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 8f9d48c3b9..bbe2a8ab35 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
@@ -147,7 +147,6 @@
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
-import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.observers.DisposableObserver;
import io.reactivex.rxjava3.observers.DisposableSingleObserver;
import io.reactivex.rxjava3.schedulers.Schedulers;
@@ -228,8 +227,10 @@ public class PagerActivity extends AppCompatActivity implements
private int defaultNavigationBarColor;
private boolean isSplitScreen = false;
- @Nullable private QuranAyahInfo lastSelectedTranslationAyah;
- @Nullable private LocalTranslation[] lastActivatedLocalTranslations;
+ @Nullable
+ private QuranAyahInfo lastSelectedTranslationAyah;
+ @Nullable
+ private LocalTranslation[] lastActivatedLocalTranslations;
private PagerActivityComponent pagerActivityComponent;
@@ -243,7 +244,7 @@ public class PagerActivity extends AppCompatActivity implements
@Inject ShareUtil shareUtil;
@Inject AudioUtils audioUtils;
@Inject QuranDisplayData quranDisplayData;
- @Inject QuranInfo quranInfo;
+ @Inject QuranInfo quranInfo;
@Inject QuranFileUtils quranFileUtils;
@Inject AudioPresenter audioPresenter;
@Inject QuranEventLogger quranEventLogger;
@@ -261,8 +262,9 @@ public class PagerActivity extends AppCompatActivity implements
private final PagerHandler handler = new PagerHandler(this);
- public static final File audioCacheDirectory= new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getPath() +
- File.separator +"quran_android_cache");
+ public static final File audioCacheDirectory = new File(
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getPath() +
+ File.separator + "quran_android_cache");
private ArrayList audioCacheFilePaths = new ArrayList<>();
private SuraAyah selectedStartSuraAyah = null;
private SuraAyah selectedEndSuraAyah = null;
@@ -305,12 +307,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
@@ -356,7 +367,7 @@ public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.quran_page_activity_slider);
if (!audioCacheDirectory.exists()) {
- if (!audioCacheDirectory.mkdirs()){
+ if (!audioCacheDirectory.mkdirs()) {
Toast.makeText(PagerActivity.this, "could not create directory", Toast.LENGTH_SHORT).show();
}
}
@@ -443,7 +454,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();
@@ -563,8 +575,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;
+ }
));
}
@@ -1393,16 +1411,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);
@@ -1419,7 +1437,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;
@@ -1452,7 +1471,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);
@@ -1501,7 +1521,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();
}
@@ -1542,7 +1563,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);
}
@@ -1785,7 +1806,7 @@ 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) {
+ } 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);
@@ -1823,7 +1844,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);
}
}
@@ -1852,7 +1874,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();
}
@@ -1867,128 +1890,117 @@ public void onError(@NonNull Throwable e) {
public void shareAyahAudio(SuraAyah start, SuraAyah end) {
audioCacheFilePaths.clear();
- if (start == null || end == null) {
- return;
- }else {
- kotlin.Pair pair;
- if (start.compareTo(end) <= 0) {
- pair = TuplesKt.to(start, end);
- } else {
- Timber.Forest.e(new IllegalStateException("End isn't larger than the start: " + start + " to " + end));
- pair = TuplesKt.to(end, start);
- }
-
- kotlin.Pair pair2 = pair;
- selectedStartSuraAyah = (SuraAyah) pair2.component1();
- selectedEndSuraAyah = (SuraAyah) pair2.component2();
- }
+ kotlin.Pair pair2 = getReorderedAyatPair(start, end);
+ selectedStartSuraAyah = (SuraAyah) pair2.component1();
+ selectedEndSuraAyah = (SuraAyah) pair2.component2();
- selectedQari = audioStatusBar.getAudioInfo();
- AudioPathInfo audioPathInfo = audioUtils.getLocalAudioPathInfo(selectedQari);
+ selectedQari = audioStatusBar.getAudioInfo();
+ AudioPathInfo audioPathInfo = audioUtils.getLocalAudioPathInfo(selectedQari);
assert audioPathInfo != null;
- if (audioPathInfo.getGaplessDatabase() != null) {
- if (!audioUtils.haveAllFiles(audioPathInfo.getUrlFormat(),audioPathInfo.getLocalDirectory(),selectedStartSuraAyah,selectedEndSuraAyah,true)){
- AudioRequest audioRequest = new AudioRequest(
- selectedStartSuraAyah, selectedEndSuraAyah, selectedQari, 0, 0, true, false, audioPathInfo);
- Intent downloadIntent = audioPresenter.getDownloadIntent(this, audioRequest);
- if (downloadIntent != null) {
- handleRequiredDownload(downloadIntent);
- }
- }else{
- createAndShareAudio(selectedStartSuraAyah,selectedEndSuraAyah,audioPathInfo);
+ boolean gaplessDatabaseExists = audioPathInfo.getGaplessDatabase() != null;
+
+ if (gaplessDatabaseExists) {
+ if (audioFilesExist(audioPathInfo)) {
+ createAndShareAudio(selectedStartSuraAyah, selectedEndSuraAyah, audioPathInfo);
+ } else {
+ requestDownload(audioPathInfo);
}
}
}
+ private kotlin.Pair getReorderedAyatPair(SuraAyah start, SuraAyah end) {
+ kotlin.Pair pair;
+ if (start.compareTo(end) <= 0) {
+ pair = TuplesKt.to(start, end);
+ } else {
+ Timber.Forest.e(
+ new IllegalStateException("End isn't larger than the start: " + start + " to " + end));
+ pair = TuplesKt.to(end, start);
+ }
+ return pair;
+ }
+
+ private boolean audioFilesExist(AudioPathInfo audioPathInfo) {
+ return audioUtils.haveAllFiles(audioPathInfo.getUrlFormat(), audioPathInfo.getLocalDirectory(),
+ selectedStartSuraAyah, selectedEndSuraAyah, true);
+ }
+
private void createAndShareAudio(SuraAyah start, SuraAyah end, AudioPathInfo audioPathInfo) {
showProgressDialog();
- String databasePath = audioPathInfo.getGaplessDatabase();
compositeDisposable.add(
- Single.fromCallable(() -> {
- assert databasePath != null;
- SuraTimingDatabaseHandler db = SuraTimingDatabaseHandler.Companion.getDatabaseHandler(databasePath);
- SparseIntArray firstSurahMap = new SparseIntArray();
- SparseIntArray lastSurahMap = new SparseIntArray();
- Cursor firstSurahCursor;
- Cursor lastSurahCursor = null;
-
- try {
- firstSurahCursor = db.getAyahTimings(start.sura);
- Timber.Forest.d("got cursor of data");
- if (firstSurahCursor != null && firstSurahCursor.moveToFirst()) {
- do {
- int ayah = firstSurahCursor.getInt(1);
- int time = firstSurahCursor.getInt(2);
- firstSurahMap.put(ayah, time);
- } while (firstSurahCursor.moveToNext());
- }
-
- lastSurahCursor = db.getAyahTimings(end.sura);
- Timber.Forest.d("got cursor of data");
- if (lastSurahCursor != null && lastSurahCursor.moveToFirst()) {
- do {
- int ayah = lastSurahCursor.getInt(1);
- int time = lastSurahCursor.getInt(2);
- lastSurahMap.put(ayah, time);
- } while (lastSurahCursor.moveToNext());
- }
- } catch (SQLException sqlException) {
- Timber.Forest.e(sqlException);
- } finally {
- closeCursor(lastSurahCursor);
- }
- ArrayList mapArray = new ArrayList<>(Arrays.asList(firstSurahMap, lastSurahMap));
- return mapArray;
- }).subscribeOn(Schedulers.io())
+ Single.fromCallable(() -> getTimingData(start, end, audioPathInfo))
+ .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSingleObserver>() {
@Override
- public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull ArrayList sparseIntArrayList) {
+ public void onSuccess(
+ @io.reactivex.rxjava3.annotations.NonNull ArrayList sparseIntArrayList) {
Intrinsics.checkNotNullExpressionValue(sparseIntArrayList, "mapArray");
int startAyah = start.ayah;
int endAyah = end.ayah;
- int startAyahTime = 0;
- int endAyahTime = sparseIntArrayList.get(1).get(endAyah+1);
-
- if (startAyah!=1){
- startAyahTime = sparseIntArrayList.get(0).get(startAyah);
+ SparseIntArray startSurahTimingDataArray = sparseIntArrayList.get(0);
+ SparseIntArray endSurahTimingDataArray = sparseIntArrayList.get(1);
+ int startAyahTime;
+ int endAyahTime;
+
+ boolean isFirstAyahInSurah = startAyah == 1;
+ int startTimeOfAyahAfterEndAyah = endSurahTimingDataArray.get(endAyah + 1);
+ boolean isLastAyahInSurah = startTimeOfAyahAfterEndAyah == 0;
+
+ if (isFirstAyahInSurah) {
+ startAyahTime = 0;
+ } else {
+ startAyahTime = startSurahTimingDataArray.get(startAyah);
}
- if (endAyahTime == 0){
- endAyahTime = audioUtils.getSurahDuration(PagerActivity.this,audioUtils.getSurahAudioPath(audioPathInfo,end.sura));
+
+ if (isLastAyahInSurah) {
+ endAyahTime = audioUtils.getSurahDuration(PagerActivity.this,
+ audioUtils.getSurahAudioPath(audioPathInfo, end.sura));
+ } else {
+ endAyahTime = startTimeOfAyahAfterEndAyah;
}
+ boolean startAndEndAyahAreInSameSurah = start.sura == end.sura;
- if (start.sura == end.sura){
- String audioSegmentPath = audioUtils.getSurahSegment(audioUtils.getSurahAudioPath(audioPathInfo,start.sura),startAyahTime,endAyahTime);
+ if (startAndEndAyahAreInSameSurah) {
+ String audioSegmentPath = audioUtils.getSurahSegment(
+ audioUtils.getSurahAudioPath(audioPathInfo, start.sura), startAyahTime,
+ endAyahTime);
audioCacheFilePaths.add(audioSegmentPath);
- renameSharableAudioFile(audioSegmentPath);
- shareUtil.shareAudioFileIntent(PagerActivity.this,new File(audioSegmentPath));
- }else {
- ArrayList paths = new ArrayList<>();
- String path1 = audioUtils.getSurahAudioPath(audioPathInfo,start.sura);
- int upperCut = audioUtils.getSurahDuration(PagerActivity.this,path1);
- String firstSegment = audioUtils.getSurahSegment(path1,startAyahTime,upperCut);
- String path2 = audioUtils.getSurahAudioPath(audioPathInfo,end.sura);
- String lastSegment = audioUtils.getSurahSegment(path2,0,endAyahTime);
-
- for (int surahIndex = start.sura; surahIndex<=end.sura; surahIndex++){
- if (surahIndex == start.sura){
- paths.add(firstSegment);
+ shareAudioSegment(renameSharableAudioFile(audioSegmentPath));
+ } else {
+ ArrayList segmentPaths = new ArrayList<>();
+ int endOfSurah = -1;
+ int startOfSurah = 0;
+ String startSegmentPath = getSurahSegmentPath(audioPathInfo, start.sura,
+ startAyahTime, endOfSurah);
+ String lastSegmentPath = getSurahSegmentPath(audioPathInfo, end.sura,
+ startOfSurah, endAyahTime);
+
+ for (int surahIndex = start.sura; surahIndex <= end.sura; surahIndex++) {
+ boolean isTheFirstSurah = surahIndex == start.sura;
+ boolean isMiddleSurah = (surahIndex != start.sura) && (surahIndex != end.sura);
+
+ if (isTheFirstSurah) {
+ segmentPaths.add(startSegmentPath);
continue;
}
- if (surahIndex != end.sura){
- paths.add(audioUtils.getSurahAudioPath(audioPathInfo,surahIndex));
+ if (isMiddleSurah) {
+ segmentPaths.add(audioUtils.getSurahAudioPath(audioPathInfo, surahIndex));
continue;
}
- paths.add(lastSegment);
+ segmentPaths.add(lastSegmentPath);
}
- if (!paths.isEmpty()){
- audioCacheFilePaths.addAll(paths);
- File sharableAudioFile = audioUtils.getMergedAudioFromSegments(paths);
- renameSharableAudioFile(sharableAudioFile.getPath());
- shareUtil.shareAudioFileIntent(PagerActivity.this,sharableAudioFile);
+
+ boolean audioSegmentsWereCreated = !segmentPaths.isEmpty();
+
+ if (audioSegmentsWereCreated) {
+ audioCacheFilePaths.addAll(segmentPaths);
+ String sharableAudioFilePath = audioUtils.getMergedAudioFromSegments(
+ segmentPaths);
+ shareAudioSegment(renameSharableAudioFile(sharableAudioFilePath));
}
}
dismissProgressDialog();
@@ -1997,21 +2009,93 @@ public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull ArrayList getTimingData(SuraAyah start, SuraAyah end,
+ AudioPathInfo audioPathInfo) {
+ String databasePath = audioPathInfo.getGaplessDatabase();
+
+ assert databasePath != null;
+ SuraTimingDatabaseHandler db = SuraTimingDatabaseHandler.Companion.getDatabaseHandler(
+ databasePath);
+ SparseIntArray firstSurahMap = new SparseIntArray();
+ SparseIntArray lastSurahMap = new SparseIntArray();
+ Cursor firstSurahCursor = null;
+ Cursor lastSurahCursor = null;
+
+ try {
+ firstSurahCursor = db.getAyahTimings(start.sura);
+ firstSurahMap = populateArrayFromCursor(firstSurahCursor);
+
+ lastSurahCursor = db.getAyahTimings(end.sura);
+ lastSurahMap = populateArrayFromCursor(lastSurahCursor);
+
+ } catch (SQLException sqlException) {
+ Timber.Forest.e(sqlException);
+ } finally {
+ closeCursor(firstSurahCursor);
+ closeCursor(lastSurahCursor);
+ }
+
+ ArrayList mapArray = new ArrayList<>(
+ Arrays.asList(firstSurahMap, lastSurahMap));
+ return mapArray;
+ }
+
+ private SparseIntArray populateArrayFromCursor(Cursor cursor) {
+ SparseIntArray sparseIntArray = new SparseIntArray();
+ if (cursor != null && cursor.moveToFirst()) {
+ do {
+ int ayah = cursor.getInt(1);
+ int time = cursor.getInt(2);
+ sparseIntArray.put(ayah, time);
+ } while (cursor.moveToNext());
+ }
+ return sparseIntArray;
+ }
+
+ private String renameSharableAudioFile(String audioSegmentPath) {
String newAudioFileName = selectedQari.getPath() + "_" + selectedStartSuraAyah.sura + "-" + selectedStartSuraAyah.ayah + "_" + selectedEndSuraAyah.sura + "-" + selectedEndSuraAyah.ayah;
- String newAudioFilePath = audioCacheDirectory + File.separator+ newAudioFileName + ".mp3";
+ String newAudioFilePath = audioCacheDirectory + File.separator + newAudioFileName + ".mp3";
new File(audioSegmentPath).renameTo(new File(newAudioFilePath));
audioCacheFilePaths.remove(audioSegmentPath);
- for (String path : audioCacheFilePaths){
+ for (String path : audioCacheFilePaths) {
new File(path).delete();
}
audioCacheFilePaths.clear();
+ return newAudioFilePath;
+ }
+
+ private void shareAudioSegment(String path) {
+ shareUtil.shareAudioFileIntent(PagerActivity.this, new File(path));
+ }
+
+ private String getSurahSegmentPath(AudioPathInfo audioPathInfo, int surah,
+ int startAyahTime, int endAyahTime) {
+ int lowerBoundTime = startAyahTime;
+ int upperBoundTime = endAyahTime;
+
+ String audioFilePath = audioUtils.getSurahAudioPath(audioPathInfo, surah);
+ boolean isFirstSegment = endAyahTime < 0;
+
+ if (isFirstSegment) {
+ upperBoundTime = audioUtils.getSurahDuration(PagerActivity.this, audioFilePath);
+ }
+
+ return audioUtils.getSurahSegment(audioFilePath, lowerBoundTime, upperBoundTime);
+ }
+
+ private void requestDownload(AudioPathInfo audioPathInfo) {
+ AudioRequest audioRequest = new AudioRequest(
+ selectedStartSuraAyah, selectedEndSuraAyah, selectedQari, 0, 0, true, false, audioPathInfo);
+
+ Intent downloadIntent = audioPresenter.getDownloadIntent(this, audioRequest);
+ if (downloadIntent != null) {
+ handleRequiredDownload(downloadIntent);
+ }
}
private void showProgressDialog() {
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 e41e4e364f..b9bd9f6be8 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
@@ -306,14 +306,14 @@ class AudioUtils @Inject constructor(
return null
}
- fun getMergedAudioFromSegments(segments: ArrayList): File {
+ fun getMergedAudioFromSegments(segments: ArrayList): String {
var mergedAudioPath = segments[0]
if (segments.size > 1) {
for (i in 1 until segments.size) {
mergedAudioPath = mergeAudios(mergedAudioPath, segments[i])!!
}
}
- return File(mergedAudioPath)
+ return mergedAudioPath
}
private fun mergeAudios(path1: String, path2: String): String? {
@@ -353,26 +353,26 @@ class AudioUtils @Inject constructor(
}
fun getSurahSegment(path: String, lowerCut: Int, upperCut: Int): String? {
+ if (lowerCut == 0 && upperCut == 0) {
+ return null
+ }
val tempAudioName = UUID.randomUUID().toString() + ".mp3"
val destFile = File(PagerActivity.audioCacheDirectory.path + File.separator + tempAudioName)
val mSoundFile = arrayOfNulls(1)
try {
mSoundFile[0] = CheapSoundFile.create(path, null)
- if (lowerCut == 0 && upperCut == 0) {
- return null
- }
val startTime = lowerCut.toFloat() / 1000
val endTime = upperCut.toFloat() / 1000
val samplesPerFrame = mSoundFile[0]?.samplesPerFrame
val sampleRate = mSoundFile[0]?.sampleRate
val avg = sampleRate?.div(samplesPerFrame!!)
val startFrames = (startTime * avg!!).roundToInt()
- val endFrames = (endTime * avg!!).roundToInt()
+ val endFrames = (endTime * avg).roundToInt()
mSoundFile[0]?.WriteFile(destFile, startFrames, endFrames - startFrames)
} catch (e: IOException) {
e.printStackTrace()
}
- return destFile.path
+ return destFile.absolutePath
}
fun getSurahDuration(context: Context,path: String): Int {
From cf84a9571ec6dd647ee252f5b2d3204100e99870 Mon Sep 17 00:00:00 2001
From: Doozy
Date: Sat, 30 Jul 2022 11:21:24 +0300
Subject: [PATCH 11/13] transffered to audio feature
---
.../labs/androidquran/ui/PagerActivity.java | 165 +----------
.../labs/androidquran/util/AudioUtils.kt | 91 +-----
feature/audio/build.gradle | 3 +
.../database/SuraTimingDatabaseHandler.kt | 126 +++++++++
.../feature/audio/util/AudioShareUtils.kt | 259 ++++++++++++++++++
.../audio/util/soundfile}/CheapMP3.java | 2 +-
.../audio/util/soundfile}/CheapSoundFile.java | 5 +-
7 files changed, 400 insertions(+), 251 deletions(-)
create mode 100644 feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/database/SuraTimingDatabaseHandler.kt
create mode 100644 feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt
rename {app/src/main/java/com/quran/labs/androidquran/util/audioConversionUtils => feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/soundfile}/CheapMP3.java (99%)
rename {app/src/main/java/com/quran/labs/androidquran/util/audioConversionUtils => feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/soundfile}/CheapSoundFile.java (97%)
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 bbe2a8ab35..891ab2c90d 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
@@ -85,6 +85,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.audio.util.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;
@@ -1902,7 +1903,11 @@ public void shareAyahAudio(SuraAyah start, SuraAyah end) {
if (gaplessDatabaseExists) {
if (audioFilesExist(audioPathInfo)) {
- createAndShareAudio(selectedStartSuraAyah, selectedEndSuraAyah, audioPathInfo);
+ AudioShareUtils audioShareUtils = new AudioShareUtils();
+ String path = audioShareUtils.createSharableAudioFile(this, selectedStartSuraAyah,
+ selectedEndSuraAyah, selectedQari, audioPathInfo.getUrlFormat(),
+ audioPathInfo.getGaplessDatabase());
+ shareAudioSegment(path);
} else {
requestDownload(audioPathInfo);
}
@@ -1926,168 +1931,10 @@ private boolean audioFilesExist(AudioPathInfo audioPathInfo) {
selectedStartSuraAyah, selectedEndSuraAyah, true);
}
- private void createAndShareAudio(SuraAyah start, SuraAyah end, AudioPathInfo audioPathInfo) {
- showProgressDialog();
- compositeDisposable.add(
- Single.fromCallable(() -> getTimingData(start, end, audioPathInfo))
- .subscribeOn(Schedulers.io())
- .observeOn(AndroidSchedulers.mainThread())
- .subscribeWith(new DisposableSingleObserver>() {
- @Override
- public void onSuccess(
- @io.reactivex.rxjava3.annotations.NonNull ArrayList sparseIntArrayList) {
- Intrinsics.checkNotNullExpressionValue(sparseIntArrayList, "mapArray");
-
- int startAyah = start.ayah;
- int endAyah = end.ayah;
- SparseIntArray startSurahTimingDataArray = sparseIntArrayList.get(0);
- SparseIntArray endSurahTimingDataArray = sparseIntArrayList.get(1);
- int startAyahTime;
- int endAyahTime;
-
- boolean isFirstAyahInSurah = startAyah == 1;
- int startTimeOfAyahAfterEndAyah = endSurahTimingDataArray.get(endAyah + 1);
- boolean isLastAyahInSurah = startTimeOfAyahAfterEndAyah == 0;
-
- if (isFirstAyahInSurah) {
- startAyahTime = 0;
- } else {
- startAyahTime = startSurahTimingDataArray.get(startAyah);
- }
-
- if (isLastAyahInSurah) {
- endAyahTime = audioUtils.getSurahDuration(PagerActivity.this,
- audioUtils.getSurahAudioPath(audioPathInfo, end.sura));
- } else {
- endAyahTime = startTimeOfAyahAfterEndAyah;
- }
-
- boolean startAndEndAyahAreInSameSurah = start.sura == end.sura;
-
- if (startAndEndAyahAreInSameSurah) {
- String audioSegmentPath = audioUtils.getSurahSegment(
- audioUtils.getSurahAudioPath(audioPathInfo, start.sura), startAyahTime,
- endAyahTime);
- audioCacheFilePaths.add(audioSegmentPath);
- shareAudioSegment(renameSharableAudioFile(audioSegmentPath));
- } else {
- ArrayList segmentPaths = new ArrayList<>();
- int endOfSurah = -1;
- int startOfSurah = 0;
- String startSegmentPath = getSurahSegmentPath(audioPathInfo, start.sura,
- startAyahTime, endOfSurah);
- String lastSegmentPath = getSurahSegmentPath(audioPathInfo, end.sura,
- startOfSurah, endAyahTime);
-
- for (int surahIndex = start.sura; surahIndex <= end.sura; surahIndex++) {
- boolean isTheFirstSurah = surahIndex == start.sura;
- boolean isMiddleSurah = (surahIndex != start.sura) && (surahIndex != end.sura);
-
- if (isTheFirstSurah) {
- segmentPaths.add(startSegmentPath);
- continue;
- }
- if (isMiddleSurah) {
- segmentPaths.add(audioUtils.getSurahAudioPath(audioPathInfo, surahIndex));
- continue;
- }
- segmentPaths.add(lastSegmentPath);
- }
-
- boolean audioSegmentsWereCreated = !segmentPaths.isEmpty();
-
- if (audioSegmentsWereCreated) {
- audioCacheFilePaths.addAll(segmentPaths);
- String sharableAudioFilePath = audioUtils.getMergedAudioFromSegments(
- segmentPaths);
- shareAudioSegment(renameSharableAudioFile(sharableAudioFilePath));
- }
- }
- dismissProgressDialog();
- }
-
- @Override
- public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
- dismissProgressDialog();
- }
- })
- );
- }
-
- private ArrayList getTimingData(SuraAyah start, SuraAyah end,
- AudioPathInfo audioPathInfo) {
- String databasePath = audioPathInfo.getGaplessDatabase();
-
- assert databasePath != null;
- SuraTimingDatabaseHandler db = SuraTimingDatabaseHandler.Companion.getDatabaseHandler(
- databasePath);
- SparseIntArray firstSurahMap = new SparseIntArray();
- SparseIntArray lastSurahMap = new SparseIntArray();
- Cursor firstSurahCursor = null;
- Cursor lastSurahCursor = null;
-
- try {
- firstSurahCursor = db.getAyahTimings(start.sura);
- firstSurahMap = populateArrayFromCursor(firstSurahCursor);
-
- lastSurahCursor = db.getAyahTimings(end.sura);
- lastSurahMap = populateArrayFromCursor(lastSurahCursor);
-
- } catch (SQLException sqlException) {
- Timber.Forest.e(sqlException);
- } finally {
- closeCursor(firstSurahCursor);
- closeCursor(lastSurahCursor);
- }
-
- ArrayList mapArray = new ArrayList<>(
- Arrays.asList(firstSurahMap, lastSurahMap));
- return mapArray;
- }
-
- private SparseIntArray populateArrayFromCursor(Cursor cursor) {
- SparseIntArray sparseIntArray = new SparseIntArray();
- if (cursor != null && cursor.moveToFirst()) {
- do {
- int ayah = cursor.getInt(1);
- int time = cursor.getInt(2);
- sparseIntArray.put(ayah, time);
- } while (cursor.moveToNext());
- }
- return sparseIntArray;
- }
-
- private String renameSharableAudioFile(String audioSegmentPath) {
- String newAudioFileName = selectedQari.getPath() + "_" + selectedStartSuraAyah.sura + "-" + selectedStartSuraAyah.ayah + "_" + selectedEndSuraAyah.sura + "-" + selectedEndSuraAyah.ayah;
- String newAudioFilePath = audioCacheDirectory + File.separator + newAudioFileName + ".mp3";
- new File(audioSegmentPath).renameTo(new File(newAudioFilePath));
- audioCacheFilePaths.remove(audioSegmentPath);
- for (String path : audioCacheFilePaths) {
- new File(path).delete();
- }
- audioCacheFilePaths.clear();
- return newAudioFilePath;
- }
-
private void shareAudioSegment(String path) {
shareUtil.shareAudioFileIntent(PagerActivity.this, new File(path));
}
- private String getSurahSegmentPath(AudioPathInfo audioPathInfo, int surah,
- int startAyahTime, int endAyahTime) {
- int lowerBoundTime = startAyahTime;
- int upperBoundTime = endAyahTime;
-
- String audioFilePath = audioUtils.getSurahAudioPath(audioPathInfo, surah);
- boolean isFirstSegment = endAyahTime < 0;
-
- if (isFirstSegment) {
- upperBoundTime = audioUtils.getSurahDuration(PagerActivity.this, audioFilePath);
- }
-
- return audioUtils.getSurahSegment(audioFilePath, lowerBoundTime, upperBoundTime);
- }
-
private void requestDownload(AudioPathInfo audioPathInfo) {
AudioRequest audioRequest = new AudioRequest(
selectedStartSuraAyah, selectedEndSuraAyah, selectedQari, 0, 0, true, false, audioPathInfo);
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 b9bd9f6be8..4df8b728cf 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
@@ -2,11 +2,7 @@ package com.quran.labs.androidquran.util
import android.content.Context
import android.content.Intent
-import android.media.MediaMetadataRetriever
-import android.net.Uri
import androidx.annotation.VisibleForTesting
-import androidx.core.content.ContextCompat.startActivity
-import androidx.core.content.FileProvider
import com.quran.data.core.QuranInfo
import com.quran.data.model.SuraAyah
import com.quran.labs.androidquran.common.audio.model.AudioConfiguration
@@ -14,13 +10,10 @@ import com.quran.labs.androidquran.common.audio.model.QariItem
import com.quran.labs.androidquran.common.audio.util.QariUtil
import com.quran.labs.androidquran.dao.audio.AudioPathInfo
import com.quran.labs.androidquran.service.AudioService
-import com.quran.labs.androidquran.ui.PagerActivity
-import com.quran.labs.androidquran.util.audioConversionUtils.CheapSoundFile
import timber.log.Timber
-import java.io.*
-import java.util.*
+import java.io.File
+import java.util.Locale
import javax.inject.Inject
-import kotlin.math.roundToInt
class AudioUtils @Inject constructor(
private val quranInfo: QuranInfo,
@@ -306,86 +299,6 @@ class AudioUtils @Inject constructor(
return null
}
- fun getMergedAudioFromSegments(segments: ArrayList): String {
- var mergedAudioPath = segments[0]
- if (segments.size > 1) {
- for (i in 1 until segments.size) {
- mergedAudioPath = mergeAudios(mergedAudioPath, segments[i])!!
- }
- }
- return mergedAudioPath
- }
-
- private fun mergeAudios(path1: String, path2: String): String? {
- val tempAudioName = UUID.randomUUID().toString() + ".mp3"
- val destFile = File(PagerActivity.audioCacheDirectory.path + File.separator + tempAudioName)
- try {
- val fileInputStream = FileInputStream(path1)
- val bArr = ByteArray(1048576)
- val fileOutputStream = FileOutputStream(destFile)
- while (true) {
- val read = fileInputStream.read(bArr)
- if (read == -1) {
- break
- }
- fileOutputStream.write(bArr, 0, read)
- fileOutputStream.flush()
- }
- fileInputStream.close()
- val fileInputStream2 = FileInputStream(path2)
- while (true) {
- val read2 = fileInputStream2.read(bArr)
- if (read2 == -1) {
- break
- }
- fileOutputStream.write(bArr, 0, read2)
- fileOutputStream.flush()
- }
- fileInputStream2.close()
- fileOutputStream.close()
- return destFile.path
- } catch (e2: FileNotFoundException) {
- e2.printStackTrace()
- } catch (e: IOException) {
- e.printStackTrace()
- }
- return null
- }
-
- fun getSurahSegment(path: String, lowerCut: Int, upperCut: Int): String? {
- if (lowerCut == 0 && upperCut == 0) {
- return null
- }
- val tempAudioName = UUID.randomUUID().toString() + ".mp3"
- val destFile = File(PagerActivity.audioCacheDirectory.path + File.separator + tempAudioName)
- val mSoundFile = arrayOfNulls(1)
- try {
- mSoundFile[0] = CheapSoundFile.create(path, null)
- val startTime = lowerCut.toFloat() / 1000
- val endTime = upperCut.toFloat() / 1000
- val samplesPerFrame = mSoundFile[0]?.samplesPerFrame
- val sampleRate = mSoundFile[0]?.sampleRate
- val avg = sampleRate?.div(samplesPerFrame!!)
- val startFrames = (startTime * avg!!).roundToInt()
- val endFrames = (endTime * avg).roundToInt()
- mSoundFile[0]?.WriteFile(destFile, startFrames, endFrames - startFrames)
- } catch (e: IOException) {
- e.printStackTrace()
- }
- return destFile.absolutePath
- }
-
- fun getSurahDuration(context: Context,path: String): Int {
- val mmr = MediaMetadataRetriever()
- mmr.setDataSource(context, Uri.parse(path))
- val durationStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
- return durationStr!!.toInt()
- }
-
- fun getSurahAudioPath(audioPathInfo: AudioPathInfo, surah: Int): String? {
- return String.format(Locale.US, audioPathInfo.urlFormat, surah)
- }
-
companion object {
const val ZIP_EXTENSION = ".zip"
const val AUDIO_EXTENSION = ".mp3"
diff --git a/feature/audio/build.gradle b/feature/audio/build.gradle
index 43eeea22b8..b04dd3534e 100644
--- a/feature/audio/build.gradle
+++ b/feature/audio/build.gradle
@@ -23,6 +23,7 @@ android {
dependencies {
implementation project(path: ':common:audio')
+ implementation project(path: ':common:data')
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${coroutinesVersion}"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${coroutinesVersion}"
@@ -36,4 +37,6 @@ dependencies {
testImplementation "junit:junit:${junitVersion}"
testImplementation "com.google.truth:truth:${truthVersion}"
+
+ implementation 'com.jakewharton.timber:timber:5.0.1'
}
diff --git a/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/database/SuraTimingDatabaseHandler.kt b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/database/SuraTimingDatabaseHandler.kt
new file mode 100644
index 0000000000..70db297573
--- /dev/null
+++ b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/database/SuraTimingDatabaseHandler.kt
@@ -0,0 +1,126 @@
+package com.quran.labs.androidquran.feature.audio.database
+
+import android.database.Cursor
+import android.database.DefaultDatabaseErrorHandler
+import android.database.sqlite.SQLiteDatabase
+import android.database.sqlite.SQLiteDatabaseCorruptException
+import timber.log.Timber
+import java.io.File
+import java.lang.Exception
+import java.sql.SQLException
+import java.util.HashMap
+
+class SuraTimingDatabaseHandler private constructor(path: String) {
+ private var database: SQLiteDatabase? = null
+
+ object TimingsTable {
+ const val TABLE_NAME = "timings"
+ const val COL_SURA = "sura"
+ const val COL_AYAH = "ayah"
+ const val COL_TIME = "time"
+ }
+
+ object PropertiesTable {
+ const val TABLE_NAME = "properties"
+ const val COL_PROPERTY = "property"
+ const val COL_VALUE = "value"
+ }
+
+ companion object {
+ private val databaseMap: MutableMap = HashMap()
+
+ @JvmStatic
+ @Synchronized
+ fun getDatabaseHandler(path: String): SuraTimingDatabaseHandler {
+ var handler = databaseMap[path]
+ if (handler == null) {
+ handler = SuraTimingDatabaseHandler(path)
+ databaseMap[path] = handler
+ }
+ return handler
+ }
+
+ @Synchronized
+ fun clearDatabaseHandlerIfExists(databasePath: String) {
+ try {
+ val handler = databaseMap.remove(databasePath)
+ if (handler != null) {
+ handler.database?.close()
+ databaseMap.remove(databasePath)
+ }
+ } catch (e: Exception) {
+ Timber.e(e)
+ }
+ }
+ }
+
+ init {
+ Timber.d("opening gapless data file, %s", path)
+ database = try {
+ SQLiteDatabase.openDatabase(
+ path, null,
+ SQLiteDatabase.NO_LOCALIZED_COLLATORS, DefaultDatabaseErrorHandler()
+ )
+ } catch (sce: SQLiteDatabaseCorruptException) {
+ Timber.d("database corrupted: %s", path)
+ null
+ } catch (se: SQLException) {
+ Timber.d("database at $path ${if (File(path).exists()) "exists " else "doesn 't exist"}")
+ Timber.e(se)
+ null
+ }
+ }
+
+ private fun validDatabase(): Boolean = database?.isOpen ?: false
+
+ fun getAyahTimings(sura: Int): Cursor? {
+ if (!validDatabase()) return null
+
+ return try {
+ database?.query(
+ TimingsTable.TABLE_NAME, arrayOf(
+ TimingsTable.COL_SURA,
+ TimingsTable.COL_AYAH, TimingsTable.COL_TIME
+ ),
+ TimingsTable.COL_SURA + "=" + sura,
+ null, null, null, TimingsTable.COL_AYAH + " ASC"
+ )
+ } catch (e: Exception) {
+ null
+ }
+ }
+
+ fun getVersion(): Int {
+ if (!validDatabase()) {
+ return -1
+ }
+ var cursor: Cursor? = null
+ return try {
+ cursor = database?.query(
+ PropertiesTable.TABLE_NAME, arrayOf(PropertiesTable.COL_VALUE),
+ PropertiesTable.COL_PROPERTY + "= 'version'", null, null, null, null
+ )
+ if (cursor != null && cursor.moveToFirst()) {
+ cursor.getInt(0)
+ } else {
+ 1
+ }
+ } catch (e: Exception) {
+ 1
+ } finally {
+ DatabaseUtils.closeCursor(cursor)
+ }
+ }
+
+ object DatabaseUtils {
+ @JvmStatic
+ fun closeCursor(cursor: Cursor?) {
+ try {
+ cursor?.close()
+ } catch (e: Exception) {
+ // no op
+ }
+ }
+ }
+}
+
diff --git a/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt
new file mode 100644
index 0000000000..95c7d8062f
--- /dev/null
+++ b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt
@@ -0,0 +1,259 @@
+package com.quran.labs.androidquran.feature.audio.util
+
+import android.content.Context
+import android.database.Cursor
+import android.database.SQLException
+import android.media.MediaMetadataRetriever
+import android.net.Uri
+import android.os.Environment
+import android.util.SparseIntArray
+import com.quran.data.model.SuraAyah
+import com.quran.labs.androidquran.common.audio.model.QariItem
+import com.quran.labs.androidquran.feature.audio.database.SuraTimingDatabaseHandler
+import com.quran.labs.androidquran.feature.audio.database.SuraTimingDatabaseHandler.DatabaseUtils.closeCursor
+import com.quran.labs.androidquran.feature.audio.util.soundfile.CheapSoundFile
+import kotlinx.coroutines.*
+import okio.BufferedSink
+import okio.buffer
+import okio.sink
+import okio.source
+import timber.log.Timber
+import java.io.File
+import java.io.FileNotFoundException
+import java.io.IOException
+import java.util.Locale
+import java.util.UUID
+import kotlin.math.roundToInt
+
+class AudioShareUtils {
+
+ val audioCacheDirectory = File(
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).path +
+ File.separator + "quran_android_cache")
+ var audioCacheFilePaths: MutableList = ArrayList()
+ var selectedQari: QariItem? = null
+ var selectedStartSuraAyah: SuraAyah? = null
+ var selectedEndSuraAyah: SuraAyah? = null
+
+
+ data class ProperAyahOrder(val start: SuraAyah, val end: SuraAyah)
+
+ private fun getReorderedAyahPair(start: SuraAyah, end: SuraAyah): ProperAyahOrder {
+ val (actualStart, actualEnd) = if (start <= end) {
+ start to end
+ } else {
+ end to start
+ }
+ return ProperAyahOrder(actualStart, actualEnd)
+ }
+
+
+ fun createSharableAudioFile(context: Context, start: SuraAyah, end: SuraAyah, qari: QariItem, urlFormat: String, gaplessDatabase: String): String? {
+ selectedStartSuraAyah = getReorderedAyahPair(start, end).start
+ selectedEndSuraAyah = getReorderedAyahPair(start, end).end
+ selectedQari = qari
+
+ var sharablePath: String? = null
+
+ return runBlocking {
+ GlobalScope.launch(Dispatchers.IO) {
+ val mapArray = async {
+ getTimingData(start, end, gaplessDatabase)
+ }.await()
+
+ val startAyah = start.ayah
+ val endAyah = end.ayah
+ val startSurahTimingDataArray: SparseIntArray = mapArray[0]
+ val endSurahTimingDataArray: SparseIntArray = mapArray[1]
+
+ val isFirstAyahInSurah = startAyah == 1
+ val startTimeOfAyahAfterEndAyah = endSurahTimingDataArray[endAyah + 1]
+ val isLastAyahInSurah = startTimeOfAyahAfterEndAyah == 0
+
+ val startAyahTime = if (isFirstAyahInSurah) {
+ 0
+ } else {
+ startSurahTimingDataArray[startAyah]
+ }
+
+ val endAyahTime = if (isLastAyahInSurah) {
+ getSurahDuration(context,
+ getSurahAudioPath(urlFormat, end.sura)!!)
+ } else {
+ startTimeOfAyahAfterEndAyah
+ }
+
+ val startAndEndAyahAreInSameSurah = start.sura == end.sura
+
+ if (startAndEndAyahAreInSameSurah) {
+ val audioSegmentPath: String = getSurahSegment(
+ getSurahAudioPath(urlFormat, start.sura)!!, startAyahTime,
+ endAyahTime)!!
+ audioCacheFilePaths.add(audioSegmentPath)
+ sharablePath = getRenamedSharableAudioFile(audioSegmentPath)
+ } else {
+ val segmentPaths = java.util.ArrayList()
+ val endOfSurah = -1
+ val startOfSurah = 0
+ val startSegmentPath: String = getSurahSegmentPath(context, urlFormat, start.sura,
+ startAyahTime, endOfSurah)
+ val lastSegmentPath: String = getSurahSegmentPath(context, urlFormat, end.sura,
+ startOfSurah, endAyahTime)
+
+ for (surahIndex in start.sura..end.sura) {
+ val isTheFirstSurah = surahIndex == start.sura
+ val isMiddleSurah = surahIndex != start.sura && surahIndex != end.sura
+ if (isTheFirstSurah) {
+ segmentPaths.add(startSegmentPath)
+ audioCacheFilePaths.add(startSegmentPath)
+ continue
+ }
+ if (isMiddleSurah) {
+ segmentPaths.add(getSurahAudioPath(urlFormat, surahIndex)!!)
+ continue
+ }
+ segmentPaths.add(lastSegmentPath)
+ audioCacheFilePaths.add(lastSegmentPath)
+ }
+
+ val audioSegmentsWereCreated = segmentPaths.isNotEmpty()
+
+ if (audioSegmentsWereCreated) {
+ val sharableAudioFilePath: String = getMergedAudioFromSegments(
+ segmentPaths)
+ sharablePath = getRenamedSharableAudioFile(sharableAudioFilePath)
+ } else {
+ sharablePath = null
+ }
+ }
+ }.join()
+ return@runBlocking sharablePath
+ }
+
+ }
+
+ private fun getSurahSegmentPath(context: Context, urlFormat: String, surah: Int,
+ startAyahTime: Int, endAyahTime: Int): String {
+ var upperBoundTime = endAyahTime
+ val audioFilePath: String = getSurahAudioPath(urlFormat, surah)!!
+ val isFirstSegment = endAyahTime < 0
+ if (isFirstSegment) {
+ upperBoundTime = getSurahDuration(context, audioFilePath)
+ }
+ return getSurahSegment(audioFilePath, startAyahTime, upperBoundTime)!!
+ }
+
+ private fun getRenamedSharableAudioFile(audioSegmentPath: String): String {
+ val newAudioFileName: String = selectedQari!!.path + "_" + selectedStartSuraAyah!!.sura + "-" + selectedStartSuraAyah!!.ayah + "_" + selectedEndSuraAyah!!.sura + "-" + selectedEndSuraAyah!!.ayah
+ val newAudioFilePath: String = audioCacheDirectory.toString() + File.separator + newAudioFileName + ".mp3"
+ File(audioSegmentPath).renameTo(File(newAudioFilePath))
+ audioCacheFilePaths.remove(audioSegmentPath)
+ for (path in audioCacheFilePaths) {
+ File(path).delete()
+ }
+ audioCacheFilePaths.clear()
+ return newAudioFilePath
+ }
+
+ private fun getSurahDuration(context: Context, path: String): Int {
+ val mmr = MediaMetadataRetriever()
+ mmr.setDataSource(context, Uri.parse(path))
+ val durationStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)
+ return durationStr!!.toInt()
+ }
+
+ private fun getSurahAudioPath(urlFormat: String, surah: Int): String? {
+ return String.format(Locale.US, urlFormat, surah)
+ }
+
+ private fun getTimingData(start: SuraAyah, end: SuraAyah, gaplessDatabase: String): ArrayList {
+ val databasePath = gaplessDatabase!!
+
+ val db: SuraTimingDatabaseHandler = SuraTimingDatabaseHandler.getDatabaseHandler(
+ databasePath)
+ var firstSurahMap = SparseIntArray()
+ var lastSurahMap = SparseIntArray()
+ var firstSurahCursor: Cursor? = null
+ var lastSurahCursor: Cursor? = null
+
+ try {
+ firstSurahCursor = db.getAyahTimings(start.sura)
+ firstSurahMap = populateArrayFromCursor(firstSurahCursor)!!
+ lastSurahCursor = db.getAyahTimings(end.sura)
+ lastSurahMap = populateArrayFromCursor(lastSurahCursor)
+ } catch (sqlException: SQLException) {
+ Timber.e(sqlException)
+ } finally {
+ closeCursor(firstSurahCursor)
+ closeCursor(lastSurahCursor)
+ }
+
+ return ArrayList(
+ listOf(firstSurahMap, lastSurahMap))
+ }
+
+ private fun populateArrayFromCursor(cursor: Cursor?): SparseIntArray {
+ val sparseIntArray = SparseIntArray()
+ if (cursor != null && cursor.moveToFirst()) {
+ do {
+ val ayah = cursor.getInt(1)
+ val time = cursor.getInt(2)
+ sparseIntArray.put(ayah, time)
+ } while (cursor.moveToNext())
+ }
+ return sparseIntArray
+ }
+
+ private fun getSurahSegment(path: String, lowerCut: Int, upperCut: Int): String? {
+ if (lowerCut == 0 && upperCut == 0) {
+ return null
+ }
+ val tempAudioName = UUID.randomUUID().toString() + ".mp3"
+ val destFile = File(audioCacheDirectory.path + File.separator + tempAudioName)
+ val mSoundFile = arrayOfNulls(1)
+ try {
+ mSoundFile[0] = CheapSoundFile.create(path, null)
+ val startTime = lowerCut.toFloat() / 1000
+ val endTime = upperCut.toFloat() / 1000
+ val samplesPerFrame = mSoundFile[0]?.samplesPerFrame
+ val sampleRate = mSoundFile[0]?.sampleRate
+ val avg = sampleRate?.div(samplesPerFrame!!)
+ val startFrames = (startTime * avg!!).roundToInt()
+ val endFrames = (endTime * avg).roundToInt()
+ mSoundFile[0]?.WriteFile(destFile, startFrames, endFrames - startFrames)
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ return destFile.absolutePath
+ }
+
+ private fun getMergedAudioFromSegments(segments: ArrayList): String {
+ var mergedAudioPath = segments[0]
+ if (segments.size > 1) {
+ for (i in 1 until segments.size) {
+ mergedAudioPath = mergeAudios(mergedAudioPath, segments[i])!!
+ audioCacheFilePaths.add(mergedAudioPath)
+ }
+ }
+ return mergedAudioPath
+ }
+
+ private fun mergeAudios(path1: String, path2: String): String? {
+ val tempAudioName = UUID.randomUUID().toString() + ".mp3"
+ val destFile = File(audioCacheDirectory.path + File.separator + tempAudioName)
+ try {
+ val bufferedSink: BufferedSink = destFile.sink().buffer()
+ bufferedSink.writeAll(File(path1).source())
+ bufferedSink.writeAll(File(path2).source())
+ bufferedSink.close()
+ return destFile.path
+ } catch (e2: FileNotFoundException) {
+ e2.printStackTrace()
+ } catch (e: IOException) {
+ e.printStackTrace()
+ }
+ return null
+ }
+
+
+}
diff --git a/app/src/main/java/com/quran/labs/androidquran/util/audioConversionUtils/CheapMP3.java b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/soundfile/CheapMP3.java
similarity index 99%
rename from app/src/main/java/com/quran/labs/androidquran/util/audioConversionUtils/CheapMP3.java
rename to feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/soundfile/CheapMP3.java
index 191a256093..bedbc1af1c 100644
--- a/app/src/main/java/com/quran/labs/androidquran/util/audioConversionUtils/CheapMP3.java
+++ b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/soundfile/CheapMP3.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.quran.labs.androidquran.util.audioConversionUtils;
+package com.quran.labs.androidquran.feature.audio.util.soundfile;
import java.io.File;
import java.io.FileInputStream;
diff --git a/app/src/main/java/com/quran/labs/androidquran/util/audioConversionUtils/CheapSoundFile.java b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/soundfile/CheapSoundFile.java
similarity index 97%
rename from app/src/main/java/com/quran/labs/androidquran/util/audioConversionUtils/CheapSoundFile.java
rename to feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/soundfile/CheapSoundFile.java
index 9a8dc9b368..9ea9dd27fa 100644
--- a/app/src/main/java/com/quran/labs/androidquran/util/audioConversionUtils/CheapSoundFile.java
+++ b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/soundfile/CheapSoundFile.java
@@ -13,13 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.quran.labs.androidquran.util.audioConversionUtils;
+package com.quran.labs.androidquran.feature.audio.util.soundfile;
import java.io.File;
import java.io.FileInputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
+
/**
* CheapSoundFile is the parent class of several subclasses that each
* do a "cheap" scan of various sound file formats, parsing as little
@@ -203,7 +204,7 @@ public String computeMd5OfFirst10Frames()
numFrames = 10;
}
- MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
+ MessageDigest digest = MessageDigest.getInstance("MD5");
FileInputStream in = new FileInputStream(mInputFile);
int pos = 0;
for (int i = 0; i < numFrames; i++) {
From 168a044da317320dcb87fb9120e4a97d77660497 Mon Sep 17 00:00:00 2001
From: Doozy
Date: Sat, 30 Jul 2022 11:30:01 +0300
Subject: [PATCH 12/13] removed greek prefix
---
.../androidquran/feature/audio/util/AudioShareUtils.kt | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt
index 95c7d8062f..e28d0633cd 100644
--- a/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt
+++ b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt
@@ -210,17 +210,17 @@ class AudioShareUtils {
}
val tempAudioName = UUID.randomUUID().toString() + ".mp3"
val destFile = File(audioCacheDirectory.path + File.separator + tempAudioName)
- val mSoundFile = arrayOfNulls(1)
+ val soundFile = arrayOfNulls(1)
try {
- mSoundFile[0] = CheapSoundFile.create(path, null)
+ soundFile[0] = CheapSoundFile.create(path, null)
val startTime = lowerCut.toFloat() / 1000
val endTime = upperCut.toFloat() / 1000
- val samplesPerFrame = mSoundFile[0]?.samplesPerFrame
- val sampleRate = mSoundFile[0]?.sampleRate
+ val samplesPerFrame = soundFile[0]?.samplesPerFrame
+ val sampleRate = soundFile[0]?.sampleRate
val avg = sampleRate?.div(samplesPerFrame!!)
val startFrames = (startTime * avg!!).roundToInt()
val endFrames = (endTime * avg).roundToInt()
- mSoundFile[0]?.WriteFile(destFile, startFrames, endFrames - startFrames)
+ soundFile[0]?.WriteFile(destFile, startFrames, endFrames - startFrames)
} catch (e: IOException) {
e.printStackTrace()
}
From e85760ce3938571bff2be8f325d8bfc3eee8b366 Mon Sep 17 00:00:00 2001
From: Doozy
Date: Sat, 30 Jul 2022 11:48:31 +0300
Subject: [PATCH 13/13] check cache directory existance at sharing
---
.../quran/labs/androidquran/ui/PagerActivity.java | 14 +++++---------
.../feature/audio/util/AudioShareUtils.kt | 8 ++++++++
2 files changed, 13 insertions(+), 9 deletions(-)
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 891ab2c90d..28c6b982b5 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
@@ -263,9 +263,6 @@ public class PagerActivity extends AppCompatActivity implements
private final PagerHandler handler = new PagerHandler(this);
- public static final File audioCacheDirectory = new File(
- Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getPath() +
- File.separator + "quran_android_cache");
private ArrayList audioCacheFilePaths = new ArrayList<>();
private SuraAyah selectedStartSuraAyah = null;
private SuraAyah selectedEndSuraAyah = null;
@@ -367,11 +364,6 @@ public void onCreate(Bundle savedInstanceState) {
compositeDisposable = new CompositeDisposable();
setContentView(R.layout.quran_page_activity_slider);
- if (!audioCacheDirectory.exists()) {
- if (!audioCacheDirectory.mkdirs()) {
- Toast.makeText(PagerActivity.this, "could not create directory", Toast.LENGTH_SHORT).show();
- }
- }
audioStatusBar = findViewById(R.id.audio_area);
audioStatusBar.setIsDualPageMode(quranScreenInfo.isDualPageMode());
audioStatusBar.setQariList(audioUtils.getQariList(this));
@@ -1907,7 +1899,11 @@ public void shareAyahAudio(SuraAyah start, SuraAyah end) {
String path = audioShareUtils.createSharableAudioFile(this, selectedStartSuraAyah,
selectedEndSuraAyah, selectedQari, audioPathInfo.getUrlFormat(),
audioPathInfo.getGaplessDatabase());
- shareAudioSegment(path);
+ if(path != null && !path.isEmpty()){
+ shareAudioSegment(path);
+ }else{
+ Toast.makeText(this, "could not share audio ayah", Toast.LENGTH_SHORT).show();
+ }
} else {
requestDownload(audioPathInfo);
}
diff --git a/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt
index e28d0633cd..f36310be79 100644
--- a/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt
+++ b/feature/audio/src/main/java/com/quran/labs/androidquran/feature/audio/util/AudioShareUtils.kt
@@ -7,6 +7,7 @@ import android.media.MediaMetadataRetriever
import android.net.Uri
import android.os.Environment
import android.util.SparseIntArray
+import android.widget.Toast
import com.quran.data.model.SuraAyah
import com.quran.labs.androidquran.common.audio.model.QariItem
import com.quran.labs.androidquran.feature.audio.database.SuraTimingDatabaseHandler
@@ -53,6 +54,13 @@ class AudioShareUtils {
selectedEndSuraAyah = getReorderedAyahPair(start, end).end
selectedQari = qari
+ if (!audioCacheDirectory.exists()) {
+ if (!audioCacheDirectory.mkdirs()) {
+ Toast.makeText(context, "could not create directory", Toast.LENGTH_SHORT).show()
+ return null;
+ }
+ }
+
var sharablePath: String? = null
return runBlocking {