Skip to content

Commit 3d2b7a8

Browse files
authored
Merge pull request #110 from hotwired/extract-animations
Add `animated` Path Configuration property
2 parents c88c127 + deaf5dd commit 3d2b7a8

File tree

6 files changed

+115
-48
lines changed

6 files changed

+115
-48
lines changed

core/src/main/assets/json/test-configuration.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@
9494
"uri": "hotwire://fragment/web/modal",
9595
"presentation": "replace_root"
9696
}
97+
},
98+
{
99+
"patterns": [
100+
"/not-animated"
101+
],
102+
"properties": {
103+
"animated": false
104+
}
97105
}
98106
]
99107
}

core/src/main/kotlin/dev/hotwire/core/turbo/config/PathConfiguration.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,6 @@ val PathConfigurationProperties.title: String?
156156

157157
val PathConfigurationProperties.pullToRefreshEnabled: Boolean
158158
get() = get("pull_to_refresh_enabled")?.toBoolean() ?: false
159+
160+
val PathConfigurationProperties.animated: Boolean
161+
get() = get("animated")?.toBoolean() ?: true

core/src/test/kotlin/dev/hotwire/core/turbo/config/PathConfigurationRepositoryTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class PathConfigurationRepositoryTest : BaseRepositoryTest() {
5050
assertThat(json).isNotNull()
5151

5252
val config = load(json)
53-
assertThat(config?.rules?.size).isEqualTo(10)
53+
assertThat(config?.rules?.size).isEqualTo(11)
5454
}
5555

5656
@Test

core/src/test/kotlin/dev/hotwire/core/turbo/config/PathConfigurationTest.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class PathConfigurationTest : BaseRepositoryTest() {
4848

4949
@Test
5050
fun assetConfigurationIsLoaded() {
51-
assertThat(pathConfiguration.rules.size).isEqualTo(10)
51+
assertThat(pathConfiguration.rules.size).isEqualTo(11)
5252
}
5353

5454
@Test
@@ -130,6 +130,13 @@ class PathConfigurationTest : BaseRepositoryTest() {
130130
assertThat(pathConfiguration.properties("$url/image.jpg").title).isEqualTo("Image Viewer")
131131
}
132132

133+
@Test
134+
fun animated() {
135+
assertThat(pathConfiguration.properties("$url/home").animated).isTrue()
136+
assertThat(pathConfiguration.properties("$url/new").animated).isTrue()
137+
assertThat(pathConfiguration.properties("$url/not-animated").animated).isFalse()
138+
}
139+
133140
@Test
134141
fun pullToRefresh() {
135142
assertThat(pathConfiguration.properties("$url/home").pullToRefreshEnabled).isTrue

navigation-fragments/src/main/java/dev/hotwire/navigation/destinations/HotwireDestination.kt

Lines changed: 5 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -137,52 +137,11 @@ interface HotwireDestination : BridgeDestination {
137137
newPathProperties: PathConfigurationProperties,
138138
action: VisitAction
139139
): NavOptions {
140-
val navigatingToModalContext = pathProperties.context == PresentationContext.DEFAULT &&
141-
newPathProperties.context == PresentationContext.MODAL
142-
143-
val navigatingWithinModalContext = pathProperties.context == PresentationContext.MODAL &&
144-
newPathProperties.context == PresentationContext.MODAL
145-
146-
val dismissingModalContext = pathProperties.context == PresentationContext.MODAL &&
147-
newPathProperties.context == PresentationContext.DEFAULT
148-
149-
val animate = (navigatingToModalContext || dismissingModalContext) ||
150-
(action != VisitAction.REPLACE &&
151-
newPathProperties.presentation != Presentation.REPLACE &&
152-
newPathProperties.presentation != Presentation.REPLACE_ROOT)
153-
154-
val clearAll = newPathProperties.presentation == Presentation.CLEAR_ALL
155-
156-
return if (navigatingToModalContext || navigatingWithinModalContext || dismissingModalContext) {
157-
navOptions {
158-
anim {
159-
enter = if (animate) R.anim.enter_slide_in_bottom else 0
160-
exit = R.anim.exit_slide_out_bottom
161-
popEnter = R.anim.enter_slide_in_bottom
162-
popExit = R.anim.exit_slide_out_bottom
163-
}
164-
}
165-
} else {
166-
if (clearAll) {
167-
navOptions {
168-
anim {
169-
enter = R.anim.exit_slide_out_left
170-
exit = R.anim.exit_slide_out_right
171-
popEnter = R.anim.enter_slide_in_left
172-
popExit = R.anim.enter_slide_in_right
173-
}
174-
}
175-
} else {
176-
navOptions {
177-
anim {
178-
enter = if (animate) R.anim.enter_slide_in_right else 0
179-
exit = R.anim.exit_slide_out_left
180-
popEnter = R.anim.enter_slide_in_left
181-
popExit = R.anim.exit_slide_out_right
182-
}
183-
}
184-
}
185-
}
140+
return HotwireDestinationAnimations.defaultNavOptions(
141+
currentPathProperties = pathProperties,
142+
newPathProperties = newPathProperties,
143+
action = action
144+
)
186145
}
187146

188147
/**
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package dev.hotwire.navigation.destinations
2+
3+
import androidx.navigation.NavOptions
4+
import androidx.navigation.navOptions
5+
import dev.hotwire.core.turbo.config.PathConfigurationProperties
6+
import dev.hotwire.core.turbo.config.animated
7+
import dev.hotwire.core.turbo.config.context
8+
import dev.hotwire.core.turbo.config.presentation
9+
import dev.hotwire.core.turbo.nav.Presentation
10+
import dev.hotwire.core.turbo.nav.PresentationContext
11+
import dev.hotwire.core.turbo.visit.VisitAction
12+
import dev.hotwire.navigation.R
13+
14+
class HotwireDestinationAnimations {
15+
companion object {
16+
fun defaultNavOptions(
17+
currentPathProperties: PathConfigurationProperties,
18+
newPathProperties: PathConfigurationProperties,
19+
action: VisitAction
20+
): NavOptions {
21+
val navigatingToModalContext = currentPathProperties.context == PresentationContext.DEFAULT &&
22+
newPathProperties.context == PresentationContext.MODAL
23+
24+
val navigatingWithinModalContext = currentPathProperties.context == PresentationContext.MODAL &&
25+
newPathProperties.context == PresentationContext.MODAL
26+
27+
val dismissingModalContext = currentPathProperties.context == PresentationContext.MODAL &&
28+
newPathProperties.context == PresentationContext.DEFAULT
29+
30+
val animate = shouldAnimate(
31+
navigatingToModalContext = navigatingToModalContext,
32+
dismissingModalContext = dismissingModalContext,
33+
newPathProperties = newPathProperties,
34+
action = action
35+
)
36+
37+
val clearAll = newPathProperties.presentation == Presentation.CLEAR_ALL
38+
39+
return if (navigatingToModalContext || navigatingWithinModalContext || dismissingModalContext) {
40+
navOptions {
41+
anim {
42+
enter = if (animate) R.anim.enter_slide_in_bottom else 0
43+
exit = R.anim.exit_slide_out_bottom
44+
popEnter = R.anim.enter_slide_in_bottom
45+
popExit = R.anim.exit_slide_out_bottom
46+
}
47+
}
48+
} else {
49+
if (clearAll) {
50+
navOptions {
51+
anim {
52+
enter = R.anim.exit_slide_out_left
53+
exit = R.anim.exit_slide_out_right
54+
popEnter = R.anim.enter_slide_in_left
55+
popExit = R.anim.enter_slide_in_right
56+
}
57+
}
58+
} else {
59+
navOptions {
60+
anim {
61+
enter = if (animate) R.anim.enter_slide_in_right else 0
62+
exit = R.anim.exit_slide_out_left
63+
popEnter = R.anim.enter_slide_in_left
64+
popExit = R.anim.exit_slide_out_right
65+
}
66+
}
67+
}
68+
}
69+
}
70+
71+
private fun shouldAnimate(
72+
navigatingToModalContext: Boolean,
73+
dismissingModalContext: Boolean,
74+
newPathProperties: PathConfigurationProperties,
75+
action: VisitAction
76+
): Boolean {
77+
if (!newPathProperties.animated) {
78+
return false
79+
}
80+
81+
if (navigatingToModalContext || dismissingModalContext) {
82+
return true
83+
}
84+
85+
return action != VisitAction.REPLACE &&
86+
newPathProperties.presentation != Presentation.REPLACE &&
87+
newPathProperties.presentation != Presentation.REPLACE_ROOT
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)