mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Live Location Sharing Banner (#5370)
* Live Location Sharing Banner # Conflicts: # ElementX.xcodeproj/project.pbxproj * updated the top banner modifier and the top banner views # Conflicts: # ElementX/Resources/Localizations/en-US.lproj/Localizable.strings # ElementX/Resources/Localizations/en.lproj/Localizable.strings * improved the stopping function from the timeline item * stop live location sharing before starting a new one. * added some tests for LiveLocationManager * pr suggestions
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// A single banner item to be displayed in a `topBanners` overlay.
|
||||
/// An individual banner in the vertical stack of a `TopBannerLayer`.
|
||||
struct TopBannerItem {
|
||||
var banner: AnyView
|
||||
var isVisible: Bool
|
||||
@@ -18,18 +18,42 @@ struct TopBannerItem {
|
||||
}
|
||||
}
|
||||
|
||||
/// A Z-axis banner slot displayed in a `topBanners` overlay. Each slot may
|
||||
/// contain one or more vertically stacked banners, each with its own
|
||||
/// visibility. The slot's overall visibility is derived from whether any of
|
||||
/// its vertical banners are visible. Later items in the `topBanners` array
|
||||
/// are overlayed on top of earlier ones (Z-axis).
|
||||
struct TopBannerLayer {
|
||||
var verticalBanners: [TopBannerItem]
|
||||
|
||||
var isVisible: Bool {
|
||||
verticalBanners.contains { $0.isVisible }
|
||||
}
|
||||
|
||||
/// Convenience initialiser for a single-banner slot.
|
||||
init(_ banner: some View, isVisible: Bool) {
|
||||
verticalBanners = [TopBannerItem(banner, isVisible: isVisible)]
|
||||
}
|
||||
|
||||
init(verticalBanners: [TopBannerItem]) {
|
||||
self.verticalBanners = verticalBanners
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
/// Overlays the given banner view at the top edge of this view, using a
|
||||
/// slide from the top edge when `isVisible` is toggled.
|
||||
func topBanner(_ banner: some View, isVisible: Bool, footer: some View = EmptyView()) -> some View {
|
||||
topBanners([TopBannerItem(banner, isVisible: isVisible)], footer: footer)
|
||||
topBanners([TopBannerLayer(banner, isVisible: isVisible)], footer: footer)
|
||||
}
|
||||
|
||||
/// Overlays the given banner views at the top edge of this view. Each banner
|
||||
/// slides from the top edge based on its own `isVisible` flag. Later items in
|
||||
/// the array are overlayed on top of earlier ones. The footer is shared across
|
||||
/// all banners and displayed below the topmost visible banner.
|
||||
func topBanners(_ items: [TopBannerItem], footer: some View = EmptyView()) -> some View {
|
||||
/// Overlays the given Z-axis banner slots at the top edge of this view.
|
||||
/// Later items in the array are overlayed on top of earlier ones. Within
|
||||
/// each slot, visible vertical banners are stacked in a VStack and slide
|
||||
/// in/out from the top edge. The shadow and bottom padding are applied to
|
||||
/// the VStack of each slot. The footer is shared and displayed below the
|
||||
/// topmost visible slot.
|
||||
func topBanners(_ items: [TopBannerLayer], footer: some View = EmptyView()) -> some View {
|
||||
let anyBannerVisible = items.contains { $0.isVisible }
|
||||
return overlay(alignment: .top) {
|
||||
ZStack(alignment: .top) {
|
||||
@@ -38,8 +62,19 @@ extension View {
|
||||
ZStack(alignment: .top) {
|
||||
ForEach(Array(items.enumerated()), id: \.offset) { _, item in
|
||||
if item.isVisible {
|
||||
item.banner
|
||||
.transition(.move(edge: .top))
|
||||
VStack(spacing: 0) {
|
||||
ForEach(Array(item.verticalBanners.enumerated()), id: \.offset) { _, vBanner in
|
||||
if vBanner.isVisible {
|
||||
vBanner.banner
|
||||
.transition(.move(edge: .top))
|
||||
}
|
||||
}
|
||||
}
|
||||
.compositingGroup()
|
||||
.shadow(color: Color(red: 0.11, green: 0.11, blue: 0.13).opacity(0.1), radius: 12, x: 0, y: 4)
|
||||
// To include the shadow in the size
|
||||
.padding(.bottom, 28)
|
||||
.transition(.move(edge: .top))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +88,7 @@ extension View {
|
||||
.hidden()
|
||||
.allowsHitTesting(false)
|
||||
}
|
||||
.animation(.elementDefault, value: items.map(\.isVisible))
|
||||
.animation(.elementDefault, value: items.map { $0.verticalBanners.map(\.isVisible) })
|
||||
.clipped()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ enum TestablePreviewsDictionary {
|
||||
"LegalInformationScreen_Previews" : LegalInformationScreen_Previews.self,
|
||||
"LinkNewDeviceScreen_Previews" : LinkNewDeviceScreen_Previews.self,
|
||||
"LiveLocationRoomTimelineView_Previews" : LiveLocationRoomTimelineView_Previews.self,
|
||||
"LiveLocationSharingBannerView_Previews" : LiveLocationSharingBannerView_Previews.self,
|
||||
"LoadableImage_Previews" : LoadableImage_Previews.self,
|
||||
"LocationMarkerView_Previews" : LocationMarkerView_Previews.self,
|
||||
"LocationPickerSheet_Previews" : LocationPickerSheet_Previews.self,
|
||||
|
||||
Reference in New Issue
Block a user