react-native-navigation 7.47.0 → 7.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. package/lib/android/app/build.gradle +2 -1
  2. package/lib/android/app/src/main/java/com/reactnativenavigation/FeatureToggles.kt +2 -0
  3. package/lib/android/app/src/main/java/com/reactnativenavigation/options/BottomTabsOptions.java +21 -1
  4. package/lib/android/app/src/main/java/com/reactnativenavigation/options/LayoutDirection.java +6 -1
  5. package/lib/android/app/src/main/java/com/reactnativenavigation/options/params/BottomTabsLayoutStyle.kt +20 -0
  6. package/lib/android/app/src/main/java/com/reactnativenavigation/utils/ColorUtils.java +4 -0
  7. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsController.java +12 -2
  8. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/bottomtabs/BottomTabsPresenter.kt +129 -11
  9. package/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/component/ComponentViewController.java +2 -1
  10. package/lib/android/app/src/main/java/com/reactnativenavigation/views/bottomtabs/BottomTabs.java +6 -6
  11. package/lib/android/app/src/main/java/com/reactnativenavigation/views/bottomtabs/BottomTabsContainer.kt +83 -5
  12. package/lib/android/app/src/main/java/com/reactnativenavigation/views/bottomtabs/BottomTabsLayout.java +58 -6
  13. package/lib/android/app/src/main/java/com/reactnativenavigation/views/bottomtabs/ShadowLayout.kt +4 -8
  14. package/lib/dist/src/interfaces/Options.d.ts +46 -3
  15. package/lib/ios/RNNSideMenu/MMDrawerController/MMDrawerController.h +22 -0
  16. package/lib/ios/RNNSideMenu/MMDrawerController/MMDrawerController.m +782 -161
  17. package/lib/ios/RNNSideMenuPresenter.m +27 -0
  18. package/lib/ios/RNNSideMenuSideOptions.h +6 -0
  19. package/lib/ios/RNNSideMenuSideOptions.m +13 -1
  20. package/lib/src/interfaces/Options.ts +46 -3
  21. package/package.json +1 -1
@@ -196,7 +196,8 @@ dependencies {
196
196
  implementation 'androidx.annotation:annotation:1.2.0'
197
197
  implementation 'com.google.android.material:material:1.2.0-alpha03'
198
198
 
199
- implementation 'com.github.wix-playground:ahbottomnavigation:3.3.0'
199
+ implementation 'com.github.wix-playground:ahbottomnavigation:4.0.0'
200
+ implementation 'com.github.Dimezis:BlurView:version-3.0.0'
200
201
  // implementation project(':AHBottomNavigation')
201
202
  implementation 'com.github.wix-playground:reflow-animator:1.0.6'
202
203
  implementation 'com.github.clans:fab:1.6.4'
@@ -5,11 +5,13 @@ import androidx.annotation.VisibleForTesting
5
5
  enum class RNNToggles {
6
6
  TOP_BAR_COLOR_ANIMATION__PUSH,
7
7
  TOP_BAR_COLOR_ANIMATION__TABS,
8
+ TAB_BAR_TRANSLUCENCE,
8
9
  }
9
10
 
10
11
  private val ToggleDefaults = mapOf(
11
12
  RNNToggles.TOP_BAR_COLOR_ANIMATION__PUSH to false,
12
13
  RNNToggles.TOP_BAR_COLOR_ANIMATION__TABS to false,
14
+ RNNToggles.TAB_BAR_TRANSLUCENCE to false,
13
15
  )
14
16
 
15
17
  object RNNFeatureToggles {
@@ -3,6 +3,7 @@ package com.reactnativenavigation.options;
3
3
  import android.content.Context;
4
4
 
5
5
  import com.reactnativenavigation.options.params.Bool;
6
+ import com.reactnativenavigation.options.params.BottomTabsLayoutStyle;
6
7
  import com.reactnativenavigation.options.params.Fraction;
7
8
  import com.reactnativenavigation.options.params.NullBool;
8
9
  import com.reactnativenavigation.options.params.NullFraction;
@@ -27,6 +28,11 @@ public class BottomTabsOptions {
27
28
  if (json == null) return options;
28
29
 
29
30
  options.backgroundColor = ThemeColour.parse(context, json.optJSONObject("backgroundColor"));
31
+ options.layoutStyle = BottomTabsLayoutStyle.fromString(json.optString("layoutStyle"));
32
+ options.bottomMargin = FractionParser.parse(json, "bottomMargin");
33
+ options.cornerRadius = FractionParser.parse(json, "cornerRadius");
34
+ options.translucent = BoolParser.parse(json, "translucent");
35
+ options.blurRadius = FractionParser.parse(json, "blurRadius");
30
36
  options.currentTabId = TextParser.parse(json, "currentTabId");
31
37
  options.currentTabIndex = NumberParser.parse(json, "currentTabIndex");
32
38
  options.hideOnScroll = BoolParser.parse(json, "hideOnScroll");
@@ -46,6 +52,11 @@ public class BottomTabsOptions {
46
52
  }
47
53
 
48
54
  public ThemeColour backgroundColor = new NullThemeColour();
55
+ public BottomTabsLayoutStyle layoutStyle = BottomTabsLayoutStyle.LAYOUT_STYLE_UNDEFINED;
56
+ public Fraction bottomMargin = new NullFraction();
57
+ public Fraction cornerRadius = new NullFraction();
58
+ public Bool translucent = new NullBool();
59
+ public Fraction blurRadius = new NullFraction();
49
60
  public Bool hideOnScroll = new NullBool();
50
61
  public Bool visible = new NullBool();
51
62
  public Bool drawBehind = new NullBool();
@@ -79,12 +90,21 @@ public class BottomTabsOptions {
79
90
  if (other.shadowOptions.hasValue()) shadowOptions = shadowOptions.copy().mergeWith(other.shadowOptions);
80
91
  if (other.borderColor.hasValue()) borderColor = other.borderColor;
81
92
  if (other.backgroundColor.hasValue()) backgroundColor = other.backgroundColor;
82
-
93
+ if (other.translucent.hasValue()) translucent = other.translucent;
94
+ if (other.blurRadius.hasValue()) blurRadius = other.blurRadius;
95
+ if (other.layoutStyle.hasValue()) layoutStyle = other.layoutStyle;
96
+ if (other.bottomMargin.hasValue()) bottomMargin = other.bottomMargin;
97
+ if (other.cornerRadius.hasValue()) cornerRadius = other.cornerRadius;
83
98
  }
84
99
 
85
100
  void mergeWithDefault(final BottomTabsOptions defaultOptions) {
86
101
  if (!borderColor.hasValue()) borderColor = defaultOptions.borderColor;
87
102
  if (!backgroundColor.hasValue()) backgroundColor = defaultOptions.backgroundColor;
103
+ if (!translucent.hasValue()) translucent = defaultOptions.translucent;
104
+ if (!blurRadius.hasValue()) blurRadius = defaultOptions.blurRadius;
105
+ if (!layoutStyle.hasValue()) layoutStyle = defaultOptions.layoutStyle;
106
+ if (!bottomMargin.hasValue()) bottomMargin = defaultOptions.bottomMargin;
107
+ if (!cornerRadius.hasValue()) cornerRadius = defaultOptions.cornerRadius;
88
108
  if (!currentTabId.hasValue()) currentTabId = defaultOptions.currentTabId;
89
109
  if (!currentTabIndex.hasValue()) currentTabIndex = defaultOptions.currentTabIndex;
90
110
  if (!hideOnScroll.hasValue()) hideOnScroll = defaultOptions.hideOnScroll;
@@ -35,7 +35,12 @@ public enum LayoutDirection {
35
35
  }
36
36
 
37
37
  public int get() {
38
- return direction;
38
+ return switch (direction) {
39
+ case View.LAYOUT_DIRECTION_RTL -> RTL.direction;
40
+ case View.LAYOUT_DIRECTION_LTR -> LTR.direction;
41
+ case View.LAYOUT_DIRECTION_LOCALE -> LOCALE.direction;
42
+ default -> DEFAULT.direction;
43
+ };
39
44
  }
40
45
 
41
46
  public int inverse() {
@@ -0,0 +1,20 @@
1
+ package com.reactnativenavigation.options.params
2
+
3
+ enum class BottomTabsLayoutStyle {
4
+ STRETCH,
5
+ COMPACT,
6
+ LAYOUT_STYLE_UNDEFINED;
7
+
8
+ fun hasValue(): Boolean = (this != LAYOUT_STYLE_UNDEFINED)
9
+
10
+ companion object {
11
+ @JvmStatic
12
+ fun fromString(mode: String?): BottomTabsLayoutStyle {
13
+ return when (mode?.lowercase()) {
14
+ "stretch" -> STRETCH
15
+ "compact" -> COMPACT
16
+ else -> LAYOUT_STYLE_UNDEFINED
17
+ }
18
+ }
19
+ }
20
+ }
@@ -21,4 +21,8 @@ public class ColorUtils {
21
21
  public static int setAlpha(int color, int alpha) {
22
22
  return (color & 0x00FFFFFF) | (alpha << 24);
23
23
  }
24
+
25
+ public static boolean isOpaque(int color) {
26
+ return (color & 0xFF000000) == 0xFF000000;
27
+ }
24
28
  }
@@ -63,7 +63,15 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
63
63
  tabPresenter.onConfigurationChanged(resolveCurrentOptions());
64
64
  }
65
65
 
66
- public BottomTabsController(Activity activity, List<ViewController<?>> tabs, ChildControllersRegistry childRegistry, EventEmitter eventEmitter, ImageLoader imageLoader, String id, Options initialOptions, Presenter presenter, BottomTabsAttacher tabsAttacher, BottomTabsPresenter bottomTabsPresenter, BottomTabPresenter bottomTabPresenter) {
66
+ public BottomTabsController(Activity activity,
67
+ List<ViewController<?>> tabs,
68
+ ChildControllersRegistry childRegistry,
69
+ EventEmitter eventEmitter,
70
+ ImageLoader imageLoader,
71
+ String id, Options initialOptions,
72
+ Presenter presenter,
73
+ BottomTabsAttacher tabsAttacher,
74
+ BottomTabsPresenter bottomTabsPresenter, BottomTabPresenter bottomTabPresenter) {
67
75
  super(activity, childRegistry, id, presenter, initialOptions);
68
76
  this.tabs = tabs;
69
77
  this.eventEmitter = eventEmitter;
@@ -86,15 +94,17 @@ public class BottomTabsController extends ParentController<BottomTabsLayout> imp
86
94
  @Override
87
95
  public BottomTabsLayout createView() {
88
96
  BottomTabsLayout root = new BottomTabsLayout(getActivity());
97
+ root.setTag("RNN.BottomTabsLayoutRoot");
89
98
 
90
99
  this.bottomTabsContainer = createBottomTabsContainer();
91
100
  this.bottomTabs = bottomTabsContainer.getBottomTabs();
92
101
  Options resolveCurrentOptions = resolveCurrentOptions();
93
102
  tabsAttacher.init(root, resolveCurrentOptions);
94
- presenter.bindView(bottomTabsContainer, this);
103
+ presenter.bindView(bottomTabsContainer, root, this);
95
104
  tabPresenter.bindView(bottomTabs);
96
105
  bottomTabs.setOnTabSelectedListener(this);
97
106
  root.addBottomTabsContainer(bottomTabsContainer);
107
+
98
108
  bottomTabs.addItems(createTabs());
99
109
  setInitialTab(resolveCurrentOptions);
100
110
  tabsAttacher.attach();
@@ -3,13 +3,20 @@ package com.reactnativenavigation.viewcontrollers.bottomtabs
3
3
  import android.animation.Animator
4
4
  import android.graphics.Color
5
5
  import android.view.ViewGroup
6
+ import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
6
7
  import androidx.annotation.IntRange
7
8
  import androidx.core.view.updateMargins
8
9
  import com.aurelhubert.ahbottomnavigation.AHBottomNavigation.TitleState
10
+ import com.reactnativenavigation.RNNFeatureToggles
11
+ import com.reactnativenavigation.RNNToggles.TAB_BAR_TRANSLUCENCE
9
12
  import com.reactnativenavigation.options.Options
13
+ import com.reactnativenavigation.options.params.BottomTabsLayoutStyle
14
+ import com.reactnativenavigation.options.params.Fraction
15
+ import com.reactnativenavigation.utils.UiUtils
10
16
  import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController
11
17
  import com.reactnativenavigation.views.bottomtabs.BottomTabs
12
18
  import com.reactnativenavigation.views.bottomtabs.BottomTabsContainer
19
+ import com.reactnativenavigation.views.bottomtabs.BottomTabsLayout
13
20
  import kotlin.math.max
14
21
  import kotlin.math.roundToInt
15
22
 
@@ -20,12 +27,13 @@ class BottomTabsPresenter(
20
27
  ) {
21
28
  private val bottomTabFinder: BottomTabFinder = BottomTabFinder(tabs)
22
29
  private lateinit var bottomTabsContainer: BottomTabsContainer
30
+ private lateinit var bottomTabsLayout: BottomTabsLayout
23
31
  private lateinit var bottomTabs: BottomTabs
24
32
  private lateinit var tabSelector: TabSelector
25
33
  private val defaultTitleState: TitleState
26
34
  get() {
27
35
  for (i in 0 until bottomTabs.itemsCount) {
28
- if (bottomTabs.getItem(i).hasIcon()) return TitleState.SHOW_WHEN_ACTIVE
36
+ if (bottomTabs.getItem(i)?.hasIcon() == true) return TitleState.SHOW_WHEN_ACTIVE
29
37
  }
30
38
  return TitleState.ALWAYS_SHOW
31
39
  }
@@ -34,8 +42,9 @@ class BottomTabsPresenter(
34
42
  this.defaultOptions = defaultOptions
35
43
  }
36
44
 
37
- fun bindView(bottomTabsContainer: BottomTabsContainer, tabSelector: TabSelector) {
45
+ fun bindView(bottomTabsContainer: BottomTabsContainer, bottomTabsLayout: BottomTabsLayout, tabSelector: TabSelector) {
38
46
  this.bottomTabsContainer = bottomTabsContainer
47
+ this.bottomTabsLayout = bottomTabsLayout
39
48
  this.bottomTabs = bottomTabsContainer.bottomTabs
40
49
  this.tabSelector = tabSelector
41
50
  animator.bindView(this.bottomTabs)
@@ -65,14 +74,51 @@ class BottomTabsPresenter(
65
74
 
66
75
  private fun mergeBottomTabsOptions(options: Options, view: ViewController<*>) {
67
76
  val bottomTabsOptions = options.bottomTabsOptions
68
- if (options.layout.direction.hasValue()) bottomTabs.setLayoutDirection(options.layout.direction)
69
- if (bottomTabsOptions.preferLargeIcons.hasValue()) bottomTabs.setPreferLargeIcons(bottomTabsOptions.preferLargeIcons.get())
70
- if (bottomTabsOptions.titleDisplayMode.hasValue()) {
71
- bottomTabs.titleState = bottomTabsOptions.titleDisplayMode.toState()
77
+
78
+ if (bottomTabsOptions.layoutStyle == BottomTabsLayoutStyle.COMPACT) {
79
+ bottomTabs.layoutParams.width = WRAP_CONTENT
80
+ bottomTabs.refresh()
81
+ }
82
+
83
+ if (bottomTabsOptions.bottomMargin.hasValue()) {
84
+ val margin = extractBottomMarginPx(bottomTabsOptions.bottomMargin)
85
+ bottomTabsLayout.setBottomMargin(margin)
86
+ }
87
+
88
+ if (bottomTabsOptions.cornerRadius.hasValue()) {
89
+ val radius = extractCornerRadius(bottomTabsOptions.cornerRadius)
90
+ bottomTabsContainer.setRoundedCorners(radius)
72
91
  }
92
+
93
+ // Keep this before the translucent check below
73
94
  if (bottomTabsOptions.backgroundColor.hasValue()) {
74
95
  bottomTabsContainer.setBackgroundColor(bottomTabsOptions.backgroundColor.get())
75
96
  }
97
+
98
+ if (RNNFeatureToggles.isEnabled(TAB_BAR_TRANSLUCENCE)) {
99
+ if (bottomTabsOptions.translucent.isTrue) {
100
+ if (bottomTabsOptions.blurRadius.hasValue()) {
101
+ bottomTabsContainer.setBlurRadius(bottomTabsOptions.blurRadius.get().toFloat())
102
+ }
103
+ if (bottomTabsOptions.backgroundColor.hasValue()) {
104
+ bottomTabsContainer.setBlurColor(bottomTabsOptions.backgroundColor.get())
105
+ }
106
+ bottomTabsContainer.enableBackgroundBlur()
107
+ } else if (bottomTabsOptions.translucent.isFalse) {
108
+ bottomTabsContainer.disableBackgroundBlur()
109
+ }
110
+ }
111
+
112
+ if (bottomTabsOptions.elevation.hasValue()) {
113
+ bottomTabsContainer.setElevation(bottomTabsOptions.elevation)
114
+ }
115
+
116
+ if (options.layout.direction.hasValue()) bottomTabs.setLayoutDirection(options.layout.direction)
117
+ if (bottomTabsOptions.preferLargeIcons.hasValue()) bottomTabs.setPreferLargeIcons(bottomTabsOptions.preferLargeIcons.get())
118
+ if (bottomTabsOptions.titleDisplayMode.hasValue()) {
119
+ bottomTabs.setTitleState(bottomTabsOptions.titleDisplayMode.toState())
120
+ }
121
+
76
122
  if (bottomTabsOptions.animateTabSelection.hasValue()) {
77
123
  bottomTabs.setAnimateTabSelection(bottomTabsOptions.animateTabSelection.get())
78
124
  }
@@ -88,7 +134,7 @@ class BottomTabsPresenter(
88
134
  if (tabIndex >= 0) tabSelector.selectTab(tabIndex)
89
135
  }
90
136
  if (bottomTabsOptions.hideOnScroll.hasValue()) {
91
- bottomTabs.isBehaviorTranslationEnabled = bottomTabsOptions.hideOnScroll.get()
137
+ bottomTabs.setBehaviorTranslationEnabled(bottomTabsOptions.hideOnScroll.get())
92
138
  }
93
139
 
94
140
  if (bottomTabsOptions.borderColor.hasValue()) {
@@ -140,10 +186,39 @@ class BottomTabsPresenter(
140
186
 
141
187
  private fun applyBottomTabsOptions(options: Options) {
142
188
  val bottomTabsOptions = options.bottomTabsOptions
189
+ if (bottomTabsOptions.layoutStyle == BottomTabsLayoutStyle.COMPACT) {
190
+ bottomTabs.layoutParams.width = WRAP_CONTENT
191
+ }
192
+
193
+ if (bottomTabsOptions.bottomMargin.hasValue()) {
194
+ val margin = extractBottomMarginPx(bottomTabsOptions.bottomMargin)
195
+ bottomTabsLayout.setBottomMargin(margin)
196
+ }
197
+
198
+ if (bottomTabsOptions.cornerRadius.hasValue()) {
199
+ val radius = extractCornerRadius(bottomTabsOptions.cornerRadius)
200
+ bottomTabsContainer.setRoundedCorners(radius)
201
+ } else {
202
+ bottomTabsContainer.clearRoundedCorners()
203
+ }
204
+
205
+ if (RNNFeatureToggles.isEnabled(TAB_BAR_TRANSLUCENCE) && bottomTabsOptions.translucent.isTrue) {
206
+ if (bottomTabsOptions.blurRadius.hasValue()) {
207
+ bottomTabsContainer.setBlurRadius(bottomTabsOptions.blurRadius.get().toFloat())
208
+ }
209
+ if (bottomTabsOptions.backgroundColor.hasValue()) {
210
+ bottomTabsContainer.setBlurColor(bottomTabsOptions.backgroundColor.get())
211
+ }
212
+ bottomTabsContainer.enableBackgroundBlur()
213
+ } else {
214
+ bottomTabsContainer.disableBackgroundBlur()
215
+ bottomTabsContainer.setBackgroundColor(bottomTabsOptions.backgroundColor.get(Color.WHITE)!!)
216
+ }
217
+
143
218
  bottomTabs.setLayoutDirection(options.layout.direction)
144
219
  bottomTabs.setPreferLargeIcons(options.bottomTabsOptions.preferLargeIcons[false])
145
- bottomTabs.titleState = bottomTabsOptions.titleDisplayMode[defaultTitleState]
146
- bottomTabsContainer.setBackgroundColor(bottomTabsOptions.backgroundColor.get(Color.WHITE)!!)
220
+ bottomTabs.setTitleState(bottomTabsOptions.titleDisplayMode[defaultTitleState])
221
+
147
222
  bottomTabs.setAnimateTabSelection(bottomTabsOptions.animateTabSelection.get(true))
148
223
  if (bottomTabsOptions.currentTabIndex.hasValue()) {
149
224
  val tabIndex = bottomTabsOptions.currentTabIndex.get()
@@ -174,6 +249,7 @@ class BottomTabsPresenter(
174
249
  bottomTabs.hideBottomNavigation(false)
175
250
  }
176
251
  }
252
+
177
253
  if (bottomTabsOptions.elevation.hasValue()) {
178
254
  bottomTabsContainer.setElevation(bottomTabsOptions.elevation)
179
255
  }
@@ -203,7 +279,7 @@ class BottomTabsPresenter(
203
279
  } else {
204
280
  bottomTabsContainer.clearShadow()
205
281
  }
206
- bottomTabs.isBehaviorTranslationEnabled = bottomTabsOptions.hideOnScroll[false]
282
+ bottomTabs.setBehaviorTranslationEnabled(bottomTabsOptions.hideOnScroll[false])
207
283
  }
208
284
 
209
285
  fun applyBottomInset(bottomInset: Int) {
@@ -246,7 +322,37 @@ class BottomTabsPresenter(
246
322
 
247
323
  fun onConfigurationChanged(options: Options) {
248
324
  val bottomTabsOptions = options.withDefaultOptions(defaultOptions).bottomTabsOptions
249
- bottomTabs.setBackgroundColor(bottomTabsOptions.backgroundColor.get(Color.WHITE)!!)
325
+
326
+ if (bottomTabsOptions.layoutStyle == BottomTabsLayoutStyle.COMPACT) {
327
+ bottomTabs.layoutParams.width = WRAP_CONTENT
328
+ }
329
+
330
+ if (bottomTabsOptions.bottomMargin.hasValue()) {
331
+ val margin = extractBottomMarginPx(bottomTabsOptions.bottomMargin)
332
+ bottomTabsLayout.setBottomMargin(margin)
333
+ }
334
+
335
+ if (bottomTabsOptions.cornerRadius.hasValue()) {
336
+ val radius = extractCornerRadius(bottomTabsOptions.cornerRadius)
337
+ bottomTabsContainer.setRoundedCorners(radius)
338
+ } else {
339
+ bottomTabsContainer.clearRoundedCorners()
340
+ }
341
+
342
+ if (RNNFeatureToggles.isEnabled(TAB_BAR_TRANSLUCENCE) && bottomTabsOptions.translucent.isTrue) {
343
+ if (bottomTabsOptions.blurRadius.hasValue()) {
344
+ bottomTabsContainer.setBlurRadius(bottomTabsOptions.blurRadius.get().toFloat())
345
+ }
346
+ if (bottomTabsOptions.backgroundColor.hasValue()) {
347
+ bottomTabsContainer.setBlurColor(bottomTabsOptions.backgroundColor.get())
348
+ }
349
+ bottomTabsContainer.enableBackgroundBlur()
350
+ } else {
351
+ bottomTabsContainer.disableBackgroundBlur()
352
+
353
+ // TODO Change to bottomTabsContainer.setBackgroundColor()?
354
+ bottomTabs.setBackgroundColor(bottomTabsOptions.backgroundColor.get(Color.WHITE)!!)
355
+ }
250
356
 
251
357
  if (bottomTabsOptions.shadowOptions.hasValue()) {
252
358
  if (bottomTabsOptions.shadowOptions.color.hasValue())
@@ -258,4 +364,16 @@ class BottomTabsPresenter(
258
364
  bottomTabsContainer.showTopLine()
259
365
  }
260
366
  }
367
+
368
+ private fun extractCornerRadius(cornerRadius: Fraction): Float {
369
+ val radiusDp = cornerRadius.get()
370
+ val radius = UiUtils.dpToPx(bottomTabsContainer.context, radiusDp.toFloat())
371
+ return radius
372
+ }
373
+
374
+ private fun extractBottomMarginPx(bottomMargin: Fraction): Int {
375
+ val marginDp = bottomMargin.get()
376
+ val margin = UiUtils.dpToPx(bottomTabsContainer.context, marginDp.toFloat()).roundToInt()
377
+ return margin
378
+ }
261
379
  }
@@ -84,8 +84,9 @@ public class ComponentViewController extends ChildController<ComponentLayout> {
84
84
  @Override
85
85
  public void onViewWillAppear() {
86
86
  super.onViewWillAppear();
87
- if (view != null)
87
+ if (view != null) {
88
88
  view.sendComponentWillStart();
89
+ }
89
90
  }
90
91
 
91
92
  @Override
@@ -1,5 +1,8 @@
1
1
  package com.reactnativenavigation.views.bottomtabs;
2
2
 
3
+ import static com.reactnativenavigation.utils.CollectionUtils.forEach;
4
+ import static com.reactnativenavigation.utils.ViewUtils.findChildByClass;
5
+
3
6
  import android.annotation.SuppressLint;
4
7
  import android.content.Context;
5
8
  import android.graphics.Color;
@@ -7,6 +10,8 @@ import android.graphics.drawable.Drawable;
7
10
  import android.view.View;
8
11
  import android.widget.LinearLayout;
9
12
 
13
+ import androidx.annotation.IntRange;
14
+
10
15
  import com.aurelhubert.ahbottomnavigation.AHBottomNavigation;
11
16
  import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem;
12
17
  import com.reactnativenavigation.R;
@@ -15,11 +20,6 @@ import com.reactnativenavigation.options.LayoutDirection;
15
20
  import java.util.ArrayList;
16
21
  import java.util.List;
17
22
 
18
- import androidx.annotation.IntRange;
19
-
20
- import static com.reactnativenavigation.utils.CollectionUtils.*;
21
- import static com.reactnativenavigation.utils.ViewUtils.findChildByClass;
22
-
23
23
  @SuppressLint("ViewConstructor")
24
24
  public class BottomTabs extends AHBottomNavigation {
25
25
  private boolean itemsCreationEnabled = true;
@@ -60,6 +60,7 @@ public class BottomTabs extends AHBottomNavigation {
60
60
  }
61
61
  }
62
62
 
63
+ // TODO Find a better way to do this
63
64
  public void superCreateItems() {
64
65
  super.createItems();
65
66
  }
@@ -77,7 +78,6 @@ public class BottomTabs extends AHBottomNavigation {
77
78
  onItemCreationEnabled.add(() -> super.setCurrentItem(position, useCallback));
78
79
  }
79
80
  }
80
-
81
81
 
82
82
  @Override
83
83
  public void setTitleState(TitleState titleState) {
@@ -3,12 +3,20 @@ package com.reactnativenavigation.views.bottomtabs
3
3
  import android.annotation.SuppressLint
4
4
  import android.content.Context
5
5
  import android.graphics.Color
6
+ import android.graphics.Outline
7
+ import android.util.Log
6
8
  import android.view.View
9
+ import android.view.ViewOutlineProvider
10
+ import android.widget.FrameLayout.LayoutParams.MATCH_PARENT
11
+ import android.widget.FrameLayout.LayoutParams.WRAP_CONTENT
7
12
  import android.widget.LinearLayout
8
13
  import androidx.annotation.RestrictTo
9
14
  import androidx.core.graphics.ColorUtils
10
15
  import com.reactnativenavigation.options.params.Fraction
11
16
  import com.reactnativenavigation.utils.UiUtils.dpToPx
17
+ import eightbitlab.com.blurview.BlurTarget
18
+ import eightbitlab.com.blurview.BlurView
19
+ import java.lang.ref.WeakReference
12
20
  import kotlin.math.roundToInt
13
21
 
14
22
 
@@ -20,16 +28,24 @@ internal const val DEFAULT_SHADOW_ANGLE = 270f
20
28
  internal const val DEFAULT_TOP_OUTLINE_SIZE_PX = 1
21
29
  internal const val DEFAULT_TOP_OUTLINE_COLOR = Color.DKGRAY
22
30
 
31
+ private const val LOG_TAG = "BottomTabs"
32
+
23
33
  class TopOutlineView(context: Context) : View(context)
24
34
 
25
35
  @SuppressLint("ViewConstructor")
26
36
  class BottomTabsContainer(context: Context, val bottomTabs: BottomTabs) : ShadowLayout(context) {
27
37
 
38
+ private val blurringView: BlurView
39
+ private var blurringSurface = WeakReference<BlurTarget>(null)
40
+ private var blurEnabled: Boolean? = null
41
+ private var blurRadius: Float? = null
42
+ private var blurColor: Int? = null
43
+
28
44
  var topOutLineView = TopOutlineView(context)
29
45
  @RestrictTo(RestrictTo.Scope.TESTS, RestrictTo.Scope.SUBCLASSES) get
30
46
  @RestrictTo(RestrictTo.Scope.TESTS) set(value) {
31
47
  this.removeView(field)
32
- addView(value, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT))
48
+ addView(value, LayoutParams(MATCH_PARENT, WRAP_CONTENT))
33
49
  field = value
34
50
  }
35
51
 
@@ -39,17 +55,23 @@ class BottomTabsContainer(context: Context, val bottomTabs: BottomTabs) : Shadow
39
55
  shadowAngle = DEFAULT_SHADOW_ANGLE
40
56
  shadowDistance = DEFAULT_SHADOW_DISTANCE
41
57
  shadowColor = DEFAULT_SHADOW_COLOR
58
+
42
59
  val linearLayout = LinearLayout(context).apply {
43
60
  orientation = LinearLayout.VERTICAL
44
- this.addView(topOutLineView, LayoutParams(LayoutParams.MATCH_PARENT, DEFAULT_TOP_OUTLINE_SIZE_PX))
45
- this.addView(bottomTabs, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
61
+ addView(topOutLineView, LayoutParams(MATCH_PARENT, DEFAULT_TOP_OUTLINE_SIZE_PX))
62
+ addView(bottomTabs, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
46
63
  }
64
+
47
65
  this.clipChildren = false
48
66
  this.clipToPadding = false
49
67
  setTopOutLineColor(DEFAULT_TOP_OUTLINE_COLOR)
50
68
  this.topOutLineView.visibility = View.GONE
51
69
 
52
- this.addView(linearLayout, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)
70
+ blurringView = BlurView(context).apply {
71
+ setBlurEnabled(false)
72
+ addView(linearLayout, WRAP_CONTENT, WRAP_CONTENT)
73
+ }
74
+ addView(blurringView, WRAP_CONTENT, WRAP_CONTENT)
53
75
  }
54
76
 
55
77
  override var shadowRadius: Float
@@ -70,6 +92,63 @@ class BottomTabsContainer(context: Context, val bottomTabs: BottomTabs) : Shadow
70
92
  shadowColor = ColorUtils.setAlphaComponent(shadowColor, (opacity * 0xFF).roundToInt())
71
93
  }
72
94
 
95
+ fun setBlurSurface(blurSurface: BlurTarget) {
96
+ if (blurSurface == blurringSurface.get()) {
97
+ return
98
+ }
99
+
100
+ blurringSurface = WeakReference(blurSurface)
101
+ blurringView
102
+ .setupWith(blurSurface)
103
+ .setBlurEnabled(blurEnabled == true).apply {
104
+ if (blurRadius != null) {
105
+ setBlurRadius(blurRadius!!)
106
+ }
107
+
108
+ if (blurColor != null) {
109
+ setOverlayColor(blurColor!!)
110
+ }
111
+ }
112
+ }
113
+
114
+ fun enableBackgroundBlur() {
115
+ blurringView.setBlurEnabled(true)
116
+ blurEnabled = true
117
+ }
118
+
119
+ fun disableBackgroundBlur() {
120
+ blurringView.setBlurEnabled(false)
121
+ blurEnabled = false
122
+ }
123
+
124
+ fun setBlurRadius(radius: Float) {
125
+ blurringView.setBlurRadius(radius)
126
+ blurRadius = radius
127
+ }
128
+
129
+ fun setBlurColor(color: Int) {
130
+ if (com.reactnativenavigation.utils.ColorUtils.isOpaque(color)) {
131
+ Log.w(LOG_TAG, "Opaque color (#${Integer.toHexString(color)}) set alongside blur-effect in bottom-tabs, rendering blur futile")
132
+ }
133
+
134
+ blurringView.setOverlayColor(color)
135
+ blurColor = color
136
+ }
137
+
138
+ fun setRoundedCorners(radius: Float) {
139
+ this.outlineProvider = object: ViewOutlineProvider() {
140
+ override fun getOutline(view: View, outline: Outline) {
141
+ outline.setRoundRect(0, 0, view.width, view.height, radius)
142
+ }
143
+ }
144
+ this.clipToOutline = true
145
+ }
146
+
147
+ fun clearRoundedCorners() {
148
+ this.outlineProvider = null
149
+ this.clipToOutline = true
150
+ }
151
+
73
152
  fun showShadow() {
74
153
  isShadowed = true
75
154
  }
@@ -98,4 +177,3 @@ class BottomTabsContainer(context: Context, val bottomTabs: BottomTabs) : Shadow
98
177
  setElevation(dpToPx(context, elevation.get().toFloat()))
99
178
  }
100
179
  }
101
-