package com.swmansion.rnscreens.gamma.tabs.screen import android.content.res.Configuration import android.graphics.drawable.Drawable import android.view.ViewGroup import androidx.fragment.app.Fragment import com.facebook.react.uimanager.ThemedReactContext import com.swmansion.rnscreens.gamma.common.FragmentProviding import com.swmansion.rnscreens.gamma.helpers.getSystemDrawableResource import com.swmansion.rnscreens.gamma.tabs.appearance.TabsAppearance import com.swmansion.rnscreens.utils.RNSLog import java.lang.ref.WeakReference import kotlin.properties.Delegates /** * React Component view. */ class TabsScreen( val reactContext: ThemedReactContext, ) : ViewGroup(reactContext), FragmentProviding { override fun onLayout( changed: Boolean, l: Int, t: Int, r: Int, b: Int, ) = Unit private var tabsScreenDelegate: WeakReference = WeakReference(null) internal lateinit var eventEmitter: TabsScreenEventEmitter var screenKey: String? = null set(value) { field = if (value?.isBlank() == true) { null } else { value } } internal val requireScreenKey: String get() = checkNotNull(screenKey) { "[RNScreens] screenKey MUST NOT be null" } var tabTitle: String? by Delegates.observable(null) { _, oldValue, newValue -> updateMenuItemAttributesIfNeeded(oldValue, newValue) } // Appearance internal var appearance: TabsAppearance? by Delegates.observable(null) { _, oldValue, newValue -> if (oldValue != newValue) { tabsScreenDelegate.get()?.onAppearanceChanged(this) } } // Badge var badgeValue: String? by Delegates.observable(null) { _, oldValue, newValue -> updateMenuItemAttributesIfNeeded(oldValue, newValue) } // Accessibility var tabBarItemTestID: String? by Delegates.observable(null) { _, oldValue, newValue -> updateMenuItemAttributesIfNeeded(oldValue, newValue) } var tabBarItemAccessibilityLabel: String? by Delegates.observable(null) { _, oldValue, newValue -> updateMenuItemAttributesIfNeeded(oldValue, newValue) } // Icon var drawableIconResourceName: String? by Delegates.observable(null) { _, oldValue, newValue -> if (newValue != oldValue) { icon = getSystemDrawableResource(reactContext, newValue) } } var selectedDrawableIconResourceName: String? by Delegates.observable(null) { _, oldValue, newValue -> if (newValue != oldValue) { selectedIcon = getSystemDrawableResource(reactContext, newValue) } } var icon: Drawable? by Delegates.observable(null) { _, oldValue, newValue -> updateMenuItemAttributesIfNeeded(oldValue, newValue) } var selectedIcon: Drawable? by Delegates.observable(null) { _, oldValue, newValue -> updateMenuItemAttributesIfNeeded(oldValue, newValue) } var shouldUseRepeatedTabSelectionScrollToTopSpecialEffect: Boolean = true var shouldUseRepeatedTabSelectionPopToRootSpecialEffect: Boolean = true var preventNativeSelection: Boolean = false private fun updateMenuItemAttributesIfNeeded( oldValue: T, newValue: T, ) { if (newValue != oldValue) { onMenuItemAttributesChange() } } override fun onAttachedToWindow() { RNSLog.d(TAG, "TabsScreen [$id] attached to window") super.onAttachedToWindow() } internal fun setTabsScreenDelegate(delegate: TabsScreenDelegate?) { tabsScreenDelegate = WeakReference(delegate) } override fun getAssociatedFragment(): Fragment? = tabsScreenDelegate.get()?.getFragmentForTabsScreen(this) private fun onMenuItemAttributesChange() { tabsScreenDelegate.get()?.onMenuItemAttributesChange(this) } internal fun onViewManagerAddEventEmitters() { // When this is called from View Manager the view tag is already set check(id != NO_ID) { "[RNScreens] TabsScreen must have its tag set when registering event emitters" } eventEmitter = TabsScreenEventEmitter(reactContext, id) } /** * Notify the view that it's associated fragment got its config updated. * * There are cases where the fragment will receive configuration change, but it's view will not, * e.g. theme update from JS via Appearance.setColorScheme. */ internal fun onFragmentConfigurationChange( fragment: TabsScreenFragment, config: Configuration, ) { tabsScreenDelegate.get()?.onFragmentConfigurationChange(this, config) } companion object { const val TAG = "TabsScreen" } }