From 4f00f7c8b796f898dec8abd98ddff297d4bc8db6 Mon Sep 17 00:00:00 2001 From: ginsudev Date: Thu, 5 Jan 2023 22:50:08 +1100 Subject: [PATCH] Added font discovery page --- WDBFontOverwrite.xcodeproj/project.pbxproj | 24 ++++++ .../MainInterface/ContentView.ViewModel.swift | 5 +- .../MainInterface/ContentView.swift | 13 ++- .../FontDiscoveryCard.ViewModel.swift | 58 +++++++++++++ .../FontDiscovery/FontDiscoveryCard.swift | 81 +++++++++++++++++++ .../FontDiscoveryView.ViewModel.swift | 70 ++++++++++++++++ .../FontDiscovery/FontDiscoveryView.swift | 56 +++++++++++++ .../Progress/ProgressManager.swift | 6 +- 8 files changed, 308 insertions(+), 5 deletions(-) create mode 100644 WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryCard.ViewModel.swift create mode 100644 WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryCard.swift create mode 100644 WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryView.ViewModel.swift create mode 100644 WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryView.swift diff --git a/WDBFontOverwrite.xcodeproj/project.pbxproj b/WDBFontOverwrite.xcodeproj/project.pbxproj index 70c43e6..fea7187 100644 --- a/WDBFontOverwrite.xcodeproj/project.pbxproj +++ b/WDBFontOverwrite.xcodeproj/project.pbxproj @@ -15,6 +15,10 @@ 4FE5EF3A296561B2003384EC /* FileEditorView.ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE5EF39296561B2003384EC /* FileEditorView.ViewModel.swift */; }; 4FE5EF3E29664537003384EC /* ProgressManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE5EF3D29664537003384EC /* ProgressManager.swift */; }; 4FE5EF4129668C9C003384EC /* AlignedRowContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE5EF4029668C9C003384EC /* AlignedRowContentView.swift */; }; + 4FE5EF452966AD87003384EC /* FontDiscoveryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE5EF442966AD87003384EC /* FontDiscoveryView.swift */; }; + 4FE5EF472966AD98003384EC /* FontDiscoveryView.ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE5EF462966AD98003384EC /* FontDiscoveryView.ViewModel.swift */; }; + 4FE5EF492966AE1A003384EC /* FontDiscoveryCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE5EF482966AE1A003384EC /* FontDiscoveryCard.swift */; }; + 4FE5EF4B2966AE72003384EC /* FontDiscoveryCard.ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FE5EF4A2966AE72003384EC /* FontDiscoveryCard.ViewModel.swift */; }; C55CF774295BA37D000DE71C /* woff2_wrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C55CF772295BA37D000DE71C /* woff2_wrapper.cpp */; }; C55CF776295BA9B1000DE71C /* BrotliPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = C55CF775295BA9B1000DE71C /* BrotliPadding.swift */; }; C55CF778295BAF42000DE71C /* libwoff2enc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C55CF76E295BA346000DE71C /* libwoff2enc.a */; }; @@ -40,6 +44,10 @@ 4FE5EF39296561B2003384EC /* FileEditorView.ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileEditorView.ViewModel.swift; sourceTree = ""; }; 4FE5EF3D29664537003384EC /* ProgressManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressManager.swift; sourceTree = ""; }; 4FE5EF4029668C9C003384EC /* AlignedRowContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlignedRowContentView.swift; sourceTree = ""; }; + 4FE5EF442966AD87003384EC /* FontDiscoveryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontDiscoveryView.swift; sourceTree = ""; }; + 4FE5EF462966AD98003384EC /* FontDiscoveryView.ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontDiscoveryView.ViewModel.swift; sourceTree = ""; }; + 4FE5EF482966AE1A003384EC /* FontDiscoveryCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontDiscoveryCard.swift; sourceTree = ""; }; + 4FE5EF4A2966AE72003384EC /* FontDiscoveryCard.ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontDiscoveryCard.ViewModel.swift; sourceTree = ""; }; C55CF76E295BA346000DE71C /* libwoff2enc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libwoff2enc.a; sourceTree = ""; }; C55CF76F295BA346000DE71C /* libwoff2common.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libwoff2common.a; sourceTree = ""; }; C55CF772295BA37D000DE71C /* woff2_wrapper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = woff2_wrapper.cpp; sourceTree = ""; }; @@ -96,6 +104,7 @@ 4FE5EF3F29668BF2003384EC /* MainInterface */ = { isa = PBXGroup; children = ( + 4FE5EF432966AD68003384EC /* FontDiscovery */, 4FE5EF362965617D003384EC /* FileEditor */, C5C9A7942959261000466D87 /* ContentView.swift */, 4F4E64A6295F9AB600D4F04D /* ContentView.ViewModel.swift */, @@ -105,6 +114,17 @@ path = MainInterface; sourceTree = ""; }; + 4FE5EF432966AD68003384EC /* FontDiscovery */ = { + isa = PBXGroup; + children = ( + 4FE5EF442966AD87003384EC /* FontDiscoveryView.swift */, + 4FE5EF462966AD98003384EC /* FontDiscoveryView.ViewModel.swift */, + 4FE5EF482966AE1A003384EC /* FontDiscoveryCard.swift */, + 4FE5EF4A2966AE72003384EC /* FontDiscoveryCard.ViewModel.swift */, + ); + path = FontDiscovery; + sourceTree = ""; + }; C55CF777295BAF42000DE71C /* Frameworks */ = { isa = PBXGroup; children = ( @@ -243,12 +263,16 @@ C5999BFF295E769700BBBE1F /* stripttc.c in Sources */, 4FE5EF3A296561B2003384EC /* FileEditorView.ViewModel.swift in Sources */, C5C9A7952959261000466D87 /* ContentView.swift in Sources */, + 4FE5EF4B2966AE72003384EC /* FontDiscoveryCard.ViewModel.swift in Sources */, C55CF776295BA9B1000DE71C /* BrotliPadding.swift in Sources */, 4FE5EF3E29664537003384EC /* ProgressManager.swift in Sources */, + 4FE5EF452966AD87003384EC /* FontDiscoveryView.swift in Sources */, C5C9A7932959261000466D87 /* WDBFontOverwriteApp.swift in Sources */, 4FE5EF38296561A5003384EC /* FileEditorView.swift in Sources */, + 4FE5EF472966AD98003384EC /* FontDiscoveryView.ViewModel.swift in Sources */, C5C9A7AA2959417100466D87 /* vm_unaligned_copy_switch_race.c in Sources */, 4FE5EF4129668C9C003384EC /* AlignedRowContentView.swift in Sources */, + 4FE5EF492966AE1A003384EC /* FontDiscoveryCard.swift in Sources */, 4FE5EF3529653188003384EC /* FontMap.swift in Sources */, C5999BFC295E69C200BBBE1F /* ttcpad.m in Sources */, 4FE5EF312963E460003384EC /* NoticeView.swift in Sources */, diff --git a/WDBFontOverwrite/MainInterface/ContentView.ViewModel.swift b/WDBFontOverwrite/MainInterface/ContentView.ViewModel.swift index 65cdd2a..d3ad2af 100644 --- a/WDBFontOverwrite/MainInterface/ContentView.ViewModel.swift +++ b/WDBFontOverwrite/MainInterface/ContentView.ViewModel.swift @@ -27,8 +27,8 @@ struct FontToReplace { } enum CustomFontType: String { - case font = "font" - case emoji = "emoji" + case font = "fonts" + case emoji = "emojis" } extension ContentView { @@ -38,6 +38,7 @@ extension ContentView { @Published var message = "Choose a font." @Published var importPresented: Bool = false @Published var isPresentedFileEditor: Bool = false + @Published var isPresentedFontDiscovery: Bool = false @Published var importTTCRepackMode: TTCRepackMode = .woff2 @Published var allowsMultipleSelection: Bool = true @Published var importType: CustomFontType = .font diff --git a/WDBFontOverwrite/MainInterface/ContentView.swift b/WDBFontOverwrite/MainInterface/ContentView.swift index cd59219..9a16671 100644 --- a/WDBFontOverwrite/MainInterface/ContentView.swift +++ b/WDBFontOverwrite/MainInterface/ContentView.swift @@ -39,6 +39,9 @@ struct ContentView: View { .sheet(isPresented: $viewModel.isPresentedFileEditor) { FileEditorView() } + .sheet(isPresented: $viewModel.isPresentedFontDiscovery) { + FontDiscoveryView() + } .onAppear { Task(priority: .background) { do { @@ -104,7 +107,15 @@ struct ContentView: View { @ViewBuilder private var customFontsList: some View { Section { - NoticeView(notice: .beforeUse) + Button { + viewModel.isPresentedFontDiscovery = true + } label: { + AlignedRowContentView( + imageName: "star", + text: "Find custom fonts/emoji here" + ) + } + Picker("Custom fonts", selection: $viewModel.customFontPickerSelection) { Text("Custom font") .tag(0) diff --git a/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryCard.ViewModel.swift b/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryCard.ViewModel.swift new file mode 100644 index 0000000..d6708ca --- /dev/null +++ b/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryCard.ViewModel.swift @@ -0,0 +1,58 @@ +// +// FontDiscoveryCell.ViewModel.swift +// WDBFontOverwrite +// +// Created by Noah Little on 5/1/2023. +// + +import SwiftUI + +extension FontDiscoveryCard { + struct ViewDescriptor { + let avatarPath: String + let name: String + let twitterHandle: String + let role: CustomFontType + let links: [FontDiscoveryLinkDescriptor] + } + + struct AvatarDownloader { + func downloadAvatar(fromURL url: String) async -> UIImage? { + guard let url = URL(string: url) else { + return nil + } + do { + let (data, response) = try await URLSession.shared.data(from: url) + let image = handleResponse(data: data, response: response) + return image + } catch { + print("Unable to load avatar for card") + return nil + } + } + + private func handleResponse(data: Data?, response: URLResponse?) -> UIImage? { + guard let data, + let image = UIImage(data: data), + let response = response as? HTTPURLResponse, + (200..<300).contains(response.statusCode) else { + print("No image") + return nil + } + return image + } + } + + final class ViewModel: ObservableObject { + let downloader = AvatarDownloader() + @Published var image = Image(systemName: "person.crop.circle") + + func fetchImage(fromURL url: String) async { + if let image = await self.downloader.downloadAvatar(fromURL: url) { + await MainActor.run { [weak self] in + self?.image = Image(uiImage: image) + } + } + } + } +} diff --git a/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryCard.swift b/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryCard.swift new file mode 100644 index 0000000..52c2318 --- /dev/null +++ b/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryCard.swift @@ -0,0 +1,81 @@ +// +// FontDiscoveryCell.swift +// WDBFontOverwrite +// +// Created by Noah Little on 5/1/2023. +// + +import SwiftUI + +// MARK: - Public + +struct FontDiscoveryCard: View { + @Environment(\.openURL) private var openURL + @StateObject private var viewModel = ViewModel() + let descriptor: ViewDescriptor + + var body: some View { + VStack(alignment: .leading) { + header + links + } + .frame(maxWidth: .infinity) + .padding() + .overlay( + RoundedRectangle(cornerRadius: 5) + .stroke(Color.secondary, lineWidth: 1) + ) + .onAppear { + Task { + await viewModel.fetchImage(fromURL: descriptor.avatarPath) + } + } + } +} + +// MARK: - Private + +private extension FontDiscoveryCard { + var header: some View { + HStack { + viewModel.image + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 60, height: 60) + .clipShape(Circle()) + .overlay( + Circle() + .stroke(Color.secondary, lineWidth: 1) + .foregroundColor(.clear) + ) + VStack(alignment: .leading) { + Text(descriptor.name) + .font(.title2) + Text(descriptor.role.rawValue.uppercased()) + .foregroundColor(.secondary) + .font(.footnote) + .bold() + } + Spacer() + } + } + + var links: some View { + HStack { + ForEach(descriptor.links, id: \.title) { link in + Button { + openURL(link.url) + } label: { + HStack(spacing: 5) { + Image(systemName: link.imageName) + Text(link.title) + } + .foregroundColor(.white) + } + .padding(EdgeInsets(top: 5, leading: 10, bottom: 5, trailing: 10)) + .background(Color(UIColor(red: 0.44, green: 0.69, blue: 0.67, alpha: 1.00))) + .clipShape(RoundedRectangle(cornerRadius: 8)) + } + } + } +} diff --git a/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryView.ViewModel.swift b/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryView.ViewModel.swift new file mode 100644 index 0000000..fa28f49 --- /dev/null +++ b/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryView.ViewModel.swift @@ -0,0 +1,70 @@ +// +// FontDiscoveryView.ViewModel.swift +// WDBFontOverwrite +// +// Created by Noah Little on 5/1/2023. +// + +import Foundation + +struct FontDiscoveryLinkDescriptor { + let url: URL + let title: String + let imageName: String +} + +extension FontDiscoveryView { + final class ViewModel: ObservableObject { + let descriptors = [ + FontDiscoveryCard.ViewDescriptor( + avatarPath: "https://unavatar.io/github/evynw", + name: "Evelyn", + twitterHandle: "ev_ynw", + role: .font, + links: [ + .init( + url: URL(string: "https://twitter.com/ev_ynw")!, + title: "Twitter", + imageName: "person.crop.circle.badge.plus" + ), + .init( + url: URL(string: "https://bit.ly/3e3nJdm")!, + title: "Font library", + imageName: "books.vertical" + ) + ] + ), + FontDiscoveryCard.ViewDescriptor( + avatarPath: "https://unavatar.io/github/PoomSmart", + name: "PoomSmart", + twitterHandle: "PoomSmart", + role: .emoji, + links: [ + .init( + url: URL(string: "https://twitter.com/PoomSmart")!, + title: "Twitter", + imageName: "person.crop.circle.badge.plus" + ), + .init( + url: URL(string: "https://github.com/PoomSmart/EmojiFonts/releases")!, + title: "Emoji library", + imageName: "face.smiling" + ) + ] + ), + FontDiscoveryCard.ViewDescriptor( + avatarPath: "https://unavatar.io/github/AlexMan1979", + name: "AlexMan1979", + twitterHandle: "AlexMan1979", + role: .font, + links: [ + .init( + url: URL(string: "https://twitter.com/AlexMan1979")!, + title: "Twitter", + imageName: "person.crop.circle.badge.plus" + ) + ] + ), + ] + } +} diff --git a/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryView.swift b/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryView.swift new file mode 100644 index 0000000..96b7e3b --- /dev/null +++ b/WDBFontOverwrite/MainInterface/FontDiscovery/FontDiscoveryView.swift @@ -0,0 +1,56 @@ +// +// FontDiscoveryView.swift +// WDBFontOverwrite +// +// Created by Noah Little on 5/1/2023. +// + +import SwiftUI + +struct FontDiscoveryView: View { + @StateObject private var viewModel = ViewModel() + + var body: some View { + NavigationView { + VStack(spacing: 10) { + message + ForEach(viewModel.descriptors, id: \.name) { descriptor in + Section { + FontDiscoveryCard(descriptor: descriptor) + .frame(maxWidth: .infinity) + .padding(.horizontal) + } + } + .navigationTitle("Discovery") + Spacer() + } + } + } + + private var message: some View { + ZStack { + RoundedRectangle(cornerRadius: 5) + .fill(Color(UIColor(red: 0.44, green: 0.69, blue: 0.67, alpha: 1.00))) + VStack(alignment: .center) { + Image(systemName: "star.fill") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 50, height: 50) + .foregroundColor(.white) + Text("Find fonts and emojis from these talented developers and themers.") + .foregroundColor(.white) + .multilineTextAlignment(.center) + } + .padding() + } + .frame(maxWidth: .infinity) + .fixedSize(horizontal: false, vertical: true) + .padding(.horizontal) + } +} + +struct FontDiscoveryView_Previews: PreviewProvider { + static var previews: some View { + FontDiscoveryView() + } +} diff --git a/WDBFontOverwrite/Progress/ProgressManager.swift b/WDBFontOverwrite/Progress/ProgressManager.swift index a1ad750..7121cf5 100644 --- a/WDBFontOverwrite/Progress/ProgressManager.swift +++ b/WDBFontOverwrite/Progress/ProgressManager.swift @@ -16,8 +16,10 @@ final class ProgressManager: ObservableObject { didSet { if !isBusy { // Reset values when done. - completedProgress = 0 - totalProgress = 0 + Task { @MainActor in + completedProgress = 0 + totalProgress = 0 + } } } }