From 0ca615422971e02d66ef6d238d551f6eece1d43c Mon Sep 17 00:00:00 2001 From: Akring Date: Mon, 19 Apr 2021 00:54:02 +0800 Subject: [PATCH] Add main view --- FontFace.xcodeproj/project.pbxproj | 36 +++++++++++++ .../UserInterfaceState.xcuserstate | Bin 7187 -> 30531 bytes Shared/ContentView.swift | 48 +++++++++++++++++- Shared/Model/FontModel.swift | 22 ++++++++ Shared/Utils/NSCharacterSetExtension.swift | 33 ++++++++++++ Shared/View/CharacterCellView.swift | 34 +++++++++++++ 6 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 Shared/Model/FontModel.swift create mode 100644 Shared/Utils/NSCharacterSetExtension.swift create mode 100644 Shared/View/CharacterCellView.swift diff --git a/FontFace.xcodeproj/project.pbxproj b/FontFace.xcodeproj/project.pbxproj index aaea663..920ec7f 100644 --- a/FontFace.xcodeproj/project.pbxproj +++ b/FontFace.xcodeproj/project.pbxproj @@ -13,6 +13,9 @@ 5705571D262C5EA1004A1FE3 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57055708262C5EA0004A1FE3 /* ContentView.swift */; }; 5705571E262C5EA1004A1FE3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 57055709262C5EA1004A1FE3 /* Assets.xcassets */; }; 5705571F262C5EA1004A1FE3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 57055709262C5EA1004A1FE3 /* Assets.xcassets */; }; + 5705572E262C5F8B004A1FE3 /* FontModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5705572D262C5F8B004A1FE3 /* FontModel.swift */; }; + 57055733262C602A004A1FE3 /* CharacterCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57055732262C602A004A1FE3 /* CharacterCellView.swift */; }; + 5705573A262C61DF004A1FE3 /* NSCharacterSetExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57055739262C61DF004A1FE3 /* NSCharacterSetExtension.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -24,6 +27,9 @@ 57055716262C5EA1004A1FE3 /* FontFace.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FontFace.app; sourceTree = BUILT_PRODUCTS_DIR; }; 57055718262C5EA1004A1FE3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57055719262C5EA1004A1FE3 /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; + 5705572D262C5F8B004A1FE3 /* FontModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontModel.swift; sourceTree = ""; }; + 57055732262C602A004A1FE3 /* CharacterCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCellView.swift; sourceTree = ""; }; + 57055739262C61DF004A1FE3 /* NSCharacterSetExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSCharacterSetExtension.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -57,6 +63,9 @@ 57055706262C5EA0004A1FE3 /* Shared */ = { isa = PBXGroup; children = ( + 57055738262C61CF004A1FE3 /* Utils */, + 57055731262C600D004A1FE3 /* View */, + 5705572C262C5F4D004A1FE3 /* Model */, 57055707262C5EA0004A1FE3 /* FontFaceApp.swift */, 57055708262C5EA0004A1FE3 /* ContentView.swift */, 57055709262C5EA1004A1FE3 /* Assets.xcassets */, @@ -90,6 +99,30 @@ path = macOS; sourceTree = ""; }; + 5705572C262C5F4D004A1FE3 /* Model */ = { + isa = PBXGroup; + children = ( + 5705572D262C5F8B004A1FE3 /* FontModel.swift */, + ); + path = Model; + sourceTree = ""; + }; + 57055731262C600D004A1FE3 /* View */ = { + isa = PBXGroup; + children = ( + 57055732262C602A004A1FE3 /* CharacterCellView.swift */, + ); + path = View; + sourceTree = ""; + }; + 57055738262C61CF004A1FE3 /* Utils */ = { + isa = PBXGroup; + children = ( + 57055739262C61DF004A1FE3 /* NSCharacterSetExtension.swift */, + ); + path = Utils; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -198,6 +231,9 @@ files = ( 5705571D262C5EA1004A1FE3 /* ContentView.swift in Sources */, 5705571B262C5EA1004A1FE3 /* FontFaceApp.swift in Sources */, + 5705572E262C5F8B004A1FE3 /* FontModel.swift in Sources */, + 5705573A262C61DF004A1FE3 /* NSCharacterSetExtension.swift in Sources */, + 57055733262C602A004A1FE3 /* CharacterCellView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/FontFace.xcodeproj/project.xcworkspace/xcuserdata/lvjun.xcuserdatad/UserInterfaceState.xcuserstate b/FontFace.xcodeproj/project.xcworkspace/xcuserdata/lvjun.xcuserdatad/UserInterfaceState.xcuserstate index 0db8a715e67e53907933b8d781a9debe5507de67..959a580d6564c39b7905e6b74a227816bc824d3e 100644 GIT binary patch literal 30531 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 diff --git a/Shared/ContentView.swift b/Shared/ContentView.swift index 6dd4429..55c78b3 100644 --- a/Shared/ContentView.swift +++ b/Shared/ContentView.swift @@ -8,12 +8,56 @@ import SwiftUI struct ContentView: View { + + let columns = [ + GridItem(.flexible()), + GridItem(.flexible()), + GridItem(.flexible()), + GridItem(.flexible()), + GridItem(.flexible()), + GridItem(.flexible()), + ] + var body: some View { - Text("Hello, world!") - .padding() + ZStack(alignment: .top) { + ScrollView { + LazyVGrid(columns: columns) { + ForEach(fetchFontList(), id: \.self) { characterModel in + CharacterCellView(name: "PingFang", characterModel: characterModel) + } + } + } + } + .padding() + .frame(minWidth: 600, idealWidth: 700, minHeight: 400, idealHeight: 800, alignment: .center) + .toolbar { + ToolbarItem(placement: .primaryAction) { + Menu { + + } label: { + Image(systemName: "square.and.arrow.up.on.square.fill") + } + } + } } } +/// 获取字符集及其 Unicode +/// - Returns: StringCharacter +func fetchFontList() -> [CharacterModel] { + if let name = NSFontManager.shared.availableFontFamilies.first { + + if let font = NSFontManager.shared.font(withFamily: name, traits: .boldFontMask, weight: 1, size: 30) { + + let set = font.coveredCharacterSet as NSCharacterSet + + return set.characters + } + } + + return [] +} + struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() diff --git a/Shared/Model/FontModel.swift b/Shared/Model/FontModel.swift new file mode 100644 index 0000000..96183ec --- /dev/null +++ b/Shared/Model/FontModel.swift @@ -0,0 +1,22 @@ +// +// FontModel.swift +// FontFace (macOS) +// +// Created by 吕俊 on 2021/4/18. +// + +import Foundation + +struct FontModel: Hashable { + var name: String + var characters: [CharacterModel] +} + +struct CharacterModel: Hashable { + var character: String + var unicode: String +} + +let mockFontModel = FontModel(name: "PingFang", characters: [mockCharacterModel]) + +let mockCharacterModel = CharacterModel(character: "T", unicode: "\u{e638}") diff --git a/Shared/Utils/NSCharacterSetExtension.swift b/Shared/Utils/NSCharacterSetExtension.swift new file mode 100644 index 0000000..f10bc1d --- /dev/null +++ b/Shared/Utils/NSCharacterSetExtension.swift @@ -0,0 +1,33 @@ +// +// NSCharacterSetExtension.swift +// FontFace (macOS) +// +// Created by 吕俊 on 2021/4/18. +// + +import Foundation + +extension NSCharacterSet { + var characters:[CharacterModel] { + var results = [CharacterModel]() + for plane:UInt8 in 0...16 { + if self.hasMemberInPlane(plane) { + let p0 = UInt32(plane) << 16 + let p1 = (UInt32(plane) + 1) << 16 + for c:UTF32Char in p0..