Merge branch 'release_1.10'
This commit is contained in:
@@ -11,11 +11,13 @@ struct SupporterBadge: View {
|
||||
let percent: Int?
|
||||
let purple_account: DamusPurple.Account?
|
||||
let style: Style
|
||||
let text_color: Color
|
||||
|
||||
init(percent: Int?, purple_account: DamusPurple.Account? = nil, style: Style) {
|
||||
init(percent: Int?, purple_account: DamusPurple.Account? = nil, style: Style, text_color: Color = .secondary) {
|
||||
self.percent = percent
|
||||
self.purple_account = purple_account
|
||||
self.style = style
|
||||
self.text_color = text_color
|
||||
}
|
||||
|
||||
let size: CGFloat = 17
|
||||
@@ -31,7 +33,7 @@ struct SupporterBadge: View {
|
||||
if self.style == .full {
|
||||
let date = format_date(date: purple_account.created_at, time_style: .none)
|
||||
Text(date)
|
||||
.foregroundStyle(.secondary)
|
||||
.foregroundStyle(text_color)
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,12 @@ struct ContentView: View {
|
||||
|
||||
@State var active_sheet: Sheets? = nil
|
||||
@State var damus_state: DamusState!
|
||||
@SceneStorage("ContentView.selected_timeline") var selected_timeline: Timeline = .home
|
||||
@State var menu_subtitle: String? = nil
|
||||
@SceneStorage("ContentView.selected_timeline") var selected_timeline: Timeline = .home {
|
||||
willSet {
|
||||
self.menu_subtitle = nil
|
||||
}
|
||||
}
|
||||
@State var muting: MuteItem? = nil
|
||||
@State var confirm_mute: Bool = false
|
||||
@State var hide_bar: Bool = false
|
||||
@@ -101,9 +106,16 @@ struct ContentView: View {
|
||||
isSideBarOpened = false
|
||||
}
|
||||
|
||||
var timelineNavItem: Text {
|
||||
return Text(timeline_name(selected_timeline))
|
||||
.bold()
|
||||
var timelineNavItem: some View {
|
||||
VStack {
|
||||
Text(timeline_name(selected_timeline))
|
||||
.bold()
|
||||
if let menu_subtitle {
|
||||
Text(menu_subtitle)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func MainContent(damus: DamusState) -> some View {
|
||||
@@ -122,7 +134,7 @@ struct ContentView: View {
|
||||
PostingTimelineView(damus_state: damus_state!, home: home, active_sheet: $active_sheet)
|
||||
|
||||
case .notifications:
|
||||
NotificationsView(state: damus, notifications: home.notifications)
|
||||
NotificationsView(state: damus, notifications: home.notifications, subtitle: $menu_subtitle)
|
||||
|
||||
case .dms:
|
||||
DirectMessagesView(damus_state: damus_state!, model: damus_state!.dms, settings: damus_state!.settings)
|
||||
|
||||
@@ -9,7 +9,7 @@ import Foundation
|
||||
|
||||
enum FriendFilter: String, StringCodable {
|
||||
case all
|
||||
case friends
|
||||
case friends_of_friends
|
||||
|
||||
init?(from string: String) {
|
||||
guard let ff = FriendFilter(rawValue: string) else {
|
||||
@@ -27,8 +27,17 @@ enum FriendFilter: String, StringCodable {
|
||||
switch self {
|
||||
case .all:
|
||||
return true
|
||||
case .friends:
|
||||
case .friends_of_friends:
|
||||
return contacts.is_in_friendosphere(pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
func description() -> String {
|
||||
switch self {
|
||||
case .all:
|
||||
return NSLocalizedString("All", comment: "Human-readable short description of the 'friends filter' when it is set to 'all'")
|
||||
case .friends_of_friends:
|
||||
return NSLocalizedString("Friends of friends", comment: "Human-readable short description of the 'friends filter' when it is set to 'friends-of-friends'")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ func process_local_notification(state: HeadlessDamusState, event ev: NostrEvent)
|
||||
|
||||
func should_display_notification(state: HeadlessDamusState, event ev: NostrEvent, mode: UserSettingsStore.NotificationsMode) -> Bool {
|
||||
// Do not show notification if it's coming from a mode different from the one selected by our user
|
||||
guard state.settings.notifications_mode == mode else {
|
||||
guard state.settings.notification_mode == mode else {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ struct NostrPost {
|
||||
}
|
||||
|
||||
/// Parse the post's contents to find more tags to apply to the final nostr event
|
||||
private func make_post_tags(post_blocks: [Block], tags: [[String]]) -> PostTags {
|
||||
func make_post_tags(post_blocks: [Block], tags: [[String]]) -> PostTags {
|
||||
var new_tags = tags
|
||||
|
||||
for post_block in post_blocks {
|
||||
@@ -89,10 +89,12 @@ struct NostrPost {
|
||||
|
||||
// MARK: - Helper structures and functions
|
||||
|
||||
/// A struct used for temporarily holding tag information that was parsed from a post contents to aid in building a nostr event
|
||||
fileprivate struct PostTags {
|
||||
let blocks: [Block]
|
||||
let tags: [[String]]
|
||||
extension NostrPost {
|
||||
/// A struct used for temporarily holding tag information that was parsed from a post contents to aid in building a nostr event
|
||||
struct PostTags {
|
||||
let blocks: [Block]
|
||||
let tags: [[String]]
|
||||
}
|
||||
}
|
||||
|
||||
func parse_post_blocks(content: String) -> [Block] {
|
||||
|
||||
@@ -18,7 +18,7 @@ struct PushNotificationClient {
|
||||
|
||||
mutating func set_device_token(new_device_token: Data) async throws {
|
||||
self.device_token = new_device_token
|
||||
if settings.enable_experimental_push_notifications && settings.notifications_mode == .push {
|
||||
if settings.enable_push_notifications && settings.notification_mode == .push {
|
||||
try await self.send_token()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,8 +155,8 @@ class UserSettingsStore: ObservableObject {
|
||||
@Setting(key: "like_notification", default_value: true)
|
||||
var like_notification: Bool
|
||||
|
||||
@StringSetting(key: "notifications_mode", default_value: .local)
|
||||
var notifications_mode: NotificationsMode
|
||||
@StringSetting(key: "notification_mode", default_value: .push)
|
||||
var notification_mode: NotificationsMode
|
||||
|
||||
@Setting(key: "notification_only_from_following", default_value: false)
|
||||
var notification_only_from_following: Bool
|
||||
@@ -207,8 +207,9 @@ class UserSettingsStore: ObservableObject {
|
||||
@Setting(key: "always_show_onboarding_suggestions", default_value: false)
|
||||
var always_show_onboarding_suggestions: Bool
|
||||
|
||||
@Setting(key: "enable_experimental_push_notifications", default_value: false)
|
||||
var enable_experimental_push_notifications: Bool
|
||||
// @Setting(key: "enable_experimental_push_notifications", default_value: false)
|
||||
// This was a feature flag setting during early development, but now this is enabled for everyone.
|
||||
var enable_push_notifications: Bool = true
|
||||
|
||||
@StringSetting(key: "push_notification_environment", default_value: .production)
|
||||
var push_notification_environment: PushNotificationClient.Environment
|
||||
|
||||
@@ -14,12 +14,12 @@ struct FriendsButton: View {
|
||||
Button(action: {
|
||||
switch self.filter {
|
||||
case .all:
|
||||
self.filter = .friends
|
||||
case .friends:
|
||||
self.filter = .friends_of_friends
|
||||
case .friends_of_friends:
|
||||
self.filter = .all
|
||||
}
|
||||
}) {
|
||||
if filter == .friends {
|
||||
if filter == .friends_of_friends {
|
||||
LINEAR_GRADIENT
|
||||
.mask(Image("user-added")
|
||||
.resizable()
|
||||
@@ -28,7 +28,7 @@ struct FriendsButton: View {
|
||||
Image("user-added")
|
||||
.resizable()
|
||||
.frame(width: 28, height: 28)
|
||||
.foregroundColor(DamusColors.adaptableGrey)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
@@ -103,7 +103,7 @@ struct DirectMessagesView: View {
|
||||
|
||||
func would_filter_non_friends_from_dms(contacts: Contacts, dms: [DirectMessageModel]) -> Bool {
|
||||
for dm in dms {
|
||||
if !FriendFilter.friends.filter(contacts: contacts, pubkey: dm.pubkey) {
|
||||
if !FriendFilter.friends_of_friends.filter(contacts: contacts, pubkey: dm.pubkey) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,8 +120,7 @@ struct NoteContentView: View {
|
||||
EventView(damus: damus_state, event: self.event, options: .embedded_text_only)
|
||||
.padding(.top)
|
||||
}
|
||||
.background(.thinMaterial)
|
||||
.preferredColorScheme(.dark)
|
||||
.background(.thickMaterial)
|
||||
.onTapGesture(perform: {
|
||||
damus_state.nav.push(route: Route.Thread(thread: .init(event: self.event, damus_state: damus_state)))
|
||||
dismiss()
|
||||
|
||||
@@ -56,6 +56,7 @@ struct NotificationsView: View {
|
||||
@ObservedObject var notifications: NotificationsModel
|
||||
@StateObject var filter = NotificationFilter()
|
||||
@SceneStorage("NotificationsView.filter_state") var filter_state: NotificationFilterState = .all
|
||||
@Binding var subtitle: String?
|
||||
|
||||
@Environment(\.colorScheme) var colorScheme
|
||||
|
||||
@@ -99,6 +100,15 @@ struct NotificationsView: View {
|
||||
.tag(NotificationFilterState.replies)
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button(
|
||||
action: { state.nav.push(route: Route.NotificationSettings(settings: state.settings)) },
|
||||
label: {
|
||||
Image("settings")
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
)
|
||||
}
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
if would_filter_non_friends_from_notifications(contacts: state.contacts, state: filter_state, items: self.notifications.notifications) {
|
||||
FriendsButton(filter: $filter.fine_filter)
|
||||
@@ -107,12 +117,14 @@ struct NotificationsView: View {
|
||||
}
|
||||
.onChange(of: filter.fine_filter) { val in
|
||||
state.settings.friend_filter = val
|
||||
self.subtitle = filter.fine_filter.description()
|
||||
}
|
||||
.onChange(of: filter_state) { val in
|
||||
filter.state = val
|
||||
}
|
||||
.onAppear {
|
||||
self.filter.fine_filter = state.settings.friend_filter
|
||||
self.subtitle = filter.fine_filter.description()
|
||||
filter.state = filter_state
|
||||
}
|
||||
.safeAreaInset(edge: .top, spacing: 0) {
|
||||
@@ -163,7 +175,7 @@ struct NotificationsView: View {
|
||||
|
||||
struct NotificationsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NotificationsView(state: test_damus_state, notifications: NotificationsModel(), filter: NotificationFilter())
|
||||
NotificationsView(state: test_damus_state, notifications: NotificationsModel(), filter: NotificationFilter(), subtitle: .constant(nil))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +186,7 @@ func would_filter_non_friends_from_notifications(contacts: Contacts, state: Noti
|
||||
continue
|
||||
}
|
||||
|
||||
if item.would_filter({ ev in FriendFilter.friends.filter(contacts: contacts, pubkey: ev.pubkey) }) {
|
||||
if item.would_filter({ ev in FriendFilter.friends_of_friends.filter(contacts: contacts, pubkey: ev.pubkey) }) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,6 @@ struct DamusPurpleAccountView: View {
|
||||
.padding(.bottom, 20)
|
||||
}
|
||||
.foregroundColor(.white.opacity(0.8))
|
||||
.preferredColorScheme(.dark)
|
||||
.background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 12, style: .continuous))
|
||||
.padding()
|
||||
}
|
||||
@@ -81,7 +80,8 @@ struct DamusPurpleAccountView: View {
|
||||
SupporterBadge(
|
||||
percent: nil,
|
||||
purple_account: account,
|
||||
style: .full
|
||||
style: .full,
|
||||
text_color: .white
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,6 @@ struct DeveloperSettingsView: View {
|
||||
.toggleStyle(.switch)
|
||||
if settings.developer_mode {
|
||||
Toggle(NSLocalizedString("Always show onboarding", comment: "Developer mode setting to always show onboarding suggestions."), isOn: $settings.always_show_onboarding_suggestions)
|
||||
|
||||
Toggle(NSLocalizedString("Enable experimental push notifications", comment: "Developer mode setting to enable experimental push notifications."), isOn: $settings.enable_experimental_push_notifications)
|
||||
.toggleStyle(.switch)
|
||||
|
||||
Picker(NSLocalizedString("Push notification environment", comment: "Prompt selection of the Push notification environment (Developer feature to switch between real/production mode to test modes)."),
|
||||
selection: Binding(
|
||||
get: { () -> PushNotificationClient.Environment in
|
||||
|
||||
@@ -36,7 +36,7 @@ struct NotificationSettingsView: View {
|
||||
do {
|
||||
try await damus_state.push_notification_client.send_token()
|
||||
await self.sync_up_remote_notification_settings()
|
||||
settings.notifications_mode = new_value
|
||||
settings.notification_mode = new_value
|
||||
}
|
||||
catch {
|
||||
notification_mode_setting_error = String(format: NSLocalizedString("Error configuring push notifications with the server: %@", comment: "Error label shown when user tries to enable push notifications but something fails"), error.localizedDescription)
|
||||
@@ -47,7 +47,7 @@ struct NotificationSettingsView: View {
|
||||
Task {
|
||||
do {
|
||||
try await damus_state.push_notification_client.revoke_token()
|
||||
settings.notifications_mode = new_value
|
||||
settings.notification_mode = new_value
|
||||
notification_preferences_sync_state = .not_applicable
|
||||
}
|
||||
catch {
|
||||
@@ -67,7 +67,7 @@ struct NotificationSettingsView: View {
|
||||
set: { new_value in
|
||||
let old_value = raw_binding.wrappedValue
|
||||
raw_binding.wrappedValue = new_value
|
||||
if self.settings.notifications_mode == .push {
|
||||
if self.settings.notification_mode == .push {
|
||||
Task {
|
||||
await self.send_push_notification_preferences(on_failure: {
|
||||
raw_binding.wrappedValue = old_value
|
||||
@@ -114,7 +114,7 @@ struct NotificationSettingsView: View {
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
if settings.enable_experimental_push_notifications {
|
||||
if settings.enable_push_notifications {
|
||||
Section(
|
||||
header: Text("General", comment: "Section header for general damus notifications user configuration"),
|
||||
footer: VStack {
|
||||
@@ -126,7 +126,7 @@ struct NotificationSettingsView: View {
|
||||
) {
|
||||
Picker(NSLocalizedString("Notifications mode", comment: "Prompt selection of the notification mode (Feature to switch between local notifications (generated from user's own phone) or push notifications (generated by Damus server)."),
|
||||
selection: Binding(
|
||||
get: { settings.notifications_mode },
|
||||
get: { settings.notification_mode },
|
||||
set: { newValue in
|
||||
self.try_to_set_notifications_mode(new_value: newValue)
|
||||
}
|
||||
@@ -194,7 +194,7 @@ struct NotificationSettingsView: View {
|
||||
}
|
||||
.onAppear(perform: {
|
||||
Task {
|
||||
if self.settings.notifications_mode == .push {
|
||||
if self.settings.notification_mode == .push {
|
||||
await self.sync_up_remote_notification_settings()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,8 @@ class ReplyTests: XCTestCase {
|
||||
let ev = NostrEvent(content: content, keypair: test_keypair, tags: [])!
|
||||
let blocks = parse_note_content(content: .init(note: ev, keypair: test_keypair)).blocks
|
||||
let post_blocks = parse_post_blocks(content: content)
|
||||
let post_tags = make_post_tags(post_blocks: post_blocks, tags: [])
|
||||
let post = NostrPost(content: content, kind: NostrKind.text, tags: [])
|
||||
let post_tags = post.make_post_tags(post_blocks: post_blocks, tags: [])
|
||||
let tr = interpret_event_refs(tags: ev.tags)
|
||||
|
||||
XCTAssertNil(tr)
|
||||
|
||||
Reference in New Issue
Block a user