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

Add support for dual pages on foldable devices #2670

Merged
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
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ dependencies {
implementation libs.androidx.recyclerview
implementation libs.material
implementation libs.androidx.swiperefreshlayout
implementation libs.androidx.window

// compose
implementation libs.compose.ui
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ object PagerActivityModule {
@Provides
@ActivityScope
fun provideImageWidth(@ActivityContext context: Context, screenInfo: QuranScreenInfo): String {
return if (QuranUtils.isDualPages(context, screenInfo)) {
return if (QuranUtils.isDualPages(context, screenInfo, false)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no way of injecting this value here so ignoring it for now. @ahmedre Could you elaborate a bit more on the use case here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discussed offline, moving forward, will consider moving this check into QuranScreenInfo if possible.

screenInfo.tabletWidthParam
} else {
screenInfo.widthParam
Expand Down
107 changes: 74 additions & 33 deletions app/src/main/java/com/quran/labs/androidquran/ui/PagerActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,15 @@ import androidx.appcompat.widget.Toolbar
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.viewpager.widget.NonRestoringViewPager
import androidx.viewpager.widget.ViewPager
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import androidx.viewpager.widget.ViewPager.SimpleOnPageChangeListener
import androidx.window.layout.FoldingFeature
import androidx.window.layout.WindowInfoTracker
import com.quran.data.core.QuranInfo
import com.quran.data.dao.BookmarksDao
import com.quran.data.model.QuranText
Expand Down Expand Up @@ -133,8 +138,10 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.buffer
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
Expand Down Expand Up @@ -168,6 +175,7 @@ class PagerActivity : AppCompatActivity(), AudioBarListener, OnBookmarkTagsUpdat
private var promptedForExtraDownload = false
private var progressDialog: ProgressDialog? = null
private var isInMultiWindowMode = false
private var isFoldableDeviceOpenAndVertical = false

private var bookmarksMenuItem: MenuItem? = null

Expand Down Expand Up @@ -262,8 +270,57 @@ class PagerActivity : AppCompatActivity(), AudioBarListener, OnBookmarkTagsUpdat
// field injection
pagerActivityComponent.inject(this)

isFoldableDeviceOpenAndVertical =
savedInstanceState?.getBoolean(LAST_FOLDING_STATE, isFoldableDeviceOpenAndVertical)
?: isFoldableDeviceOpenAndVertical

lifecycleScope.launch(scope.coroutineContext) {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
WindowInfoTracker.getOrCreate(this@PagerActivity)
.windowLayoutInfo(this@PagerActivity)
.mapNotNull { it.displayFeatures.filterIsInstance<FoldingFeature>().firstOrNull() }
.collectLatest { foldingFeatures ->
val localState = foldingFeatures.state == FoldingFeature.State.FLAT &&
foldingFeatures.orientation == FoldingFeature.Orientation.VERTICAL
if (isFoldableDeviceOpenAndVertical != localState) {
isFoldableDeviceOpenAndVertical = localState
initialize(savedInstanceState)
}
}
}
}

setContentView(R.layout.quran_page_activity_slider)
initialize(savedInstanceState)
requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean? ->
audioPresenter.onPostNotificationsPermissionResponse(
isGranted!!
)
}

// read the list of translations
requestTranslationsList()

downloadBridge.subscribeToDownloads {
onDownloadSuccess()
}

bookmarksDao.pageBookmarksWithoutTags().combine(currentPageFlow) { bookmarks, currentPage ->
bookmarks to currentPage
}.onEach { (bookmarks, page) ->
val isBookmarked = if (isDualPages) {
bookmarks.any { it.page == page || it.page == page - 1 }
} else {
bookmarks.any { it.page == page }
}
refreshBookmarksMenu(isBookmarked)
}.launchIn(scope)
}

private fun initialize(savedInstanceState: Bundle?) {
var shouldAdjustPageNumber = false
isDualPages = QuranUtils.isDualPages(this, quranScreenInfo)
isDualPages = QuranUtils.isDualPages(this, quranScreenInfo, isFoldableDeviceOpenAndVertical)
isSplitScreen = quranSettings.isQuranSplitWithTranslation
audioStatusRepositoryBridge = AudioStatusRepositoryBridge(
audioStatusRepository,
Expand Down Expand Up @@ -323,7 +380,6 @@ class PagerActivity : AppCompatActivity(), AudioBarListener, OnBookmarkTagsUpdat

compositeDisposable = CompositeDisposable()

setContentView(R.layout.quran_page_activity_slider)
audioStatusBar = findViewById(R.id.audio_area)
audioBarParams = audioStatusBar.layoutParams as MarginLayoutParams

Expand Down Expand Up @@ -498,31 +554,6 @@ class PagerActivity : AppCompatActivity(), AudioBarListener, OnBookmarkTagsUpdat
{ ayah: SuraAyah -> ensurePage(ayah.sura, ayah.ayah) },
{ sliderPage: Int -> showSlider(slidingPagerAdapter.getPagePosition(sliderPage)) }
))

requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean? ->
audioPresenter.onPostNotificationsPermissionResponse(
isGranted!!
)
}

// read the list of translations
requestTranslationsList()

downloadBridge.subscribeToDownloads {
onDownloadSuccess()
}

bookmarksDao.pageBookmarksWithoutTags().combine(currentPageFlow) { bookmarks, currentPage ->
bookmarks to currentPage
}.onEach { (bookmarks, page) ->
val isBookmarked = if (isDualPages) {
bookmarks.any { it.page == page || it.page == page - 1 }
} else {
bookmarks.any { it.page == page }
}
refreshBookmarksMenu(isBookmarked)
}.launchIn(scope)
}

override fun onRequestPermissionsResult(
Expand Down Expand Up @@ -551,9 +582,9 @@ class PagerActivity : AppCompatActivity(), AudioBarListener, OnBookmarkTagsUpdat
viewPager.addOnPageChangeListener(pageChangedListener)
awaitClose { viewPager.removeOnPageChangeListener(pageChangedListener) }
}
.onStart { emit(currentPage) }
.buffer(onBufferOverflow = BufferOverflow.DROP_OLDEST)
.shareIn(scope, SharingStarted.Eagerly, 1)
.onStart { emit(currentPage) }
.buffer(onBufferOverflow = BufferOverflow.DROP_OLDEST)
.shareIn(scope, SharingStarted.Eagerly, 1)

private val statusBarHeight: Int
get() {
Expand Down Expand Up @@ -646,9 +677,17 @@ class PagerActivity : AppCompatActivity(), AudioBarListener, OnBookmarkTagsUpdat

private fun startPosition(ayahSelection: AyahSelection): SuraAyah? {
return when (ayahSelection) {
is AyahSelection.Ayah -> { ayahSelection.suraAyah }
is AyahRange -> { ayahSelection.startSuraAyah }
else -> { null }
is AyahSelection.Ayah -> {
ayahSelection.suraAyah
}

is AyahRange -> {
ayahSelection.startSuraAyah
}

else -> {
null
}
}
}

Expand Down Expand Up @@ -979,6 +1018,7 @@ class PagerActivity : AppCompatActivity(), AudioBarListener, OnBookmarkTagsUpdat
state.putBoolean(LAST_READING_MODE_IS_TRANSLATION, showingTranslation)
state.putBoolean(LAST_ACTIONBAR_STATE, isActionBarHidden)
state.putBoolean(LAST_WAS_DUAL_PAGES, isDualPages)
state.putBoolean(LAST_FOLDING_STATE, isFoldableDeviceOpenAndVertical)
super.onSaveInstanceState(state)
}

Expand Down Expand Up @@ -1839,6 +1879,7 @@ class PagerActivity : AppCompatActivity(), AudioBarListener, OnBookmarkTagsUpdat
private const val LAST_READ_PAGE = "LAST_READ_PAGE"
private const val LAST_READING_MODE_IS_TRANSLATION = "LAST_READING_MODE_IS_TRANSLATION"
private const val LAST_ACTIONBAR_STATE = "LAST_ACTIONBAR_STATE"
private const val LAST_FOLDING_STATE = "LAST_FOLDING_STATE"

const val EXTRA_JUMP_TO_TRANSLATION: String = "jumpToTranslation"
const val EXTRA_HIGHLIGHT_SURA: String = "highlightSura"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ public static String getLocalizedNumber(Context context, int number) {
return numberFormat.format(number);
}

public static boolean isDualPages(Context context, QuranScreenInfo qsi) {
public static boolean isDualPages(Context context, QuranScreenInfo qsi, boolean isValidFoldableDeviceAndOpen) {
if (context != null && qsi != null) {
final Resources resources = context.getResources();
if (qsi.isDualPageMode() &&
if ((qsi.isDualPageMode() &&
resources.getConfiguration().orientation ==
Configuration.ORIENTATION_LANDSCAPE) {
Configuration.ORIENTATION_LANDSCAPE) || isValidFoldableDeviceAndOpen) {
final SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getBoolean(Constants.PREF_DUAL_PAGE_ENABLED,
Expand Down
3 changes: 2 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ androidxSwipeRefreshVersion = "1.1.0"
androidxPagingVersion = "3.2.1"
androidxPagingComposeVersion = "3.2.1"
androidxWorkManagerVersion = "2.9.0"
androidxWindowManager = "1.2.0"

# firebase
firebaseAnalyticsVersion = "21.6.2"
Expand Down Expand Up @@ -96,7 +97,7 @@ androidx-work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version
androidx-paging-runtime-ktx = { module = "androidx.paging:paging-runtime-ktx", version.ref = "androidxPagingVersion" }
androidx-paging-compose = { module = "androidx.paging:paging-compose", version.ref = "androidxPagingComposeVersion" }
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidxNavigationVersion" }

androidx-window = { module = "androidx.window:window", version.ref = "androidxWindowManager" }
# compose
compose-compiler = { module = "androidx.compose.compiler:compiler", version.ref = "compose-compiler" }
compose-foundation = { module = "androidx.compose.foundation:foundation" }
Expand Down
Loading