diff --git a/IceCubesApp.xcodeproj/project.pbxproj b/IceCubesApp.xcodeproj/project.pbxproj index 793debab..15d91717 100644 --- a/IceCubesApp.xcodeproj/project.pbxproj +++ b/IceCubesApp.xcodeproj/project.pbxproj @@ -101,6 +101,7 @@ 9FFF677C299B7B2C00FE700A /* Notifications in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF677B299B7B2C00FE700A /* Notifications */; }; 9FFF6780299B7D2B00FE700A /* DesignSystem in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF677F299B7D2B00FE700A /* DesignSystem */; }; 9FFF6782299B7D3A00FE700A /* Account in Frameworks */ = {isa = PBXBuildFile; productRef = 9FFF6781299B7D3A00FE700A /* Account */; }; + C8FD00C12B582F7300EB60EE /* DesignKit in Frameworks */ = {isa = PBXBuildFile; productRef = C8FD00C02B582F7300EB60EE /* DesignKit */; }; C9B22677297F6C2E001F9EFE /* ContentSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B22676297F6C2E001F9EFE /* ContentSettingsView.swift */; }; D08A9C3529956CFA00204A4A /* SwipeActionsSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08A9C3429956CFA00204A4A /* SwipeActionsSettingsView.swift */; }; DA0B24FB2A6876D50045BDD7 /* SFSafeSymbols in Frameworks */ = {isa = PBXBuildFile; productRef = DA0B24FA2A6876D50045BDD7 /* SFSafeSymbols */; }; @@ -316,6 +317,7 @@ 9F295540292B6C3400E0E81B /* Timeline in Frameworks */, 9F35DB4A29506FA100B3281A /* Notifications in Frameworks */, 9FC2A38B2B49D19A00DFD1C1 /* StatusKit in Frameworks */, + C8FD00C12B582F7300EB60EE /* DesignKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -650,6 +652,7 @@ DA0B24FA2A6876D50045BDD7 /* SFSafeSymbols */, 9FC2A38A2B49D19A00DFD1C1 /* StatusKit */, 9FE4CCAA2B4C848A00DA5F13 /* GiphyUISDK */, + C8FD00C02B582F7300EB60EE /* DesignKit */, ); productName = IceCubesApp; productReference = 9FBFE639292A715500C250E9 /* Ice Cubes.app */; @@ -731,6 +734,7 @@ 9F2A540829699705009B2D7C /* XCRemoteSwiftPackageReference "purchases-ios" */, DA0B24F92A6876D40045BDD7 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */, 9FE4CCA92B4C848A00DA5F13 /* XCRemoteSwiftPackageReference "giphy-ios-sdk" */, + C8FD00BF2B582F7300EB60EE /* XCRemoteSwiftPackageReference "mozilla-social-ios" */, ); productRefGroup = 9FBFE63A292A715500C250E9 /* Products */; projectDirPath = ""; @@ -1439,6 +1443,14 @@ minimumVersion = 2.2.7; }; }; + C8FD00BF2B582F7300EB60EE /* XCRemoteSwiftPackageReference "mozilla-social-ios" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/MozillaSocial/mozilla-social-ios"; + requirement = { + branch = ios17; + kind = branch; + }; + }; DA0B24F92A6876D40045BDD7 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/SFSafeSymbols/SFSafeSymbols"; @@ -1581,6 +1593,11 @@ isa = XCSwiftPackageProductDependency; productName = Account; }; + C8FD00C02B582F7300EB60EE /* DesignKit */ = { + isa = XCSwiftPackageProductDependency; + package = C8FD00BF2B582F7300EB60EE /* XCRemoteSwiftPackageReference "mozilla-social-ios" */; + productName = DesignKit; + }; DA0B24FA2A6876D50045BDD7 /* SFSafeSymbols */ = { isa = XCSwiftPackageProductDependency; package = DA0B24F92A6876D40045BDD7 /* XCRemoteSwiftPackageReference "SFSafeSymbols" */; diff --git a/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 234d1dfd..434a8370 100644 --- a/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/IceCubesApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,14 @@ { "pins" : [ + { + "identity" : "apollo-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apollographql/apollo-ios.git", + "state" : { + "revision" : "fdb97fe7016edc10dd217e530864dd3eee0f114b", + "version" : "1.7.0" + } + }, { "identity" : "bodega", "kind" : "remoteSourceControl", @@ -14,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/Dean151/ButtonKit", "state" : { - "revision" : "377f5bab4ed047704316d531e0826d4de5ebf6a4", - "version" : "0.1.1" + "revision" : "d4ed31ead81d04165591148f80bd2e56688bdbd7", + "version" : "0.1.2" } }, { @@ -36,6 +45,15 @@ "version" : "2.2.7" } }, + { + "identity" : "glean-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mozilla/glean-swift", + "state" : { + "revision" : "63e6475bd275399b701951925c64fd4c9a5f7c2d", + "version" : "54.0.0" + } + }, { "identity" : "keychain-swift", "kind" : "remoteSourceControl", @@ -54,6 +72,15 @@ "version" : "1.3.2" } }, + { + "identity" : "lottie-spm", + "kind" : "remoteSourceControl", + "location" : "https://github.com/airbnb/lottie-spm.git", + "state" : { + "revision" : "96790253c1a82223bd43da651121abfd7e96d0f3", + "version" : "4.3.4" + } + }, { "identity" : "lrucache", "kind" : "remoteSourceControl", @@ -63,6 +90,15 @@ "version" : "1.0.4" } }, + { + "identity" : "mozilla-social-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/MozillaSocial/mozilla-social-ios", + "state" : { + "branch" : "ios17", + "revision" : "68ed7ae56d73da0b18894717d3c81172c9eae588" + } + }, { "identity" : "nuke", "kind" : "remoteSourceControl", diff --git a/IceCubesApp/App/Tabs/Tabs.swift b/IceCubesApp/App/Tabs/Tabs.swift index 49f1aa74..183d40ed 100644 --- a/IceCubesApp/App/Tabs/Tabs.swift +++ b/IceCubesApp/App/Tabs/Tabs.swift @@ -15,6 +15,7 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable { case post case followedTags case lists + case discover nonisolated var id: Int { rawValue @@ -69,6 +70,10 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable { } case .post: VStack { } + case .discover: + NavigationTab { + Text("Todays Top Picks, Coming Soon!") + } case .other: EmptyView() } @@ -78,7 +83,7 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable { var label: some View { switch self { case .timeline: - Label("tab.timeline", systemImage: iconName) + Image(systemName: iconName) case .trending: Label("tab.trending", systemImage: iconName) case .local: @@ -86,7 +91,7 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable { case .federated: Label("tab.federated", systemImage: iconName) case .notifications: - Label("tab.notifications", systemImage: iconName) + Image(systemName: iconName) case .mentions: Label("tab.mentions", systemImage: iconName) case .explore: @@ -96,17 +101,19 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable { case .settings: Label("tab.settings", systemImage: iconName) case .profile: - Label("tab.profile", systemImage: iconName) + Image(systemName: iconName) case .bookmarks: Label("accessibility.tabs.profile.picker.bookmarks", systemImage: iconName) case .favorites: Label("accessibility.tabs.profile.picker.favorites", systemImage: iconName) case .post: - Label("menu.new-post", systemImage: iconName) + Image(iconName) case .followedTags: Label("timeline.filter.tags", systemImage: iconName) case .lists: Label("timeline.filter.lists", systemImage: iconName) + case .discover: + Image(systemName: iconName) case .other: EmptyView() @@ -116,7 +123,7 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable { var iconName: String { switch self { case .timeline: - "rectangle.stack" + "house" case .trending: "chart.line.uptrend.xyaxis" case .local: @@ -140,11 +147,13 @@ enum Tab: Int, Identifiable, Hashable, CaseIterable, Codable { case .favorites: "star" case .post: - "square.and.pencil" + "hexagonPlus" case .followedTags: "tag" case .lists: "list.bullet" + case .discover: + "safari" case .other: "" } @@ -204,9 +213,9 @@ class iOSTabs { class Storage { @AppStorage(TabEntries.first.rawValue) var firstTab = Tab.timeline - @AppStorage(TabEntries.second.rawValue) var secondTab = Tab.notifications - @AppStorage(TabEntries.third.rawValue) var thirdTab = Tab.explore - @AppStorage(TabEntries.fourth.rawValue) var fourthTab = Tab.messages + @AppStorage(TabEntries.second.rawValue) var secondTab = Tab.discover + @AppStorage(TabEntries.third.rawValue) var thirdTab = Tab.post + @AppStorage(TabEntries.fourth.rawValue) var fourthTab = Tab.notifications @AppStorage(TabEntries.fifth.rawValue) var fifthTab = Tab.profile } diff --git a/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift b/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift index 8f703750..8534fb7d 100644 --- a/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift +++ b/IceCubesApp/App/Tabs/Timeline/TimelineTab.swift @@ -49,6 +49,13 @@ struct TimelineTab: View { .withAppRouter() .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .toolbar { + ToolbarItem(placement: .navigation){ + Image("mozillaLogo") + .resizable() + .frame(width: 96, height: 27) + .padding(.vertical, 10) + } + toolbarView } .toolbarBackground(theme.primaryBackgroundColor.opacity(0.50), for: .navigationBar) diff --git a/IceCubesApp/App/Tabs/ToolbarTab.swift b/IceCubesApp/App/Tabs/ToolbarTab.swift index ff36b40d..abe6c915 100644 --- a/IceCubesApp/App/Tabs/ToolbarTab.swift +++ b/IceCubesApp/App/Tabs/ToolbarTab.swift @@ -2,6 +2,7 @@ import SwiftUI import Env import AppAccount import DesignSystem +import Explore @MainActor struct ToolbarTab: ToolbarContent { @@ -11,17 +12,16 @@ struct ToolbarTab: ToolbarContent { @Environment(UserPreferences.self) private var userPreferences @Binding var routerPath: RouterPath - + @State private var scrollToTopSignal: Int = 0 + var body: some ToolbarContent { if !isSecondaryColumn { - statusEditorToolbarItem(routerPath: routerPath, - visibility: userPreferences.postVisibility) - if UIDevice.current.userInterfaceIdiom != .pad || - (UIDevice.current.userInterfaceIdiom == .pad && horizontalSizeClass == .compact) { - ToolbarItem(placement: .navigationBarLeading) { - AppAccountsSelectorView(routerPath: routerPath) + ToolbarItem { + NavigationLink(destination: ExploreView(scrollToTopSignal: $scrollToTopSignal)) { + Image(systemName: "magnifyingglass") + .foregroundStyle(Theme.shared.labelColor) + } } - } } if UIDevice.current.userInterfaceIdiom == .pad && horizontalSizeClass == .regular { if (!isSecondaryColumn && !userPreferences.showiPadSecondaryColumn) || isSecondaryColumn { diff --git a/IceCubesApp/Assets.xcassets/HexagonPlus.imageset/Contents.json b/IceCubesApp/Assets.xcassets/HexagonPlus.imageset/Contents.json new file mode 100644 index 00000000..41d13234 --- /dev/null +++ b/IceCubesApp/Assets.xcassets/HexagonPlus.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "filename" : "HexagonPlus.svg", + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "HexagonPlusDarkMode.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "compression-type" : "automatic", + "template-rendering-intent" : "original" + } +} diff --git a/IceCubesApp/Assets.xcassets/HexagonPlus.imageset/HexagonPlus.svg b/IceCubesApp/Assets.xcassets/HexagonPlus.imageset/HexagonPlus.svg new file mode 100644 index 00000000..d8fc07eb --- /dev/null +++ b/IceCubesApp/Assets.xcassets/HexagonPlus.imageset/HexagonPlus.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/IceCubesApp/Assets.xcassets/HexagonPlus.imageset/HexagonPlusDarkMode.svg b/IceCubesApp/Assets.xcassets/HexagonPlus.imageset/HexagonPlusDarkMode.svg new file mode 100644 index 00000000..2388fc9a --- /dev/null +++ b/IceCubesApp/Assets.xcassets/HexagonPlus.imageset/HexagonPlusDarkMode.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/IceCubesApp/Assets.xcassets/mozillaLogo.imageset/Contents.json b/IceCubesApp/Assets.xcassets/mozillaLogo.imageset/Contents.json new file mode 100644 index 00000000..e06b095b --- /dev/null +++ b/IceCubesApp/Assets.xcassets/mozillaLogo.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "mozillaLogo.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/IceCubesApp/Assets.xcassets/mozillaLogo.imageset/mozillaLogo.pdf b/IceCubesApp/Assets.xcassets/mozillaLogo.imageset/mozillaLogo.pdf new file mode 100644 index 00000000..5b8268a5 --- /dev/null +++ b/IceCubesApp/Assets.xcassets/mozillaLogo.imageset/mozillaLogo.pdf @@ -0,0 +1,194 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +0.000000 0.000000 0.000000 scn +0.000000 40.000000 m +140.529633 40.000000 l +140.529633 0.000000 l +0.000000 0.000000 l +0.000000 40.000000 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 8.340332 7.833496 cm +1.000000 1.000000 1.000000 scn +125.879425 3.455029 m +125.605675 3.378027 125.373596 3.336029 125.142036 3.336029 c +124.319763 3.336029 123.933502 3.686029 123.933502 4.693029 c +123.933502 12.296528 l +123.933502 16.290028 120.736328 18.234531 116.955986 18.234531 c +114.067741 18.234531 112.515625 17.884531 109.430473 16.647030 c +108.742317 12.618029 l +112.754219 12.191528 l +113.323326 14.164028 l +114.145599 14.590528 114.960838 14.667528 116.014168 14.667528 c +118.860222 14.667528 118.902412 12.534028 118.902412 10.750528 c +118.902412 10.170528 l +118.003288 10.289028 116.991150 10.324028 116.014168 10.324028 c +112.002266 10.324028 107.828621 9.317028 107.828621 5.008528 c +107.828621 1.364527 110.709343 0.000526 113.245979 0.000526 c +116.091530 0.000526 117.883247 1.707027 118.895386 3.490528 c +119.126953 1.357527 120.412849 0.000526 122.753090 0.000526 c +123.842079 0.000526 124.973274 0.308027 125.907555 0.819027 c +125.879425 3.455528 l +125.879425 3.455029 l +h +115.086914 3.567028 m +113.568954 3.567028 113.020935 4.462029 113.020935 5.588530 c +113.020935 7.491030 114.581093 7.994528 116.372818 7.994528 c +117.188057 7.994528 118.087181 7.875528 118.909454 7.763529 c +118.789902 4.847029 116.878639 3.567028 115.086914 3.567028 c +115.086914 3.567028 l +h +108.334450 27.082031 m +100.731567 0.384527 l +95.778343 0.384527 l +103.380722 27.081532 l +108.334450 27.081532 l +108.334450 27.082031 l +h +98.125107 27.082031 m +90.522232 0.384527 l +85.575546 0.384527 l +93.178421 27.081532 l +98.125107 27.081532 l +98.125107 27.082031 l +h +77.017288 17.884029 m +82.280434 17.884029 l +82.280434 11.603529 l +77.017288 11.603529 l +77.017288 17.884029 l +77.017288 17.884029 l +h +77.017288 6.672529 m +82.280434 6.672529 l +82.280434 0.384527 l +77.017288 0.384527 l +77.017288 6.672529 l +h +69.358658 6.903528 m +73.335403 6.518528 l +72.246407 0.384527 l +56.886440 0.384527 l +56.380627 3.021526 l +66.048973 14.079529 l +60.554268 14.079529 l +59.774689 11.365528 l +56.148560 11.757528 l +56.773926 17.891029 l +72.211243 17.891029 l +72.605042 15.254529 l +62.851810 4.189529 l +68.543411 4.189529 l +69.358658 6.903528 l +69.358658 6.903528 l +h +44.168610 18.233532 m +37.851635 18.233532 34.732319 14.002528 34.732319 8.882528 c +34.732319 3.294027 38.477001 0.000027 43.894352 0.000027 c +49.508602 0.000027 53.563198 3.532028 53.563198 9.120029 c +53.563198 14.009530 50.478554 18.234032 44.168610 18.234032 c +44.168610 18.233532 l +h +44.049061 3.840029 m +41.323055 3.840029 39.917606 6.169027 39.917606 9.197529 c +39.917606 12.498529 41.512428 14.394030 44.091759 14.394030 c +46.466148 14.394030 48.377415 12.806529 48.377415 9.274029 c +48.377415 5.938028 46.663052 3.840029 44.049061 3.840029 c +h +30.207062 4.189529 m +32.546795 4.189529 l +32.546795 0.384527 l +25.175985 0.384527 l +25.175985 10.239529 l +25.175985 13.268029 24.164345 14.429529 22.175722 14.429529 c +19.758635 14.429529 18.782156 12.722528 18.782156 10.274529 c +18.782156 4.189529 l +21.121889 4.189529 l +21.121889 0.384527 l +13.758110 0.384527 l +13.758110 10.239529 l +13.758110 13.268029 12.745967 14.429529 10.757848 14.429529 c +8.340760 14.429529 7.363779 12.722528 7.363779 10.274529 c +7.363779 4.189529 l +10.715654 4.189529 l +10.715654 0.384527 l +0.000000 0.384527 l +0.000000 4.189529 l +2.340235 4.189529 l +2.340235 14.086529 l +0.000000 14.086529 l +0.000000 17.891529 l +7.363779 17.891529 l +7.363779 15.254529 l +8.418115 17.114529 10.252028 18.241032 12.704276 18.241032 c +15.240912 18.241032 17.573612 17.038029 18.437576 14.478029 c +19.414558 16.807030 21.402676 18.241032 24.171377 18.241032 c +27.325846 18.241032 30.214094 16.338530 30.214094 12.191029 c +30.214094 4.189529 l +30.207062 4.189529 l +h +f +n +Q + +endstream +endobj + +3 0 obj + 3949 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 140.529602 40.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Pages 5 0 R + /Type /Catalog + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000004039 00000 n +0000004062 00000 n +0000004236 00000 n +0000004310 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +4369 +%%EOF \ No newline at end of file diff --git a/IceCubesApp/Resources/Localization/Localizable.xcstrings b/IceCubesApp/Resources/Localization/Localizable.xcstrings index c55a1a70..9c189c69 100644 --- a/IceCubesApp/Resources/Localization/Localizable.xcstrings +++ b/IceCubesApp/Resources/Localization/Localizable.xcstrings @@ -72365,6 +72365,7 @@ } }, "tab.notifications" : { + "extractionState" : "stale", "localizations" : { "be" : { "stringUnit" : { @@ -72483,6 +72484,7 @@ } }, "tab.profile" : { + "extractionState" : "stale", "localizations" : { "be" : { "stringUnit" : { @@ -76430,6 +76432,9 @@ } } } + }, + "Todays Top Picks, Coming Soon!" : { + } }, "version" : "1.0" diff --git a/Packages/DesignSystem/Sources/DesignSystem/ColorSet.swift b/Packages/DesignSystem/Sources/DesignSystem/ColorSet.swift index 60dd6042..32947af1 100644 --- a/Packages/DesignSystem/Sources/DesignSystem/ColorSet.swift +++ b/Packages/DesignSystem/Sources/DesignSystem/ColorSet.swift @@ -7,7 +7,8 @@ public let availableColorsSets: [ColorSetCouple] = .init(light: NemesisLight(), dark: NemesisDark()), .init(light: MediumLight(), dark: MediumDark()), .init(light: ConstellationLight(), dark: ConstellationDark()), - .init(light: ThreadsLight(), dark: ThreadsDark())] + .init(light: ThreadsLight(), dark: ThreadsDark()), + .init(light: MozillaLight(), dark: MozillaDark())] public protocol ColorSet { var name: ColorSetName { get } @@ -37,6 +38,8 @@ public enum ColorSetName: String { case constellationDark = "Constellation - Dark" case threadsLight = "Threads - Light" case threadsDark = "Threads - Dark" + case mozillaLight = "Mozilla - Light" + case mozillaDark = "Mozilla - Dark" } public struct ColorSetCouple: Identifiable { @@ -202,3 +205,25 @@ public struct ThreadsLight: ColorSet { public init() {} } +public struct MozillaLight: ColorSet { + public var name: ColorSetName = .mozillaLight + public var scheme: ColorScheme = .light + public var tintColor: Color = .init(hex: 0x7542E5) + public var primaryBackgroundColor: Color = .init(hex: 0xFFFFFF) + public var secondaryBackgroundColor: Color = .init(hex: 0xFFFFFF) + public var labelColor: Color = .black + + public init() {} +} + +public struct MozillaDark: ColorSet { + public var name: ColorSetName = .mozillaDark + public var scheme: ColorScheme = .dark + public var tintColor: Color = .init(hex: 0xCB9EFF) + public var primaryBackgroundColor: Color = .init(hex: 0x101010) + public var secondaryBackgroundColor: Color = .init(hex: 0x181818) + public var labelColor: Color = .init(hex: 0xE2E4E2) + + public init() {} +} + diff --git a/Packages/DesignSystem/Sources/DesignSystem/Theme.swift b/Packages/DesignSystem/Sources/DesignSystem/Theme.swift index 6961544a..2fc89fe1 100644 --- a/Packages/DesignSystem/Sources/DesignSystem/Theme.swift +++ b/Packages/DesignSystem/Sources/DesignSystem/Theme.swift @@ -310,7 +310,9 @@ import SwiftUI ConstellationLight(), ConstellationDark(), ThreadsLight(), - ThreadsDark() + ThreadsDark(), + MozillaLight(), + MozillaDark() ] } diff --git a/Packages/Models/Sources/Models/Alias/ServerDate.swift b/Packages/Models/Sources/Models/Alias/ServerDate.swift index 986e19d4..c75f803d 100644 --- a/Packages/Models/Sources/Models/Alias/ServerDate.swift +++ b/Packages/Models/Sources/Models/Alias/ServerDate.swift @@ -14,8 +14,8 @@ public struct ServerDate: Codable, Hashable, Equatable, Sendable { return DateFormatterCache.shared.createdAtRelativeFormatter.localizedString(for: date, relativeTo: Date()) } else { - return Duration.seconds(-date.timeIntervalSinceNow).formatted(.units(width: .narrow, - maximumUnitCount: 1)) + return Duration.seconds(-date.timeIntervalSinceNow).formatted(.units(width: .wide, + maximumUnitCount: 1)) + " ago" } } diff --git a/Packages/StatusKit/Sources/StatusKit/Row/StatusActionButtonStyle.swift b/Packages/StatusKit/Sources/StatusKit/Row/StatusActionButtonStyle.swift index 8370d81f..ddeac080 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/StatusActionButtonStyle.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/StatusActionButtonStyle.swift @@ -18,7 +18,6 @@ struct StatusActionButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { configuration.label - .foregroundColor(isOn ? tintColor : Color(UIColor.secondaryLabel)) .animation(nil, value: isOn) .brightness(brightness(configuration: configuration)) .animation(configuration.isPressed ? nil : .default, value: isOn) diff --git a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift index 2e9e1e8b..19a65a87 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/StatusRowView.swift @@ -35,6 +35,10 @@ public struct StatusRowView: View { StatusRowContextMenu(viewModel: viewModel, showTextForSelection: $showSelectableText) } + var headerView: some View { + StatusRowHeaderView(showTextForSelection: $showSelectableText, viewModel: viewModel) + } + public var body: some View { HStack(spacing: 0) { if !isCompact { @@ -61,12 +65,9 @@ public struct StatusRowView: View { } } else { if !isCompact && context != .detail { - Group { StatusRowTagView(viewModel: viewModel) StatusRowReblogView(viewModel: viewModel) StatusRowReplyView(viewModel: viewModel) - } - .padding(.leading, theme.avatarPosition == .top ? 0 : AvatarView.FrameConfig.status.width + .statusColumnsSpacing) } HStack(alignment: .top, spacing: .statusColumnsSpacing) { if !isCompact, @@ -80,7 +81,7 @@ public struct StatusRowView: View { } VStack(alignment: .leading, spacing: .statusComponentSpacing) { if !isCompact { - StatusRowHeaderView(viewModel: viewModel) + headerView } StatusRowContentView(viewModel: viewModel) .contentShape(Rectangle()) diff --git a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowActionsView.swift b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowActionsView.swift index a3bae1fc..00dfe745 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowActionsView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowActionsView.swift @@ -28,12 +28,13 @@ struct StatusRowActionsView: View { } var actions: [Action] { - switch theme.statusActionSecondary { - case .share: - return [.respond, .boost, .favorite, .share, .menu] - case .bookmark: - return [.respond, .boost, .favorite, .bookmark, .menu] - } +// switch theme.statusActionSecondary { +// case .share: +// return [.respond, .boost, .favorite, .share, .menu] +// case .bookmark: +// return [.respond, .boost, .favorite, .bookmark, .menu] +// } + [.respond, .boost, .favorite, .share] } @MainActor @@ -43,7 +44,7 @@ struct StatusRowActionsView: View { func image(dataController: StatusDataController, privateBoost: Bool = false) -> Image { switch self { case .respond: - return Image(systemName: "arrowshape.turn.up.left") + return Image(systemName: "bubble.left.and.bubble.right") case .boost: if privateBoost { if dataController.isReblogged { @@ -52,9 +53,9 @@ struct StatusRowActionsView: View { return Image(systemName: "lock.rotation") } } - return Image(dataController.isReblogged ? "Rocket.Fill" : "Rocket") + return Image(systemName: dataController.isReblogged ? "arrow.2.squarepath" : "arrow.2.squarepath") case .favorite: - return Image(systemName: dataController.isFavorited ? "star.fill" : "star") + return Image(systemName: dataController.isFavorited ? "heart.fill" : "heart") case .bookmark: return Image(systemName: dataController.isBookmarked ? "bookmark.fill" : "bookmark") case .share: @@ -171,27 +172,9 @@ struct StatusRowActionsView: View { .accessibilityLabel("status.action.share-link") } } - Spacer() - } else if action == .menu { - Menu { - StatusRowContextMenu(viewModel: viewModel, showTextForSelection: $showTextForSelection) - .onAppear { - Task { - await viewModel.loadAuthorRelationship() - } - } - } label: { - Label("", systemImage: "ellipsis") - .padding(.vertical, 6) - } - .menuStyle(.button) - .buttonStyle(.borderless) - .foregroundStyle(.secondary) - .contentShape(Rectangle()) - .accessibilityLabel("status.action.context-menu") } else { - actionButton(action: action) - Spacer() + actionButton(action: action) + Spacer() } } } @@ -207,17 +190,10 @@ struct StatusRowActionsView: View { handleAction(action: action) } label: { HStack(spacing: 2) { - if action == .boost { - action - .image(dataController: statusDataController, privateBoost: privateBoost()) - .imageScale(.medium) - .font(.scaledBody) - .fontWeight(.black) - } else { - action - .image(dataController: statusDataController, privateBoost: privateBoost()) - .font(.scaledBody) - } + action + .image(dataController: statusDataController, privateBoost: privateBoost()) + .font(.scaledBody) + if !isNarrow, let count = action.count(dataController: statusDataController, isFocused: isFocused, @@ -227,7 +203,7 @@ struct StatusRowActionsView: View { .lineLimit(1) .minimumScaleFactor(0.6) .contentTransition(.numericText(value: Double(count))) - .foregroundColor(Color(UIColor.secondaryLabel)) + .foregroundColor(.black) .font(.scaledFootnote) .monospacedDigit() .opacity(count > 0 ? 1 : 0) diff --git a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowHeaderView.swift b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowHeaderView.swift index b4226a6b..102eb13c 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowHeaderView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowHeaderView.swift @@ -12,19 +12,42 @@ struct StatusRowHeaderView: View { @Environment(Theme.self) private var theme + @Binding var showTextForSelection: Bool + let viewModel: StatusRowViewModel var body: some View { - HStack(alignment: theme.avatarPosition == .top ? .center : .top) { - Button { - viewModel.navigateToAccountDetail(account: viewModel.finalStatus.account) - } label: { - accountView + HStack() + { + VStack(alignment: .leading, spacing: 0) { + Button { + viewModel.navigateToAccountDetail(account: viewModel.finalStatus.account) + } label: { + accountView + } + .buttonStyle(.plain) + + if !redactionReasons.contains(.placeholder) { + dateView + } } - .buttonStyle(.plain) Spacer() - if !redactionReasons.contains(.placeholder) { - dateView + + Menu { + StatusRowContextMenu(viewModel: viewModel, showTextForSelection: $showTextForSelection) + .onAppear { + Task { + await viewModel.loadAuthorRelationship() + } + } + } label: { + Label("", systemImage: "ellipsis") + .foregroundStyle(Theme.shared.labelColor) + .padding(.vertical, 6) } + .menuStyle(.button) + .buttonStyle(.borderless) + .contentShape(Rectangle()) + .accessibilityLabel("status.action.context-menu") } .accessibilityElement(children: .combine) .accessibilityLabel(Text("\(viewModel.finalStatus.account.safeDisplayName)") + Text(", ") + Text(viewModel.finalStatus.createdAt.relativeFormatted)) @@ -45,7 +68,6 @@ struct StatusRowHeaderView: View { Group { EmojiTextApp(.init(stringValue: viewModel.finalStatus.account.safeDisplayName), emojis: viewModel.finalStatus.account.emojis) - .font(.scaledSubheadline) .foregroundColor(theme.labelColor) .emojiSize(Font.scaledSubheadlineFont.emojiSize) .emojiBaselineOffset(Font.scaledSubheadlineFont.emojiBaselineOffset) @@ -85,12 +107,11 @@ struct StatusRowHeaderView: View { private var dateView: some View { Group { - Text(Image(systemName: viewModel.finalStatus.visibility.iconName)) + - Text(" βΈ± ") + - Text(viewModel.finalStatus.createdAt.relativeFormatted) + Text(viewModel.finalStatus.createdAt.relativeFormatted) + + Text(" - ") + + Text("@\(viewModel.finalStatus.account.acct)") } - .font(.scaledFootnote) .foregroundStyle(.secondary) - .lineLimit(1) + .lineLimit(2) } } diff --git a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowReblogView.swift b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowReblogView.swift index 08e8325a..27e66f7b 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowReblogView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowReblogView.swift @@ -7,8 +7,7 @@ struct StatusRowReblogView: View { var body: some View { if viewModel.status.reblog != nil { HStack(spacing: 2) { - Image("Rocket.Fill") - AvatarView(viewModel.status.account.avatar, config: .boost) + Image(systemName: "arrow.2.squarepath") EmojiTextApp(.init(stringValue: viewModel.status.account.safeDisplayName), emojis: viewModel.status.account.emojis) Text("status.row.was-boosted") } @@ -21,7 +20,6 @@ struct StatusRowReblogView: View { .font(.scaledFootnote) .emojiSize(Font.scaledFootnoteFont.emojiSize) .emojiBaselineOffset(Font.scaledFootnoteFont.emojiBaselineOffset) - .foregroundStyle(.secondary) .fontWeight(.semibold) .onTapGesture { viewModel.navigateToAccountDetail(account: viewModel.status.account) diff --git a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowReplyView.swift b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowReplyView.swift index 162670f0..72623c2e 100644 --- a/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowReplyView.swift +++ b/Packages/StatusKit/Sources/StatusKit/Row/Subviews/StatusRowReplyView.swift @@ -34,7 +34,6 @@ struct StatusRowReplyView: View { } } .font(.scaledFootnote) - .foregroundStyle(.secondary) .fontWeight(.semibold) } } diff --git a/Packages/Timeline/Sources/Timeline/TimelineFilter.swift b/Packages/Timeline/Sources/Timeline/TimelineFilter.swift index 3cb808d5..db6862ee 100644 --- a/Packages/Timeline/Sources/Timeline/TimelineFilter.swift +++ b/Packages/Timeline/Sources/Timeline/TimelineFilter.swift @@ -30,7 +30,6 @@ public enum RemoteTimelineFilter: String, CaseIterable, Hashable, Equatable { } public enum TimelineFilter: Hashable, Equatable, Identifiable { - case home, local, federated, trending case hashtag(tag: String, accountId: String?) case tagGroup(title: String, tags: [String], symbolName: String?) @@ -39,10 +38,14 @@ public enum TimelineFilter: Hashable, Equatable, Identifiable { case latest case resume + public static var mozillaFilters: [TimelineFilter] { + [.home, .local, .federated,] + } + public var id: String { title } - + public func hash(into hasher: inout Hasher) { hasher.combine(title) } diff --git a/Packages/Timeline/Sources/Timeline/View/TimelineView.swift b/Packages/Timeline/Sources/Timeline/View/TimelineView.swift index 72fdfe61..257d67fc 100644 --- a/Packages/Timeline/Sources/Timeline/View/TimelineView.swift +++ b/Packages/Timeline/Sources/Timeline/View/TimelineView.swift @@ -1,4 +1,5 @@ import Charts +import DesignKit import DesignSystem import Env import Models @@ -25,6 +26,8 @@ public struct TimelineView: View { @State private var wasBackgrounded: Bool = false @State private var collectionView: UICollectionView? + @State private var selectedTimelineFilter: LocalizedStringKey + @Binding var timeline: TimelineFilter @Binding var pinnedFilters: [TimelineFilter] @Binding var selectedTagGroup: TagGroup? @@ -45,15 +48,28 @@ public struct TimelineView: View { _selectedTagGroup = selectedTagGroup _scrollToTopSignal = scrollToTopSignal self.canFilterTimeline = canFilterTimeline + _selectedTimelineFilter = State(initialValue: TimelineFilter.mozillaFilters.first!.localizedTitle()) } public var body: some View { + SegmentedControl(sources: TimelineFilter.mozillaFilters.map { $0.localizedTitle() }, selected: $selectedTimelineFilter) + .onChange(of: selectedTimelineFilter) { newValue in + if let selectedTimeline = TimelineFilter.mozillaFilters.first(where: { $0.localizedTitle() == newValue }) { + self.timeline = selectedTimeline + } + } ScrollViewReader { proxy in ZStack(alignment: .top) { List { scrollToTopView TimelineTagGroupheaderView(group: $selectedTagGroup, timeline: $timeline) + .background { + Color.red + } TimelineTagHeaderView(tag: $viewModel.tag) + .background { + Color.blue + } switch viewModel.timeline { case .remoteLocal: StatusesListView(fetcher: viewModel, client: client, routerPath: routerPath, isRemote: true) @@ -110,7 +126,6 @@ public struct TimelineView: View { } } .toolbar { - toolbarTitleView toolbarTagGroupButton } .navigationBarTitleDisplayMode(.inline)