mirror of
https://github.com/GLEGram/GLEGram-iOS.git
synced 2026-04-23 19:36:26 +02:00
4647310322
Based on Swiftgram 12.5 (Telegram iOS 12.5). All GLEGram features ported and organized in GLEGram/ folder. Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass, Font Replacement, Fake Profile, Chat Export, Plugin System, and more. See CHANGELOG_12.5.md for full details.
164 lines
6.3 KiB
Swift
Executable File
164 lines
6.3 KiB
Swift
Executable File
// MARK: Swiftgram - Font replacement picker (A-Font style)
|
|
import SGSimpleSettings
|
|
import Foundation
|
|
import UIKit
|
|
import CoreText
|
|
import CoreGraphics
|
|
import Display
|
|
import SwiftSignalKit
|
|
import TelegramPresentationData
|
|
import ItemListUI
|
|
import AccountContext
|
|
|
|
/// Bundled default fonts shown at the top of the picker (display name, bundle filename without extension).
|
|
private let bundledDefaultFonts: [(displayName: String, fileName: String)] = [
|
|
(displayName: "Minecraft Default Bold", fileName: "MinecraftDefault-Bold-2"),
|
|
]
|
|
|
|
/// Registers a .ttf from the given bundle if present and returns its PostScript name, or nil.
|
|
private func registerBundledFont(bundle: Bundle, fileName: String) -> String? {
|
|
guard let path = bundle.path(forResource: fileName, ofType: "ttf") else {
|
|
return nil
|
|
}
|
|
let url = URL(fileURLWithPath: path)
|
|
guard let provider = CGDataProvider(url: url as CFURL),
|
|
let cgFont = CGFont(provider),
|
|
let name = cgFont.postScriptName as String?, !name.isEmpty else {
|
|
return nil
|
|
}
|
|
CTFontManagerRegisterFontURLs([url] as CFArray, .process, true, nil)
|
|
return name
|
|
}
|
|
|
|
public enum FontReplacementPickerMode {
|
|
case main
|
|
case bold
|
|
}
|
|
|
|
private struct FontReplacementPickerArguments {
|
|
let selectFont: (String) -> Void
|
|
let dismiss: () -> Void
|
|
}
|
|
|
|
private struct FontReplacementPickerEntry: ItemListNodeEntry {
|
|
let entryId: Int
|
|
let fontName: String
|
|
let displayTitle: String
|
|
|
|
var section: ItemListSectionId { 0 }
|
|
var stableId: Int { entryId }
|
|
var id: Int { entryId }
|
|
|
|
static func == (lhs: FontReplacementPickerEntry, rhs: FontReplacementPickerEntry) -> Bool {
|
|
lhs.entryId == rhs.entryId && lhs.fontName == rhs.fontName
|
|
}
|
|
static func < (lhs: FontReplacementPickerEntry, rhs: FontReplacementPickerEntry) -> Bool {
|
|
lhs.entryId < rhs.entryId
|
|
}
|
|
|
|
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
|
let args = arguments as! FontReplacementPickerArguments
|
|
let fontSize = presentationData.fontSize.itemListBaseFontSize
|
|
let textColor = presentationData.theme.list.itemAccentColor
|
|
let attributedTitle: NSAttributedString?
|
|
if fontName.isEmpty {
|
|
attributedTitle = nil
|
|
} else if let font = UIFont(name: fontName, size: fontSize) {
|
|
attributedTitle = NSAttributedString(string: displayTitle, font: font, textColor: textColor)
|
|
} else {
|
|
attributedTitle = nil
|
|
}
|
|
return ItemListDisclosureItem(
|
|
presentationData: presentationData,
|
|
title: displayTitle,
|
|
attributedTitle: attributedTitle,
|
|
label: "",
|
|
sectionId: section,
|
|
style: .blocks,
|
|
disclosureStyle: .none,
|
|
action: {
|
|
args.selectFont(self.fontName)
|
|
args.dismiss()
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
public func FontReplacementPickerController(context: AccountContext, mode: FontReplacementPickerMode, onSave: @escaping () -> Void) -> ViewController {
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
var dismissImpl: (() -> Void)?
|
|
|
|
// Re-register downloaded fonts so they appear in the list
|
|
registerAllDownloadedFonts()
|
|
|
|
let (fontNames, bundledDisplayNames): ([String], [String: String]) = {
|
|
var list: [String] = []
|
|
var bundledMap: [String: String] = [:]
|
|
for (displayName, fileName) in bundledDefaultFonts {
|
|
if let postScriptName = registerBundledFont(bundle: .main, fileName: fileName), !list.contains(postScriptName) {
|
|
list.append(postScriptName)
|
|
bundledMap[postScriptName] = displayName
|
|
}
|
|
}
|
|
for family in UIFont.familyNames.sorted() {
|
|
for name in UIFont.fontNames(forFamilyName: family).sorted() {
|
|
if !list.contains(name) {
|
|
list.append(name)
|
|
}
|
|
}
|
|
}
|
|
return (list.sorted(), bundledMap)
|
|
}()
|
|
|
|
let selectFont: (String) -> Void = { name in
|
|
switch mode {
|
|
case .main:
|
|
SGSimpleSettings.shared.fontReplacementName = name
|
|
SGSimpleSettings.shared.fontReplacementFilePath = "" // only "Import from file" sets path
|
|
case .bold:
|
|
SGSimpleSettings.shared.fontReplacementBoldName = name
|
|
SGSimpleSettings.shared.fontReplacementBoldFilePath = ""
|
|
}
|
|
onSave()
|
|
dismissImpl?()
|
|
}
|
|
|
|
let arguments = FontReplacementPickerArguments(
|
|
selectFont: selectFont,
|
|
dismiss: { dismissImpl?() }
|
|
)
|
|
|
|
var entries: [FontReplacementPickerEntry] = []
|
|
let systemTitle = presentationData.strings.baseLanguageCode == "ru" ? "Системный" : "System"
|
|
let autoTitle = presentationData.strings.baseLanguageCode == "ru" ? "Авто" : "Auto"
|
|
entries.append(FontReplacementPickerEntry(entryId: 0, fontName: "", displayTitle: mode == .main ? systemTitle : autoTitle))
|
|
for (idx, name) in fontNames.enumerated() {
|
|
let displayTitle = bundledDisplayNames[name] ?? name
|
|
entries.append(FontReplacementPickerEntry(entryId: idx + 1, fontName: name, displayTitle: displayTitle))
|
|
}
|
|
|
|
let controllerState = ItemListControllerState(
|
|
presentationData: ItemListPresentationData(presentationData),
|
|
title: .text(mode == .main ? (presentationData.strings.baseLanguageCode == "ru" ? "Шрифт" : "Font") : (presentationData.strings.baseLanguageCode == "ru" ? "Жирный шрифт" : "Bold font")),
|
|
leftNavigationButton: nil,
|
|
rightNavigationButton: nil,
|
|
backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)
|
|
)
|
|
|
|
let listState = ItemListNodeState(
|
|
presentationData: ItemListPresentationData(presentationData),
|
|
entries: entries,
|
|
style: .blocks,
|
|
ensureVisibleItemTag: nil,
|
|
initialScrollToItem: nil
|
|
)
|
|
|
|
let signal: Signal<(ItemListControllerState, (ItemListNodeState, FontReplacementPickerArguments)), NoError> = .single((controllerState, (listState, arguments)))
|
|
|
|
let controller = ItemListController(context: context, state: signal)
|
|
dismissImpl = { [weak controller] in
|
|
controller?.dismiss()
|
|
}
|
|
return controller
|
|
}
|