Skip to content

Commit edd1af2

Browse files
committed
Support plus feature flag
1 parent bf811c9 commit edd1af2

File tree

9 files changed

+82
-8
lines changed

9 files changed

+82
-8
lines changed

Core/Package.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,12 @@ let package = Package(
263263
]
264264
),
265265
.target(name: "UserDefaultsObserver"),
266+
.target(
267+
name: "PlusFeatureFlag",
268+
dependencies: [
269+
.product(name: "LicenseManagement", package: "Tool"),
270+
]
271+
),
266272

267273
// MARK: - GitHub Copilot
268274

Core/Sources/ChatGPTChatTab/ChatGPTChatTab.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class ChatGPTChatTab: ChatTab {
1515

1616
struct Builder: ChatTabBuilder {
1717
var title: String
18+
var buildable: Bool { true }
1819
var customCommand: CustomCommand?
1920

2021
func build() -> any ChatTab {

Core/Sources/HostApp/HostApp.swift

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,49 @@
1-
import Foundation
1+
import Client
22
import ComposableArchitecture
3+
import Foundation
4+
5+
#if canImport(LicenseManagement)
6+
import LicenseManagement
7+
#endif
38

49
struct HostApp: ReducerProtocol {
510
struct State: Equatable {
611
var general = General.State()
712
}
8-
13+
914
enum Action: Equatable {
1015
case appear
16+
case informExtensionServiceAboutLicenseKeyChange
1117
case general(General.Action)
1218
}
13-
19+
20+
@Dependency(\.toast) var toast
21+
1422
var body: some ReducerProtocol<State, Action> {
1523
Scope(state: \.general, action: /Action.general) {
1624
General()
1725
}
18-
26+
1927
Reduce { _, action in
2028
switch action {
2129
case .appear:
2230
return .none
31+
case .informExtensionServiceAboutLicenseKeyChange:
32+
return .run { _ in
33+
#if canImport(LicenseManagement)
34+
let service = try getService()
35+
do {
36+
try await service
37+
.postNotification(name: Notification.Name.licenseKeyChanged.rawValue)
38+
} catch {
39+
toast(error.localizedDescription, .error)
40+
}
41+
#endif
42+
}
2343
case .general:
2444
return .none
2545
}
2646
}
2747
}
2848
}
49+

Core/Sources/HostApp/TabContainer.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ public struct TabContainer: View {
5959
image: "command.square"
6060
)
6161
#if canImport(ProHostApp)
62-
PlusView().tabBarItem(
62+
PlusView(onLicenseKeyChanged: {
63+
store.send(.informExtensionServiceAboutLicenseKeyChange)
64+
}).tabBarItem(
6365
tag: 5,
6466
title: "Plus",
6567
image: "plus.diamond"
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Dependencies
2+
import Foundation
3+
import SwiftUI
4+
5+
#if canImport(LicenseManagement)
6+
7+
import LicenseManagement
8+
9+
public func withFeatureEnabled(
10+
_ flag: KeyPath<PlusFeatureFlags, PlusFeatureFlag>,
11+
then: () throws -> Void
12+
) rethrows {
13+
try LicenseManagement.withFeatureEnabled(flag, then: then)
14+
}
15+
16+
public func withFeatureEnabled(
17+
_ flag: KeyPath<PlusFeatureFlags, PlusFeatureFlag>,
18+
then: () async throws -> Void
19+
) async rethrows {
20+
try await LicenseManagement.withFeatureEnabled(flag, then: then)
21+
}
22+
23+
public func isFeatureAvailable(_ flag: KeyPath<PlusFeatureFlags, PlusFeatureFlag>) -> Bool {
24+
LicenseManagement.isFeatureAvailable(flag)
25+
}
26+
27+
#endif

Core/Sources/Service/GUI/GraphicalUserInterfaceController.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ struct GUI: ReducerProtocol {
4141
Reduce { _, action in
4242
switch action {
4343
case let .createNewTapButtonClicked(kind):
44-
let chatTap = kind?.builder.build() ?? ChatGPTChatTab()
44+
guard let builder = kind?.builder, builder.buildable else { return .none }
45+
let chatTap = builder.build()
4546
return .run { send in
4647
await send(.appendAndSelectTab(chatTap))
4748
}

Core/Sources/SuggestionWidget/ChatWindowView.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ struct ChatTabBar: View {
224224
store.send(.createNewTapButtonClicked(kind: kind))
225225
}) {
226226
Text(kind.title)
227-
}
227+
}.disabled(!kind.builder.buildable)
228228
case let .folder(title, list):
229229
Menu {
230230
ForEach(0..<list.endIndex, id: \.self) { index in
@@ -360,6 +360,7 @@ class FakeChatTab: ChatTab {
360360

361361
struct Builder: ChatTabBuilder {
362362
var title: String = "Title"
363+
var buildable: Bool { true }
363364

364365
func build() -> any ChatTab {
365366
return FakeChatTab(id: "id", title: "Title")

Pro

Submodule Pro updated from d52ada1 to 9b31802

Tool/Sources/ChatTab/ChatTab.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,24 @@ open class BaseChatTab: Equatable {
9494
public protocol ChatTabBuilder {
9595
/// A visible title for user.
9696
var title: String { get }
97+
/// whether the chat tab is buildable.
98+
var buildable: Bool { get }
9799
/// Build the chat tab.
98100
func build() -> any ChatTab
99101
}
100102

103+
public struct DisabledChatTabBuilder: ChatTabBuilder {
104+
public var title: String
105+
public var buildable: Bool { false }
106+
public func build() -> any ChatTab {
107+
EmptyChatTab(id: UUID().uuidString)
108+
}
109+
110+
public init(title: String) {
111+
self.title = title
112+
}
113+
}
114+
101115
public protocol ChatTabType {
102116
/// The type of the external dependency required by this chat tab.
103117
associatedtype ExternalDependency
@@ -127,6 +141,7 @@ public class EmptyChatTab: ChatTab {
127141

128142
struct Builder: ChatTabBuilder {
129143
let title: String
144+
var buildable: Bool { true }
130145
func build() -> any ChatTab {
131146
EmptyChatTab()
132147
}

0 commit comments

Comments
 (0)