Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Observe stream of translations in PagerActivity #2488

Merged
merged 1 commit into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.quran.labs.androidquran.util.QuranFileUtils
import com.quran.mobile.di.qualifier.ApplicationContext
import com.quran.mobile.translation.data.TranslationsDataSource
import com.quran.mobile.translation.model.LocalTranslation
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
Expand All @@ -22,6 +23,8 @@ class TranslationsDBAdapter @Inject constructor(
private val dataSource: TranslationsDataSource,
private val quranFileUtils: QuranFileUtils
) {
private val scope = MainScope()

fun getTranslations(): Flow<List<LocalTranslation>> {
return dataSource.translations()
.filterNotNull()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import java.util.Collections

internal open class BaseTranslationPresenter<T : Any> internal constructor(
open class BaseTranslationPresenter<T : Any> internal constructor(
private val translationModel: TranslationModel,
private val translationsAdapter: TranslationsDBAdapter,
private val translationUtil: TranslationUtil,
Expand Down Expand Up @@ -189,8 +189,8 @@ internal open class BaseTranslationPresenter<T : Any> internal constructor(
}
}

internal class ResultHolder(val translations: Array<LocalTranslation>,
val ayahInformation: List<QuranAyahInfo>)
class ResultHolder(val translations: Array<LocalTranslation>,
val ayahInformation: List<QuranAyahInfo>)

override fun bind(what: T) {
translationScreen = what
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.quran.labs.androidquran.presenter.translation

import com.quran.data.core.QuranInfo
import com.quran.data.model.VerseRange
import com.quran.labs.androidquran.common.QuranAyahInfo
import com.quran.labs.androidquran.database.TranslationsDBAdapter
import com.quran.labs.androidquran.model.translation.TranslationModel
import com.quran.labs.androidquran.presenter.translationlist.TranslationListPresenter
import com.quran.labs.androidquran.util.QuranSettings
import com.quran.labs.androidquran.util.TranslationUtil
import com.quran.mobile.translation.model.LocalTranslation
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.observers.DisposableSingleObserver
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject

class InlineTranslationPresenter @Inject constructor(
translationModel: TranslationModel,
dbAdapter: TranslationsDBAdapter,
translationUtil: TranslationUtil,
private val quranSettings: QuranSettings,
private val translationListPresenter: TranslationListPresenter,
quranInfo: QuranInfo
) : BaseTranslationPresenter<InlineTranslationPresenter.TranslationScreen>(
translationModel, dbAdapter, translationUtil, quranInfo
) {
private val scope = MainScope()
private var cachedTranslations = emptyList<LocalTranslation>()

init {
translationListPresenter.translations()
.onEach { translations ->
cachedTranslations = translations
translationScreen?.onTranslationsUpdated(translations)
}
.launchIn(scope)
}

fun refresh(verseRange: VerseRange) {
disposable?.dispose()
disposable = getVerses(false, getTranslations(quranSettings), verseRange)
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object : DisposableSingleObserver<ResultHolder>() {
override fun onSuccess(result: ResultHolder) {
translationScreen?.setVerses(result.translations, result.ayahInformation)
}

override fun onError(e: Throwable) {}
})
}

override fun bind(what: TranslationScreen) {
super.bind(what)
val translations = cachedTranslations
if (translations.isNotEmpty()) {
what.onTranslationsUpdated(translations)
}
}

interface TranslationScreen {
fun setVerses(translations: Array<LocalTranslation>, verses: List<QuranAyahInfo>)
fun onTranslationsUpdated(translations: List<LocalTranslation>)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,22 @@ import javax.inject.Inject
class TranslationListPresenter @Inject constructor(
private val dataSource: TranslationsDataSource
) {
private val scope = MainScope()

fun translations(): Flow<List<LocalTranslation>> {
return dataSource.translations()
.filterNotNull()
.map { translations -> translations.sortedBy { it.displayOrder } }
}

fun registerForTranslations(callback: TranslationListCallback): Job {
return translations()
.onEach { translations ->
callback.onTranslationsUpdated(
titles = translations.map { translation -> translation.resolveTranslatorName() }.toTypedArray(),
translations = translations
)
}
.launchIn(scope)
}
}
94 changes: 34 additions & 60 deletions app/src/main/java/com/quran/labs/androidquran/ui/PagerActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.SparseBooleanArray;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
Expand Down Expand Up @@ -68,21 +67,20 @@
import com.quran.labs.androidquran.SearchActivity;
import com.quran.labs.androidquran.bridge.AudioEventPresenterBridge;
import com.quran.labs.androidquran.bridge.ReadingEventPresenterBridge;
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.dao.audio.AudioRequest;
import com.quran.labs.androidquran.data.Constants;
import com.quran.labs.androidquran.data.QuranDataProvider;
import com.quran.labs.androidquran.data.QuranDisplayData;
import com.quran.labs.androidquran.database.TranslationsDBAdapter;
import com.quran.labs.androidquran.di.component.activity.PagerActivityComponent;
import com.quran.labs.androidquran.model.bookmark.BookmarkModel;
import com.quran.labs.androidquran.model.translation.ArabicDatabaseUtils;
import com.quran.labs.androidquran.presenter.audio.AudioPresenter;
import com.quran.labs.androidquran.presenter.bookmark.RecentPagePresenter;
import com.quran.labs.androidquran.presenter.data.QuranEventLogger;
import com.quran.labs.androidquran.presenter.recitation.PagerActivityRecitationPresenter;
import com.quran.labs.androidquran.presenter.translationlist.TranslationListPresenter;
import com.quran.labs.androidquran.service.AudioService;
import com.quran.labs.androidquran.service.QuranDownloadService;
import com.quran.labs.androidquran.service.util.DefaultDownloadReceiver;
Expand Down Expand Up @@ -130,23 +128,21 @@
import com.quran.reading.common.ReadingEventPresenter;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;

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 kotlinx.coroutines.Job;
import timber.log.Timber;

/**
Expand Down Expand Up @@ -233,7 +229,6 @@ public class PagerActivity extends AppCompatActivity implements
@Inject QuranSettings quranSettings;
@Inject QuranScreenInfo quranScreenInfo;
@Inject ArabicDatabaseUtils arabicDatabaseUtils;
@Inject TranslationsDBAdapter translationsDBAdapter;
@Inject QuranAppUtils quranAppUtils;
@Inject ShareUtil shareUtil;
@Inject AudioUtils audioUtils;
Expand All @@ -248,10 +243,12 @@ public class PagerActivity extends AppCompatActivity implements
@Inject PageViewFactoryProvider pageProviderFactoryProvider;
@Inject Set<AyahActionFragmentProvider> additionalAyahPanels;
@Inject PagerActivityRecitationPresenter pagerActivityRecitationPresenter;
@Inject TranslationListPresenter translationListPresenter;

private AudioEventPresenterBridge audioEventPresenterBridge;
private ReadingEventPresenterBridge readingEventPresenterBridge;

private Job translationJob;
private CompositeDisposable compositeDisposable;
private final CompositeDisposable foregroundDisposable = new CompositeDisposable();

Expand Down Expand Up @@ -543,6 +540,9 @@ public void onPageSelected(int position) {
registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
audioPresenter.onPostNotificationsPermissionResponse(isGranted);
});

// read the list of translations
requestTranslationsList();
}

@Override
Expand Down Expand Up @@ -761,9 +761,6 @@ public void onResume() {
recentPagePresenter.bind(this);
isInMultiWindowMode = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && isInMultiWindowMode();

// read the list of translations
requestTranslationsList();

if (shouldReconnect) {
foregroundDisposable.add(Completable.timer(500, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
Expand Down Expand Up @@ -971,6 +968,7 @@ public void onPause() {
}
recentPagePresenter.unbind(this);
quranSettings.setWasShowingTranslation(pagerAdapter.isShowingTranslation());

super.onPause();
}

Expand All @@ -996,6 +994,9 @@ protected void onDestroy() {
downloadReceiver = null;
}

if (translationJob != null) {
translationJob.cancel(new CancellationException());
}
currentQariBridge.unsubscribeAll();
compositeDisposable.dispose();
audioEventPresenterBridge.dispose();
Expand Down Expand Up @@ -1372,56 +1373,29 @@ private void ensurePage(int sura, int ayah) {
}

private void requestTranslationsList() {
compositeDisposable.add(
Single.fromCallable(() ->
translationsDBAdapter.legacyGetTranslations())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSingleObserver<List<LocalTranslation>>() {
@Override
public void onSuccess(@NonNull List<LocalTranslation> translationList) {
final List<LocalTranslation> sortedTranslations = new ArrayList<>(translationList);
Collections.sort(sortedTranslations, new LocalTranslationDisplaySort());

int items = sortedTranslations.size();
String[] titles = new String[items];
for (int i = 0; i < items; i++) {
LocalTranslation item = sortedTranslations.get(i);
if (!TextUtils.isEmpty(item.getTranslatorForeign())) {
titles[i] = item.getTranslatorForeign();
} else if (!TextUtils.isEmpty(item.getTranslator())) {
titles[i] = item.getTranslator();
} else {
titles[i] = item.getName();
}
}

Set<String> currentActiveTranslationsFilesNames = quranSettings.getActiveTranslations();
if (currentActiveTranslationsFilesNames.isEmpty() && items > 0) {
currentActiveTranslationsFilesNames = new HashSet<>();
for (int i = 0; i < items; i++) {
currentActiveTranslationsFilesNames.add(sortedTranslations.get(i).getFilename());
}
}
activeTranslationsFilesNames = currentActiveTranslationsFilesNames;

if (translationsSpinnerAdapter != null) {
translationsSpinnerAdapter
.updateItems(titles, sortedTranslations, activeTranslationsFilesNames);
}
translationNames = titles;
translations = sortedTranslations;

if (showingTranslation) {
// Since translation items have changed, need to
updateActionBarSpinner();
}
}
translationJob = translationListPresenter.registerForTranslations((titles, updatedTranslations) -> {
Set<String> currentActiveTranslationsFilesNames = quranSettings.getActiveTranslations();
if (currentActiveTranslationsFilesNames.isEmpty() && !updatedTranslations.isEmpty()) {
currentActiveTranslationsFilesNames = new HashSet<>();
final int items = updatedTranslations.size();
for (int i = 0; i < items; i++) {
currentActiveTranslationsFilesNames.add(updatedTranslations.get(i).getFilename());
}
}
activeTranslationsFilesNames = currentActiveTranslationsFilesNames;

@Override
public void onError(@NonNull Throwable e) {
}
}));
if (translationsSpinnerAdapter != null) {
translationsSpinnerAdapter
.updateItems(titles, updatedTranslations, activeTranslationsFilesNames);
}
translationNames = titles;
translations = updatedTranslations;

if (showingTranslation) {
// Since translation items have changed, need to
updateActionBarSpinner();
}
});
}

private void toggleBookmark(final Integer sura, final Integer ayah, final int page) {
Expand Down
Loading