diff --git a/TPU_Mac.xcodeproj/project.pbxproj b/TPU_Mac.xcodeproj/project.pbxproj index 4597c99..b615819 100644 --- a/TPU_Mac.xcodeproj/project.pbxproj +++ b/TPU_Mac.xcodeproj/project.pbxproj @@ -518,7 +518,7 @@ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 0.3.5; + MARKETING_VERSION = 0.3.6; PRODUCT_BUNDLE_IDENTIFIER = "ElectricS01.TPU-Mac"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; @@ -561,7 +561,7 @@ LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 0.3.5; + MARKETING_VERSION = 0.3.6; PRODUCT_BUNDLE_IDENTIFIER = "ElectricS01.TPU-Mac"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; diff --git a/TPU_Mac/ChatView.swift b/TPU_Mac/ChatView.swift index dbdddf7..a1e8e16 100644 --- a/TPU_Mac/ChatView.swift +++ b/TPU_Mac/ChatView.swift @@ -236,195 +236,197 @@ struct ChatView: View { } var body: some View { - VStack { - ScrollViewReader { proxy in - ScrollView { - LazyVStack(alignment: .leading, spacing: 0) { - ForEach(Array(chatMessages.enumerated()), id: \.element) { index, message in - let dontMerge = merge(message: message, previousMessage: index != 0 ? chatMessages[index - 1] : nil) - Spacer(minLength: dontMerge ? 16 : 0) - if message.id == unreadId { - HStack { - VStack { Divider().background(.red) } - Text("New Message").foregroundStyle(.red) - VStack { Divider().background(.red) } - } - } - if message.reply != nil { - Button(action: { - proxy.scrollTo(message.replyId) - }) { + #if !os(macOS) + VStack { + ScrollViewReader { proxy in + ScrollView { + LazyVStack(alignment: .leading, spacing: 0) { + ForEach(Array(chatMessages.enumerated()), id: \.element) { index, message in + let dontMerge = merge(message: message, previousMessage: index != 0 ? chatMessages[index - 1] : nil) + Spacer(minLength: dontMerge ? 16 : 0) + if message.id == unreadId { HStack { - Image(systemName: "arrow.turn.up.right").frame(width: 16, height: 16) - ProfilePicture(avatar: message.reply?.user?.avatar, size: 16) - Text(message.reply?.user?.username ?? "User has been deleted") - Text((message.reply?.content ?? "Message has been deleted").replacingOccurrences(of: "\n", with: "")).textSelection(.enabled).lineLimit(1) - }.padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 0)) - }.buttonStyle(.plain) - } - HStack(alignment: .top, spacing: 6) { - if dontMerge { - ProfilePicture(avatar: message.user?.avatar) - } else { - Spacer().frame(width: 32) + VStack { Divider().background(.red) } + Text("New Message").foregroundStyle(.red) + VStack { Divider().background(.red) } + } } - VStack { - if dontMerge { + if message.reply != nil { + Button(action: { + proxy.scrollTo(message.replyId) + }) { HStack { - Text(message.user?.username ?? "User has been deleted") - Text(DateUtils.dateFormat(message.createdAt)) - }.frame(minWidth: 0, - maxWidth: .infinity, - minHeight: 0, - maxHeight: 10, - alignment: .topLeading) - } - if editingId != message.id { - Text(.init(message.content ?? "Message has been deleted")) - .textSelection(.enabled) - .frame(minWidth: 0, - maxWidth: .infinity, - alignment: .leading) - .lineLimit(nil) + Image(systemName: "arrow.turn.up.right").frame(width: 16, height: 16) + ProfilePicture(avatar: message.reply?.user?.avatar, size: 16) + Text(message.reply?.user?.username ?? "User has been deleted") + Text((message.reply?.content ?? "Message has been deleted").replacingOccurrences(of: "\n", with: "")).textSelection(.enabled).lineLimit(1) + }.padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 0)) + }.buttonStyle(.plain) + } + HStack(alignment: .top, spacing: 6) { + if dontMerge { + ProfilePicture(avatar: message.user?.avatar) } else { - TextField("Keep it civil!", text: $editingMessage) - .onSubmit { - editMessage() - } - .focused($focusedField, equals: .editing) - .textFieldStyle(RoundedBorderTextFieldStyle()) + Spacer().frame(width: 32) } - ForEach(message.embeds, id: \.self) { embed in - if embed.media != [] { - LazyImage(url: URL(string: embed.media?[0].attachment == nil ? ("https://i.electrics01.com" + (embed.media?[0].proxyUrl ?? "")) : ("https://i.electrics01.com/i/" + (embed.media?[0].attachment ?? "")))) { state in - if let image = state.image { - image.resizable().aspectRatio(contentMode: .fit) - // .onAppear { - //// if chatMessages.count != 0 { - //// proxy.scrollTo(0, anchor: .bottom) - //// } - // } - } else if state.error != nil { - Color.red - } else { - ProgressView() + VStack { + if dontMerge { + HStack { + Text(message.user?.username ?? "User has been deleted") + Text(DateUtils.dateFormat(message.createdAt)) + }.frame(minWidth: 0, + maxWidth: .infinity, + minHeight: 0, + maxHeight: 10, + alignment: .topLeading) + } + if editingId != message.id { + Text(.init(message.content ?? "Message has been deleted")) + .textSelection(.enabled) + .frame(minWidth: 0, + maxWidth: .infinity, + alignment: .leading) + .lineLimit(nil) + } else { + TextField("Keep it civil!", text: $editingMessage) + .onSubmit { + editMessage() } - }.frame(minWidth: 0, maxWidth: 600, minHeight: 0, maxHeight: 400) + .focused($focusedField, equals: .editing) + .textFieldStyle(RoundedBorderTextFieldStyle()) } - }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading) - } - Button(action: { - if replyingId != message.id { - replyingId = message.id - } else { replyingId = -1 } - }) { - Image(systemName: "arrowshape.turn.up.left.fill").frame(width: 16, height: 16) - } - Button(action: { - pinMessage(messageId: message.id, pinned: message.pinned) - }) { - Image(systemName: message.pinned ? "pin.slash.fill" : "pin.fill").frame(width: 16, height: 16) - } - if coreUser?.id == message.userId { + ForEach(message.embeds, id: \.self) { embed in + if embed.media != [] { + LazyImage(url: URL(string: embed.media?[0].attachment == nil ? ("https://i.electrics01.com" + (embed.media?[0].proxyUrl ?? "")) : ("https://i.electrics01.com/i/" + (embed.media?[0].attachment ?? "")))) { state in + if let image = state.image { + image.resizable().aspectRatio(contentMode: .fit) + // .onAppear { + //// if chatMessages.count != 0 { + //// proxy.scrollTo(0, anchor: .bottom) + //// } + // } + } else if state.error != nil { + Color.red + } else { + ProgressView() + } + }.frame(minWidth: 0, maxWidth: 600, minHeight: 0, maxHeight: 400) + } + }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading) + } Button(action: { - replyingId = -1 - if editingId != message.id { - editingId = message.id - editingMessage = message.content ?? "" - } else { editingId = -1 } + if replyingId != message.id { + replyingId = message.id + } else { replyingId = -1 } }) { - Image(systemName: "pencil").frame(width: 16, height: 16) + Image(systemName: "arrowshape.turn.up.left.fill").frame(width: 16, height: 16) } - } - }.padding(EdgeInsets(top: 0, leading: 4, bottom: 0, trailing: 4)).id(message.id) - // .background(Color(hoverItem == message.id ? Color.primary : .clear)) - // .onHover(perform: { _ in - // hoverItem = message.id - // }) - }.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 12)) - } - .id(0) - .frame( - minWidth: 0, - maxWidth: .infinity, - minHeight: 0, - maxHeight: .infinity, - alignment: .topLeading - ) - .onAppear { - if chatMessages.count != 0 { + Button(action: { + pinMessage(messageId: message.id, pinned: message.pinned) + }) { + Image(systemName: message.pinned ? "pin.slash.fill" : "pin.fill").frame(width: 16, height: 16) + } + if coreUser?.id == message.userId { + Button(action: { + replyingId = -1 + if editingId != message.id { + editingId = message.id + editingMessage = message.content ?? "" + } else { editingId = -1 } + }) { + Image(systemName: "pencil").frame(width: 16, height: 16) + } + } + }.padding(EdgeInsets(top: 0, leading: 4, bottom: 0, trailing: 4)).id(message.id) + // .background(Color(hoverItem == message.id ? Color.primary : .clear)) + // .onHover(perform: { _ in + // hoverItem = message.id + // }) + }.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 12)) + } + .id(0) + .frame( + minWidth: 0, + maxWidth: .infinity, + minHeight: 0, + maxHeight: .infinity, + alignment: .topLeading + ) + .onAppear { + if chatMessages.count != 0 { + proxy.scrollTo(0, anchor: .bottom) + } + } + .onChange(of: chatMessages) { proxy.scrollTo(0, anchor: .bottom) } } - .onChange(of: chatMessages) { - proxy.scrollTo(0, anchor: .bottom) + if replyingId != -1 { + HStack { + Image(systemName: "arrow.turn.up.right").frame(width: 16, height: 16) + Text(chatMessages.last(where: { $0.id == replyingId })?.user?.username ?? "User has been deleted") + Text(chatMessages.last(where: { $0.id == replyingId })?.content ?? "Message has been deleted") + .textSelection(.enabled) + .lineLimit(1) + .onAppear { + if chatMessages.count != 0 { + proxy.scrollTo(0, anchor: .bottom) + } + } + }.padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 0)) + .frame(minWidth: 0, + maxWidth: .infinity, + alignment: .topLeading) } + TextField("Keep it civil!", text: $inputMessage) + .focused($focusedField, equals: .editing) + .onSubmit { + sendMessage() + } + .textFieldStyle(RoundedBorderTextFieldStyle()) } - if replyingId != -1 { - HStack { - Image(systemName: "arrow.turn.up.right").frame(width: 16, height: 16) - Text(chatMessages.last(where: { $0.id == replyingId })?.user?.username ?? "User has been deleted") - Text(chatMessages.last(where: { $0.id == replyingId })?.content ?? "Message has been deleted") - .textSelection(.enabled) - .lineLimit(1) - .onAppear { - if chatMessages.count != 0 { - proxy.scrollTo(0, anchor: .bottom) - } + .navigationTitle(chatsList[chatOpen].recipient?.username ?? chatsList[chatOpen].name) + .navigationBarTitleDisplayMode(.inline) + .toolbar(content: { + ToolbarItem(placement: .principal) { + Text(chatsList[chatOpen].recipient?.username ?? chatsList[chatOpen].name) + .bold() + .onTapGesture { + showingSheet.toggle() + } + .sheet(isPresented: $showingSheet) { + List { + ForEach(0 ..< chatsList[chatOpen].users.count, id: \.self) { result in + Button(action: { print("Clicked: " + (chatsList[chatOpen].users[result].user?.username ?? "User's name could not be found")) }) { + HStack { + ProfilePicture(avatar: chatsList[chatOpen].users[result].user?.avatar) + Text(chatsList[chatOpen].users[result].user?.username ?? "User's name could not be found") + Spacer() + }.contentShape(Rectangle()) + }.buttonStyle(.plain) + } + }.padding(EdgeInsets(top: -8, leading: -10, bottom: -8, trailing: 0)) } - }.padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 0)) - .frame(minWidth: 0, - maxWidth: .infinity, - alignment: .topLeading) - } - TextField("Keep it civil!", text: $inputMessage) - .focused($focusedField, equals: .editing) - .onSubmit { - sendMessage() } - .textFieldStyle(RoundedBorderTextFieldStyle()) + }) } - .navigationTitle(chatsList[chatOpen].recipient?.username ?? chatsList[chatOpen].name) - .navigationBarTitleDisplayMode(.inline) - .toolbar(content: { - ToolbarItem(placement: .principal) { - Text(chatsList[chatOpen].recipient?.username ?? chatsList[chatOpen].name) - .bold() - .onTapGesture { - showingSheet.toggle() - } - .sheet(isPresented: $showingSheet) { - List { - ForEach(0 ..< chatsList[chatOpen].users.count, id: \.self) { result in - Button(action: { print("Clicked: " + (chatsList[chatOpen].users[result].user?.username ?? "User's name could not be found")) }) { - HStack { - ProfilePicture(avatar: chatsList[chatOpen].users[result].user?.avatar) - Text(chatsList[chatOpen].users[result].user?.username ?? "User's name could not be found") - Spacer() - }.contentShape(Rectangle()) - }.buttonStyle(.plain) - } - }.padding(EdgeInsets(top: -8, leading: -10, bottom: -8, trailing: 0)) - } + .navigationTitle("Comms") + .onAppear { + getChat(chatId: chatOpen) + messagesSubscription() + editingSubscription() + } + .onDisappear { + if let subscription = apolloSubscription { + subscription.cancel() + apolloSubscription = nil } - }) - } - .navigationTitle("Comms") - .onAppear { - getChat(chatId: chatOpen) - messagesSubscription() - editingSubscription() - } - .onDisappear { - if let subscription = apolloSubscription { - subscription.cancel() - apolloSubscription = nil } - } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("NavigateToPage"))) { notification in - if let userInfo = notification.userInfo, let pageID = userInfo["to"] as? Int { - getChat(chatId: chatsList.firstIndex(where: { $0.id == pageID })) + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("NavigateToPage"))) { notification in + if let userInfo = notification.userInfo, let pageID = userInfo["to"] as? Int { + getChat(chatId: chatsList.firstIndex(where: { $0.id == pageID })) + } } - } + #endif } } diff --git a/TPU_Mac/CollectionsView.swift b/TPU_Mac/CollectionsView.swift index 24c8fe2..51d39a1 100644 --- a/TPU_Mac/CollectionsView.swift +++ b/TPU_Mac/CollectionsView.swift @@ -55,94 +55,13 @@ struct CollectionsView: View { var body: some View { NavigationStack { ScrollView { - HStack { - #if !os(macOS) - Button(action: { showingSheet.toggle() }) { - Circle() - .fill(showOwned && showShared ? .gray.opacity(0.15) : .blue) - .frame(width: 30, height: 30) - .overlay { - Image(systemName: "line.3.horizontal.decrease") - .font(.system(size: 13.0, weight: .semibold)) - .foregroundColor(showOwned && showShared ? .blue : .primary) - }.sheet(isPresented: $showingSheet) { - NavigationView { - Form { - Button(action: { - showOwned = true - showShared = true - getCollections() - }) { - HStack { - Label { - Text("All Items").foregroundColor(.primary) - } icon: { - Image(systemName: "photo.on.rectangle") - } - if showOwned && showShared { - Spacer() - Image(systemName: "checkmark").foregroundColor(.blue) - } - } - } - Section(header: Text("Show")) { - Button(action: { - showOwned.toggle() - getCollections() - }) { - HStack { - Label { - Text("Owned").foregroundColor(.primary) - } icon: { - Image(systemName: "person") - } - if showOwned { - Spacer() - Image(systemName: "checkmark").foregroundColor(.blue) - } - } - } - Button(action: { - showShared.toggle() - getCollections() - }) { - HStack { - Label { - Text("Shared").foregroundColor(.primary) - } icon: { - Image(systemName: "shared.with.you") - } - if showShared { - Spacer() - Image(systemName: "checkmark").foregroundColor(.blue) - } - } - } - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - self.showingSheet = false - }) { - Text("Done").bold() - } - } - } - .navigationTitle("Filter") - .navigationBarTitleDisplayMode(.inline) - } - } - } - #endif - }.padding(EdgeInsets(top: 10, leading: 10, bottom: -8, trailing: 10)) LazyVGrid(columns: [GridItem(.adaptive(minimum: 316))], spacing: 10) { ForEach(Array($collectionItems.wrappedValue.enumerated()), id: \.element) { _, collectionItem in NavigationLink(destination: CollectionView(collection: .constant(collectionItem))) { HStack(alignment: .center) { LazyImage(url: URL(string: "https://i.electrics01.com/i/" + (collectionItem.banner ?? "a050d6f271c3.png"))) { state in if let image = state.image { - image.resizable().aspectRatio(contentMode: .fill) + image.resizable().aspectRatio(contentMode: .fill).clipped() } else if state.error != nil { Color.red } else { @@ -166,29 +85,108 @@ struct CollectionsView: View { }.buttonStyle(.plain) } } - .toolbar { - Toggle(isOn: $showOwned) { - Label("Owned", systemImage: "person.fill") - }.onChange(of: showOwned) { - getCollections() - }.help("Owned") - Toggle(isOn: $showShared) { - Label("Shared", systemImage: "shared.with.you") - }.onChange(of: showShared) { - getCollections() - }.help("Shared") - } .id(0) .padding(EdgeInsets(top: 10, leading: 10, bottom: 0, trailing: 10)) #if os(macOS) .searchable(text: $inputSearch) + .toolbar { + Toggle(isOn: $showOwned) { + Label("Owned", systemImage: "person.fill") + }.onChange(of: showOwned) { + getCollections() + }.help("Owned") + Toggle(isOn: $showShared) { + Label("Shared", systemImage: "shared.with.you") + }.onChange(of: showShared) { + getCollections() + }.help("Shared") + } #else .searchable(text: $inputSearch, placement: .navigationBarDrawer(displayMode: .always)) + .toolbar { + Button(action: { showingSheet.toggle() }) { + Circle() + .fill(showOwned && showShared ? .gray.opacity(0.15) : .blue) + .frame(width: 30, height: 30) + .overlay { + Image(systemName: "line.3.horizontal.decrease") + .font(.system(size: 13.0, weight: .semibold)) + .foregroundColor(showOwned && showShared ? .blue : .primary) + }.sheet(isPresented: $showingSheet) { + NavigationView { + Form { + Button(action: { + showOwned = true + showShared = true + getCollections() + }) { + HStack { + Label { + Text("All Items").foregroundColor(.primary) + } icon: { + Image(systemName: "photo.on.rectangle") + } + if showOwned && showShared { + Spacer() + Image(systemName: "checkmark").foregroundColor(.blue) + } + } + } + Section(header: Text("Show")) { + Button(action: { + showOwned.toggle() + getCollections() + }) { + HStack { + Label { + Text("Owned").foregroundColor(.primary) + } icon: { + Image(systemName: "person") + } + if showOwned { + Spacer() + Image(systemName: "checkmark").foregroundColor(.blue) + } + } + } + Button(action: { + showShared.toggle() + getCollections() + }) { + HStack { + Label { + Text("Shared").foregroundColor(.primary) + } icon: { + Image(systemName: "shared.with.you") + } + if showShared { + Spacer() + Image(systemName: "checkmark").foregroundColor(.blue) + } + } + } + } + } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: { + self.showingSheet = false + }) { + Text("Done").bold() + } + } + } + .navigationTitle("Filter") + .navigationBarTitleDisplayMode(.inline) + } + } + } + } #endif - .onSubmit(of: .search) { - currentPage = 1 - getCollections() - } + .onSubmit(of: .search) { + currentPage = 1 + getCollections() + } HStack { Text("Pages: " + String(collectionData?.pager.totalPages ?? 0)) Button("Last Page") { diff --git a/TPU_Mac/CommsView.swift b/TPU_Mac/CommsView.swift index 3f20dd9..d69159e 100644 --- a/TPU_Mac/CommsView.swift +++ b/TPU_Mac/CommsView.swift @@ -247,295 +247,297 @@ struct CommsView: View { } var body: some View { - VStack { - #if os(macOS) - HStack { - List { - ForEach(0 ..< chatsList.count, id: \.self) { result in - Button(action: { getChat(chatId: result) }) { - HStack { - ProfilePicture(avatar: chatsList[result].recipient?.avatar ?? chatsList[result].icon) - Text(chatsList[result].recipient?.username ?? chatsList[result].name).lineLimit(1) - Spacer() - if chatsList[result].unread != 0 { - Text(String(chatsList[result].unread!)) - .frame(minWidth: 16, minHeight: 16) - .background(Color.red) - .cornerRadius(10) - } - }.contentShape(Rectangle()) - }.buttonStyle(.plain) - } + #if os(macOS) + HStack { + List { + ForEach(0 ..< chatsList.count, id: \.self) { result in + Button(action: { getChat(chatId: result) }) { + HStack { + ProfilePicture(avatar: chatsList[result].recipient?.avatar ?? chatsList[result].icon) + Text(chatsList[result].recipient?.username ?? chatsList[result].name).lineLimit(1) + Spacer() + if chatsList[result].unread != 0 { + Text(String(chatsList[result].unread!)) + .frame(minWidth: 16, minHeight: 16) + .background(Color.red) + .cornerRadius(10) + } + }.contentShape(Rectangle()) + }.buttonStyle(.plain) } - .frame(width: 150) - .padding(EdgeInsets(top: -8, leading: -10, bottom: -8, trailing: 0)) - if chatOpen != -1 { - ScrollViewReader { proxy in - ScrollView { - LazyVStack(alignment: .leading, spacing: 0) { - ForEach(Array(chatMessages.enumerated()), id: \.element) { index, message in - let dontMerge = merge(message: message, previousMessage: index != 0 ? chatMessages[index - 1] : nil) - Spacer(minLength: dontMerge ? 16 : 0) - if message.id == unreadId { - HStack { - VStack { Divider().background(.red) } - Text("New Message").foregroundStyle(.red) - VStack { Divider().background(.red) } - } + } + .frame(width: 150) + .padding(EdgeInsets(top: -8, leading: -10, bottom: -8, trailing: 0)) + if chatOpen != -1 { + ScrollViewReader { proxy in + ScrollView { + LazyVStack(alignment: .leading, spacing: 0) { + ForEach(Array(chatMessages.enumerated()), id: \.element) { index, message in + let dontMerge = merge(message: message, previousMessage: index != 0 ? chatMessages[index - 1] : nil) + Spacer(minLength: dontMerge ? 16 : 0) + if message.id == unreadId { + HStack { + VStack { Divider().background(.red) } + Text("New Message").foregroundStyle(.red) + VStack { Divider().background(.red) } } - if message.reply != nil { - Button(action: { - proxy.scrollTo(message.replyId) - }) { - HStack { - Image(systemName: "arrow.turn.up.right").frame(width: 16, height: 16) - ProfilePicture(avatar: message.reply?.user?.avatar, size: 16) - Text(message.reply?.user?.username ?? "User has been deleted") - Text((message.reply?.content ?? "Message has been deleted").replacingOccurrences(of: "\n", with: "")).textSelection(.enabled).lineLimit(1) - }.padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 0)) - }.buttonStyle(.plain) + } + if message.reply != nil { + Button(action: { + proxy.scrollTo(message.replyId) + }) { + HStack { + Image(systemName: "arrow.turn.up.right").frame(width: 16, height: 16) + ProfilePicture(avatar: message.reply?.user?.avatar, size: 16) + Text(message.reply?.user?.username ?? "User has been deleted") + Text((message.reply?.content ?? "Message has been deleted").replacingOccurrences(of: "\n", with: "")).textSelection(.enabled).lineLimit(1) + }.padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 0)) + }.buttonStyle(.plain) + } + HStack(alignment: .top, spacing: 6) { + if dontMerge { + ProfilePicture(avatar: message.user?.avatar) + } else { + Spacer().frame(width: 32) } - HStack(alignment: .top, spacing: 6) { + VStack { if dontMerge { - ProfilePicture(avatar: message.user?.avatar) + HStack { + Text(message.user?.username ?? "User has been deleted") + Text(DateUtils.dateFormat(message.createdAt)) + }.frame(minWidth: 0, + maxWidth: .infinity, + minHeight: 0, + maxHeight: 10, + alignment: .topLeading) + } + if editingId != message.id { + Text(.init(message.content ?? "Message has been deleted")) + .textSelection(.enabled) + .frame(minWidth: 0, + maxWidth: .infinity, + alignment: .leading) + .lineLimit(nil) } else { - Spacer().frame(width: 32) + TextField("Keep it civil!", text: $editingMessage) + .focused($focusedField, equals: .editing) + .onExitCommand(perform: { + editingId = -1 + focusedField = .sending + }) + .onSubmit { + editMessage() + } + .textFieldStyle(RoundedBorderTextFieldStyle()) } - VStack { - if dontMerge { - HStack { - Text(message.user?.username ?? "User has been deleted") - Text(DateUtils.dateFormat(message.createdAt)) - }.frame(minWidth: 0, - maxWidth: .infinity, - minHeight: 0, - maxHeight: 10, - alignment: .topLeading) - } - if editingId != message.id { - Text(.init(message.content ?? "Message has been deleted")) - .textSelection(.enabled) - .frame(minWidth: 0, - maxWidth: .infinity, - alignment: .leading) - .lineLimit(nil) - } else { - TextField("Keep it civil!", text: $editingMessage) - .focused($focusedField, equals: .editing) - .onExitCommand(perform: { - editingId = -1 - focusedField = .sending - }) - .onSubmit { - editMessage() - } - .textFieldStyle(RoundedBorderTextFieldStyle()) - } - ForEach(message.embeds, id: \.self) { embed in - if embed.media != [] { - LazyImage(url: URL(string: embed.media?[0].attachment == nil ? ("https://i.electrics01.com" + (embed.media?[0].proxyUrl ?? "")) : ("https://i.electrics01.com/i/" + (embed.media?[0].attachment ?? "")))) { state in - if let image = state.image { - image.resizable().aspectRatio(contentMode: .fit) + ForEach(message.embeds, id: \.self) { embed in + if embed.media != [] { + LazyImage(url: URL(string: embed.media?[0].attachment == nil ? ("https://i.electrics01.com" + (embed.media?[0].proxyUrl ?? "")) : ("https://i.electrics01.com/i/" + (embed.media?[0].attachment ?? "")))) { state in + if let image = state.image { + image.resizable().aspectRatio(contentMode: .fit) // .onAppear { - //// if chatMessages.count != 0 { - //// proxy.scrollTo(0, anchor: .bottom) - //// } + //// if chatMessages.count != 0 { + //// proxy.scrollTo(0, anchor: .bottom) + //// } // } - } else if state.error != nil { - Color.red - } else { - ProgressView() - } - }.frame(minWidth: 0, maxWidth: 600, minHeight: 0, maxHeight: 400) - } - }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading) - } - Button(action: { - if replyingId != message.id { - replyingId = message.id - } else { replyingId = -1 } - }) { - Image(systemName: "arrowshape.turn.up.left.fill").frame(width: 16, height: 16) - } - Button(action: { - deleteMessage(messageId: message.id) - }) { - Image(systemName: "trash.fill").frame(width: 16, height: 16) - } + } else if state.error != nil { + Color.red + } else { + ProgressView() + } + }.frame(minWidth: 0, maxWidth: 600, minHeight: 0, maxHeight: 400) + } + }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading) + } + Button(action: { + if replyingId != message.id { + replyingId = message.id + } else { replyingId = -1 } + }) { + Image(systemName: "arrowshape.turn.up.left.fill").frame(width: 16, height: 16) + } + Button(action: { + deleteMessage(messageId: message.id) + }) { + Image(systemName: "trash.fill").frame(width: 16, height: 16) + } + Button(action: { + pinMessage(messageId: message.id, pinned: message.pinned) + }) { + Image(systemName: message.pinned ? "pin.slash.fill" : "pin.fill").frame(width: 16, height: 16) + } + if coreUser?.id == message.userId { Button(action: { - pinMessage(messageId: message.id, pinned: message.pinned) + replyingId = -1 + if editingId != message.id { + editingId = message.id + editingMessage = message.content ?? "" + focusedField = .editing + } else { editingId = -1 } }) { - Image(systemName: message.pinned ? "pin.slash.fill" : "pin.fill").frame(width: 16, height: 16) + Image(systemName: "pencil").frame(width: 16, height: 16) } - if coreUser?.id == message.userId { - Button(action: { - replyingId = -1 - if editingId != message.id { - editingId = message.id - editingMessage = message.content ?? "" - focusedField = .editing - } else { editingId = -1 } - }) { - Image(systemName: "pencil").frame(width: 16, height: 16) - } - } - }.padding(EdgeInsets(top: 0, leading: 4, bottom: 0, trailing: 4)).id(message.id) - // .background(Color(hoverItem == message.id ? Color.primary : .clear)) - // .onHover(perform: { _ in - // hoverItem = message.id - // }) - }.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 12)) - } - .id(0) - .frame( - minWidth: 0, - maxWidth: .infinity, - minHeight: 0, - maxHeight: .infinity, - alignment: .topLeading - ) - .onAppear { - if chatMessages.count != 0 { - proxy.scrollTo(0, anchor: .bottom) - } - } - .onChange(of: chatMessages) { + } + }.padding(EdgeInsets(top: 0, leading: 4, bottom: 0, trailing: 4)).id(message.id) + // .background(Color(hoverItem == message.id ? Color.primary : .clear)) + // .onHover(perform: { _ in + // hoverItem = message.id + // }) + }.padding(EdgeInsets(top: 0, leading: 8, bottom: 0, trailing: 12)) + } + .id(0) + .frame( + minWidth: 0, + maxWidth: .infinity, + minHeight: 0, + maxHeight: .infinity, + alignment: .topLeading + ) + .onAppear { + if chatMessages.count != 0 { proxy.scrollTo(0, anchor: .bottom) } } - if replyingId != -1 { - HStack { - Image(systemName: "arrow.turn.up.right").frame(width: 16, height: 16) - Text(chatMessages.last(where: { $0.id == replyingId })?.user?.username ?? "User has been deleted") - Text(chatMessages.last(where: { $0.id == replyingId })?.content ?? "Message has been deleted") - .textSelection(.enabled) - .lineLimit(1) - .onAppear { - if chatMessages.count != 0 { - proxy.scrollTo(0, anchor: .bottom) - } - } - }.padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 0)) - .frame(minWidth: 0, - maxWidth: .infinity, - alignment: .topLeading) + .onChange(of: chatMessages) { + proxy.scrollTo(0, anchor: .bottom) } - TextField("Keep it civil!", text: $inputMessage) - .focused($focusedField, equals: .sending) - .onSubmit { - sendMessage() - } - .textFieldStyle(RoundedBorderTextFieldStyle()) } - .navigationTitle(chatsList[chatOpen].recipient?.username ?? chatsList[chatOpen].name) - List { - Section(header: Text("Online")) { - ForEach(0 ..< chatsList[chatOpen].users.count, id: \.self) { index in - let user = coreUsers.unsafelyUnwrapped.first { $0.id == chatsList[chatOpen].users[index].user?.id } - if let user = user, user.status.value != .offline { - Button(action: { - print(user.username) - }) { - HStack { - Circle().fill(user.status.value != .online ? user.status.value == .busy ? .red : .yellow : .green).frame(width: 6, height: 6) - ProfilePicture(avatar: user.avatar) - Text(user.username) - Spacer() - }.contentShape(Rectangle()) - }.buttonStyle(.plain) - .contextMenu { - if user.status.rawValue == "ACCEPTED" { - Button { - print("Action for context menu item 1") - } label: { - Label("Add friend", systemImage: "person.badge.plus") - } + if replyingId != -1 { + HStack { + Image(systemName: "arrow.turn.up.right").frame(width: 16, height: 16) + Text(chatMessages.last(where: { $0.id == replyingId })?.user?.username ?? "User has been deleted") + Text(chatMessages.last(where: { $0.id == replyingId })?.content ?? "Message has been deleted") + .textSelection(.enabled) + .lineLimit(1) + .onAppear { + if chatMessages.count != 0 { + proxy.scrollTo(0, anchor: .bottom) + } + } + }.padding(EdgeInsets(top: 0, leading: 18, bottom: 0, trailing: 0)) + .frame(minWidth: 0, + maxWidth: .infinity, + alignment: .topLeading) + } + TextField("Keep it civil!", text: $inputMessage) + .focused($focusedField, equals: .sending) + .onSubmit { + sendMessage() + } + .textFieldStyle(RoundedBorderTextFieldStyle()) + } + .navigationTitle(chatsList[chatOpen].recipient?.username ?? chatsList[chatOpen].name) + List { + Section(header: Text("Online")) { + ForEach(0 ..< chatsList[chatOpen].users.count, id: \.self) { index in + let user = coreUsers.unsafelyUnwrapped.first { $0.id == chatsList[chatOpen].users[index].user?.id } + if let user = user, user.status.value != .offline { + Button(action: { + print(user.username) + }) { + HStack { + Circle().fill(user.status.value != .online ? user.status.value == .busy ? .red : .yellow : .green).frame(width: 6, height: 6) + ProfilePicture(avatar: user.avatar) + Text(user.username) + Spacer() + }.contentShape(Rectangle()) + }.buttonStyle(.plain) + .contextMenu { + if user.status.rawValue == "ACCEPTED" { + Button { + print("Action for context menu item 1") + } label: { + Label("Add friend", systemImage: "person.badge.plus") } } - } + } } } - Section(header: Text("Offline")) { - ForEach(0 ..< chatsList[chatOpen].users.count, id: \.self) { index in - let user = coreUsers.unsafelyUnwrapped.first { $0.id == chatsList[chatOpen].users[index].user?.id } - if let user = user, user.status.value == .offline { - Button(action: { - print("Clicked: " + (user.username)) - }) { - HStack { - Circle().fill(.gray).frame(width: 6, height: 6) - ProfilePicture(avatar: user.avatar) - Text(user.username).foregroundStyle(.gray) - Spacer() - }.contentShape(Rectangle()) - }.buttonStyle(.plain) - .contextMenu { - if user.status.rawValue == "ACCEPTED" { - Button { - print("Action for context menu item 1") - } label: { - Label("Add friend", systemImage: "person.badge.plus") - } + } + Section(header: Text("Offline")) { + ForEach(0 ..< chatsList[chatOpen].users.count, id: \.self) { index in + let user = coreUsers.unsafelyUnwrapped.first { $0.id == chatsList[chatOpen].users[index].user?.id } + if let user = user, user.status.value == .offline { + Button(action: { + print("Clicked: " + (user.username)) + }) { + HStack { + Circle().fill(.gray).frame(width: 6, height: 6) + ProfilePicture(avatar: user.avatar) + Text(user.username).foregroundStyle(.gray) + Spacer() + }.contentShape(Rectangle()) + }.buttonStyle(.plain) + .contextMenu { + if user.status.rawValue == "ACCEPTED" { + Button { + print("Action for context menu item 1") + } label: { + Label("Add friend", systemImage: "person.badge.plus") } } - } + } } } - }.frame(width: 150) - .padding(EdgeInsets(top: -8, leading: -10, bottom: -8, trailing: 0)) - } else { - VStack { + } + }.frame(width: 150) + .padding(EdgeInsets(top: -8, leading: -10, bottom: -8, trailing: 0)) + } else { + VStack { + Spacer() + HStack { Spacer() - HStack { - Spacer() - Text("Comms") - Spacer() - } + Text("Comms") Spacer() } + Spacer() } } - .navigationTitle("Comms") - .onAppear { - getChats() - messagesSubscription() - editingSubscription() + } + .navigationTitle("Comms") + .onAppear { + getChats() + messagesSubscription() + editingSubscription() + } + .onDisappear { + if let subscription = apolloSubscription { + subscription.cancel() + apolloSubscription = nil } - .onDisappear { - if let subscription = apolloSubscription { - subscription.cancel() - apolloSubscription = nil - } + } + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("NavigateToPage"))) { notification in + if let userInfo = notification.userInfo, let pageID = userInfo["to"] as? Int { + getChat(chatId: chatsList.firstIndex(where: { $0.id == pageID })) } - #else - NavigationStack { - List { - ForEach(0 ..< chatsList.count, id: \.self) { result in - NavigationLink(destination: ChatView(coreUser: $coreUser, coreUsers: $coreUsers, chatsList: $chatsList, chatOpen: .constant(result))) { - HStack { - ProfilePicture(avatar: chatsList[result].recipient?.avatar ?? chatsList[result].icon) - Text(chatsList[result].recipient?.username ?? chatsList[result].name).lineLimit(1) - Spacer() - if chatsList[result].unread != 0 { - Text(String(chatsList[result].unread!)) - .frame(minWidth: 16, minHeight: 16) - .background(Color.red) - .cornerRadius(10) - } - }.contentShape(Rectangle()) - }.buttonStyle(.plain) - } + } + #else + NavigationStack { + List { + ForEach(0 ..< chatsList.count, id: \.self) { result in + NavigationLink(destination: ChatView(coreUser: $coreUser, coreUsers: $coreUsers, chatsList: $chatsList, chatOpen: .constant(result))) { + HStack { + ProfilePicture(avatar: chatsList[result].recipient?.avatar ?? chatsList[result].icon) + Text(chatsList[result].recipient?.username ?? chatsList[result].name).lineLimit(1) + Spacer() + if chatsList[result].unread != 0 { + Text(String(chatsList[result].unread!)) + .frame(minWidth: 16, minHeight: 16) + .background(Color.red) + .cornerRadius(10) + } + }.contentShape(Rectangle()) + }.buttonStyle(.plain) } } .onAppear { getChats() } - #endif - } - .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("NavigateToPage"))) { notification in - if let userInfo = notification.userInfo, let pageID = userInfo["to"] as? Int { - getChat(chatId: chatsList.firstIndex(where: { $0.id == pageID })) + .onReceive(NotificationCenter.default.publisher(for: NSNotification.Name("NavigateToPage"))) { notification in + if let userInfo = notification.userInfo, let pageID = userInfo["to"] as? Int { + getChat(chatId: chatsList.firstIndex(where: { $0.id == pageID })) + } } - } + #endif } } diff --git a/TPU_Mac/ContentView.swift b/TPU_Mac/ContentView.swift index c6a07b7..49d05b5 100644 --- a/TPU_Mac/ContentView.swift +++ b/TPU_Mac/ContentView.swift @@ -248,7 +248,7 @@ struct SettingsView: View { Text("Coming soon") #else Text("TPU iOS").font(.system(size: 32, weight: .semibold)) - Text("Version " + (Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "") + " (1/10/2024)") + Text("Version " + (Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "") + " (3/10/2024)") Text("Made by ElectricS01") Text("[Give it a Star on GitHub](https://github.com/ElectricS01/TPU-Mac)") #endif @@ -267,7 +267,7 @@ struct AboutView: View { Text("About") .navigationTitle("About") Text("TPU Mac").font(.system(size: 32, weight: .semibold)) - Text("Version " + (Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "") + " (1/10/2024)") + Text("Version " + (Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "") + " (3/10/2024)") Text("Made by ElectricS01") Text("[Give it a Star on GitHub](https://github.com/ElectricS01/TPU-Mac)") } diff --git a/TPU_Mac/GalleryView.swift b/TPU_Mac/GalleryView.swift index 057ebbd..f290c0e 100644 --- a/TPU_Mac/GalleryView.swift +++ b/TPU_Mac/GalleryView.swift @@ -90,267 +90,271 @@ struct GalleryView: View { NavigationStack { ScrollViewReader { proxy in ScrollView { - VStack { - HStack { -#if !os(macOS) - Button(action: { showingSheet.toggle() }) { - Circle() - .fill(showImages && showVideos && showOther ? .gray.opacity(0.15) : .blue) - .frame(width: 30, height: 30) - .overlay { - Image(systemName: "line.3.horizontal.decrease") - .font(.system(size: 13.0, weight: .semibold)) - .foregroundColor(showImages && showVideos && showOther ? .blue : .primary) - }.sheet(isPresented: $showingSheet) { - NavigationView { - Form { - Section(header: Text("Type").font(.system(size: 14)).foregroundColor(.gray)) { - Button(action: { - stateStars.toggle() - getGallery() - }) { - HStack { - Label { - Text("All Items").foregroundColor(.primary) - } icon: { - Image(systemName: "photo.on.rectangle") - } - if !stateStars { - Spacer() - Image(systemName: "checkmark").foregroundColor(.blue) - } - } - } - Button(action: { - stateStars.toggle() - getGallery() - }) { - HStack { - Label { - Text("Stars").foregroundColor(.primary) - } icon: { - Image(systemName: "star") - } - if stateStars { - Spacer() - Image(systemName: "checkmark").foregroundColor(.blue) - } - } - } - } - Section(header: Text("Show").font(.system(size: 14)).foregroundColor(.gray)) { - Button(action: { - showImages.toggle() - getGallery() - }) { - HStack { - Label { - Text("Images").foregroundColor(.primary) - } icon: { - Image(systemName: "photo") - } - if showImages { - Spacer() - Image(systemName: "checkmark").foregroundColor(.blue) - } - } - } - Button(action: { - showVideos.toggle() - getGallery() - }) { - HStack { - Label { - Text("Videos").foregroundColor(.primary) - } icon: { - Image(systemName: "video") - } - if showVideos { - Spacer() - Image(systemName: "checkmark").foregroundColor(.blue) - } - } - } - Button(action: { - showOther.toggle() - getGallery() - }) { - HStack { - Label { - Text("Other").foregroundColor(.primary) - } icon: { - Image(systemName: "doc") - } - if showOther { - Spacer() - Image(systemName: "checkmark").foregroundColor(.blue) - } - } - } - } - } - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { - self.showingSheet = false - }) { - Text("Done").bold() - } - } - } - .navigationTitle("Filter") - .navigationBarTitleDisplayMode(.inline) - } + LazyVGrid(columns: [GridItem(.adaptive(minimum: 316))], spacing: 10) { + ForEach(Array(galleryItems.enumerated()), id: \.element) { index, galleryItem in + VStack(alignment: .leading) { + HStack { + Text(galleryItem.name ?? "Unknown").font(.title2).lineLimit(1) + Spacer() + Image(systemName: galleryItem.starred == nil ? "star" : "star.fill").resizable().frame(width: 16, height: 16).onTapGesture { + starUpload(attachment: galleryItem.attachment, index: index) } - } -#endif - }.padding(EdgeInsets(top: 10, leading: 10, bottom: -8, trailing: 10)) - LazyVGrid(columns: [GridItem(.adaptive(minimum: 316))], spacing: 10) { - ForEach(Array(galleryItems.enumerated()), id: \.element) { index, galleryItem in - VStack(alignment: .leading) { - HStack { - Text(galleryItem.name ?? "Unknown").font(.title2).lineLimit(1) - Spacer() - Image(systemName: galleryItem.starred == nil ? "star" : "star.fill").resizable().frame(width: 16, height: 16).onTapGesture { - starUpload(attachment: galleryItem.attachment, index: index) - } - } - HStack(alignment: .center) { - if galleryItem.type == "image" { - LazyImage(url: URL(string: "https://i.electrics01.com/i/" + galleryItem.attachment)) { state in - if let image = state.image { - image.resizable().aspectRatio(contentMode: .fit) - } else if state.error != nil { - Color.red - } else { - ProgressView() - } - }.frame(minWidth: 268, maxWidth: .infinity, minHeight: 160, maxHeight: 160) - } else if galleryItem.type == "video" { - if isPlaying != galleryItem.id { - Button(action: { - isPlaying = galleryItem.id - }) { - Image(systemName: "play.circle.fill") - .resizable() - .frame(width: 160, height: 160) - .foregroundColor(.white) - } + } + HStack(alignment: .center) { + if galleryItem.type == "image" { + LazyImage(url: URL(string: "https://i.electrics01.com/i/" + galleryItem.attachment)) { state in + if let image = state.image { + image.resizable().aspectRatio(contentMode: .fit) + } else if state.error != nil { + Color.red } else { - let player = AVPlayer(url: URL(string: "https://i.electrics01.com/i/" + galleryItem.attachment)!) - VideoPlayer(player: player) - .onAppear { - player.play() - } + ProgressView() } - } else if galleryItem.type == "binary" { - Image(systemName: "doc.zipper").resizable().aspectRatio(contentMode: .fit).frame(width: 84, height: 84).font(.largeTitle).padding(38) - } else if galleryItem.type == "text" { - Image(systemName: "doc.plaintext").resizable().aspectRatio(contentMode: .fit).frame(width: 84, height: 84).font(.largeTitle).padding(38) + }.frame(minWidth: 268, maxWidth: .infinity, minHeight: 160, maxHeight: 160) + } else if galleryItem.type == "video" { + if isPlaying != galleryItem.id { + Button(action: { + isPlaying = galleryItem.id + }) { + Image(systemName: "play.circle.fill") + .resizable() + .frame(width: 160, height: 160) + .foregroundColor(.white) + } + } else { + let player = AVPlayer(url: URL(string: "https://i.electrics01.com/i/" + galleryItem.attachment)!) + VideoPlayer(player: player) + .onAppear { + player.play() + } } + } else if galleryItem.type == "binary" { + Image(systemName: "doc.zipper").resizable().aspectRatio(contentMode: .fit).frame(width: 84, height: 84).font(.largeTitle).padding(38) + } else if galleryItem.type == "text" { + Image(systemName: "doc.plaintext").resizable().aspectRatio(contentMode: .fit).frame(width: 84, height: 84).font(.largeTitle).padding(38) } - .frame( - minWidth: 0, - maxWidth: .infinity - ) - Text("Type: " + (galleryItem.type)) - Text("Upload name: " + (galleryItem.attachment)) - Text("Created at: " + DateUtils.dateFormat(galleryItem.createdAt)) - Text("Size: " + formatFileSize(galleryItem.fileSize)) - HStack { - Button("Copy Link") { -#if os(iOS) + } + .frame( + minWidth: 0, + maxWidth: .infinity + ) + Text("Type: " + (galleryItem.type)) + Text("Upload name: " + (galleryItem.attachment)) + Text("Created at: " + DateUtils.dateFormat(galleryItem.createdAt)) + Text("Size: " + formatFileSize(galleryItem.fileSize)) + HStack { + Button("Copy Link") { + #if os(iOS) UIPasteboard.general.setValue("https://i.electrics01.com/i/" + galleryItem.attachment, forPasteboardType: UTType.plainText.identifier) -#elseif os(macOS) + #elseif os(macOS) NSPasteboard.general.clearContents(); NSPasteboard.general.setString("https://i.electrics01.com/i/" + galleryItem.attachment, forType: .string) -#endif - } - Button("Open image") { - openURL(URL(string: "https://i.electrics01.com/i/" + galleryItem.attachment)!) - } - Button("Download") { - let downloadTask = URLSession.shared.downloadTask(with: URL(string: "https://i.electrics01.com/i/" + galleryItem.attachment)!) { location, _, error in - guard let location = location else { - if let error = error { - print("Download failed with error: \(error.localizedDescription)") - } - return - } - do { - let documentsDirectory = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first! - let destinationURL = documentsDirectory.appendingPathComponent(galleryItem.attachment) - try FileManager.default.moveItem(at: location, to: destinationURL) - print("File downloaded successfully and moved to \(destinationURL)") - } catch { - print("Error moving file: \(error.localizedDescription)") + #endif + } + Button("Open") { + openURL(URL(string: "https://i.electrics01.com/i/" + galleryItem.attachment)!) + } + Button("Download") { + let downloadTask = URLSession.shared.downloadTask(with: URL(string: "https://i.electrics01.com/i/" + galleryItem.attachment)!) { location, _, error in + guard let location = location else { + if let error = error { + print("Download failed with error: \(error.localizedDescription)") } + return + } + do { + let documentsDirectory = FileManager.default.urls(for: .downloadsDirectory, in: .userDomainMask).first! + let destinationURL = documentsDirectory.appendingPathComponent(galleryItem.attachment) + try FileManager.default.moveItem(at: location, to: destinationURL) + print("File downloaded successfully and moved to \(destinationURL)") + } catch { + print("Error moving file: \(error.localizedDescription)") } - downloadTask.resume() } - Button("Delete") { - Network.shared.apollo.perform(mutation: DeleteUploadsMutation(input: DeleteUploadInput(items: [galleryItem.id]))) { result in - switch result { - case .success: - galleryItems.remove(at: galleryItems.firstIndex(of: galleryItem)!) - case .failure(let error): - print("Failure! Error: \(error)") - } + downloadTask.resume() + } + Button("Delete") { + Network.shared.apollo.perform(mutation: DeleteUploadsMutation(input: DeleteUploadInput(items: [galleryItem.id]))) { result in + switch result { + case .success: + galleryItems.remove(at: galleryItems.firstIndex(of: galleryItem)!) + case .failure(let error): + print("Failure! Error: \(error)") } } } } - .padding() - .frame(minWidth: 300, minHeight: 300) - .background() - .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous)) } + .padding() + .frame(minWidth: 300, minHeight: 300) + .background() + .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous)) } + } + .id(0) + .padding(EdgeInsets(top: 10, leading: 10, bottom: 0, trailing: 10)) + #if os(macOS) + .searchable(text: $inputSearch) .toolbar { Toggle(isOn: $showImages) { Label("Images", systemImage: "photo") }.onChange(of: showImages) { getGallery() + proxy.scrollTo(0, anchor: .top) }.help("Images") Toggle(isOn: $showVideos) { Label("Videos", systemImage: "video") }.onChange(of: showVideos) { getGallery() + proxy.scrollTo(0, anchor: .top) }.help("Videos") Toggle(isOn: $showOther) { Label("Other", systemImage: "doc") }.onChange(of: showOther) { getGallery() + proxy.scrollTo(0, anchor: .top) }.help("Other") } - .id(0) - .padding(EdgeInsets(top: 10, leading: 10, bottom: 0, trailing: 10)) -#if os(macOS) - .searchable(text: $inputSearch) -#else - .searchable(text: $inputSearch, placement: .navigationBarDrawer(displayMode: .always)) -#endif + #else + .searchable(text: $inputSearch, placement: .navigationBarDrawer(displayMode: .always)) + .toolbar { + Button(action: { showingSheet.toggle() }) { + Circle() + .fill(showImages && showVideos && showOther ? .gray.opacity(0.15) : .blue) + .frame(width: 30, height: 30) + .overlay { + Image(systemName: "line.3.horizontal.decrease") + .font(.system(size: 13.0, weight: .semibold)) + .foregroundColor(showImages && showVideos && showOther ? .blue : .primary) + }.sheet(isPresented: $showingSheet) { + NavigationView { + Form { + Section(header: Text("Type").font(.system(size: 14)).foregroundColor(.gray)) { + Button(action: { + stateStars.toggle() + getGallery() + proxy.scrollTo(0, anchor: .top) + }) { + HStack { + Label { + Text("All Items").foregroundColor(.primary) + } icon: { + Image(systemName: "photo.on.rectangle") + } + if !stateStars { + Spacer() + Image(systemName: "checkmark").foregroundColor(.blue) + } + } + } + Button(action: { + stateStars.toggle() + getGallery() + proxy.scrollTo(0, anchor: .top) + }) { + HStack { + Label { + Text("Stars").foregroundColor(.primary) + } icon: { + Image(systemName: "star") + } + if stateStars { + Spacer() + Image(systemName: "checkmark").foregroundColor(.blue) + } + } + } + } + Section(header: Text("Show").font(.system(size: 14)).foregroundColor(.gray)) { + Button(action: { + showImages.toggle() + getGallery() + proxy.scrollTo(0, anchor: .top) + }) { + HStack { + Label { + Text("Images").foregroundColor(.primary) + } icon: { + Image(systemName: "photo") + } + if showImages { + Spacer() + Image(systemName: "checkmark").foregroundColor(.blue) + } + } + } + Button(action: { + showVideos.toggle() + getGallery() + proxy.scrollTo(0, anchor: .top) + }) { + HStack { + Label { + Text("Videos").foregroundColor(.primary) + } icon: { + Image(systemName: "video") + } + if showVideos { + Spacer() + Image(systemName: "checkmark").foregroundColor(.blue) + } + } + } + Button(action: { + showOther.toggle() + getGallery() + proxy.scrollTo(0, anchor: .top) + }) { + HStack { + Label { + Text("Other").foregroundColor(.primary) + } icon: { + Image(systemName: "doc") + } + if showOther { + Spacer() + Image(systemName: "checkmark").foregroundColor(.blue) + } + } + } + } + } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: { + self.showingSheet = false + }) { + Text("Done").bold() + } + } + } + .navigationTitle("Filter") + .navigationBarTitleDisplayMode(.inline) + } + } + } + } + #endif .onSubmit(of: .search) { currentPage = 1 getGallery() } - HStack { - Text("Pages: " + String(galleryData?.pager.totalPages ?? 0)) - Button("Last Page") { - currentPage -= 1 - getGallery() - } - .disabled(currentPage < 2) - Button("Next Page") { - currentPage += 1 - getGallery() - } - .disabled(currentPage >= galleryData?.pager.totalPages ?? 0) - Text("Page: " + String(currentPage)) + HStack { + Text("Pages: " + String(galleryData?.pager.totalPages ?? 0)) + Button("Last Page") { + currentPage -= 1 + getGallery() + } + .disabled(currentPage < 2) + Button("Next Page") { + currentPage += 1 + getGallery() } - .padding(EdgeInsets(top: 0, leading: 0, bottom: 10, trailing: 0)) + .disabled(currentPage >= galleryData?.pager.totalPages ?? 0) + Text("Page: " + String(currentPage)) } - .navigationTitle((collectionId != nil && collectionId != -1 ? collectionName : stars != true ? "Gallery" : "Stars") ?? "Collectionsz") + .padding(EdgeInsets(top: 0, leading: 0, bottom: 10, trailing: 0)) + .navigationTitle((collectionId != nil && collectionId != -1 ? collectionName : stars != true ? "Gallery" : "Stars") ?? "Collections") .onAppear { getGallery() }