mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Playground UIKit base and controllers
This commit is contained in:
parent
3b002dd983
commit
1af6300df5
@ -9,9 +9,17 @@ load(
|
||||
"//Swiftgram/Playground:custom_bazel_path.bzl", "custom_bazel_path"
|
||||
)
|
||||
|
||||
objc_library(
|
||||
name = "PlaygroundMain",
|
||||
srcs = [
|
||||
"Sources/main.m"
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
swift_library(
|
||||
name = "playgroundLib",
|
||||
srcs = glob(["Sources/*.swift"]),
|
||||
name = "PlaygroundLib",
|
||||
srcs = glob(["Sources/**/*.swift"]),
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/Display:Display",
|
||||
@ -30,7 +38,8 @@ ios_application(
|
||||
infoplists = ["Resources/Info.plist"],
|
||||
minimum_os_version = "14.0",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":playgroundLib"],
|
||||
launch_storyboard = "Resources/LaunchScreen.storyboard",
|
||||
deps = [":PlaygroundMain", ":PlaygroundLib"],
|
||||
)
|
||||
|
||||
xcodeproj(
|
||||
|
25
Swiftgram/Playground/Resources/LaunchScreen.storyboard
Normal file
25
Swiftgram/Playground/Resources/LaunchScreen.storyboard
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
@ -1,12 +0,0 @@
|
||||
import SwiftUI
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
|
||||
@main
|
||||
struct BazelApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
Text("Hello from Bazel!")
|
||||
}
|
||||
}
|
||||
}
|
39
Swiftgram/Playground/Sources/AppDelegate.swift
Normal file
39
Swiftgram/Playground/Sources/AppDelegate.swift
Normal file
@ -0,0 +1,39 @@
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
|
||||
|
||||
@objc(AppDelegate)
|
||||
final class AppDelegate: NSObject, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
|
||||
private var mainWindow: Window1?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
|
||||
let statusBarHost = ApplicationStatusBarHost()
|
||||
let (window, hostView) = nativeWindowHostView()
|
||||
let mainWindow = Window1(hostView: hostView, statusBarHost: statusBarHost)
|
||||
self.mainWindow = mainWindow
|
||||
hostView.containerView.backgroundColor = UIColor.white
|
||||
self.window = window
|
||||
|
||||
|
||||
let navigationController = NavigationController(
|
||||
mode: .single,
|
||||
theme: NavigationControllerTheme(
|
||||
statusBar: .black,
|
||||
navigationBar: THEME.navigationBar,
|
||||
emptyAreaColor: .white
|
||||
)
|
||||
)
|
||||
|
||||
mainWindow.viewController = navigationController
|
||||
|
||||
navigationController.setViewControllers([PlaygroundScreen(), PlaygroundSplashScreen()], animated: false)
|
||||
|
||||
self.window?.makeKeyAndVisible()
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
100
Swiftgram/Playground/Sources/AppNavigationSetup.swift
Normal file
100
Swiftgram/Playground/Sources/AppNavigationSetup.swift
Normal file
@ -0,0 +1,100 @@
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
|
||||
public func isKeyboardWindow(window: NSObject) -> Bool {
|
||||
let typeName = NSStringFromClass(type(of: window))
|
||||
if #available(iOS 9.0, *) {
|
||||
if typeName.hasPrefix("UI") && typeName.hasSuffix("RemoteKeyboardWindow") {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
if typeName.hasPrefix("UI") && typeName.hasSuffix("TextEffectsWindow") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public func isKeyboardView(view: NSObject) -> Bool {
|
||||
let typeName = NSStringFromClass(type(of: view))
|
||||
if typeName.hasPrefix("UI") && typeName.hasSuffix("InputSetHostView") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public func isKeyboardViewContainer(view: NSObject) -> Bool {
|
||||
let typeName = NSStringFromClass(type(of: view))
|
||||
if typeName.hasPrefix("UI") && typeName.hasSuffix("InputSetContainerView") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public class ApplicationStatusBarHost: StatusBarHost {
|
||||
private let application = UIApplication.shared
|
||||
|
||||
public var isApplicationInForeground: Bool {
|
||||
switch self.application.applicationState {
|
||||
case .background:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public var statusBarFrame: CGRect {
|
||||
return self.application.statusBarFrame
|
||||
}
|
||||
public var statusBarStyle: UIStatusBarStyle {
|
||||
get {
|
||||
return self.application.statusBarStyle
|
||||
} set(value) {
|
||||
self.setStatusBarStyle(value, animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
public func setStatusBarStyle(_ style: UIStatusBarStyle, animated: Bool) {
|
||||
if self.shouldChangeStatusBarStyle?(style) ?? true {
|
||||
self.application.internalSetStatusBarStyle(style, animated: animated)
|
||||
}
|
||||
}
|
||||
|
||||
public var shouldChangeStatusBarStyle: ((UIStatusBarStyle) -> Bool)?
|
||||
|
||||
public func setStatusBarHidden(_ value: Bool, animated: Bool) {
|
||||
self.application.internalSetStatusBarHidden(value, animation: animated ? .fade : .none)
|
||||
}
|
||||
|
||||
public var keyboardWindow: UIWindow? {
|
||||
if #available(iOS 16.0, *) {
|
||||
return UIApplication.shared.internalGetKeyboard()
|
||||
}
|
||||
|
||||
for window in UIApplication.shared.windows {
|
||||
if isKeyboardWindow(window: window) {
|
||||
return window
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public var keyboardView: UIView? {
|
||||
guard let keyboardWindow = self.keyboardWindow else {
|
||||
return nil
|
||||
}
|
||||
|
||||
for view in keyboardWindow.subviews {
|
||||
if isKeyboardViewContainer(view: view) {
|
||||
for subview in view.subviews {
|
||||
if isKeyboardView(view: subview) {
|
||||
return subview
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
5
Swiftgram/Playground/Sources/Application.swift
Normal file
5
Swiftgram/Playground/Sources/Application.swift
Normal file
@ -0,0 +1,5 @@
|
||||
import UIKit
|
||||
|
||||
@objc(Application) class Application: UIApplication {
|
||||
|
||||
}
|
94
Swiftgram/Playground/Sources/PlaygroundScreen.swift
Normal file
94
Swiftgram/Playground/Sources/PlaygroundScreen.swift
Normal file
@ -0,0 +1,94 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
|
||||
private final class PlaygroundScreenNode: ASDisplayNode {
|
||||
private let headerBackgroundNode: ASDisplayNode
|
||||
private let headerCornerNode: ASImageNode
|
||||
|
||||
private var isDismissed = false
|
||||
|
||||
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||
|
||||
override init() {
|
||||
self.headerBackgroundNode = ASDisplayNode()
|
||||
self.headerBackgroundNode.backgroundColor = .black
|
||||
|
||||
self.headerCornerNode = ASImageNode()
|
||||
self.headerCornerNode.displaysAsynchronously = false
|
||||
self.headerCornerNode.displayWithoutProcessing = true
|
||||
self.headerCornerNode.image = generateImage(CGSize(width: 20.0, height: 10.0), rotatedContext: { size, context in
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||
context.setBlendMode(.copy)
|
||||
context.setFillColor(UIColor.clear.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: 20.0, height: 20.0)))
|
||||
})?.stretchableImage(withLeftCapWidth: 10, topCapHeight: 1)
|
||||
super.init()
|
||||
|
||||
self.backgroundColor = THEME.list.itemBlocksBackgroundColor
|
||||
|
||||
self.addSubnode(self.headerBackgroundNode)
|
||||
self.addSubnode(self.headerCornerNode)
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
if self.isDismissed {
|
||||
return
|
||||
}
|
||||
self.validLayout = (layout, navigationHeight)
|
||||
|
||||
let headerHeight = navigationHeight + 260.0
|
||||
|
||||
transition.updateFrame(node: self.headerBackgroundNode, frame: CGRect(origin: CGPoint(x: -1.0, y: 0), size: CGSize(width: layout.size.width + 2.0, height: headerHeight)))
|
||||
transition.updateFrame(node: self.headerCornerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: headerHeight), size: CGSize(width: layout.size.width, height: 10.0)))
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
guard let (layout, navigationHeight) = self.validLayout else {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
self.isDismissed = true
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.4, curve: .spring)
|
||||
|
||||
let headerHeight = navigationHeight + 260.0
|
||||
|
||||
transition.updateFrame(node: self.headerBackgroundNode, frame: CGRect(origin: CGPoint(x: -1.0, y: -headerHeight - 10.0), size: CGSize(width: layout.size.width + 2.0, height: headerHeight)), completion: { _ in
|
||||
completion()
|
||||
})
|
||||
transition.updateFrame(node: self.headerCornerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -10.0), size: CGSize(width: layout.size.width, height: 10.0)))
|
||||
}
|
||||
}
|
||||
|
||||
public final class PlaygroundScreen: ViewController {
|
||||
|
||||
public init() {
|
||||
|
||||
let navigationBarTheme = NavigationBarTheme(buttonColor: .white, disabledButtonColor: .white, primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: true, separatorColor: .clear, badgeBackgroundColor: THEME.navigationBar.badgeBackgroundColor, badgeStrokeColor: THEME.navigationBar.badgeStrokeColor, badgeTextColor: THEME.navigationBar.badgeTextColor)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: "", close: "")))
|
||||
|
||||
self.statusBar.statusBarStyle = .White
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = PlaygroundScreenNode()
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
(self.displayNode as! PlaygroundScreenNode).containerLayoutUpdated(layout: layout, navigationHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||
}
|
||||
|
||||
public func animateOut(completion: @escaping () -> Void) {
|
||||
self.statusBar.statusBarStyle = .Black
|
||||
(self.displayNode as! PlaygroundScreenNode).animateOut(completion: completion)
|
||||
}
|
||||
}
|
95
Swiftgram/Playground/Sources/PlaygroundSplashScreen.swift
Normal file
95
Swiftgram/Playground/Sources/PlaygroundSplashScreen.swift
Normal file
@ -0,0 +1,95 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
|
||||
private final class PlaygroundSplashScreenNode: ASDisplayNode {
|
||||
private let headerBackgroundNode: ASDisplayNode
|
||||
private let headerCornerNode: ASImageNode
|
||||
|
||||
private var isDismissed = false
|
||||
|
||||
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||
|
||||
override init() {
|
||||
self.headerBackgroundNode = ASDisplayNode()
|
||||
self.headerBackgroundNode.backgroundColor = .black
|
||||
|
||||
self.headerCornerNode = ASImageNode()
|
||||
self.headerCornerNode.displaysAsynchronously = false
|
||||
self.headerCornerNode.displayWithoutProcessing = true
|
||||
self.headerCornerNode.image = generateImage(CGSize(width: 20.0, height: 10.0), rotatedContext: { size, context in
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
context.fill(CGRect(origin: CGPoint(), size: size))
|
||||
context.setBlendMode(.copy)
|
||||
context.setFillColor(UIColor.clear.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: 20.0, height: 20.0)))
|
||||
})?.stretchableImage(withLeftCapWidth: 10, topCapHeight: 1)
|
||||
|
||||
super.init()
|
||||
|
||||
self.backgroundColor = THEME.list.itemBlocksBackgroundColor
|
||||
|
||||
self.addSubnode(self.headerBackgroundNode)
|
||||
self.addSubnode(self.headerCornerNode)
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
if self.isDismissed {
|
||||
return
|
||||
}
|
||||
self.validLayout = (layout, navigationHeight)
|
||||
|
||||
let headerHeight = navigationHeight + 260.0
|
||||
|
||||
transition.updateFrame(node: self.headerBackgroundNode, frame: CGRect(origin: CGPoint(x: -1.0, y: 0), size: CGSize(width: layout.size.width + 2.0, height: headerHeight)))
|
||||
transition.updateFrame(node: self.headerCornerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: headerHeight), size: CGSize(width: layout.size.width, height: 10.0)))
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
guard let (layout, navigationHeight) = self.validLayout else {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
self.isDismissed = true
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.4, curve: .spring)
|
||||
|
||||
let headerHeight = navigationHeight + 260.0
|
||||
|
||||
transition.updateFrame(node: self.headerBackgroundNode, frame: CGRect(origin: CGPoint(x: -1.0, y: -headerHeight - 10.0), size: CGSize(width: layout.size.width + 2.0, height: headerHeight)), completion: { _ in
|
||||
completion()
|
||||
})
|
||||
transition.updateFrame(node: self.headerCornerNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -10.0), size: CGSize(width: layout.size.width, height: 10.0)))
|
||||
}
|
||||
}
|
||||
|
||||
public final class PlaygroundSplashScreen: ViewController {
|
||||
|
||||
public init() {
|
||||
|
||||
let navigationBarTheme = NavigationBarTheme(buttonColor: .white, disabledButtonColor: .white, primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: true, separatorColor: .clear, badgeBackgroundColor: THEME.navigationBar.badgeBackgroundColor, badgeStrokeColor: THEME.navigationBar.badgeStrokeColor, badgeTextColor: THEME.navigationBar.badgeTextColor)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: "", close: "")))
|
||||
|
||||
self.statusBar.statusBarStyle = .White
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override public func loadDisplayNode() {
|
||||
self.displayNode = PlaygroundSplashScreenNode()
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
(self.displayNode as! PlaygroundSplashScreenNode).containerLayoutUpdated(layout: layout, navigationHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
|
||||
}
|
||||
|
||||
public func animateOut(completion: @escaping () -> Void) {
|
||||
self.statusBar.statusBarStyle = .Black
|
||||
(self.displayNode as! PlaygroundSplashScreenNode).animateOut(completion: completion)
|
||||
}
|
||||
}
|
362
Swiftgram/Playground/Sources/PlaygroundTheme.swift
Normal file
362
Swiftgram/Playground/Sources/PlaygroundTheme.swift
Normal file
@ -0,0 +1,362 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
|
||||
|
||||
public final class PlaygroundInfoTheme {
|
||||
public let buttonBackgroundColor: UIColor
|
||||
public let buttonTextColor: UIColor
|
||||
public let incomingFundsTitleColor: UIColor
|
||||
public let outgoingFundsTitleColor: UIColor
|
||||
|
||||
public init(
|
||||
buttonBackgroundColor: UIColor,
|
||||
buttonTextColor: UIColor,
|
||||
incomingFundsTitleColor: UIColor,
|
||||
outgoingFundsTitleColor: UIColor
|
||||
) {
|
||||
self.buttonBackgroundColor = buttonBackgroundColor
|
||||
self.buttonTextColor = buttonTextColor
|
||||
self.incomingFundsTitleColor = incomingFundsTitleColor
|
||||
self.outgoingFundsTitleColor = outgoingFundsTitleColor
|
||||
}
|
||||
}
|
||||
|
||||
public final class PlaygroundTransactionTheme {
|
||||
public let descriptionBackgroundColor: UIColor
|
||||
public let descriptionTextColor: UIColor
|
||||
|
||||
public init(
|
||||
descriptionBackgroundColor: UIColor,
|
||||
descriptionTextColor: UIColor
|
||||
) {
|
||||
self.descriptionBackgroundColor = descriptionBackgroundColor
|
||||
self.descriptionTextColor = descriptionTextColor
|
||||
}
|
||||
}
|
||||
|
||||
public final class PlaygroundSetupTheme {
|
||||
public let buttonFillColor: UIColor
|
||||
public let buttonForegroundColor: UIColor
|
||||
public let inputBackgroundColor: UIColor
|
||||
public let inputPlaceholderColor: UIColor
|
||||
public let inputTextColor: UIColor
|
||||
public let inputClearButtonColor: UIColor
|
||||
|
||||
public init(
|
||||
buttonFillColor: UIColor,
|
||||
buttonForegroundColor: UIColor,
|
||||
inputBackgroundColor: UIColor,
|
||||
inputPlaceholderColor: UIColor,
|
||||
inputTextColor: UIColor,
|
||||
inputClearButtonColor: UIColor
|
||||
) {
|
||||
self.buttonFillColor = buttonFillColor
|
||||
self.buttonForegroundColor = buttonForegroundColor
|
||||
self.inputBackgroundColor = inputBackgroundColor
|
||||
self.inputPlaceholderColor = inputPlaceholderColor
|
||||
self.inputTextColor = inputTextColor
|
||||
self.inputClearButtonColor = inputClearButtonColor
|
||||
}
|
||||
}
|
||||
|
||||
public final class PlaygroundListTheme {
|
||||
public let itemPrimaryTextColor: UIColor
|
||||
public let itemSecondaryTextColor: UIColor
|
||||
public let itemPlaceholderTextColor: UIColor
|
||||
public let itemDestructiveColor: UIColor
|
||||
public let itemAccentColor: UIColor
|
||||
public let itemDisabledTextColor: UIColor
|
||||
public let plainBackgroundColor: UIColor
|
||||
public let blocksBackgroundColor: UIColor
|
||||
public let itemPlainSeparatorColor: UIColor
|
||||
public let itemBlocksBackgroundColor: UIColor
|
||||
public let itemBlocksSeparatorColor: UIColor
|
||||
public let itemHighlightedBackgroundColor: UIColor
|
||||
public let sectionHeaderTextColor: UIColor
|
||||
public let freeTextColor: UIColor
|
||||
public let freeTextErrorColor: UIColor
|
||||
public let inputClearButtonColor: UIColor
|
||||
|
||||
public init(
|
||||
itemPrimaryTextColor: UIColor,
|
||||
itemSecondaryTextColor: UIColor,
|
||||
itemPlaceholderTextColor: UIColor,
|
||||
itemDestructiveColor: UIColor,
|
||||
itemAccentColor: UIColor,
|
||||
itemDisabledTextColor: UIColor,
|
||||
plainBackgroundColor: UIColor,
|
||||
blocksBackgroundColor: UIColor,
|
||||
itemPlainSeparatorColor: UIColor,
|
||||
itemBlocksBackgroundColor: UIColor,
|
||||
itemBlocksSeparatorColor: UIColor,
|
||||
itemHighlightedBackgroundColor: UIColor,
|
||||
sectionHeaderTextColor: UIColor,
|
||||
freeTextColor: UIColor,
|
||||
freeTextErrorColor: UIColor,
|
||||
inputClearButtonColor: UIColor
|
||||
) {
|
||||
self.itemPrimaryTextColor = itemPrimaryTextColor
|
||||
self.itemSecondaryTextColor = itemSecondaryTextColor
|
||||
self.itemPlaceholderTextColor = itemPlaceholderTextColor
|
||||
self.itemDestructiveColor = itemDestructiveColor
|
||||
self.itemAccentColor = itemAccentColor
|
||||
self.itemDisabledTextColor = itemDisabledTextColor
|
||||
self.plainBackgroundColor = plainBackgroundColor
|
||||
self.blocksBackgroundColor = blocksBackgroundColor
|
||||
self.itemPlainSeparatorColor = itemPlainSeparatorColor
|
||||
self.itemBlocksBackgroundColor = itemBlocksBackgroundColor
|
||||
self.itemBlocksSeparatorColor = itemBlocksSeparatorColor
|
||||
self.itemHighlightedBackgroundColor = itemHighlightedBackgroundColor
|
||||
self.sectionHeaderTextColor = sectionHeaderTextColor
|
||||
self.freeTextColor = freeTextColor
|
||||
self.freeTextErrorColor = freeTextErrorColor
|
||||
self.inputClearButtonColor = inputClearButtonColor
|
||||
}
|
||||
}
|
||||
|
||||
public final class PlaygroundTheme: Equatable {
|
||||
public let info: PlaygroundInfoTheme
|
||||
public let transaction: PlaygroundTransactionTheme
|
||||
public let setup: PlaygroundSetupTheme
|
||||
public let list: PlaygroundListTheme
|
||||
public let statusBarStyle: StatusBarStyle
|
||||
public let navigationBar: NavigationBarTheme
|
||||
public let keyboardAppearance: UIKeyboardAppearance
|
||||
public let alert: AlertControllerTheme
|
||||
public let actionSheet: ActionSheetControllerTheme
|
||||
|
||||
private let resourceCache = PlaygroundThemeResourceCache()
|
||||
|
||||
public init(info: PlaygroundInfoTheme, transaction: PlaygroundTransactionTheme, setup: PlaygroundSetupTheme, list: PlaygroundListTheme, statusBarStyle: StatusBarStyle, navigationBar: NavigationBarTheme, keyboardAppearance: UIKeyboardAppearance, alert: AlertControllerTheme, actionSheet: ActionSheetControllerTheme) {
|
||||
self.info = info
|
||||
self.transaction = transaction
|
||||
self.setup = setup
|
||||
self.list = list
|
||||
self.statusBarStyle = statusBarStyle
|
||||
self.navigationBar = navigationBar
|
||||
self.keyboardAppearance = keyboardAppearance
|
||||
self.alert = alert
|
||||
self.actionSheet = actionSheet
|
||||
}
|
||||
|
||||
func image(_ key: Int32, _ generate: (PlaygroundTheme) -> UIImage?) -> UIImage? {
|
||||
return self.resourceCache.image(key, self, generate)
|
||||
}
|
||||
|
||||
public static func ==(lhs: PlaygroundTheme, rhs: PlaygroundTheme) -> Bool {
|
||||
return lhs === rhs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final class PlaygroundThemeResourceCacheHolder {
|
||||
var images: [Int32: UIImage] = [:]
|
||||
}
|
||||
|
||||
private final class PlaygroundThemeResourceCache {
|
||||
private let imageCache = Atomic<PlaygroundThemeResourceCacheHolder>(value: PlaygroundThemeResourceCacheHolder())
|
||||
|
||||
public func image(_ key: Int32, _ theme: PlaygroundTheme, _ generate: (PlaygroundTheme) -> UIImage?) -> UIImage? {
|
||||
let result = self.imageCache.with { holder -> UIImage? in
|
||||
return holder.images[key]
|
||||
}
|
||||
if let result = result {
|
||||
return result
|
||||
} else {
|
||||
if let image = generate(theme) {
|
||||
self.imageCache.with { holder -> Void in
|
||||
holder.images[key] = image
|
||||
}
|
||||
return image
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum PlaygroundThemeResourceKey: Int32 {
|
||||
case itemListCornersBoth
|
||||
case itemListCornersTop
|
||||
case itemListCornersBottom
|
||||
case itemListClearInputIcon
|
||||
case itemListDisclosureArrow
|
||||
case navigationShareIcon
|
||||
case transactionLockIcon
|
||||
|
||||
case clockMin
|
||||
case clockFrame
|
||||
}
|
||||
|
||||
func cornersImage(_ theme: PlaygroundTheme, top: Bool, bottom: Bool) -> UIImage? {
|
||||
if !top && !bottom {
|
||||
return nil
|
||||
}
|
||||
let key: PlaygroundThemeResourceKey
|
||||
if top && bottom {
|
||||
key = .itemListCornersBoth
|
||||
} else if top {
|
||||
key = .itemListCornersTop
|
||||
} else {
|
||||
key = .itemListCornersBottom
|
||||
}
|
||||
return theme.image(key.rawValue, { theme in
|
||||
return generateImage(CGSize(width: 50.0, height: 50.0), rotatedContext: { (size, context) in
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
context.setFillColor(theme.list.blocksBackgroundColor.cgColor)
|
||||
context.fill(bounds)
|
||||
|
||||
context.setBlendMode(.clear)
|
||||
|
||||
var corners: UIRectCorner = []
|
||||
if top {
|
||||
corners.insert(.topLeft)
|
||||
corners.insert(.topRight)
|
||||
}
|
||||
if bottom {
|
||||
corners.insert(.bottomLeft)
|
||||
corners.insert(.bottomRight)
|
||||
}
|
||||
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: 11.0, height: 11.0))
|
||||
context.addPath(path.cgPath)
|
||||
context.fillPath()
|
||||
})?.stretchableImage(withLeftCapWidth: 25, topCapHeight: 25)
|
||||
})
|
||||
}
|
||||
|
||||
func itemListClearInputIcon(_ theme: PlaygroundTheme) -> UIImage? {
|
||||
return theme.image(PlaygroundThemeResourceKey.itemListClearInputIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Playground/ClearInput"), color: theme.list.inputClearButtonColor)
|
||||
})
|
||||
}
|
||||
|
||||
func navigationShareIcon(_ theme: PlaygroundTheme) -> UIImage? {
|
||||
return theme.image(PlaygroundThemeResourceKey.navigationShareIcon.rawValue, { theme in
|
||||
generateTintedImage(image: UIImage(bundleImageName: "Playground/NavigationShare"), color: theme.navigationBar.buttonColor)
|
||||
})
|
||||
}
|
||||
|
||||
func disclosureArrowImage(_ theme: PlaygroundTheme) -> UIImage? {
|
||||
return theme.image(PlaygroundThemeResourceKey.itemListDisclosureArrow.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Playground/DisclosureArrow"), color: theme.list.itemSecondaryTextColor)
|
||||
})
|
||||
}
|
||||
|
||||
func clockFrameImage(_ theme: PlaygroundTheme) -> UIImage? {
|
||||
return theme.image(PlaygroundThemeResourceKey.clockFrame.rawValue, { theme in
|
||||
let color = theme.list.itemSecondaryTextColor
|
||||
return generateImage(CGSize(width: 11.0, height: 11.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setStrokeColor(color.cgColor)
|
||||
context.setFillColor(color.cgColor)
|
||||
let strokeWidth: CGFloat = 1.0
|
||||
context.setLineWidth(strokeWidth)
|
||||
context.strokeEllipse(in: CGRect(x: strokeWidth / 2.0, y: strokeWidth / 2.0, width: size.width - strokeWidth, height: size.height - strokeWidth))
|
||||
context.fill(CGRect(x: (11.0 - strokeWidth) / 2.0, y: strokeWidth * 3.0, width: strokeWidth, height: 11.0 / 2.0 - strokeWidth * 3.0))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func clockMinImage(_ theme: PlaygroundTheme) -> UIImage? {
|
||||
return theme.image(PlaygroundThemeResourceKey.clockMin.rawValue, { theme in
|
||||
let color = theme.list.itemSecondaryTextColor
|
||||
return generateImage(CGSize(width: 11.0, height: 11.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(color.cgColor)
|
||||
let strokeWidth: CGFloat = 1.0
|
||||
context.fill(CGRect(x: (11.0 - strokeWidth) / 2.0, y: (11.0 - strokeWidth) / 2.0, width: 11.0 / 2.0 - strokeWidth, height: strokeWidth))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func PlaygroundTransactionLockIcon(_ theme: PlaygroundTheme) -> UIImage? {
|
||||
return theme.image(PlaygroundThemeResourceKey.transactionLockIcon.rawValue, { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Playground/EncryptedComment"), color: theme.list.itemSecondaryTextColor)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
public let ACCENT_COLOR = UIColor(rgb: 0x007ee5)
|
||||
public let NAVIGATION_BAR_THEME = NavigationBarTheme(
|
||||
buttonColor: ACCENT_COLOR,
|
||||
disabledButtonColor: UIColor(rgb: 0xd0d0d0),
|
||||
primaryTextColor: .black,
|
||||
backgroundColor: UIColor(rgb: 0xf7f7f7),
|
||||
enableBackgroundBlur: true,
|
||||
separatorColor: UIColor(rgb: 0xb1b1b1),
|
||||
badgeBackgroundColor: UIColor(rgb: 0xff3b30),
|
||||
badgeStrokeColor: UIColor(rgb: 0xff3b30),
|
||||
badgeTextColor: .white
|
||||
)
|
||||
public let THEME = PlaygroundTheme(
|
||||
info: PlaygroundInfoTheme(
|
||||
buttonBackgroundColor: UIColor(rgb: 0x32aafe),
|
||||
buttonTextColor: .white,
|
||||
incomingFundsTitleColor: UIColor(rgb: 0x00b12c),
|
||||
outgoingFundsTitleColor: UIColor(rgb: 0xff3b30)
|
||||
), transaction: PlaygroundTransactionTheme(
|
||||
descriptionBackgroundColor: UIColor(rgb: 0xf1f1f4),
|
||||
descriptionTextColor: .black
|
||||
), setup: PlaygroundSetupTheme(
|
||||
buttonFillColor: ACCENT_COLOR,
|
||||
buttonForegroundColor: .white,
|
||||
inputBackgroundColor: UIColor(rgb: 0xe9e9e9),
|
||||
inputPlaceholderColor: UIColor(rgb: 0x818086),
|
||||
inputTextColor: .black,
|
||||
inputClearButtonColor: UIColor(rgb: 0x7b7b81).withAlphaComponent(0.8)
|
||||
),
|
||||
list: PlaygroundListTheme(
|
||||
itemPrimaryTextColor: .black,
|
||||
itemSecondaryTextColor: UIColor(rgb: 0x8e8e93),
|
||||
itemPlaceholderTextColor: UIColor(rgb: 0xc8c8ce),
|
||||
itemDestructiveColor: UIColor(rgb: 0xff3b30),
|
||||
itemAccentColor: ACCENT_COLOR,
|
||||
itemDisabledTextColor: UIColor(rgb: 0x8e8e93),
|
||||
plainBackgroundColor: .white,
|
||||
blocksBackgroundColor: UIColor(rgb: 0xefeff4),
|
||||
itemPlainSeparatorColor: UIColor(rgb: 0xc8c7cc),
|
||||
itemBlocksBackgroundColor: .white,
|
||||
itemBlocksSeparatorColor: UIColor(rgb: 0xc8c7cc),
|
||||
itemHighlightedBackgroundColor: UIColor(rgb: 0xe5e5ea),
|
||||
sectionHeaderTextColor: UIColor(rgb: 0x6d6d72),
|
||||
freeTextColor: UIColor(rgb: 0x6d6d72),
|
||||
freeTextErrorColor: UIColor(rgb: 0xcf3030),
|
||||
inputClearButtonColor: UIColor(rgb: 0xcccccc)
|
||||
),
|
||||
statusBarStyle: .Black,
|
||||
navigationBar: NAVIGATION_BAR_THEME,
|
||||
keyboardAppearance: .light,
|
||||
alert: AlertControllerTheme(
|
||||
backgroundType: .light,
|
||||
backgroundColor: .white,
|
||||
separatorColor: UIColor(white: 0.9, alpha: 1.0),
|
||||
highlightedItemColor: UIColor(rgb: 0xe5e5ea),
|
||||
primaryColor: .black,
|
||||
secondaryColor: UIColor(rgb: 0x5e5e5e),
|
||||
accentColor: ACCENT_COLOR,
|
||||
contrastColor: .green,
|
||||
destructiveColor: UIColor(rgb: 0xff3b30),
|
||||
disabledColor: UIColor(rgb: 0xd0d0d0),
|
||||
controlBorderColor: .green,
|
||||
baseFontSize: 17.0
|
||||
),
|
||||
actionSheet: ActionSheetControllerTheme(
|
||||
dimColor: UIColor(white: 0.0, alpha: 0.4),
|
||||
backgroundType: .light,
|
||||
itemBackgroundColor: .white,
|
||||
itemHighlightedBackgroundColor: UIColor(white: 0.9, alpha: 1.0),
|
||||
standardActionTextColor: ACCENT_COLOR,
|
||||
destructiveActionTextColor: UIColor(rgb: 0xff3b30),
|
||||
disabledActionTextColor: UIColor(rgb: 0xb3b3b3),
|
||||
primaryTextColor: .black,
|
||||
secondaryTextColor: UIColor(rgb: 0x5e5e5e),
|
||||
controlAccentColor: ACCENT_COLOR,
|
||||
controlColor: UIColor(rgb: 0x7e8791),
|
||||
switchFrameColor: UIColor(rgb: 0xe0e0e0),
|
||||
switchContentColor: UIColor(rgb: 0x77d572),
|
||||
switchHandleColor: UIColor(rgb: 0xffffff),
|
||||
baseFontSize: 17.0
|
||||
)
|
||||
)
|
7
Swiftgram/Playground/Sources/main.m
Normal file
7
Swiftgram/Playground/Sources/main.m
Normal file
@ -0,0 +1,7 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, @"Application", @"AppDelegate");
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user