Skip to content

Commit

Permalink
Implement Edge2Edge (leonlatsch#249)
Browse files Browse the repository at this point in the history
**Description:**

- [x] enable edge2edge for main activity
- [x] remove splash theme
- [x] add correct content padding for all fragments
- [x] animation for gallery title and gradient
- [x] change status bar icon color on scroll


Closes leonlatsch#240
  • Loading branch information
leonlatsch authored Feb 18, 2024
1 parent 2d4a3fe commit 7700680
Show file tree
Hide file tree
Showing 21 changed files with 222 additions and 68 deletions.
3 changes: 2 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ android {
}

composeOptions {
kotlinCompilerExtensionVersion = "1.4.5"
kotlinCompilerExtensionVersion = "1.5.9"
}

compileOptions {
Expand All @@ -62,6 +62,7 @@ android {
lint {
lintConfig = file("$rootDir/gradle/lint.xml")
}
namespace = "dev.leonlatsch.photok"
}

licenseReport {
Expand Down
5 changes: 2 additions & 3 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="dev.leonlatsch.photok">
xmlns:tools="http://schemas.android.com/tools">

<!-- Legacy Permission -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
Expand All @@ -36,7 +35,7 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/SplashScreenTheme">
android:theme="@style/AppTheme">

<!-- MAIN LAUNCHER: Starts the app -->
<activity-alias
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,12 @@ class GalleryFragment : Fragment() {
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return ComposeView(requireContext()).apply {
setContent {
CompositionLocalProvider(
LocalEncryptedImageLoader provides viewModel.encryptedImageLoader
) {
GalleryScreen(viewModel)
}
): View = ComposeView(requireContext()).apply {
setContent {
CompositionLocalProvider(
LocalEncryptedImageLoader provides viewModel.encryptedImageLoader
) {
GalleryScreen(viewModel)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,64 +16,108 @@

package dev.leonlatsch.photok.cgallery.ui.compose

import android.content.res.Configuration
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.FiniteAnimationSpec
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.scrollable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat
import dev.leonlatsch.photok.R
import dev.leonlatsch.photok.cgallery.ui.GalleryUiEvent
import dev.leonlatsch.photok.cgallery.ui.GalleryUiState
import dev.leonlatsch.photok.cgallery.ui.MultiSelectionState
import dev.leonlatsch.photok.cgallery.ui.PhotoTile
import dev.leonlatsch.photok.model.database.entity.PhotoType
import dev.leonlatsch.photok.uicomponnets.compose.AppName
import dev.leonlatsch.photok.uicomponnets.compose.findWindow
import java.util.UUID

private const val AnimationStiffness = Spring.StiffnessLow
private val FadeAnimationSpec: FiniteAnimationSpec<Float> = spring(stiffness = AnimationStiffness)

@Composable
fun GalleryContent(uiState: GalleryUiState.Content, handleUiEvent: (GalleryUiEvent) -> Unit) {
val scrollState = rememberScrollState()
val gridState = rememberLazyGridState()
val window = findWindow()
val isDarkTheme = isSystemInDarkTheme()

Box(
modifier = Modifier.scrollable(scrollState, orientation = Orientation.Vertical)
) {
Box {
PhotosGrid(
photos = uiState.photos,
multiSelectionState = uiState.multiSelectionState,
handleUiEvent = handleUiEvent,
modifier = Modifier.fillMaxHeight()
modifier = Modifier.fillMaxHeight(),
extraTopPadding = 120.dp,
gridState = gridState
)

Box(
modifier = Modifier
.fillMaxWidth()
.height(120.dp)
.background(
Brush.verticalGradient(
listOf(colorResource(R.color.black_semi_transparent), Color.Transparent)
val scrolling by remember { derivedStateOf { gridState.canScrollBackward } }

AnimatedVisibility(
visible = scrolling,
enter = fadeIn(FadeAnimationSpec),
exit = fadeOut(FadeAnimationSpec),
) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(120.dp)
.background(
Brush.verticalGradient(
listOf(colorResource(R.color.black_semi_transparent), Color.Transparent)
)
)
)
)
}

LaunchedEffect(scrolling) {
window?.let { window ->
WindowCompat.getInsetsController(
window, window.decorView
).isAppearanceLightStatusBars = isDarkTheme.not() && scrolling.not()
}
}

val titleColor by animateColorAsState(
targetValue = if (scrolling) Color.White else colorResource(R.color.appTitleColor),
animationSpec = spring(stiffness = AnimationStiffness),
label = "titleColor"
)

AppName(
color = Color.White,
color = titleColor,
modifier = Modifier
.align(Alignment.TopCenter)
.padding(14.dp)
.padding(WindowInsets.statusBars.asPaddingValues())
)

AnimatedVisibility(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package dev.leonlatsch.photok.cgallery.ui.compose

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Box
Expand All @@ -28,8 +29,11 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyGridState
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.Icon
Expand All @@ -43,6 +47,7 @@ import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import dev.leonlatsch.photok.R
import dev.leonlatsch.photok.cgallery.ui.GalleryUiEvent
Expand All @@ -57,12 +62,15 @@ fun PhotosGrid(
photos: List<PhotoTile>,
multiSelectionState: MultiSelectionState,
handleUiEvent: (GalleryUiEvent) -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
extraTopPadding: Dp = 0.dp,
gridState: LazyGridState = rememberLazyGridState()
) {
LazyVerticalGrid(
columns = GridCells.Fixed(3),
modifier = modifier.fillMaxWidth(),
contentPadding = PaddingValues(top = 100.dp)
contentPadding = PaddingValues(top = extraTopPadding),
state = gridState
) {
items(photos, key = { it.uuid }) {
GalleryPhotoTile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import dev.leonlatsch.photok.databinding.FragmentImageViewerBinding
import dev.leonlatsch.photok.other.INTENT_PHOTO_UUID
import dev.leonlatsch.photok.other.REQ_PERM_EXPORT
import dev.leonlatsch.photok.other.extensions.*
import dev.leonlatsch.photok.other.statusBarPadding
import dev.leonlatsch.photok.other.systemBarsPadding
import dev.leonlatsch.photok.settings.data.Config
import dev.leonlatsch.photok.uicomponnets.Dialogs
import dev.leonlatsch.photok.uicomponnets.bindings.BindableFragment
Expand All @@ -57,11 +59,12 @@ class ImageViewerFragment : BindableFragment<FragmentImageViewerBinding>(R.layou

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.systemBarsPadding()

setHasOptionsMenu(true)
setToolbar(binding.viewPhotoToolbar)
binding.viewPhotoToolbar.setNavigationOnClickListener {
requireActivity().onBackPressed()
findNavController().navigateUp()
}

initializeSystemUI()
Expand Down Expand Up @@ -146,7 +149,6 @@ class ImageViewerFragment : BindableFragment<FragmentImageViewerBinding>(R.layou

@Suppress("DEPRECATION")
private fun initializeSystemUI() {
requireActivity().window.setStatusBarColorRes(android.R.color.black)

requireActivity().window.addSystemUIVisibilityListener {
systemUiVisible = it
Expand Down Expand Up @@ -187,7 +189,6 @@ class ImageViewerFragment : BindableFragment<FragmentImageViewerBinding>(R.layou
override fun onDestroy() {
super.onDestroy()
requireActivity().showSystemUI()
requireActivity().window.setStatusBarColorRes(R.color.colorPrimary)
}

override fun bind(binding: FragmentImageViewerBinding) {
Expand Down
13 changes: 11 additions & 2 deletions app/src/main/java/dev/leonlatsch/photok/main/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@ package dev.leonlatsch.photok.main.ui

import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.os.Bundle
import androidx.activity.SystemBarStyle
import androidx.activity.addCallback
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
Expand All @@ -35,7 +41,6 @@ import dev.leonlatsch.photok.gallery.ui.importing.ImportBottomSheetDialogFragmen
import dev.leonlatsch.photok.main.ui.navigation.MainMenu
import dev.leonlatsch.photok.other.REQ_PERM_SHARED_IMPORT
import dev.leonlatsch.photok.other.extensions.getBaseApplication
import dev.leonlatsch.photok.other.extensions.setNavBarColorRes
import dev.leonlatsch.photok.permissions.getReadImagesPermission
import dev.leonlatsch.photok.permissions.getReadVideosPermission
import dev.leonlatsch.photok.settings.data.Config
Expand Down Expand Up @@ -66,8 +71,8 @@ class MainActivity : BindableActivity<ActivityMainBinding>(R.layout.activity_mai
var onOrientationChanged: (Int) -> Unit = {} // Init empty

override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
super.onCreate(savedInstanceState)
window.setNavBarColorRes(android.R.color.black)
}

override fun onPostCreate(savedInstanceState: Bundle?) {
Expand Down Expand Up @@ -95,6 +100,10 @@ class MainActivity : BindableActivity<ActivityMainBinding>(R.layout.activity_mai
val showMenu = FragmentsWithMenu.contains(destination.id)
binding.mainMenuComposeContainer.isVisible = showMenu

WindowCompat.getInsetsController(
window, window.decorView
).isAppearanceLightStatusBars = (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) != Configuration.UI_MODE_NIGHT_YES

viewModel.onDestinationChanged(destination.id)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.viewpager.widget.ViewPager
import dagger.hilt.android.AndroidEntryPoint
import dev.leonlatsch.photok.R
import dev.leonlatsch.photok.databinding.FragmentOnboardingBinding
import dev.leonlatsch.photok.other.systemBarsPadding
import dev.leonlatsch.photok.settings.data.Config
import dev.leonlatsch.photok.uicomponnets.ViewPagerAdapter
import dev.leonlatsch.photok.uicomponnets.bindings.BindableFragment
Expand All @@ -47,6 +48,7 @@ class OnBoardingFragment :

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.systemBarsPadding()

binding.onBoardingDotSelector1.isSelected = true
binding.onBoardingDotSelector2.isSelected = false
Expand Down
Loading

0 comments on commit 7700680

Please sign in to comment.