diff --git a/client/ios/DivKit/Extensions/DivTabsExtensions.swift b/client/ios/DivKit/Extensions/DivTabsExtensions.swift index 3bd317d7e..d11e0b064 100644 --- a/client/ios/DivKit/Extensions/DivTabsExtensions.swift +++ b/client/ios/DivKit/Extensions/DivTabsExtensions.swift @@ -44,6 +44,7 @@ extension DivTabs: DivBlockModeling { expressionResolver: expressionResolver, context: context ), + layoutDirection: context.layoutDirection, listPaddings: titlePaddings.makeEdgeInsets(context: context) ) @@ -53,7 +54,8 @@ extension DivTabs: DivBlockModeling { ? .bySelectedPage : .byHighestPage, path: tabsContext.parentPath, - scrollingEnabled: resolveSwitchTabsByContentSwipeEnabled(expressionResolver) + scrollingEnabled: resolveSwitchTabsByContentSwipeEnabled(expressionResolver), + layoutDirection: context.layoutDirection ) return try TabsBlock( diff --git a/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabContentsView.swift b/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabContentsView.swift index c9d929514..38a01b9d0 100644 --- a/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabContentsView.swift +++ b/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabContentsView.swift @@ -88,6 +88,11 @@ internal class TabContentsView: BlockView { self.observer = observer self.overscrollDelegate = overscrollDelegate + if oldModel?.layoutDirection != model.layoutDirection { + collectionView.semanticContentAttribute = model + .layoutDirection == .rightToLeft ? .forceRightToLeft : .forceLeftToRight + } + if oldModel == nil || oldModel.pages !== model.pages || oldObserver !== observer { dataSource.models = [model.pages.map { $0.block as! CollectionCellModel }] diff --git a/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListSelectionDataSourceImpl.swift b/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListSelectionDataSourceImpl.swift index db91febd6..42555828e 100644 --- a/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListSelectionDataSourceImpl.swift +++ b/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListSelectionDataSourceImpl.swift @@ -46,6 +46,7 @@ final class TabListSelectionDataSourceImpl: TabListSelectionDataSource { return TabTitlesViewModel( items: items, + layoutDirection: listModel.layoutDirection, listPaddings: listModel.listPaddings, titlePaddings: listModel.titleStyle.paddings, selectedBackgroundColor: listModel.titleStyle.activeBackgroundColor, diff --git a/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListView.swift b/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListView.swift index 8f81261c6..3563dcabe 100644 --- a/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListView.swift +++ b/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListView.swift @@ -5,7 +5,7 @@ import CommonCorePublic final class TabListView: UIView { private let collectionView: UICollectionView private let delegate: TabListViewDelegate - private let collectionViewLayout = UICollectionViewFlowLayout.make() + private let collectionViewLayout = GenericCollectionViewFlowLayout.make() private var selectedItemBackground: UIView! var isMovingToSelectedItem = false @@ -23,6 +23,11 @@ final class TabListView: UIView { dataSource = TabListViewDataSource(tabs: model.items) delegate.tabs = model.items } + if oldValue?.layoutDirection != model.layoutDirection { + collectionView.semanticContentAttribute = model + .layoutDirection == .rightToLeft ? .forceRightToLeft : .forceLeftToRight + delegate.layoutDirection = model.layoutDirection + } collectionViewLayout.sectionInset = model.listPaddings collectionViewLayout.minimumLineSpacing = model.itemSpacing ?? 0 selectedItemBackground.backgroundColor = model.selectedBackgroundColor.systemColor @@ -205,14 +210,18 @@ private struct AnimationInfo { } } -extension UICollectionViewFlowLayout { - fileprivate static func make() -> UICollectionViewFlowLayout { - let flowLayout = UICollectionViewFlowLayout() +final class GenericCollectionViewFlowLayout: UICollectionViewFlowLayout { + fileprivate static func make() -> GenericCollectionViewFlowLayout { + let flowLayout = GenericCollectionViewFlowLayout() flowLayout.scrollDirection = .horizontal flowLayout.minimumLineSpacing = 0 flowLayout.minimumInteritemSpacing = 0 return flowLayout } + + override var flipsHorizontallyInOppositeLayoutDirection: Bool { + true + } } private func makeCollectionView(layout: UICollectionViewLayout) -> UICollectionView { diff --git a/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListViewDelegate.swift b/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListViewDelegate.swift index 0a49daca3..4f72af98c 100644 --- a/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListViewDelegate.swift +++ b/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabListViewDelegate.swift @@ -5,6 +5,7 @@ import LayoutKitInterface final class TabListViewDelegate: NSObject, UICollectionViewDelegateFlowLayout { private let collectionView: UICollectionView + public var layoutDirection: UserInterfaceLayoutDirection = .leftToRight private var itemSizes: [CGSize] = [] { didSet { @@ -66,7 +67,7 @@ final class TabListViewDelegate: NSObject, UICollectionViewDelegateFlowLayout { let nextItemVisibilityFraction = itemSelection - CGFloat(baseItemIndex) let contentOffsetX: CGFloat - let pillOriginX: CGFloat + var pillOriginX: CGFloat let bouncingLeft = itemSelection <= 0 let bouncingRight = itemSelection >= CGFloat(tabs.count - 1) @@ -94,6 +95,11 @@ final class TabListViewDelegate: NSObject, UICollectionViewDelegateFlowLayout { pillOriginX = originX.interpolated(to: nextOriginX, progress: nextItemVisibilityFraction) } + if layoutDirection == .rightToLeft { + let pillSizeWidth = itemSizes.map { $0.width }.interim(at: itemSelection) + pillOriginX = size.width - pillSizeWidth - pillOriginX + } + if let offset = offset { return Layout( contentOffset: CGPoint(x: offset, y: 0), diff --git a/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabTitlesViewModel.swift b/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabTitlesViewModel.swift index c97aa485d..2820438c2 100644 --- a/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabTitlesViewModel.swift +++ b/client/ios/LayoutKit/LayoutKit/UI/Views/TabbedPages/TabTitlesViewModel.swift @@ -4,6 +4,7 @@ import CommonCorePublic struct TabTitlesViewModel { let items: [TabTitleViewModel] + let layoutDirection: UserInterfaceLayoutDirection let listPaddings: EdgeInsets let titlePaddings: EdgeInsets let selectedBackgroundColor: Color diff --git a/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabContentsViewModel.swift b/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabContentsViewModel.swift index 29f7b6953..047e1e14e 100644 --- a/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabContentsViewModel.swift +++ b/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabContentsViewModel.swift @@ -11,6 +11,7 @@ public struct TabContentsViewModel: Equatable { public let footer: Block? public let scrollingEnabled: Bool public let contentInsets: EdgeInsets + public let layoutDirection: UserInterfaceLayoutDirection public init( pages: [TabPageViewModel], @@ -19,7 +20,8 @@ public struct TabContentsViewModel: Equatable { path: UIElementPath? = nil, background: Background? = nil, footer: Block? = nil, - scrollingEnabled: Bool = true + scrollingEnabled: Bool = true, + layoutDirection: UserInterfaceLayoutDirection = .leftToRight ) throws { self.path = path self.pages = pages @@ -28,6 +30,7 @@ public struct TabContentsViewModel: Equatable { self.background = background self.footer = footer self.scrollingEnabled = scrollingEnabled + self.layoutDirection = layoutDirection try checkConstraints() } diff --git a/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabListViewModel.swift b/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabListViewModel.swift index 384366721..d08ea1579 100644 --- a/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabListViewModel.swift +++ b/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabListViewModel.swift @@ -8,6 +8,7 @@ public final class TabListViewModel: Equatable { public let tabTitles: [UILink] public let titleStyle: TabTitleStyle + public let layoutDirection: UserInterfaceLayoutDirection public let listPaddings: EdgeInsets lazy var tabs: [TabTitleViewModel] = tabTitles.map { item in @@ -27,10 +28,12 @@ public final class TabListViewModel: Equatable { public init( tabTitles: [UILink], titleStyle: TabTitleStyle = TabTitleStyle(), + layoutDirection: UserInterfaceLayoutDirection = .leftToRight, listPaddings: EdgeInsets = defaultListPaddings ) { self.tabTitles = tabTitles self.titleStyle = titleStyle + self.layoutDirection = layoutDirection self.listPaddings = listPaddings } diff --git a/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabViewModel.swift b/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabViewModel.swift index 13b203b16..2c481ff3c 100644 --- a/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabViewModel.swift +++ b/client/ios/LayoutKit/LayoutKit/ViewModels/TabbedPages/TabViewModel.swift @@ -49,7 +49,8 @@ extension TabContentsViewModel { path: path, background: background, footer: footer, - scrollingEnabled: scrollingEnabled + scrollingEnabled: scrollingEnabled, + layoutDirection: layoutDirection ) } }